microsoft/typespec

Public

mirrored from https://github.com/microsoft/typespecAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
bd60b0a68bb23817a01ab4aef22170c18abd81ed

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

packages/openapi3/test/models.test.ts

895lines · modecode

1import { expectDiagnostics } from "@cadl-lang/compiler/testing";
2import { deepStrictEqual, ok, strictEqual } from "assert";
3import {
4 createOpenAPITestRunner,
5 diagnoseOpenApiFor,
6 oapiForModel,
7 openApiFor,
8} from "./test-host.js";
9
10describe("openapi3: models", () => {
11 it("defines models", async () => {
12 const res = await oapiForModel(
13 "Foo",
14 `model Foo {
15 x: int32;
16 };`
17 );
18
19 ok(res.isRef);
20 deepStrictEqual(res.schemas.Foo, {
21 type: "object",
22 properties: {
23 x: { type: "integer", format: "int32" },
24 },
25 required: ["x"],
26 });
27 });
28
29 it("uses json name specified", async () => {
30 const res = await oapiForModel(
31 "Foo",
32 `model Foo {
33 @projectedName("json", "xJson")
34 x: int32;
35 };`
36 );
37
38 ok(res.isRef);
39 deepStrictEqual(res.schemas.Foo, {
40 type: "object",
41 properties: {
42 xJson: { type: "integer", format: "int32" },
43 },
44 required: ["xJson"],
45 });
46 });
47
48 it("errors on duplicate model names", async () => {
49 const diagnostics = await diagnoseOpenApiFor(
50 `
51 model P {
52 propA: string;
53 }
54
55 @friendlyName("P")
56 model Q {
57 propB: string;
58 }
59
60 @route("/test1")
61 @get
62 op test1(p: P): Q;
63 `
64 );
65
66 expectDiagnostics(diagnostics, [
67 {
68 code: "@cadl-lang/openapi/duplicate-type-name",
69 message: /type/,
70 },
71 ]);
72 });
73
74 it("doesn't define anonymous models", async () => {
75 const res = await oapiForModel("{ x: int32 }", "");
76
77 ok(!res.isRef);
78 strictEqual(Object.keys(res.schemas).length, 0);
79 deepStrictEqual(res.useSchema, {
80 type: "object",
81 properties: {
82 x: { type: "integer", format: "int32" },
83 },
84 required: ["x"],
85 "x-cadl-name": "(anonymous model)",
86 });
87 });
88
89 it("defines templated models", async () => {
90 const res = await oapiForModel(
91 "Foo<int32>",
92 `model Foo<T> {
93 x: T;
94 };`
95 );
96
97 ok(!res.isRef);
98 deepStrictEqual(res.useSchema, {
99 type: "object",
100 properties: {
101 x: { type: "integer", format: "int32" },
102 },
103 required: ["x"],
104 "x-cadl-name": "Foo<int32>",
105 });
106 });
107
108 it("defines templated models when template param is in a namespace", async () => {
109 const res = await oapiForModel(
110 "Foo<Test.M>",
111 `
112 namespace Test {
113 model M {}
114 }
115 model Foo<T> {
116 x: T;
117 };`
118 );
119
120 ok(!res.isRef);
121 deepStrictEqual(res.useSchema, {
122 type: "object",
123 properties: {
124 x: { $ref: "#/components/schemas/Test.M" },
125 },
126 required: ["x"],
127 "x-cadl-name": "Foo<Test.M>",
128 });
129 });
130
131 it("defines models extended from models", async () => {
132 const res = await oapiForModel(
133 "Bar",
134 `
135 model Foo {
136 y: int32;
137 };
138 model Bar extends Foo {}`
139 );
140
141 ok(res.isRef);
142 ok(res.schemas.Foo, "expected definition named Foo");
143 ok(res.schemas.Bar, "expected definition named Bar");
144 deepStrictEqual(res.schemas.Bar, {
145 type: "object",
146 properties: {},
147 allOf: [{ $ref: "#/components/schemas/Foo" }],
148 });
149
150 deepStrictEqual(res.schemas.Foo, {
151 type: "object",
152 properties: { y: { type: "integer", format: "int32" } },
153 required: ["y"],
154 });
155 });
156
157 it("specify default value on enum property", async () => {
158 const res = await oapiForModel(
159 "Foo",
160 `
161 model Foo {
162 optionalEnum?: MyEnum = MyEnum.a;
163 };
164
165 enum MyEnum {
166 a: "a-value",
167 b,
168 }
169 `
170 );
171
172 ok(res.isRef);
173 ok(res.schemas.Foo, "expected definition named Foo");
174 ok(res.schemas.MyEnum, "expected definition named MyEnum");
175 deepStrictEqual(res.schemas.Foo, {
176 type: "object",
177 properties: {
178 optionalEnum: {
179 allOf: [{ $ref: "#/components/schemas/MyEnum" }],
180 default: "a-value",
181 },
182 },
183 });
184 });
185
186 it("emits models extended from models when parent is emitted", async () => {
187 const res = await openApiFor(
188 `
189 model Parent {
190 x?: int32;
191 };
192 model Child extends Parent {
193 y?: int32;
194 }
195 @route("/") op test(): Parent;
196 `
197 );
198 deepStrictEqual(res.components.schemas.Parent, {
199 type: "object",
200 properties: { x: { type: "integer", format: "int32" } },
201 });
202 deepStrictEqual(res.components.schemas.Child, {
203 type: "object",
204 allOf: [{ $ref: "#/components/schemas/Parent" }],
205 properties: { y: { type: "integer", format: "int32" } },
206 });
207 });
208
209 it("ignore uninstantiated template types", async () => {
210 const res = await openApiFor(
211 `
212 model Parent {
213 x?: int32;
214 };
215 @friendlyName("TParent_{name}", T)
216 model TParent<T> extends Parent {
217 t: T;
218 }
219 model Child extends TParent<string> {
220 y?: int32;
221 }
222 @route("/") op test(): Parent;
223 `
224 );
225 ok(
226 !("TParent" in res.components.schemas),
227 "Parent templated type shouldn't be included in OpenAPI"
228 );
229 deepStrictEqual(res.components.schemas.Parent, {
230 type: "object",
231 properties: { x: { type: "integer", format: "int32" } },
232 });
233 deepStrictEqual(res.components.schemas.TParent_string, {
234 type: "object",
235 properties: { t: { type: "string" } },
236 required: ["t"],
237 allOf: [{ $ref: "#/components/schemas/Parent" }],
238 });
239 deepStrictEqual(res.components.schemas.Child, {
240 type: "object",
241 allOf: [{ $ref: "#/components/schemas/TParent_string" }],
242 properties: { y: { type: "integer", format: "int32" } },
243 });
244 });
245
246 it("shouldn't emit instantiated template child types that are only used in is", async () => {
247 const res = await openApiFor(
248 `
249 model Parent {
250 x?: int32;
251 };
252 model TParent<T> extends Parent {
253 t: T;
254 }
255 model Child is TParent<string> {
256 y?: int32;
257 }
258 @route("/") op test(): Parent;
259 `
260 );
261 ok(
262 !("TParent_string" in res.components.schemas),
263 "Parent instantiated templated type shouldn't be included in OpenAPI"
264 );
265 });
266
267 it("defines models with properties extended from models", async () => {
268 const res = await oapiForModel(
269 "Bar",
270 `
271 model Foo {
272 y: int32;
273 };
274 model Bar extends Foo {
275 x: int32;
276 }`
277 );
278
279 ok(res.isRef);
280 ok(res.schemas.Foo, "expected definition named Foo");
281 ok(res.schemas.Bar, "expected definition named Bar");
282 deepStrictEqual(res.schemas.Bar, {
283 type: "object",
284 properties: { x: { type: "integer", format: "int32" } },
285 allOf: [{ $ref: "#/components/schemas/Foo" }],
286 required: ["x"],
287 });
288
289 deepStrictEqual(res.schemas.Foo, {
290 type: "object",
291 properties: { y: { type: "integer", format: "int32" } },
292 required: ["y"],
293 });
294 });
295
296 it("defines models extended from templated models", async () => {
297 const res = await oapiForModel(
298 "Bar",
299 `
300 model Foo<T> {
301 y: T;
302 };
303 model Bar extends Foo<int32> {}`
304 );
305
306 ok(res.isRef);
307 ok(res.schemas["Foo_int32"] === undefined, "no definition named Foo_int32");
308 ok(res.schemas.Bar, "expected definition named Bar");
309 deepStrictEqual(res.schemas.Bar, {
310 type: "object",
311 properties: { y: { type: "integer", format: "int32" } },
312 required: ["y"],
313 });
314 });
315
316 it("defines models with properties extended from templated models", async () => {
317 const res = await oapiForModel(
318 "Bar",
319 `
320 @friendlyName("Foo_{name}", T)
321 model Foo<T> {
322 y: T;
323 };
324 model Bar extends Foo<int32> {
325 x: int32
326 }`
327 );
328
329 ok(res.isRef);
330 ok(res.schemas.Foo_int32, "expected definition named Foo_int32");
331 ok(res.schemas.Bar, "expected definition named Bar");
332 deepStrictEqual(res.schemas.Bar, {
333 type: "object",
334 properties: { x: { type: "integer", format: "int32" } },
335 allOf: [{ $ref: "#/components/schemas/Foo_int32" }],
336 required: ["x"],
337 });
338
339 deepStrictEqual(res.schemas.Foo_int32, {
340 type: "object",
341 properties: { y: { type: "integer", format: "int32" } },
342 required: ["y"],
343 });
344 });
345
346 it("defines templated models with properties extended from templated models", async () => {
347 const res = await oapiForModel(
348 "Bar<int32>",
349 `
350 model Foo<T> {
351 y: T;
352 };
353 model Bar<T> extends Foo<T> {
354 x: T
355 }`
356 );
357
358 ok(!res.isRef);
359 deepStrictEqual(res.useSchema, {
360 type: "object",
361 properties: {
362 x: { type: "integer", format: "int32" },
363 },
364 required: ["x"],
365 "x-cadl-name": "Bar<int32>",
366 allOf: [
367 {
368 type: "object",
369 properties: {
370 y: { type: "integer", format: "int32" },
371 },
372 required: ["y"],
373 "x-cadl-name": "Foo<int32>",
374 },
375 ],
376 });
377 });
378
379 it("defines models with no properties extended", async () => {
380 const res = await oapiForModel(
381 "Bar",
382 `
383 model Foo {};
384 model Bar extends Foo {};`
385 );
386
387 ok(res.isRef);
388 ok(res.schemas.Foo, "expected definition named Foo");
389 ok(res.schemas.Bar, "expected definition named Bar");
390 deepStrictEqual(res.schemas.Bar, {
391 type: "object",
392 properties: {},
393 allOf: [{ $ref: "#/components/schemas/Foo" }],
394 });
395
396 deepStrictEqual(res.schemas.Foo, {
397 type: "object",
398 properties: {},
399 });
400 });
401
402 it("defines models with no properties extended twice", async () => {
403 const res = await oapiForModel(
404 "Baz",
405 `
406 model Foo { x: int32 };
407 model Bar extends Foo {};
408 model Baz extends Bar {};`
409 );
410
411 ok(res.isRef);
412 ok(res.schemas.Foo, "expected definition named Foo");
413 ok(res.schemas.Bar, "expected definition named Bar");
414 ok(res.schemas.Baz, "expected definition named Baz");
415 deepStrictEqual(res.schemas.Baz, {
416 type: "object",
417 properties: {},
418 allOf: [{ $ref: "#/components/schemas/Bar" }],
419 });
420
421 deepStrictEqual(res.schemas.Bar, {
422 type: "object",
423 properties: {},
424 allOf: [{ $ref: "#/components/schemas/Foo" }],
425 });
426
427 deepStrictEqual(res.schemas.Foo, {
428 type: "object",
429 properties: {
430 x: {
431 format: "int32",
432 type: "integer",
433 },
434 },
435 required: ["x"],
436 });
437 });
438
439 it("defines enum types", async () => {
440 const res = await oapiForModel(
441 "Pet",
442 `
443 enum PetType {
444 Dog, Cat
445 }
446 model Pet { type: PetType };
447 `
448 );
449 ok(res.isRef);
450 strictEqual(res.schemas.Pet.properties.type.$ref, "#/components/schemas/PetType");
451 deepStrictEqual(res.schemas.PetType.enum, ["Dog", "Cat"]);
452 });
453
454 it("defines enum types with custom values", async () => {
455 const res = await oapiForModel(
456 "Pet",
457 `
458 enum PetType {
459 Dog: 0, Cat: 1
460 }
461 model Pet { type: PetType };
462 `
463 );
464 ok(res.isRef);
465 strictEqual(res.schemas.Pet.properties.type.$ref, "#/components/schemas/PetType");
466 deepStrictEqual(res.schemas.PetType.enum, [0, 1]);
467 });
468
469 it("defines known values", async () => {
470 const res = await oapiForModel(
471 "Pet",
472 `
473 enum KnownPetType {
474 Dog, Cat
475 }
476
477 @knownValues(KnownPetType)
478 scalar PetType extends string;
479 model Pet { type: PetType };
480 `
481 );
482 ok(res.isRef);
483 strictEqual(res.schemas.Pet.properties.type.$ref, "#/components/schemas/PetType");
484 deepStrictEqual(res.schemas.PetType, {
485 oneOf: [{ type: "string" }, { type: "string", enum: ["Dog", "Cat"] }],
486 });
487 });
488
489 it("defines nullable properties", async () => {
490 const res = await oapiForModel(
491 "Pet",
492 `
493 model Pet {
494 name: string | null;
495 };
496 `
497 );
498 ok(res.isRef);
499 deepStrictEqual(res.schemas.Pet, {
500 type: "object",
501 properties: {
502 name: {
503 type: "string",
504 nullable: true,
505 "x-cadl-name": "string | null",
506 },
507 },
508 required: ["name"],
509 });
510 });
511
512 it("defines nullable array", async () => {
513 const res = await oapiForModel(
514 "Pet",
515 `
516 model Pet {
517 name: int32[] | null;
518 };
519 `
520 );
521 ok(res.isRef);
522 deepStrictEqual(res.schemas.Pet, {
523 type: "object",
524 properties: {
525 name: {
526 type: "array",
527 items: {
528 type: "integer",
529 format: "int32",
530 },
531 nullable: true,
532 "x-cadl-name": "int32[] | null",
533 },
534 },
535 required: ["name"],
536 });
537 });
538
539 it("throws diagnostics for empty enum definitions", async () => {
540 const runner = await createOpenAPITestRunner();
541
542 const diagnostics = await runner.diagnose(`
543 enum PetType {
544 }
545 model Pet { type: PetType };
546 op read(): Pet;
547 `);
548
549 expectDiagnostics(diagnostics, {
550 code: "@cadl-lang/openapi3/union-unsupported",
551 message:
552 "Empty unions are not supported for OpenAPI v3 - enums must have at least one value.",
553 });
554 });
555
556 it("defines request bodies as unions of models", async () => {
557 const openApi = await openApiFor(`
558 model Cat {
559 meow: int32;
560 }
561 model Dog {
562 bark: string;
563 }
564 @post op create(@body body: Cat | Dog): { ...Response<200> };
565 `);
566 ok(openApi.components.schemas.Cat, "expected definition named Cat");
567 ok(openApi.components.schemas.Dog, "expected definition named Dog");
568 deepStrictEqual(openApi.paths["/"].post.requestBody.content["application/json"].schema, {
569 "x-cadl-name": "Cat | Dog",
570 anyOf: [{ $ref: "#/components/schemas/Cat" }, { $ref: "#/components/schemas/Dog" }],
571 });
572 });
573
574 it("defines request bodies as unions of model and non-model types", async () => {
575 const openApi = await openApiFor(`
576 model Cat {
577 meow: int32;
578 }
579
580 @post op create(@body body: Cat | string): { ...Response<200> };
581 `);
582 ok(openApi.components.schemas.Cat, "expected definition named Cat");
583 deepStrictEqual(openApi.paths["/"].post.requestBody.content["application/json"].schema, {
584 "x-cadl-name": "Cat | string",
585 anyOf: [{ $ref: "#/components/schemas/Cat" }, { type: "string" }],
586 });
587 });
588
589 it("defines request bodies aliased to a union of models", async () => {
590 const openApi = await openApiFor(`
591 model Cat {
592 meow: int32;
593 }
594 model Dog {
595 bark: string;
596 }
597 alias Pet = Cat | Dog;
598 @post op create(@body body: Pet): { ...Response<200> };
599 `);
600 ok(openApi.components.schemas.Cat, "expected definition named Cat");
601 ok(openApi.components.schemas.Dog, "expected definition named Dog");
602 deepStrictEqual(openApi.paths["/"].post.requestBody.content["application/json"].schema, {
603 "x-cadl-name": "Cat | Dog",
604 anyOf: [{ $ref: "#/components/schemas/Cat" }, { $ref: "#/components/schemas/Dog" }],
605 });
606 });
607
608 it("defines response bodies as unions of models", async () => {
609 const openApi = await openApiFor(`
610 model Cat {
611 meow: int32;
612 }
613 model Dog {
614 bark: string;
615 }
616
617 op read(): { @body body: Cat | Dog };
618 `);
619 ok(openApi.components.schemas.Cat, "expected definition named Cat");
620 ok(openApi.components.schemas.Dog, "expected definition named Dog");
621 deepStrictEqual(openApi.paths["/"].get.responses["200"].content["application/json"].schema, {
622 "x-cadl-name": "Cat | Dog",
623 anyOf: [{ $ref: "#/components/schemas/Cat" }, { $ref: "#/components/schemas/Dog" }],
624 });
625 });
626
627 it("defines response bodies as unions of model and non-model types", async () => {
628 const openApi = await openApiFor(`
629 model Cat {
630 meow: int32;
631 }
632
633 op read(): { @body body: Cat | string };
634 `);
635 ok(openApi.components.schemas.Cat, "expected definition named Cat");
636 deepStrictEqual(openApi.paths["/"].get.responses["200"].content["application/json"].schema, {
637 "x-cadl-name": "Cat | string",
638 anyOf: [{ $ref: "#/components/schemas/Cat" }, { type: "string" }],
639 });
640 });
641
642 it("defines response bodies aliased to a union from models", async () => {
643 const openApi = await openApiFor(`
644 model Cat {
645 meow: int32;
646 }
647 model Dog {
648 bark: string;
649 }
650 alias Pet = Cat | Dog;
651 op read(): { @body body: Pet };
652 `);
653 ok(openApi.components.schemas.Cat, "expected definition named Cat");
654 ok(openApi.components.schemas.Dog, "expected definition named Dog");
655 deepStrictEqual(openApi.paths["/"].get.responses["200"].content["application/json"].schema, {
656 "x-cadl-name": "Cat | Dog",
657 anyOf: [{ $ref: "#/components/schemas/Cat" }, { $ref: "#/components/schemas/Dog" }],
658 });
659 });
660
661 it("defines response bodies unioned and intersected with OkResponse as unions of models", async () => {
662 const openApi = await openApiFor(`
663 model Cat {
664 meow: int32;
665 }
666 model Dog {
667 bark: string;
668 }
669 op read(): OkResponse & Body<Cat | Dog>;
670 `);
671 ok(openApi.components.schemas.Cat, "expected definition named Cat");
672 ok(openApi.components.schemas.Dog, "expected definition named Dog");
673 deepStrictEqual(openApi.paths["/"].get.responses["200"].content["application/json"].schema, {
674 "x-cadl-name": "Cat | Dog",
675 anyOf: [{ $ref: "#/components/schemas/Cat" }, { $ref: "#/components/schemas/Dog" }],
676 });
677 });
678
679 it("defines unions with named variants similarly to unnamed unions (it ignores variant names)", async () => {
680 const openApi = await openApiFor(`
681 model Cat {
682 meow: int32;
683 }
684 model Dog {
685 bark: string;
686 }
687 union Pet { cat: Cat, dog: Dog }
688
689 op read(): { @body body: Pet };
690 `);
691 ok(openApi.components.schemas.Cat, "expected definition named Cat");
692 ok(openApi.components.schemas.Dog, "expected definition named Dog");
693 ok(openApi.components.schemas.Pet, "expected definition named Pet");
694 deepStrictEqual(openApi.components.schemas.Pet, {
695 anyOf: [{ $ref: "#/components/schemas/Cat" }, { $ref: "#/components/schemas/Dog" }],
696 });
697 deepStrictEqual(openApi.paths["/"].get.responses["200"].content["application/json"].schema, {
698 $ref: "#/components/schemas/Pet",
699 });
700 });
701
702 it("defines oneOf schema for unions with @oneOf decorator", async () => {
703 const openApi = await openApiFor(`
704 model Cat {
705 meow: int32;
706 }
707 model Dog {
708 bark: string;
709 }
710 @oneOf
711 union Pet { cat: Cat, dog: Dog }
712 op read(): { @body body: Pet };
713 `);
714 ok(openApi.components.schemas.Cat, "expected definition named Cat");
715 ok(openApi.components.schemas.Dog, "expected definition named Dog");
716 ok(openApi.components.schemas.Pet, "expected definition named Pet");
717 deepStrictEqual(openApi.components.schemas.Pet, {
718 oneOf: [{ $ref: "#/components/schemas/Cat" }, { $ref: "#/components/schemas/Dog" }],
719 });
720 deepStrictEqual(openApi.paths["/"].get.responses["200"].content["application/json"].schema, {
721 $ref: "#/components/schemas/Pet",
722 });
723 });
724
725 it("recovers logical type name", async () => {
726 const oapi = await openApiFor(
727 `
728 model Input {
729 name?: string;
730 }
731
732 model Output {
733 text?: string;
734 }
735
736 @route("/things/{id}")
737 @get
738 op get(@path id: string, @query test: string, ...Input): Output & { @header test: string; };
739 `
740 );
741
742 deepStrictEqual(oapi.components.schemas.Input, {
743 type: "object",
744 properties: {
745 name: {
746 type: "string",
747 },
748 },
749 });
750
751 deepStrictEqual(oapi.components.schemas.Output, {
752 type: "object",
753 properties: {
754 text: {
755 type: "string",
756 },
757 },
758 });
759
760 deepStrictEqual(oapi.paths["/things/{id}"].get.requestBody.content["application/json"].schema, {
761 $ref: "#/components/schemas/Input",
762 });
763
764 deepStrictEqual(
765 oapi.paths["/things/{id}"].get.responses["200"].content["application/json"].schema,
766 {
767 $ref: "#/components/schemas/Output",
768 }
769 );
770 });
771
772 it("detects cycles in inline type", async () => {
773 const diagnostics = await diagnoseOpenApiFor(
774 `
775 model Thing<T> { inner?: Thing<T>; }
776 op get(): Thing<string>;
777 `,
778 { "omit-unreachable-types": true }
779 );
780
781 expectDiagnostics(diagnostics, [{ code: "@cadl-lang/openapi3/inline-cycle" }]);
782 });
783
784 it("excludes properties with type 'never'", async () => {
785 const res = await oapiForModel(
786 "Bar",
787 `
788 model Foo {
789 y: int32;
790 nope: never;
791 };
792 model Bar extends Foo {
793 x: int32;
794 }`
795 );
796
797 ok(res.isRef);
798 ok(res.schemas.Foo, "expected definition named Foo");
799 ok(res.schemas.Bar, "expected definition named Bar");
800 deepStrictEqual(res.schemas.Bar, {
801 type: "object",
802 properties: { x: { type: "integer", format: "int32" } },
803 allOf: [{ $ref: "#/components/schemas/Foo" }],
804 required: ["x"],
805 });
806
807 deepStrictEqual(res.schemas.Foo, {
808 type: "object",
809 properties: { y: { type: "integer", format: "int32" } },
810 required: ["y"],
811 });
812 });
813
814 describe("referencing another property as type", () => {
815 it("use the type of the other property", async () => {
816 const res = await oapiForModel(
817 "Bar",
818 `
819 model Foo {
820 name: string;
821 }
822 model Bar {
823 x: Foo.name
824 }`
825 );
826
827 ok(res.schemas.Bar, "expected definition named Bar");
828 deepStrictEqual(res.schemas.Bar.properties.x, {
829 type: "string",
830 });
831 });
832
833 it("use the type of the other property with ref", async () => {
834 const res = await oapiForModel(
835 "Bar",
836 `
837 model Name {first: string}
838 model Foo {
839 name: Name;
840 }
841 model Bar {
842 x: Foo.name
843 }`
844 );
845
846 ok(res.schemas.Bar, "expected definition named Bar");
847 deepStrictEqual(res.schemas.Bar.properties.x, {
848 $ref: "#/components/schemas/Name",
849 });
850 });
851
852 it("should include decorators on both referenced property and source property itself", async () => {
853 const res = await oapiForModel(
854 "Bar",
855 `
856 model Foo {
857 @format("uri")
858 name: string;
859 }
860 model Bar {
861 @doc("My doc")
862 x: Foo.name
863 }`
864 );
865
866 ok(res.schemas.Bar, "expected definition named Bar");
867 deepStrictEqual(res.schemas.Bar.properties.x, {
868 type: "string",
869 format: "uri",
870 description: "My doc",
871 });
872 });
873
874 it("decorators on the property should override the value of referenced property", async () => {
875 const res = await oapiForModel(
876 "Bar",
877 `
878 model Foo {
879 @doc("Default doc")
880 name: string;
881 }
882 model Bar {
883 @doc("My doc override")
884 x: Foo.name
885 }`
886 );
887
888 ok(res.schemas.Bar, "expected definition named Bar");
889 deepStrictEqual(res.schemas.Bar.properties.x, {
890 type: "string",
891 description: "My doc override",
892 });
893 });
894 });
895});
896