diff --git a/shepherd.js/src/tour.ts b/shepherd.js/src/tour.ts index 6255ea691..d1e4824df 100644 --- a/shepherd.js/src/tour.ts +++ b/shepherd.js/src/tour.ts @@ -400,10 +400,14 @@ export class Tour extends Evented { * @private */ _showStep(step: Step) { + // `currentStep` is `undefined` until a step has shown, so normalize to + // `null` to keep `previous` consistent across every path into `show` + const previous = this.currentStep ?? null; + this.currentStep = step; this.trigger('show', { step, - previous: this.currentStep + previous }); step.show(); diff --git a/shepherd.js/test/unit/tour.spec.js b/shepherd.js/test/unit/tour.spec.js index 28f670b60..4babff03f 100644 --- a/shepherd.js/test/unit/tour.spec.js +++ b/shepherd.js/test/unit/tour.spec.js @@ -533,6 +533,51 @@ describe('Tour | Top-Level Class', function () { ).toBeFalsy(); }); + it('triggers show with the step that was showing before as `previous`', function () { + const shows = []; + instance.on('show', ({ step, previous }) => + shows.push({ step, previous }) + ); + + instance.start(); + instance.next(); + + const [firstShow, secondShow] = shows; + + expect(firstShow.step.id).toBe('test'); + expect( + firstShow.previous, + 'there is no previous step on the first show' + ).toBeNull(); + + expect(secondShow.step.id).toBe('test2'); + expect( + secondShow.previous.id, + '`previous` is the step that was showing before' + ).toBe('test'); + expect( + secondShow.previous, + '`previous` is not the same object as `step`' + ).not.toBe(secondShow.step); + }); + + it('reports `previous` as null when no step was showing before', function () { + // `removeStep` clears `currentStep` to `undefined` before showing the + // next step, so `previous` has to be normalized on that path too + instance.start(); + + let previousStep; + instance.on('show', ({ previous }) => (previousStep = previous)); + + instance.removeStep('test'); + + expect(instance.getCurrentStep().id).toBe('test2'); + expect( + previousStep, + '`previous` is null rather than undefined when nothing was showing' + ).toBeNull(); + }); + it('showOn determines which steps to skip', function () { instance.start(); expect(instance.getCurrentStep().id).toBe('test');