Skip to content

New testing framework #7151

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 62 commits into from
Jun 24, 2025
Merged
Changes from 1 commit
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
dec22bd
Initial host builder
timotheeguerin Apr 26, 2025
9a669a7
wrap
timotheeguerin Apr 27, 2025
69b55ff
Clone fs
timotheeguerin Apr 27, 2025
4452fcd
cleanup
timotheeguerin Apr 27, 2025
97e51a7
tweaks
timotheeguerin Apr 28, 2025
a534b40
auto import and using
timotheeguerin Apr 28, 2025
48fc2c2
.
timotheeguerin Apr 28, 2025
8242a64
Simplify
timotheeguerin Apr 28, 2025
4af3ea0
marked template v1
timotheeguerin Apr 29, 2025
5d22b31
Simpler?
timotheeguerin Apr 29, 2025
7b57e21
Merge branch 'main' of https://github.com/Microsoft/typespec into tes…
timotheeguerin May 9, 2025
219a2d9
connect marker
timotheeguerin May 9, 2025
a6885a4
works with values
timotheeguerin May 9, 2025
dcf71e2
Better
timotheeguerin May 9, 2025
595ff1b
.
timotheeguerin May 9, 2025
fd4c0ce
type check
timotheeguerin May 9, 2025
e01aec9
update openapi
timotheeguerin May 9, 2025
59779c7
remove log
timotheeguerin May 9, 2025
555512a
.
timotheeguerin May 9, 2025
e0dd02b
simplify
timotheeguerin May 9, 2025
ccc79ca
test
timotheeguerin May 9, 2025
9e16b20
.
timotheeguerin May 9, 2025
ab0380e
.
timotheeguerin May 9, 2025
342c388
Works with multi file
timotheeguerin May 9, 2025
ad30cbf
fix
timotheeguerin May 9, 2025
e8b3792
simplify
timotheeguerin May 11, 2025
776bf33
emitter testing support
timotheeguerin May 12, 2025
f2d9522
Merge branch 'main' of https://github.com/Microsoft/typespec into tes…
timotheeguerin May 13, 2025
9205a98
Separate FS and add generic functions
timotheeguerin May 13, 2025
afc3463
try
timotheeguerin May 13, 2025
f287465
Create tester
timotheeguerin May 13, 2025
a64c1e0
Missing
timotheeguerin May 13, 2025
9f3c4a3
fix
timotheeguerin May 13, 2025
12402d2
fixup and basic connect to openapi3
timotheeguerin May 13, 2025
37d93a2
More migration openapi3
timotheeguerin May 13, 2025
b512337
more fixes
timotheeguerin May 13, 2025
a306d02
Simplify openapiFor
timotheeguerin May 13, 2025
d342f06
fix
timotheeguerin May 14, 2025
627d219
Migrate xml
timotheeguerin May 14, 2025
8acb8dd
Migrate sse and streams
timotheeguerin May 14, 2025
61f8c52
migrate rest
timotheeguerin May 14, 2025
600686c
migrate http and better node resolution
timotheeguerin May 14, 2025
d9bdc80
migrate versioning
timotheeguerin May 14, 2025
8f941cb
Handle change to output dir
timotheeguerin May 14, 2025
d8d3596
Merge branch 'main' into tester-v2
timotheeguerin May 14, 2025
4d7ecd3
Create tester-v2-2025-4-14-20-23-17.md
timotheeguerin May 15, 2025
36814a8
Create tester-v2-2025-4-15-17-52-11.md
timotheeguerin May 15, 2025
7ca1450
Merge branch 'main' of https://github.com/Microsoft/typespec into tes…
timotheeguerin May 23, 2025
9acf7db
Rename
timotheeguerin May 23, 2025
92c65ab
parity and add files
timotheeguerin May 23, 2025
3b379e2
piping
timotheeguerin May 23, 2025
7c8a7ec
Fix values
timotheeguerin May 23, 2025
79a1e38
works
timotheeguerin May 23, 2025
ac12908
Merge branch 'main' into tester-v2
timotheeguerin May 29, 2025
e19dbaa
Merge branch 'main' into tester-v2
timotheeguerin Jun 3, 2025
c59c9ec
add docs for marked template
timotheeguerin Jun 3, 2025
6f6fd7a
add docs
timotheeguerin Jun 3, 2025
d96573f
add back for back compat
timotheeguerin Jun 3, 2025
1db6ad0
Apply suggestions from code review
timotheeguerin Jun 9, 2025
46e607e
Merge branch 'main' of https://github.com/Microsoft/typespec into tes…
timotheeguerin Jun 21, 2025
729e5eb
handle review comments
timotheeguerin Jun 21, 2025
983c2e4
.
timotheeguerin Jun 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
simplify
  • Loading branch information
timotheeguerin committed May 11, 2025
commit e8b379220fff465d4459289ec3faf3b04e3659d0
97 changes: 44 additions & 53 deletions packages/openapi/test/decorators.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Namespace } from "@typespec/compiler";
import { expectDiagnostics, t, TesterInstance } from "@typespec/compiler/testing";
import { expectDiagnostics, t } from "@typespec/compiler/testing";
import { deepStrictEqual } from "assert";
import { beforeEach, describe, it } from "vitest";
import { describe, it } from "vitest";
import {
getExtensions,
getExternalDocs,
@@ -13,15 +12,9 @@ import {
import { Tester } from "./test-host.js";

describe("openapi: decorators", () => {
let runner: TesterInstance;

beforeEach(async () => {
runner = Tester.createInstance();
});

describe("@operationId", () => {
it("emit diagnostic if use on non operation", async () => {
const diagnostics = await runner.diagnose(`
const diagnostics = await Tester.diagnose(`
@operationId("foo")
model Foo {}
`);
@@ -34,7 +27,7 @@ describe("openapi: decorators", () => {
});

it("emit diagnostic if operation id is not a string", async () => {
const diagnostics = await runner.diagnose(`
const diagnostics = await Tester.diagnose(`
@operationId(123)
op foo(): string;
`);
@@ -47,27 +40,27 @@ describe("openapi: decorators", () => {

describe("@extension", () => {
it("apply extension on model", async () => {
const { Foo } = await runner.compile(t.code`
const { program, Foo } = await Tester.compile(t.code`
@extension("x-custom", "Bar")
model ${t.model("Foo")} {
prop: string
}
`);

deepStrictEqual(Object.fromEntries(getExtensions(runner.program, Foo)), {
deepStrictEqual(Object.fromEntries(getExtensions(program, Foo)), {
"x-custom": "Bar",
});
});

it("apply extension with complex value", async () => {
const { Foo } = await runner.compile(t.code`
const { program, Foo } = await Tester.compile(t.code`
@extension("x-custom", #{foo: 123, bar: "string"})
model ${t.model("Foo")} {
prop: string
}
`);

deepStrictEqual(Object.fromEntries(getExtensions(runner.program, Foo)), {
deepStrictEqual(Object.fromEntries(getExtensions(program, Foo)), {
"x-custom": { foo: 123, bar: "string" },
});
});
@@ -81,31 +74,31 @@ describe("openapi: decorators", () => {
{ value: `"hi"`, expected: "hi" },
{ value: `null`, expected: null },
])("treats value $value as raw value", async ({ value, expected }) => {
const { Foo } = await runner.compile(t.code`
const { program, Foo } = await Tester.compile(t.code`
@extension("x-custom", ${value})
model ${t.model("Foo")} {}
`);

deepStrictEqual(Object.fromEntries(getExtensions(runner.program, Foo)), {
deepStrictEqual(Object.fromEntries(getExtensions(program, Foo)), {
"x-custom": expected,
});
});

it("supports extension key not starting with `x-`", async () => {
const { Foo } = await runner.compile(t.code`
const { program, Foo } = await Tester.compile(t.code`
@extension("foo", "Bar")
model ${t.model("Foo")} {
prop: string
}
`);

deepStrictEqual(Object.fromEntries(getExtensions(runner.program, Foo)), {
deepStrictEqual(Object.fromEntries(getExtensions(program, Foo)), {
foo: "Bar",
});
});

it("emit diagnostics when passing non string extension key", async () => {
const diagnostics = await runner.diagnose(`
const diagnostics = await Tester.diagnose(`
@extension(123, "Bar")
@test
model Foo {
@@ -121,7 +114,7 @@ describe("openapi: decorators", () => {

describe("@externalDocs", () => {
it("emit diagnostic if url is not a string", async () => {
const diagnostics = await runner.diagnose(`
const diagnostics = await Tester.diagnose(`
@externalDocs(123)
model Foo {}
`);
@@ -132,7 +125,7 @@ describe("openapi: decorators", () => {
});

it("emit diagnostic if description is not a string", async () => {
const diagnostics = await runner.diagnose(`
const diagnostics = await Tester.diagnose(`
@externalDocs("https://example.com", 123)
model Foo {}
`);
@@ -143,21 +136,21 @@ describe("openapi: decorators", () => {
});

it("set the external url", async () => {
const { Foo } = await runner.compile(t.code`
const { program, Foo } = await Tester.compile(t.code`
@externalDocs("https://example.com")
model ${t.model("Foo")} {}
`);

deepStrictEqual(getExternalDocs(runner.program, Foo), { url: "https://example.com" });
deepStrictEqual(getExternalDocs(program, Foo), { url: "https://example.com" });
});

it("set the external url with description", async () => {
const { Foo } = await runner.compile(t.code`
const { program, Foo } = await Tester.compile(t.code`
@externalDocs("https://example.com", "More info there")
model ${t.model("Foo")} {}
`);

deepStrictEqual(getExternalDocs(runner.program, Foo), {
deepStrictEqual(getExternalDocs(program, Foo), {
url: "https://example.com",
description: "More info there",
});
@@ -172,7 +165,7 @@ describe("openapi: decorators", () => {
["contact", `#{ contact: #{ foo:"Bar"} }`],
["complex", `#{ contact: #{ \`x-custom\`: "string" }, foo:"Bar" }`],
])("%s", async (_, code) => {
const diagnostics = await runner.diagnose(`
const diagnostics = await Tester.diagnose(`
@info(${code})
@test namespace Service;
`);
@@ -184,7 +177,7 @@ describe("openapi: decorators", () => {
});

it("multiple", async () => {
const diagnostics = await runner.diagnose(`
const diagnostics = await Tester.diagnose(`
@info(#{
license: #{ name: "Apache 2.0", foo1:"Bar"},
contact: #{ \`x-custom\`: "string", foo2:"Bar" },
@@ -211,7 +204,7 @@ describe("openapi: decorators", () => {
});

it("emit diagnostic if termsOfService is not a valid url", async () => {
const diagnostics = await runner.diagnose(`
const diagnostics = await Tester.diagnose(`
@info(#{termsOfService:"notvalidurl"})
namespace Service {}
`);
@@ -223,7 +216,7 @@ describe("openapi: decorators", () => {
});

it("emit diagnostic if use on non namespace", async () => {
const diagnostics = await runner.diagnose(`
const diagnostics = await Tester.diagnose(`
@info(#{})
model Foo {}
`);
@@ -235,7 +228,7 @@ describe("openapi: decorators", () => {
});

it("emit diagnostic if info parameter is not an object", async () => {
const diagnostics = await runner.diagnose(`
const diagnostics = await Tester.diagnose(`
@info(123)
namespace Service {}
`);
@@ -246,7 +239,7 @@ describe("openapi: decorators", () => {
});

it("set all properties", async () => {
const { Service } = (await runner.compile(t.code`
const { program, Service } = await Tester.compile(t.code`
@info(#{
title: "My API",
version: "1.0.0",
@@ -263,9 +256,9 @@ describe("openapi: decorators", () => {
},
})
namespace ${t.namespace("Service")} {}
`)) as { Service: Namespace };
`);

deepStrictEqual(getInfo(runner.program, Service), {
deepStrictEqual(getInfo(program, Service), {
title: "My API",
version: "1.0.0",
summary: "My API summary",
@@ -283,8 +276,7 @@ describe("openapi: decorators", () => {
});

it("resolveInfo() merge with data from @service and @summary", async () => {
const { Service } = await runner.compile(t.code`
#suppress "deprecated" "Test"
const { program, Service } = await Tester.compile(t.code`
@service(#{
title: "Service API",
})
@@ -296,7 +288,7 @@ describe("openapi: decorators", () => {
namespace ${t.namespace("Service")} {}
`);

deepStrictEqual(resolveInfo(runner.program, Service), {
deepStrictEqual(resolveInfo(program, Service), {
title: "Service API",
version: "1.0.0",
summary: "My summary",
@@ -305,18 +297,18 @@ describe("openapi: decorators", () => {
});

it("resolveInfo() returns empty object if nothing is provided", async () => {
const { Service } = await runner.compile(t.code`
const { program, Service } = await Tester.compile(t.code`
namespace ${t.namespace("Service")} {}
`);

deepStrictEqual(resolveInfo(runner.program, Service), {});
deepStrictEqual(resolveInfo(program, Service), {});
});

it("setInfo() function for setting info object directly", async () => {
const { Service } = (await runner.compile(t.code`
const { program, Service } = await Tester.compile(t.code`
namespace ${t.namespace("Service")} {}
`)) as { Service: Namespace };
setInfo(runner.program, Service, {
`);
setInfo(program, Service, {
title: "My API",
version: "1.0.0",
summary: "My API summary",
@@ -332,7 +324,7 @@ describe("openapi: decorators", () => {
},
"x-custom": "Bar",
});
deepStrictEqual(getInfo(runner.program, Service), {
deepStrictEqual(getInfo(program, Service), {
title: "My API",
version: "1.0.0",
summary: "My API summary",
@@ -353,7 +345,7 @@ describe("openapi: decorators", () => {

describe("@tagMetadata", () => {
it("emit an error if a non-service namespace", async () => {
const diagnostics = await runner.diagnose(
const diagnostics = await Tester.diagnose(
`
@tagMetadata("tagName", #{})
namespace Test {}
@@ -372,7 +364,7 @@ describe("openapi: decorators", () => {
["description is not a string", `@tagMetadata("tagName", #{ description: 123, })`],
["externalDocs is not an object", `@tagMetadata("tagName", #{ externalDocs: 123, })`],
])("%s", async (_, code) => {
const diagnostics = await runner.diagnose(
const diagnostics = await Tester.diagnose(
`
${code}
namespace PetStore{};
@@ -385,7 +377,7 @@ describe("openapi: decorators", () => {
});

it("emit diagnostic if dup tagName", async () => {
const diagnostics = await runner.diagnose(
const diagnostics = await Tester.diagnose(
`
@service()
@tagMetadata("tagName", #{})
@@ -408,7 +400,7 @@ describe("openapi: decorators", () => {
`#{ externalDocs: #{ url: "https://example.com", \`x-custom\`: "string" }, foo:"Bar" }`,
],
])("%s", async (_, code) => {
const diagnostics = await runner.diagnose(
const diagnostics = await Tester.diagnose(
`
@service()
@tagMetadata("tagName", ${code})
@@ -423,7 +415,7 @@ describe("openapi: decorators", () => {
});

it("multiple", async () => {
const diagnostics = await runner.diagnose(
const diagnostics = await Tester.diagnose(
`
@service()
@tagMetadata("tagName", #{
@@ -448,7 +440,7 @@ describe("openapi: decorators", () => {
});

it("emit diagnostic if externalDocs.url is not a valid url", async () => {
const diagnostics = await runner.diagnose(
const diagnostics = await Tester.diagnose(
`
@service
@tagMetadata("tagName", #{
@@ -465,7 +457,7 @@ describe("openapi: decorators", () => {
});

it("emit diagnostic if use on non namespace", async () => {
const diagnostics = await runner.diagnose(
const diagnostics = await Tester.diagnose(
`
@tagMetadata("tagName", #{})
model Foo {}
@@ -535,13 +527,12 @@ describe("openapi: decorators", () => {
],
];
it.each(testCases)("%s", async (_, tagMetaDecorator, expected) => {
const runner = Tester.createInstance();
const { PetStore } = await runner.compile(t.code`
const { program, PetStore } = await Tester.compile(t.code`
@service()
${tagMetaDecorator}
namespace ${t.namespace("PetStore")} {}
`);
deepStrictEqual(getTagsMetadata(runner.program, PetStore), expected);
deepStrictEqual(getTagsMetadata(program, PetStore), expected);
});
});
});
Loading
Oops, something went wrong.