diff --git a/src/controller.ts b/src/controller.ts index b6120d7..8931fae 100644 --- a/src/controller.ts +++ b/src/controller.ts @@ -5,8 +5,13 @@ import type { PresetField, ProgressState, ReachElementParams, + CommonPreset, + EventsMap, + EventTypes, + PresetStatus, + ResolvedOptions, + UserPreset, } from './types'; -import {CommonPreset, EventsMap, EventTypes, PresetStatus, ResolvedOptions} from './types'; import {HintStore} from './hints/hintStore'; import {createLogger, Logger} from './logger'; import {createDebounceHandler} from './debounce'; @@ -138,7 +143,7 @@ export class Controller { - this.assertProgressLoaded(); + this.progressLoadedGuard(); this.options.onSave.progress(this.state.progress); }, 100); @@ -263,7 +268,7 @@ export class Controller { - let status: PresetStatus = 'unPassed'; + return userExistedPresetSlugs + .map((presetSlug) => { + let status: PresetStatus = 'unPassed'; + let slug: Presets | undefined; - const slug = this.resolvePresetSlug(presetSlug); + try { + slug = this.resolvePresetSlug(presetSlug); + } catch (e) { + status = 'unPassed'; + } - if (this.state.base.activePresets.includes(slug)) { - status = 'inProgress'; - } else if (this.state.progress?.finishedPresets.includes(slug)) { - status = 'finished'; - } + if (!slug) { + status = 'unPassed'; + } else if (this.state.base.activePresets.includes(slug)) { + status = 'inProgress'; + } else if (this.state.progress?.finishedPresets.includes(slug)) { + status = 'finished'; + } - return { - slug: presetSlug, - name: (this.options.config.presets[presetSlug] as CommonPreset) - .name, - description: ( - this.options.config.presets[presetSlug] as CommonPreset - ).description, - status, - }; - }); + return { + slug: presetSlug, + name: ( + this.options.config.presets[presetSlug] as CommonPreset + ).name, + description: ( + this.options.config.presets[presetSlug] as CommonPreset + ).description, + status, + }; + }) + .filter((userPreset) => Boolean(userPreset)) as UserPreset[]; } addPreset = async (presetArg: string | string[]) => { @@ -410,21 +425,23 @@ export class Controller { - this.ensurePresetExists(presetToRunSlug); + if (!this.presetExistsGuard(presetToRunSlug)) { + return false; + } const presetToRun = this.options.config.presets[presetToRunSlug]; const presetSlug = ( @@ -433,7 +450,7 @@ export class Controller { // take normal or find internal const presetSlug = this.resolvePresetSlug(presetToFinish); + if (!presetSlug) { + return false; + } + this.logger.debug('Preset finished', presetToFinish); this.events.emit('finishPreset', {preset: presetSlug}); @@ -490,7 +513,7 @@ export class Controller activePresetSlug !== presetSlug, @@ -504,6 +527,8 @@ export class Controller { this.logger.debug('Reset progress for', presetArg); await this.ensureRunning(); - this.assertProgressLoaded(); + this.progressLoadedGuard(); const presets = this.filterExistedPresets( Array.isArray(presetArg) ? presetArg : [presetArg], - ).map((preset) => this.resolvePresetSlug(preset)); + ) + .map((preset) => this.resolvePresetSlug(preset)) + .filter((preset) => Boolean(preset)) as Presets[]; this.state.progress.finishedPresets = this.state.progress.finishedPresets.filter( (preset) => !presets.includes(preset as Presets), @@ -613,7 +640,10 @@ export class Controller { + private resolvePresetSlug = (presetSlug: string) => { + if (!this.presetExistsGuard(presetSlug)) { + return undefined; + } const preset = this.options.config.presets[presetSlug]; return preset.type === 'combined' ? this.findInternalPreset(presetSlug) : presetSlug; @@ -623,16 +653,16 @@ export class Controller preset.internalPresets.includes(activePreset), - ) as Presets; + ) as Presets | undefined; const finishedInternalPreset = this.state.progress?.finishedPresets.find((finishedPreset) => preset.internalPresets.includes(finishedPreset), - ) as Presets; + ) as Presets | undefined; return activeInternalPreset || finishedInternalPreset; }; @@ -643,12 +673,12 @@ export class Controller { - const preset = this.options.config.presets[presetSlug as Presets]; - - if (!preset) { + if (!this.checkPresetExists(presetSlug)) { return false; } + const preset = this.options.config.presets[presetSlug as Presets]; + const isInternal = preset.type === 'internal'; if (isInternal) { return false; @@ -665,7 +695,7 @@ export class Controller void) { this.logger.debug('Save passed step data', preset, step); - this.assertProgressLoaded(); + this.progressLoadedGuard(); const passedSteps = this.state.progress.presetPassedSteps[preset] ?? []; @@ -751,7 +781,7 @@ export class Controller { + const prepareOptions = () => { + const options = getOptions(); + options.ignoreUnknownPresets = true; + + return options; + }; + let options = prepareOptions(); + + beforeEach(() => { + options = prepareOptions(); + }); + + it('run preset -> nothing', async function () { + const controller = new Controller(options); + + const result = await controller.runPreset('createQueue123'); + + expect(result).toBe(false); + expect(options.onSave.state).not.toHaveBeenCalled(); + expect(options.onSave.progress).not.toHaveBeenCalled(); + }); + + it('suggest not existed preset -> false', async function () { + const controller = new Controller(options); + + const result = await controller.suggestPresetOnce('unknownPreset'); + + expect(result).toBe(false); + expect(options.logger.logger.error).toHaveBeenCalled(); + }); + + it('run not existed preset -> return false', async function () { + const controller = new Controller(options); + + const result = await controller.runPreset('unknownPreset'); + + expect(result).toBe(false); + expect(options.logger.logger.error).toHaveBeenCalled(); + }); + }); }); it('resetToDefaultState -> hidden and empty ', async function () { diff --git a/src/tests/utils.ts b/src/tests/utils.ts index 85a0d1f..8f18637 100644 --- a/src/tests/utils.ts +++ b/src/tests/utils.ts @@ -57,6 +57,7 @@ export const getOptions = ( }, showHint: jest.fn(), debugMode: false, + ignoreUnknownPresets: false, logger: { level: 'error' as const, logger: { diff --git a/src/types.ts b/src/types.ts index a378749..39d11a0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -82,6 +82,13 @@ export type CombinedPreset = { pickPreset: () => InternalPresets | Promise; }; +export type UserPreset = { + slug: Presets; + name: string; + description: string; + status: PresetStatus; +}; + export type PresetFunctions = { goNextStep: VoidFn; goPrevStep: VoidFn; @@ -133,6 +140,7 @@ export type InitOptions) => void; logger?: LoggerOptions; + ignoreUnknownPresets?: boolean; debugMode?: boolean; plugins?: OnboardingPlugin[]; hooks?: {