-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathvitest.config.ts
More file actions
111 lines (107 loc) · 3.2 KB
/
Copy pathvitest.config.ts
File metadata and controls
111 lines (107 loc) · 3.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import { existsSync } from "node:fs";
import { dirname, join } from "node:path";
import { defineConfig, type Plugin } from "vitest/config";
const JS_EXT_RE = /\.js$/;
/**
* Vite plugin to rewrite lazy `require("./relative/path.js")` calls in
* `.ts` source files to the corresponding `.ts` path when the `.ts` file
* exists on disk. Node.js `require()` bypasses Vite's resolve pipeline,
* so `resolve.extensions` doesn't apply.
*/
function requireJsToTsPlugin(): Plugin {
return {
name: "require-js-to-ts",
enforce: "pre",
transform(code, id) {
if (!(id.endsWith(".ts") && code.includes("require("))) {
return;
}
let changed = false;
const transformed = code.replace(
/require\(["'](\.[\w/.]+)\.js["']\)/g,
(match, relPath) => {
const dir = dirname(id);
const tsPath = join(dir, `${relPath}.ts`);
if (existsSync(tsPath)) {
changed = true;
return `require(${JSON.stringify(tsPath)})`;
}
return match;
}
);
if (changed) {
return { code: transformed, map: null };
}
return;
},
};
}
/**
* Vite plugin to resolve `.js` imports to `.ts` files.
* The codebase uses ESM `.js` extensions in imports (TypeScript convention),
* but the actual source files are `.ts`. Vite's SSR resolver sometimes
* bypasses `resolve.extensions` — this plugin catches those cases.
*/
function jsToTsResolvePlugin(): Plugin {
return {
name: "js-to-ts-resolve",
enforce: "pre",
resolveId(source, importer) {
if (!(importer && source.endsWith(".js"))) {
return;
}
// Only handle relative imports from our source tree
if (!source.startsWith(".")) {
return;
}
const dir = dirname(importer);
const tsPath = join(dir, source.replace(JS_EXT_RE, ".ts"));
if (existsSync(tsPath)) {
return tsPath;
}
return;
},
};
}
export default defineConfig({
plugins: [requireJsToTsPlugin(), jsToTsResolvePlugin()],
resolve: {
// Allow .js imports to resolve to .ts files (ESM convention used throughout)
extensions: [".ts", ".tsx", ".js", ".jsx", ".json"],
conditions: ["import", "module", "default"],
},
test: {
setupFiles: ["./test/preload.ts"],
testTimeout: 15_000,
isolate: true,
pool: "forks",
poolOptions: {
forks: {
execArgv: [],
env: { UV_USE_IO_URING: "0" },
},
},
include: ["test/**/*.test.ts", "test/**/*.test.tsx"],
exclude: ["**/node_modules/**", "**/dist/**"],
coverage: {
reporter: ["lcov"],
},
server: {
deps: {
// Inline modules so vitest can intercept their exports with
// vi.spyOn. Without inlining, ESM namespace objects are frozen
// and spyOn throws "Cannot redefine property".
inline: [
"@sentry/node-core",
"@sentry/core",
"@clack/prompts",
"node:child_process",
],
},
},
// Use vi.mock() hoisting mode that intercepts all module bindings
// (not just the test's namespace import) so vi.spyOn on a namespace
// affects what the source module sees at call time.
mockReset: false,
},
});