From a4c397454b70cdb66fc9558f1eed54d5701dac96 Mon Sep 17 00:00:00 2001 From: vanilla-wave Date: Tue, 25 Feb 2025 19:29:05 +0100 Subject: [PATCH 1/3] test(onboarding): add tests for closeHint event subscription --- src/tests/event-hooks.test.ts | 109 ++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/src/tests/event-hooks.test.ts b/src/tests/event-hooks.test.ts index 888b4fd..cfcb08a 100644 --- a/src/tests/event-hooks.test.ts +++ b/src/tests/event-hooks.test.ts @@ -287,6 +287,115 @@ 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(); + }); + }); + it('passStep', async function () { const controller = new Controller(getOptions()); From bdc97e458b982b3ea5419086c65333605e91513c Mon Sep 17 00:00:00 2001 From: vanilla-wave Date: Tue, 25 Feb 2025 19:41:35 +0100 Subject: [PATCH 2/3] feat(onboarding): add closeHintByUser event --- src/controller.ts | 4 ++ src/tests/event-hooks.test.ts | 97 +++++++++++++++++++++++++++++++++++ src/types.ts | 1 + 3 files changed, 102 insertions(+) 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('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']}; }; From 486a4eedb0207030f3fc4eb44dc7b891e17d3684 Mon Sep 17 00:00:00 2001 From: vanilla-wave Date: Tue, 25 Feb 2025 19:47:13 +0100 Subject: [PATCH 3/3] refactor(onboarding): refactor beforeShowHint event tests --- src/tests/event-hooks.test.ts | 78 +++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/src/tests/event-hooks.test.ts b/src/tests/event-hooks.test.ts index 731b38a..96957fe 100644 --- a/src/tests/event-hooks.test.ts +++ b/src/tests/event-hooks.test.ts @@ -221,50 +221,68 @@ describe('preset hooks', function () { }); }); describe('event subscriptions', function () { - it('beforeShowHint', async function () { - const controller = new Controller(getOptions()); + describe('beforeShowHint', () => { + 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('beforeShowHint with cancel -> call all hooks', async function () { - const controller = new Controller(getOptions()); + it('cancel hint show -> hint still not open', 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 () {