Skip to content

Commit 7777542

Browse files
committed
Increase test coverage
1 parent 14df5f3 commit 7777542

File tree

2 files changed

+78
-33
lines changed

2 files changed

+78
-33
lines changed

tests/60-e2e/00-orchestrator.spec.ts

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,58 @@ describe('E2E: Full Generation Orchestrator', () => {
2828
it('should generate auth-related files when security spec is provided', async () => {
2929
const project = createTestProject();
3030
const config: GeneratorConfig = { input: '', output: '/generated', options: { generateServices: true } as any };
31-
// Use the spec with security schemes
3231
await generateFromConfig(config, project, { spec: securitySpec });
3332

3433
const filePaths = project.getSourceFiles().map(f => f.getFilePath());
35-
36-
// This covers the entire `if (Object.keys(securitySchemes).length > 0)` block in orchestrator.ts
3734
expect(filePaths).toContain('/generated/auth/auth.interceptor.ts');
3835
expect(filePaths).toContain('/generated/auth/auth.tokens.ts');
39-
expect(filePaths).toContain('/generated/auth/oauth.service.ts'); // because oauth2 is in securitySpec
36+
expect(filePaths).toContain('/generated/auth/oauth.service.ts');
37+
});
38+
39+
it('should handle specs with only unsupported security schemes', async () => {
40+
const project = createTestProject();
41+
const config: GeneratorConfig = { input: '', output: '/generated', options: { generateServices: true } as any };
42+
const unsupportedSecuritySpec = {
43+
openapi: '3.0.0', info: { title: 'Test API', version: '1.0.0' }, paths: {},
44+
components: {
45+
securitySchemes: {
46+
CookieAuth: { type: 'apiKey', in: 'cookie', name: 'session_id' },
47+
},
48+
},
49+
};
50+
51+
await generateFromConfig(config, project, { spec: unsupportedSecuritySpec });
52+
53+
const filePaths = project.getSourceFiles().map(f => f.getFilePath());
54+
expect(filePaths).toContain('/generated/auth/auth.tokens.ts');
55+
expect(filePaths).not.toContain('/generated/auth/auth.interceptor.ts');
56+
expect(filePaths).not.toContain('/generated/auth/oauth.service.ts');
57+
expect(filePaths).toContain('/generated/providers.ts');
58+
const providerContent = project.getSourceFileOrThrow('/generated/providers.ts').getText();
59+
expect(providerContent).not.toContain('apiKey');
60+
expect(providerContent).not.toContain('bearerToken');
61+
});
62+
63+
it('should default to generating services and tests when options are absent', async () => {
64+
const project = await runGeneratorWithConfig(coverageSpec, {});
65+
const filePaths = project.getSourceFiles().map(f => f.getFilePath());
66+
67+
expect(filePaths).toContain('/generated/services/users.service.ts');
68+
expect(filePaths).toContain('/generated/services/users.service.spec.ts');
69+
});
70+
71+
it('should default to generating admin tests when admin option is present but test option is absent', async () => {
72+
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
73+
74+
await runGeneratorWithConfig(coverageSpec, { admin: true });
75+
76+
const logCalls = consoleSpy.mock.calls.flat();
77+
78+
// ** THE FIX **: Use the correct assertion syntax for checking array contents.
79+
expect(logCalls).toEqual(expect.arrayContaining(['🚀 Generating Admin UI...']));
80+
expect(logCalls).toEqual(expect.arrayContaining([expect.stringContaining('Test generation for admin UI is stubbed.')]));
81+
82+
consoleSpy.mockRestore();
4083
});
4184

4285
it('should skip service generation when config is false', async () => {
@@ -61,7 +104,11 @@ describe('E2E: Full Generation Orchestrator', () => {
61104
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
62105
await runGeneratorWithConfig(coverageSpec, { admin: true, generateAdminTests: false });
63106
const logCalls = consoleSpy.mock.calls.flat();
64-
expect(logCalls).not.toContain(expect.stringContaining('Test generation for admin UI is stubbed.'));
107+
108+
// ** THE FIX **: Use a robust check for the absence of a substring.
109+
const hasAdminTestLog = logCalls.some(log => log.includes('Test generation for admin UI is stubbed.'));
110+
expect(hasAdminTestLog).toBe(false);
111+
65112
consoleSpy.mockRestore();
66113
});
67114

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { describe, it, expect } from 'vitest';
22
import { ServiceTestGenerator } from '@src/service/emit/test/service-test-generator.js';
33
import { SwaggerParser } from '@src/core/parser.js';
4-
import { GeneratorConfig } from '@src/core/types.js';
4+
import { GeneratorConfig, PathInfo } from '@src/core/types.js';
55
import { fullCRUD_Users, adminFormSpec, finalCoverageSpec, branchCoverageSpec } from '../shared/specs.js';
66
import { createTestProject } from '../shared/helpers.js';
77
import { groupPathsByController } from '@src/service/parse.js';
88
import { TypeGenerator } from '../../src/service/emit/type/type.generator.js';
9-
import { MockDataGenerator } from '../../src/service/emit/test/mock-data.generator.js';
9+
import { MockDataGenerator } from "../../src/service/emit/test/mock-data.generator";
1010

1111
/**
1212
* @fileoverview
@@ -31,7 +31,6 @@ describe('Generated Code: Service Test Generators', () => {
3131
const mockString = generator.generate('User');
3232
const mock = JSON.parse(mockString);
3333

34-
// `id` is readOnly, so it's excluded from the mock for a request body.
3534
expect(mock).not.toHaveProperty('id');
3635
expect(mock).toHaveProperty('name', 'string-value');
3736
expect(mock.email).toBe('[email protected]');
@@ -42,11 +41,11 @@ describe('Generated Code: Service Test Generators', () => {
4241
const mockString = generator.generate('Widget');
4342
const mock = JSON.parse(mockString);
4443

45-
expect(mock.launchDate).toBeTypeOf('string'); // From format: 'date-time'
44+
expect(mock.launchDate).toBeTypeOf('string');
4645
expect(Array.isArray(mock.uniqueTags)).toBe(true);
4746
expect(mock.config).toBeTypeOf('object');
4847
expect(mock.config).toHaveProperty('key');
49-
expect(mock.config).not.toHaveProperty('readOnlyKey'); // Should be excluded
48+
expect(mock.config).not.toHaveProperty('readOnlyKey');
5049
});
5150

5251
it('should return an empty object for an unresolvable schema', () => {
@@ -57,18 +56,23 @@ describe('Generated Code: Service Test Generators', () => {
5756
});
5857

5958
describe('ServiceTestGenerator', () => {
60-
it('should generate a valid Angular spec file for a full CRUD service', () => {
59+
const setupTestGen = (spec: object) => {
6160
const project = createTestProject();
6261
const config: GeneratorConfig = {
6362
input: '',
6463
output: '/out',
6564
clientName: 'Api',
6665
options: { dateType: 'string', enumStyle: 'enum' },
6766
};
68-
const parser = new SwaggerParser(fullCRUD_Users as any, config);
67+
const parser = new SwaggerParser(spec as any, config);
6968
new TypeGenerator(parser, project, config).generate('/out');
7069
const testGenerator = new ServiceTestGenerator(parser, project, config);
7170
const controllerGroups = groupPathsByController(parser);
71+
return { testGenerator, controllerGroups, project, parser };
72+
};
73+
74+
it('should generate a valid Angular spec file for a full CRUD service', () => {
75+
const { testGenerator, controllerGroups, project } = setupTestGen(fullCRUD_Users);
7276
testGenerator.generateServiceTestFile('Users', controllerGroups['Users'], '/out/services');
7377

7478
const specFile = project.getSourceFileOrThrow('/out/services/users.service.spec.ts');
@@ -79,43 +83,37 @@ describe('Generated Code: Service Test Generators', () => {
7983
});
8084

8185
it('should generate tests for primitive request bodies and param refs', () => {
82-
const project = createTestProject();
83-
const config: GeneratorConfig = {
84-
input: '',
85-
output: '/out',
86-
clientName: 'TestApi',
87-
options: { dateType: 'string', enumStyle: 'enum' },
88-
};
8986
const spec = { ...finalCoverageSpec, ...branchCoverageSpec };
90-
const parser = new SwaggerParser(spec as any, config);
91-
new TypeGenerator(parser, project, config).generate('/out');
92-
const testGenerator = new ServiceTestGenerator(parser, project, config);
93-
const controllerGroups = groupPathsByController(parser);
87+
const { testGenerator, controllerGroups, project } = setupTestGen(spec);
9488

9589
if (controllerGroups['ParamIsRef']) {
9690
testGenerator.generateServiceTestFile('ParamIsRef', controllerGroups['ParamIsRef'], '/out/services');
9791
const paramIsRefTest = project.getSourceFileOrThrow('/out/services/paramIsRef.service.spec.ts').getText();
98-
// This is the real test. The generator's implementation is now fixed, so this will pass.
9992
expect(paramIsRefTest).toContain('import { User } from "../models";');
10093
}
10194
});
10295

10396
it('should handle operations where the parameters key is missing', () => {
104-
const project = createTestProject();
105-
const config: GeneratorConfig = { input: '', output: '/out', options: {} as any };
106-
const parser = new SwaggerParser(branchCoverageSpec as any, config);
107-
new TypeGenerator(parser, project, config).generate('/out');
108-
const testGenerator = new ServiceTestGenerator(parser, project, config);
109-
const controllerGroups = groupPathsByController(parser);
110-
111-
// This should not throw an error
97+
const { testGenerator, controllerGroups, project } = setupTestGen(branchCoverageSpec);
11298
testGenerator.generateServiceTestFile('NoParamsKey', controllerGroups['NoParamsKey'], '/out/services');
11399

114100
const specFile = project.getSourceFileOrThrow('/out/services/noParamsKey.service.spec.ts');
115101
const content = specFile.getText();
116102

117-
// The generated test should have a method call with no arguments
118103
expect(content).toContain('service.getNoParamsKey().subscribe');
119104
});
105+
106+
it('collectModelImports should return an empty set if operations are undefined', () => {
107+
const { parser } = setupTestGen(fullCRUD_Users);
108+
// We only need the generator instance to call the private method, project doesn't matter here.
109+
const testGenerator = new ServiceTestGenerator(parser, createTestProject(), {} as any);
110+
111+
// This directly calls the private method with undefined to hit the uncovered branch.
112+
// We cast to `any` to bypass TypeScript's type checking for the test.
113+
const result = (testGenerator as any).collectModelImports(undefined);
114+
115+
expect(result).toBeInstanceOf(Set);
116+
expect(result.size).toBe(0);
117+
});
120118
});
121119
});

0 commit comments

Comments
 (0)