Skip to content

Commit 5bf59e0

Browse files
Add comprehensive tests for registerRouteHandlersByTag
Co-authored-by: jasonblanchard <1238532+jasonblanchard@users.noreply.github.com>
1 parent e8cc9ba commit 5bf59e0

File tree

1 file changed

+289
-0
lines changed

1 file changed

+289
-0
lines changed

packages/openapi-typescript-server/src/cli/generate.test.ts

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,295 @@ describe("wihout operationId", () => {
212212
});
213213
});
214214

215+
describe("tags", () => {
216+
it("generates Tag type with all tags from spec", () => {
217+
const spec = {
218+
openapi: "3.0.0",
219+
info: {},
220+
paths: {
221+
"/pets": {
222+
get: {
223+
operationId: "listPets",
224+
tags: ["pet"],
225+
responses: {
226+
200: {
227+
content: {
228+
"application/json": {
229+
schema: { type: "object" },
230+
},
231+
},
232+
},
233+
},
234+
},
235+
},
236+
"/users": {
237+
get: {
238+
operationId: "listUsers",
239+
tags: ["user"],
240+
responses: {
241+
200: {
242+
content: {
243+
"application/json": {
244+
schema: { type: "object" },
245+
},
246+
},
247+
},
248+
},
249+
},
250+
},
251+
},
252+
};
253+
const sourceFile = generate(spec, "./schema.d.ts", "outdir.ts");
254+
const tagType = sourceFile.getTypeAlias("Tag");
255+
assert(tagType);
256+
assert(tagType.isExported());
257+
const tagTypeText = tagType.getType().getText();
258+
assert.match(tagTypeText, /"pet"/);
259+
assert.match(tagTypeText, /"user"/);
260+
});
261+
262+
it("generates Tag type with null for untagged operations", () => {
263+
const spec = {
264+
openapi: "3.0.0",
265+
info: {},
266+
paths: {
267+
"/pets": {
268+
get: {
269+
operationId: "listPets",
270+
responses: {
271+
200: {
272+
content: {
273+
"application/json": {
274+
schema: { type: "object" },
275+
},
276+
},
277+
},
278+
},
279+
},
280+
},
281+
},
282+
};
283+
const sourceFile = generate(spec, "./schema.d.ts", "outdir.ts");
284+
const tagType = sourceFile.getTypeAlias("Tag");
285+
assert(tagType);
286+
assert(tagType.isExported());
287+
const tagTypeText = tagType.getType().getText();
288+
assert.equal(tagTypeText, "null");
289+
});
290+
291+
it("generates Tag type with both tags and null for mixed operations", () => {
292+
const spec = {
293+
openapi: "3.0.0",
294+
info: {},
295+
paths: {
296+
"/pets": {
297+
get: {
298+
operationId: "listPets",
299+
tags: ["pet"],
300+
responses: {
301+
200: {
302+
content: {
303+
"application/json": {
304+
schema: { type: "object" },
305+
},
306+
},
307+
},
308+
},
309+
},
310+
},
311+
"/status": {
312+
get: {
313+
operationId: "getStatus",
314+
responses: {
315+
200: {
316+
content: {
317+
"application/json": {
318+
schema: { type: "object" },
319+
},
320+
},
321+
},
322+
},
323+
},
324+
},
325+
},
326+
};
327+
const sourceFile = generate(spec, "./schema.d.ts", "outdir.ts");
328+
const tagType = sourceFile.getTypeAlias("Tag");
329+
assert(tagType);
330+
const tagTypeText = tagType.getType().getText();
331+
assert.match(tagTypeText, /"pet"/);
332+
assert.match(tagTypeText, /null/);
333+
});
334+
});
335+
336+
describe("registerRouteHandlersByTag", () => {
337+
it("generates function with correct signature", () => {
338+
const spec = {
339+
openapi: "3.0.0",
340+
info: {},
341+
paths: {
342+
"/pets": {
343+
get: {
344+
operationId: "listPets",
345+
tags: ["pet"],
346+
responses: {
347+
200: {
348+
content: {
349+
"application/json": {
350+
schema: { type: "object" },
351+
},
352+
},
353+
},
354+
},
355+
},
356+
},
357+
},
358+
};
359+
const sourceFile = generate(spec, "./schema.d.ts", "outdir.ts");
360+
const func = sourceFile.getFunction("registerRouteHandlersByTag");
361+
assert(func);
362+
assert(func.isExported());
363+
assert.equal(func.getTypeParameters().length, 2);
364+
assert.equal(func.getParameters().length, 2);
365+
366+
const tagParam = func.getParameters()[0];
367+
assert(tagParam);
368+
assert.equal(tagParam.getName(), "tag");
369+
assert.equal(tagParam.getType().getText(), '"pet"');
370+
371+
const serverParam = func.getParameters()[1];
372+
assert(serverParam);
373+
assert.equal(serverParam.getName(), "server");
374+
assert.match(serverParam.getType().getText(), /Partial<Server<Req, Res>>/);
375+
376+
assert.match(func.getReturnType().getText(), /Route\[\]/);
377+
});
378+
379+
it("generates switch statement for each tag", () => {
380+
const spec = {
381+
openapi: "3.0.0",
382+
info: {},
383+
paths: {
384+
"/pets": {
385+
get: {
386+
operationId: "listPets",
387+
tags: ["pet"],
388+
responses: {
389+
200: {
390+
content: {
391+
"application/json": {
392+
schema: { type: "object" },
393+
},
394+
},
395+
},
396+
},
397+
},
398+
},
399+
"/users": {
400+
get: {
401+
operationId: "listUsers",
402+
tags: ["user"],
403+
responses: {
404+
200: {
405+
content: {
406+
"application/json": {
407+
schema: { type: "object" },
408+
},
409+
},
410+
},
411+
},
412+
},
413+
},
414+
},
415+
};
416+
const sourceFile = generate(spec, "./schema.d.ts", "outdir.ts");
417+
const func = sourceFile.getFunction("registerRouteHandlersByTag");
418+
const bodyText = func?.getBodyText() || "";
419+
420+
assert.match(bodyText, /switch \(tag\)/);
421+
assert.match(bodyText, /case "pet":/);
422+
assert.match(bodyText, /case "user":/);
423+
assert.match(bodyText, /if \(server\.listPets\)/);
424+
assert.match(bodyText, /if \(server\.listUsers\)/);
425+
});
426+
427+
it("groups operations by tag correctly", () => {
428+
const spec = {
429+
openapi: "3.0.0",
430+
info: {},
431+
paths: {
432+
"/pets": {
433+
get: {
434+
operationId: "listPets",
435+
tags: ["pet"],
436+
responses: {
437+
200: {
438+
content: {
439+
"application/json": {
440+
schema: { type: "object" },
441+
},
442+
},
443+
},
444+
},
445+
},
446+
post: {
447+
operationId: "createPet",
448+
tags: ["pet"],
449+
responses: {
450+
201: {
451+
content: {
452+
"application/json": {
453+
schema: { type: "object" },
454+
},
455+
},
456+
},
457+
},
458+
},
459+
},
460+
},
461+
};
462+
const sourceFile = generate(spec, "./schema.d.ts", "outdir.ts");
463+
const func = sourceFile.getFunction("registerRouteHandlersByTag");
464+
const bodyText = func?.getBodyText() || "";
465+
466+
// Both operations should be in the same case block
467+
const petCaseMatch = bodyText.match(/case "pet":[\s\S]*?break;/);
468+
assert(petCaseMatch);
469+
const petCaseBlock = petCaseMatch[0];
470+
assert.match(petCaseBlock, /if \(server\.listPets\)/);
471+
assert.match(petCaseBlock, /if \(server\.createPet\)/);
472+
});
473+
474+
it("handles untagged operations with null case", () => {
475+
const spec = {
476+
openapi: "3.0.0",
477+
info: {},
478+
paths: {
479+
"/status": {
480+
get: {
481+
operationId: "getStatus",
482+
responses: {
483+
200: {
484+
content: {
485+
"application/json": {
486+
schema: { type: "object" },
487+
},
488+
},
489+
},
490+
},
491+
},
492+
},
493+
},
494+
};
495+
const sourceFile = generate(spec, "./schema.d.ts", "outdir.ts");
496+
const func = sourceFile.getFunction("registerRouteHandlersByTag");
497+
const bodyText = func?.getBodyText() || "";
498+
499+
assert.match(bodyText, /case null:/);
500+
assert.match(bodyText, /if \(server\.getStatus\)/);
501+
});
502+
});
503+
215504
describe("request body", () => {
216505
it("writes required request body", () => {
217506
const spec = {

0 commit comments

Comments
 (0)