Skip to content

Commit d6cf11d

Browse files
committed
Increase test coverage
1 parent 167e694 commit d6cf11d

File tree

3 files changed

+86
-8
lines changed

3 files changed

+86
-8
lines changed

src/service/emit/service/service-method.generator.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ export class ServiceMethodGenerator {
8484

8585
const requestBody = operation.requestBody;
8686
if (requestBody) {
87-
// FIX: Look at the first available content type's schema, not just application/json.
8887
const content = requestBody.content?.[Object.keys(requestBody.content)[0]];
8988
if (content?.schema) {
9089
let bodyType = getTypeScriptType(content.schema as SwaggerDefinition, this.config, knownTypes);
@@ -193,10 +192,8 @@ export class ServiceMethodGenerator {
193192
].map(overload => {
194193
const hasOptionalParam = parameters.some(p => p.hasQuestionToken);
195194
if (hasOptionalParam) {
196-
const optionsParam = overload.parameters.find(p => p.name === 'options');
197-
if (optionsParam) {
198-
optionsParam.hasQuestionToken = true;
199-
}
195+
// This is guaranteed to exist in our templates.
196+
overload.parameters.find(p => p.name === 'options')!.hasQuestionToken = true;
200197
}
201198
return overload;
202199
});

tests/30-emit-service/01-service-method-generator.spec.ts

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ const serviceMethodGenSpec = {
4141
parameters: [{ name: 'limit', in: 'query', type: 'integer' }] // No 'schema' key
4242
}
4343
},
44-
4544
'/post-no-req-schema': {
4645
post: {
4746
operationId: 'postNoReqSchema',
@@ -50,6 +49,26 @@ const serviceMethodGenSpec = {
5049
responses: { '204': {} }
5150
}
5251
},
52+
// NEW paths for coverage
53+
'/all-required/{id}': {
54+
post: {
55+
tags: ['RequiredParams'],
56+
operationId: 'postAllRequired',
57+
parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],
58+
requestBody: {
59+
required: true,
60+
content: { 'application/json': { schema: { type: 'string' } } }
61+
}
62+
}
63+
},
64+
'/form-data-no-consumes': {
65+
post: {
66+
tags: ['FormData'],
67+
operationId: 'postFormDataNoConsumes',
68+
// No 'consumes' array here
69+
parameters: [{ name: 'file', in: 'formData', type: 'file' }]
70+
}
71+
}
5372
}
5473
};
5574

@@ -121,6 +140,37 @@ describe('Emitter: ServiceMethodGenerator', () => {
121140
});
122141
});
123142

143+
describe('Overload Generation', () => {
144+
it('should make options optional if other parameters are optional', () => {
145+
const { methodGen, serviceClass, parser } = createTestEnvironment();
146+
// This operation has an optional query param
147+
const op = parser.operations.find(o => o.operationId === 'getWithSwagger2Param')!;
148+
op.methodName = 'getWithSwagger2Param';
149+
methodGen.addServiceMethod(serviceClass, op);
150+
151+
const method = serviceClass.getMethodOrThrow('getWithSwagger2Param');
152+
const responseOverload = method.getOverloads().find(o => o.getReturnType().getText().includes('HttpResponse'))!;
153+
const optionsParam = responseOverload.getParameters().find(p => p.getName() === 'options')!;
154+
155+
// because 'limit' is optional, 'options' must also be optional.
156+
expect(optionsParam.hasQuestionToken()).toBe(true);
157+
});
158+
159+
it('should keep options required if all other parameters are required', () => {
160+
const { methodGen, serviceClass, parser } = createTestEnvironment();
161+
const op = parser.operations.find(o => o.operationId === 'postAllRequired')!;
162+
op.methodName = 'postAllRequired';
163+
methodGen.addServiceMethod(serviceClass, op);
164+
165+
const method = serviceClass.getMethodOrThrow('postAllRequired');
166+
const responseOverload = method.getOverloads().find(o => o.getReturnType().getText().includes('HttpResponse'))!;
167+
const optionsParam = responseOverload.getParameters().find(p => p.getName() === 'options')!;
168+
169+
// because 'id' and 'body' are required, 'options' for observe:'response' remains required.
170+
expect(optionsParam.hasQuestionToken()).toBe(false);
171+
});
172+
});
173+
124174
describe('Parameter and Body Generation', () => {
125175
const { methodGen, serviceClass, parser } = createTestEnvironment();
126176

@@ -171,6 +221,30 @@ describe('Emitter: ServiceMethodGenerator', () => {
171221
const param = impl.getParameters().find(p => p.getType().getText() === 'string');
172222
expect(param?.getName()).toBe('body');
173223
});
224+
225+
it('should handle request body without a schema', () => {
226+
const { methodGen, serviceClass, parser } = createTestEnvironment();
227+
const op = parser.operations.find(o => o.operationId === 'postNoReqSchema')!;
228+
op.methodName = 'postNoReqSchema';
229+
methodGen.addServiceMethod(serviceClass, op);
230+
231+
const method = serviceClass.getMethodOrThrow('postNoReqSchema');
232+
const bodyParam = method.getParameters().find(p => p.getName() === 'body')!;
233+
expect(bodyParam).toBeDefined();
234+
expect(bodyParam.getType().getText()).toBe('unknown');
235+
});
236+
237+
it('should handle formData params when consumes array is missing', () => {
238+
const { methodGen, serviceClass, parser } = createTestEnvironment();
239+
const op = parser.operations.find(o => o.operationId === 'postFormDataNoConsumes')!;
240+
op.methodName = 'postFormDataNoConsumes';
241+
methodGen.addServiceMethod(serviceClass, op);
242+
243+
const body = serviceClass.getMethodOrThrow('postFormDataNoConsumes').getBodyText()!;
244+
// isMultipartForm will be false, so it falls through. Since there's no other body, 'null' is used.
245+
expect(body).toContain('return this.http.post(url, null, requestOptions);');
246+
expect(body).not.toContain('new FormData()');
247+
});
174248
});
175249

176250
describe('Response Type Resolution', () => {
@@ -204,7 +278,6 @@ describe('Emitter: ServiceMethodGenerator', () => {
204278
});
205279
});
206280

207-
// --- Existing Tests from original file for regression ---
208281
it('should fall back to a generic `body: unknown` parameter for non-json content', () => {
209282
const { methodGen, serviceClass, parser } = createTestEnvironment();
210283
const operation = parser.operations.find(op => op.operationId === 'allParams')!;

tests/shared/specs.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,10 +776,18 @@ export const branchCoverageSpec = {
776776
},
777777
},
778778
},
779+
// FIX: Add the new PATCH resource path here
780+
'/patch-resource/{id}': {
781+
patch: {
782+
tags: ['PatchResource'],
783+
parameters: [{ name: 'id', in: 'path' }],
784+
requestBody: { content: { 'application/json': { schema: { type: 'object' } } } }
785+
}
786+
},
779787
},
780788
components: {
781789
securitySchemes: {
782-
CookieAuth: { type: 'apiKey', in: 'cookie', name: 'session_id' },
790+
CookieAuth: { type: 'apiKey', in: 'cookie', name: 'sid' },
783791
// For auth-interceptor: Bearer with non-function value
784792
BearerTokenSimple: { type: 'http', scheme: 'bearer' },
785793
},

0 commit comments

Comments
 (0)