diff --git a/src/controller.ts b/src/controller.ts index 6591d13..d189e6a 100644 --- a/src/controller.ts +++ b/src/controller.ts @@ -336,6 +336,10 @@ export class Controller { + it('element reached -> trigger event', async function () { + const controller = new Controller(getOptions()); - const mock = jest.fn(); - controller.events.subscribe('beforeShowHint', mock); + const mock = jest.fn(); + controller.events.subscribe('beforeShowHint', mock); - await controller.stepElementReached({ - stepSlug: 'createSprint', - element: getAnchorElement(), + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); + + expect(mock).toHaveBeenCalled(); }); - expect(mock).toHaveBeenCalled(); - }); + it('element reached -> hint shown', async function () { + const controller = new Controller(getOptions()); - it('beforeShowHint with cancel -> no hint', async function () { - const controller = new Controller(getOptions()); + const mock = jest.fn(); + controller.events.subscribe('beforeShowHint', mock); - const mock = jest.fn(() => false); - controller.events.subscribe('beforeShowHint', mock); + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); - await controller.stepElementReached({ - stepSlug: 'createSprint', - element: getAnchorElement(), + expect(controller.hintStore.state.open).toBe(true); }); - expect(controller.hintStore.state.open).toBe(false); - }); + it('cancel hint show -> hint still not open', async function () { + const controller = new Controller(getOptions()); - it('beforeShowHint with cancel -> call all hooks', async function () { - const controller = new Controller(getOptions()); - - const mock1 = jest.fn(() => false); - const mock2 = jest.fn(); + // return false to cancel hint show + const mock = jest.fn(() => false); + controller.events.subscribe('beforeShowHint', mock); - controller.events.subscribe('beforeShowHint', mock1); - controller.events.subscribe('beforeShowHint', mock2); + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); - await controller.stepElementReached({ - stepSlug: 'createSprint', - element: getAnchorElement(), + expect(controller.hintStore.state.open).toBe(false); }); - expect(mock1).toHaveBeenCalled(); - expect(mock2).toHaveBeenCalled(); + it('cancel hint show -> call all hooks', async function () { + const controller = new Controller(getOptions()); + + // return false to cancel hint show + const mock1 = jest.fn(() => false); + const mock2 = jest.fn(); + + controller.events.subscribe('beforeShowHint', mock1); + controller.events.subscribe('beforeShowHint', mock2); + + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); + + expect(mock1).toHaveBeenCalled(); + expect(mock2).toHaveBeenCalled(); + }); }); it('showHint', async function () { @@ -287,6 +305,212 @@ describe('event subscriptions', function () { ); }); + describe('closeHint event', () => { + it('pass step -> trigger event', async function () { + const controller = new Controller(getOptions()); + + const mock = jest.fn(); + controller.events.subscribe('closeHint', mock); + + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); + await controller.passStep('createSprint'); + + expect(mock).toHaveBeenCalledWith( + { + hint: { + preset: 'createProject', + step: { + slug: 'createSprint', + name: '', + description: '', + }, + }, + }, + controller, + ); + }); + + it('element disappeared -> trigger event', async function () { + const controller = new Controller(getOptions()); + + const mock = jest.fn(); + controller.events.subscribe('closeHint', mock); + + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); + controller.stepElementDisappeared('createSprint'); + + expect(mock).toHaveBeenCalledWith( + { + hint: { + preset: 'createProject', + step: { + slug: 'createSprint', + name: '', + description: '', + }, + }, + }, + controller, + ); + }); + + it('user close hint -> trigger event', async function () { + const controller = new Controller(getOptions()); + + const mock = jest.fn(); + controller.events.subscribe('closeHint', mock); + + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); + controller.closeHint('createSprint'); + + expect(mock).toHaveBeenCalledWith( + { + hint: { + preset: 'createProject', + step: { + slug: 'createSprint', + name: '', + description: '', + }, + }, + }, + controller, + ); + }); + + it('no open hint -> NOT trigger event', async function () { + const controller = new Controller(getOptions()); + + const mock = jest.fn(); + controller.events.subscribe('closeHint', mock); + + controller.closeHint(); + + expect(mock).not.toHaveBeenCalled(); + }); + + it('try close other hint -> NOT trigger event', async function () { + const controller = new Controller(getOptions()); + + const mock = jest.fn(); + controller.events.subscribe('closeHint', mock); + + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); + controller.closeHint('openBoard'); + + expect(mock).not.toHaveBeenCalled(); + }); + }); + + describe('closeHintByUser event', () => { + it('pass step -> trigger event', async function () { + const controller = new Controller(getOptions()); + + const mock = jest.fn(); + controller.events.subscribe('closeHintByUser', mock); + + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); + await controller.passStep('createSprint'); + + expect(mock).toHaveBeenCalledWith( + { + hint: { + preset: 'createProject', + step: { + slug: 'createSprint', + name: '', + description: '', + }, + }, + }, + controller, + ); + }); + + it('element disappeared -> NOT trigger event', async function () { + const controller = new Controller(getOptions()); + + const mock = jest.fn(); + controller.events.subscribe('closeHintByUser', mock); + + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); + controller.stepElementDisappeared('createSprint'); + + expect(mock).not.toHaveBeenCalled(); + }); + + it('user close hint -> trigger event', async function () { + const controller = new Controller(getOptions()); + + const mock = jest.fn(); + controller.events.subscribe('closeHintByUser', mock); + + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); + controller.closeHintByUser('createSprint'); + + expect(mock).toHaveBeenCalledWith( + { + hint: { + preset: 'createProject', + step: { + slug: 'createSprint', + name: '', + description: '', + }, + }, + }, + controller, + ); + }); + + it('no open hint -> NOT trigger event', async function () { + const controller = new Controller(getOptions()); + + const mock = jest.fn(); + controller.events.subscribe('closeHintByUser', mock); + + controller.closeHintByUser(); + + expect(mock).not.toHaveBeenCalled(); + }); + + it('try close other hint -> NOT trigger event', async function () { + const controller = new Controller(getOptions()); + + const mock = jest.fn(); + controller.events.subscribe('closeHintByUser', mock); + + await controller.stepElementReached({ + stepSlug: 'createSprint', + element: getAnchorElement(), + }); + controller.closeHintByUser('openBoard'); + + expect(mock).not.toHaveBeenCalled(); + }); + }); + it('passStep', async function () { const controller = new Controller(getOptions()); diff --git a/src/types.ts b/src/types.ts index d4b742d..46c2f3e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -183,6 +183,7 @@ export type EventsMap< stateChange: {state: Controller['state']}; hintDataChanged: {state: HintState}; closeHint: {hint: Pick, 'preset' | 'step'>}; + closeHintByUser: {hint: Pick, 'preset' | 'step'>}; init: {}; wizardStateChanged: {wizardState: BaseState['wizardState']}; };