import { expect, stripAnsi } from '../../../test-utils'; import { CLIAlterationHook, CLIProductModuleDefinition } from '../../domain/product-module-definition'; import { validateAlterationHookKeys } from '../validate-alteration-hook-keys'; const hook = (key: string): CLIAlterationHook => ({ key, name: key, schema: [] }); const buildDefinition = (params: { alterationHooks?: CLIAlterationHook[]; applicationAlterationHooks?: CLIAlterationHook[]; memberAlterationHooks?: CLIAlterationHook[]; }): CLIProductModuleDefinition => ({ workflows: { quoteSchema: [], applicationSchema: [], claimsBlocks: [], alterationHooks: params.alterationHooks ?? [], applicationAlterationHooks: params.applicationAlterationHooks ?? [], memberAlterationHooks: params.memberAlterationHooks ?? [], }, }) as unknown as CLIProductModuleDefinition; const captureError = (definition: CLIProductModuleDefinition): Error | undefined => { try { validateAlterationHookKeys(definition); return undefined; } catch (error) { return error as Error; } }; describe('validateAlterationHookKeys', function () { it('does not throw when both lists are empty', function () { expect(() => validateAlterationHookKeys(buildDefinition({}))).to.not.throw(); }); it('does not throw when all keys are unique within each list', function () { const definition = buildDefinition({ alterationHooks: [hook('foo'), hook('bar')], applicationAlterationHooks: [hook('baz'), hook('qux')], memberAlterationHooks: [hook('quux')], }); expect(() => validateAlterationHookKeys(definition)).to.not.throw(); }); it('does not throw when the definition has no memberAlterationHooks list', function () { const definition = { workflows: { alterationHooks: [hook('foo')], applicationAlterationHooks: [hook('bar')], }, } as unknown as CLIProductModuleDefinition; expect(() => validateAlterationHookKeys(definition)).to.not.throw(); }); it('throws when the same key appears in both alterationHooks and applicationAlterationHooks', function () { const thrown = captureError( buildDefinition({ alterationHooks: [hook('shared')], applicationAlterationHooks: [hook('shared')], }), ); expect(thrown, 'expected an error to be thrown').to.not.equal(undefined); expect(stripAnsi(thrown!.message)).to.contain('"shared" — alterationHooks, applicationAlterationHooks'); }); it('throws and names the key when alterationHooks contains a duplicate', function () { const thrown = captureError( buildDefinition({ alterationHooks: [hook('foo'), hook('foo'), hook('bar')], }), ); expect(thrown, 'expected an error to be thrown').to.not.equal(undefined); expect(stripAnsi(thrown!.message)).to.contain('"foo" — alterationHooks ×2'); }); it('throws and names the key when applicationAlterationHooks contains a duplicate', function () { const thrown = captureError( buildDefinition({ applicationAlterationHooks: [hook('xyz'), hook('xyz'), hook('xyz')], }), ); expect(thrown, 'expected an error to be thrown').to.not.equal(undefined); expect(stripAnsi(thrown!.message)).to.contain('"xyz" — applicationAlterationHooks ×3'); }); it('throws and names the key when memberAlterationHooks contains a duplicate', function () { const thrown = captureError( buildDefinition({ memberAlterationHooks: [hook('change_insured_value'), hook('change_insured_value')], }), ); expect(thrown, 'expected an error to be thrown').to.not.equal(undefined); expect(stripAnsi(thrown!.message)).to.contain('"change_insured_value" — memberAlterationHooks ×2'); }); it('throws when the same key appears in both alterationHooks and memberAlterationHooks', function () { const thrown = captureError( buildDefinition({ alterationHooks: [hook('shared')], memberAlterationHooks: [hook('shared')], }), ); expect(thrown, 'expected an error to be thrown').to.not.equal(undefined); expect(stripAnsi(thrown!.message)).to.contain('"shared" — alterationHooks, memberAlterationHooks'); }); it('reports duplicates from within and across all three lists in the same error', function () { const thrown = captureError( buildDefinition({ alterationHooks: [hook('foo'), hook('foo'), hook('shared')], applicationAlterationHooks: [hook('bar'), hook('bar'), hook('shared')], memberAlterationHooks: [hook('baz'), hook('baz'), hook('shared')], }), ); expect(thrown, 'expected an error to be thrown').to.not.equal(undefined); const message = stripAnsi(thrown!.message); expect(message).to.contain('"foo" — alterationHooks ×2'); expect(message).to.contain('"bar" — applicationAlterationHooks ×2'); expect(message).to.contain('"baz" — memberAlterationHooks ×2'); expect(message).to.contain('"shared" — alterationHooks, applicationAlterationHooks, memberAlterationHooks'); }); });