Skip to content

Commit c750ca5

Browse files
authored
typegen: add tests (#12214)
1 parent 0d1a584 commit c750ca5

File tree

3 files changed

+123
-3
lines changed

3 files changed

+123
-3
lines changed

integration/helpers/vite-template/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"dev": "react-router dev",
99
"build": "react-router build",
1010
"start": "react-router-serve ./build/server/index.js",
11-
"typecheck": "tsc"
11+
"typecheck": "react-router typegen && tsc"
1212
},
1313
"dependencies": {
1414
"@react-router/express": "workspace:*",

integration/helpers/vite-template/tsconfig.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
{
2-
"include": ["env.d.ts", "**/*.ts", "**/*.tsx"],
2+
"include": [
3+
"env.d.ts",
4+
"**/*.ts",
5+
"**/*.tsx",
6+
".react-router/types/**/*.d.ts"
7+
],
38
"compilerOptions": {
49
"lib": ["DOM", "DOM.Iterable", "ES2022"],
510
"isolatedModules": true,
@@ -17,6 +22,7 @@
1722
"paths": {
1823
"~/*": ["./app/*"]
1924
},
20-
"noEmit": true
25+
"noEmit": true,
26+
"rootDirs": [".", ".react-router/types/"]
2127
}
2228
}

integration/typegen-test.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { spawnSync } from "node:child_process";
2+
3+
import { expect, test } from "@playwright/test";
4+
import dedent from "dedent";
5+
6+
import { createProject } from "./helpers/vite";
7+
8+
const tsx = dedent;
9+
10+
const nodeBin = process.argv[0];
11+
const reactRouterBin = "node_modules/@react-router/dev/dist/cli/index.js";
12+
const tscBin = "node_modules/typescript/bin/tsc";
13+
14+
function typecheck(cwd: string) {
15+
const typegen = spawnSync(nodeBin, [reactRouterBin, "typegen"], { cwd });
16+
expect(typegen.stdout.toString()).toBe("");
17+
expect(typegen.stderr.toString()).toBe("");
18+
expect(typegen.status).toBe(0);
19+
20+
return spawnSync(nodeBin, [tscBin], { cwd });
21+
}
22+
23+
const viteConfig = tsx`
24+
import { reactRouter } from "@react-router/dev/vite";
25+
import tsconfigPaths from "vite-tsconfig-paths";
26+
27+
export default {
28+
plugins: [
29+
reactRouter(),
30+
tsconfigPaths()
31+
],
32+
};
33+
`;
34+
35+
test.describe("typegen", () => {
36+
test("basic", async () => {
37+
const cwd = await createProject({
38+
"vite.config.ts": viteConfig,
39+
"app/routes/products.$id.tsx": tsx`
40+
import type { Route } from "./+types.products.$id"
41+
42+
function assertType<T>(t: T) {}
43+
44+
export function loader({ params }: Route.LoaderArgs) {
45+
assertType<string>(params.id)
46+
return { planet: "world" }
47+
}
48+
49+
export default function Component({ loaderData }: Route.ComponentProps) {
50+
assertType<string>(loaderData.planet)
51+
return <h1>Hello, {loaderData.planet}!</h1>
52+
}
53+
`,
54+
});
55+
56+
const proc = typecheck(cwd);
57+
expect(proc.stdout.toString()).toBe("");
58+
expect(proc.stderr.toString()).toBe("");
59+
expect(proc.status).toBe(0);
60+
});
61+
62+
test("repeated param", async () => {
63+
const cwd = await createProject({
64+
"vite.config.ts": viteConfig,
65+
"app/routes/repeated.$id.$id?.$id.tsx": tsx`
66+
import type { Route } from "./+types.repeated.$id.$id?.$id"
67+
68+
function assertType<T>(t: T) {}
69+
70+
export function loader({ params }: Route.LoaderArgs) {
71+
assertType<[string, string | undefined, string]>(params.id)
72+
return null
73+
}
74+
`,
75+
});
76+
const proc = typecheck(cwd);
77+
expect(proc.stdout.toString()).toBe("");
78+
expect(proc.stderr.toString()).toBe("");
79+
expect(proc.status).toBe(0);
80+
});
81+
82+
test("clientLoader.hydrate = true", async () => {
83+
const cwd = await createProject({
84+
"vite.config.ts": viteConfig,
85+
"app/routes/_index.tsx": tsx`
86+
import type { Route } from "./+types._index"
87+
88+
function assertType<T>(t: T) {}
89+
90+
export function loader() {
91+
return { server: "server" }
92+
}
93+
94+
export function clientLoader() {
95+
return { client: "client" }
96+
}
97+
clientLoader.hydrate = true as const
98+
99+
export function HydrateFallback() {
100+
return <h1>Loading...</h1>
101+
}
102+
103+
export default function Component({ loaderData }: Route.ComponentProps) {
104+
assertType<{ client: string }>(loaderData)
105+
return <h1>Hello from {loaderData.client}!</h1>
106+
}
107+
`,
108+
});
109+
const proc = typecheck(cwd);
110+
expect(proc.stdout.toString()).toBe("");
111+
expect(proc.stderr.toString()).toBe("");
112+
expect(proc.status).toBe(0);
113+
});
114+
});

0 commit comments

Comments
 (0)