Skip to content

Commit

Permalink
Merge pull request #152 from gravity-ui/fix-step-hooks
Browse files Browse the repository at this point in the history
fix(onboarding): dont call stepPass hook for passed steps
  • Loading branch information
vanilla-wave authored Feb 3, 2025
2 parents 8f5c403 + 6833f89 commit 32ff354
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 68 deletions.
6 changes: 3 additions & 3 deletions src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,10 @@ export class Controller<HintParams, Presets extends string, Steps extends string
}
}

this.events.emit('stepPass', {preset, step: stepSlug});
step?.hooks?.onStepPass?.();

await this.savePassedStepData(preset, stepSlug, () => {
step?.hooks?.onStepPass?.();
this.events.emit('stepPass', {preset, step: stepSlug});

if (step?.passMode !== 'onShowHint') {
this.logger.debug('Close hint on step', stepSlug);
this.closeHintByUser();
Expand Down
138 changes: 80 additions & 58 deletions src/tests/event-hooks.test.ts
Original file line number Diff line number Diff line change
@@ -1,85 +1,107 @@
import {getAnchorElement, getOptions, getOptionsWithHooks, waitForNextTick} from './utils';
import {Controller} from '../controller';

it('reachElement -> showHint called', async function () {
const options = getOptionsWithHooks();
const controller = new Controller(options);
describe('showHint event', () => {
it('reachElement -> showHint called', async function () {
const options = getOptionsWithHooks();
const controller = new Controller(options);

await controller.stepElementReached({
stepSlug: 'createSprint',
element: getAnchorElement(),
});

await controller.stepElementReached({
stepSlug: 'createSprint',
element: getAnchorElement(),
expect(options.hooks.showHint).toHaveBeenCalledWith(
{
preset: 'createProject',
step: 'createSprint',
},
controller,
);
});

expect(options.hooks.showHint).toHaveBeenCalledWith(
{
preset: 'createProject',
step: 'createSprint',
},
controller,
);
});
it('reachElement on NOT active preset -> NOT calls showHint', async function () {
const options = getOptionsWithHooks({activePresets: []});
const controller = new Controller(options);

it('reachElement on NOT active preset -> NOT calls showHint', async function () {
const options = getOptionsWithHooks({activePresets: []});
const controller = new Controller(options);
await controller.stepElementReached({
stepSlug: 'createSprint',
element: getAnchorElement(),
});

await controller.stepElementReached({
stepSlug: 'createSprint',
element: getAnchorElement(),
expect(options.hooks.showHint).not.toHaveBeenCalled();
});

expect(options.hooks.showHint).not.toHaveBeenCalled();
it('reachElement on passed step -> NOT calls showHint', async function () {
const options = getOptionsWithHooks();

const controller = new Controller(options);
await controller.stepElementReached({
stepSlug: 'createIssue',
element: getAnchorElement(),
});

expect(options.hooks.showHint).not.toHaveBeenCalled();
});
});

it('reachElement on passed step -> NOT calls showHint', async function () {
const options = getOptionsWithHooks();
describe('stepPass event', () => {
it('pass step on active preset -> calls passStep', async function () {
const options = getOptionsWithHooks();

const controller = new Controller(options);
await controller.passStep('createSprint');

const controller = new Controller(options);
await controller.stepElementReached({
stepSlug: 'createIssue',
element: getAnchorElement(),
expect(options.hooks.stepPass).toHaveBeenCalledWith(
{
preset: 'createProject',
step: 'createSprint',
},
controller,
);
});

expect(options.hooks.showHint).not.toHaveBeenCalled();
});
it('pass step on NOT active, but available preset -> calls passStep', async function () {
const options = getOptionsWithHooks({activePresets: []});

const controller = new Controller(options);
await controller.passStep('createSprint');

expect(options.hooks.stepPass).toHaveBeenCalledWith(
{
preset: 'createProject',
step: 'createSprint',
},
controller,
);
});

it('pass step on active preset -> calls passStep', async function () {
const options = getOptionsWithHooks();
it('pass step on NOT active and NOT available preset -> NOT calls passStep', async function () {
const options = getOptionsWithHooks({activePresets: [], availablePresets: []});

const controller = new Controller(options);
await controller.passStep('createSprint');
const controller = new Controller(options);
await controller.passStep('createSprint');

expect(options.hooks.stepPass).toHaveBeenCalledWith(
{
preset: 'createProject',
step: 'createSprint',
},
controller,
);
});
expect(options.hooks.stepPass).not.toHaveBeenCalled();
});

it('pass step on NOT active, but available preset -> calls passStep', async function () {
const options = getOptionsWithHooks({activePresets: []});
it('unknown preset -> NOT calls passStep', async function () {
const options = getOptionsWithHooks();

const controller = new Controller(options);
await controller.passStep('createSprint');
const controller = new Controller(options);
await controller.passStep('someUnknownStep');

expect(options.hooks.stepPass).toHaveBeenCalledWith(
{
preset: 'createProject',
step: 'createSprint',
},
controller,
);
});
expect(options.hooks.stepPass).not.toHaveBeenCalled();
});

it('pass step on NOT active and NOT available preset -> NOT calls passStep', async function () {
const options = getOptionsWithHooks({activePresets: [], availablePresets: []});
it('step already passed -> NOT calls passStep', async function () {
const options = getOptionsWithHooks();

const controller = new Controller(options);
await controller.passStep('createSprint');
const controller = new Controller(options);
await controller.passStep('openBoard');

expect(options.hooks.stepPass).not.toHaveBeenCalled();
expect(options.hooks.stepPass).not.toHaveBeenCalled();
});
});

describe('preset hooks', function () {
Expand Down
28 changes: 21 additions & 7 deletions src/tests/steps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,16 +195,30 @@ describe('pass step', function () {
});

describe('step hooks', function () {
it('pass step -> call onPass hook', async function () {
const options = getOptions();
const mock = jest.fn();
describe('onStepPass', () => {
it('pass step -> call onPass hook', async function () {
const options = getOptions();
const mock = jest.fn();

options.config.presets.createProject.steps[1].hooks = {onStepPass: mock};
options.config.presets.createProject.steps[1].hooks = {onStepPass: mock};

const controller = new Controller(options);
await controller.passStep('createSprint');
const controller = new Controller(options);
await controller.passStep('createSprint');

expect(mock).toHaveBeenCalled();
});

expect(mock).toHaveBeenCalled();
it('passedStep -> dont call hook', async function () {
const options = getOptions();
const mock = jest.fn();

options.config.presets.createProject.steps[0].hooks = {onStepPass: mock};

const controller = new Controller(options);
await controller.passStep('openBoard');

expect(mock).not.toHaveBeenCalled();
});
});

it('user close hint -> call onCloseHintByUser and onCloseHint', async function () {
Expand Down

0 comments on commit 32ff354

Please sign in to comment.