import sinon from 'sinon'; import fs from 'fs'; import { expect } from '../../../test-utils'; import { checkValidProductModuleDirectory } from '../check-valid-product-module-directory'; import { RootConfigWrite } from '../../domain/root-config'; const baseConfig: RootConfigWrite = { settings: {}, scheduledFunctions: [], fulfillmentTypes: [], stack: 'root-node-24', productModuleName: 'Test Module', productModuleKey: 'test_module', organizationId: '00000000-0000-0000-0000-000000000001', host: 'http://localhost:4000', alterationHooks: [], applicationAlterationHooks: [], memberAlterationHooks: [], codeFileOrder: ['main.js'], }; describe('checkValidProductModuleDirectory - TypeScript entry point validation', () => { const sandbox = sinon.createSandbox(); afterEach(() => { sandbox.restore(); }); it('should throw when typescriptProductModuleCode is enabled but code/src/index.ts does not exist', () => { sandbox.stub(fs, 'existsSync').returns(false); sandbox.stub(fs, 'readdirSync').returns([]); sandbox.stub(fs, 'mkdirSync'); const config: RootConfigWrite = { ...baseConfig, settings: { typescriptProductModuleCode: true }, }; expect(() => checkValidProductModuleDirectory({ productModuleConfig: config })) .to.throw(Error) .with.property('message') .that.contains('TypeScript entry file') .and.contains('code/src/index.ts'); }); it('should not throw when typescriptProductModuleCode is enabled and code/src/index.ts exists', () => { sandbox.stub(fs, 'existsSync').returns(true); sandbox.stub(fs, 'readdirSync').returns([]); sandbox.stub(fs, 'mkdirSync'); const config: RootConfigWrite = { ...baseConfig, settings: { typescriptProductModuleCode: true }, }; expect(() => checkValidProductModuleDirectory({ productModuleConfig: config })).to.not.throw(); }); it('should not check for code/src/index.ts when typescriptProductModuleCode is not enabled', () => { const existsSyncStub = sandbox.stub(fs, 'existsSync').returns(true); const readdirStub = sandbox.stub(fs, 'readdirSync'); readdirStub.withArgs('workflows/alteration-hooks').returns([] as any); readdirStub.withArgs('workflows/application-alteration-hooks').returns([] as any); readdirStub.withArgs('workflows/member-alteration-hooks').returns([] as any); readdirStub.withArgs('code').returns(['main.js', 'unit-tests'] as any); readdirStub.returns([] as any); sandbox.stub(fs, 'mkdirSync'); const config: RootConfigWrite = { ...baseConfig, settings: {}, codeFileOrder: ['main.js'], }; checkValidProductModuleDirectory({ productModuleConfig: config }); const calledWithEntryPoint = existsSyncStub.getCalls().some((call) => { return (call.args[0] as string).includes('index.ts'); }); expect(calledWithEntryPoint).to.equal(false); }); }); describe('checkValidProductModuleDirectory - member alteration hook validation', function () { const sandbox = sinon.createSandbox(); const stubDirectory = (memberAlterationHookFileNames: string[]) => { sandbox.stub(fs, 'existsSync').returns(true); const readdirStub = sandbox.stub(fs, 'readdirSync'); readdirStub.withArgs('workflows/alteration-hooks').returns([] as any); readdirStub.withArgs('workflows/application-alteration-hooks').returns([] as any); readdirStub.withArgs('workflows/member-alteration-hooks').returns(memberAlterationHookFileNames as any); readdirStub.withArgs('code').returns(['main.js', 'unit-tests'] as any); readdirStub.returns([] as any); sandbox.stub(fs, 'mkdirSync'); }; afterEach(function () { sandbox.restore(); }); it('should not throw when every member alteration hook key has a matching schema file', function () { stubDirectory(['change_insured_value.json']); const config: RootConfigWrite = { ...baseConfig, memberAlterationHooks: [{ key: 'change_insured_value', name: 'Change insured value' }], }; expect(() => checkValidProductModuleDirectory({ productModuleConfig: config })).to.not.throw(); }); it('should throw when a member alteration hook key has no schema file', function () { stubDirectory([]); const config: RootConfigWrite = { ...baseConfig, memberAlterationHooks: [{ key: 'change_insured_value', name: 'Change insured value' }], }; expect(() => checkValidProductModuleDirectory({ productModuleConfig: config })) .to.throw(Error) .with.property('message') .that.contains('Member alteration hook mismatch') .and.contains('change_insured_value.json') .and.contains('memberAlterationHooks'); }); it('should throw when a schema file has no member alteration hook entry in the config', function () { stubDirectory(['orphan_hook.json']); expect(() => checkValidProductModuleDirectory({ productModuleConfig: baseConfig })) .to.throw(Error) .with.property('message') .that.contains('Member alteration hook mismatch') .and.contains('orphan_hook.json'); }); it('should not throw when the config has no memberAlterationHooks key at all', function () { stubDirectory([]); const config = { ...baseConfig } as RootConfigWrite; delete (config as Partial).memberAlterationHooks; expect(() => checkValidProductModuleDirectory({ productModuleConfig: config })).to.not.throw(); }); it('should create the member alteration hooks folder when it does not exist', function () { const existsSyncStub = sandbox.stub(fs, 'existsSync'); existsSyncStub.withArgs('workflows/member-alteration-hooks').returns(false); existsSyncStub.returns(true); const readdirStub = sandbox.stub(fs, 'readdirSync'); readdirStub.withArgs('code').returns(['main.js', 'unit-tests'] as any); readdirStub.returns([] as any); const mkdirStub = sandbox.stub(fs, 'mkdirSync'); checkValidProductModuleDirectory({ productModuleConfig: baseConfig }); sandbox.assert.calledWith(mkdirStub, 'workflows/member-alteration-hooks'); }); });