vitest 4.0.17 → 4.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +36 -0
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +2 -2
- package/dist/chunks/acorn.B2iPLyUM.js +5958 -0
- package/dist/chunks/{base.XJJQZiKB.js → base.DiopZV8F.js} +49 -14
- package/dist/chunks/{benchmark.B3N2zMcH.js → benchmark.BoqSLF53.js} +1 -1
- package/dist/chunks/{browser.d.ChKACdzH.d.ts → browser.d.BE4kbYok.d.ts} +4 -1
- package/dist/chunks/{cac.jRCLJDDc.js → cac.C4jjt2RX.js} +816 -14
- package/dist/chunks/{cli-api.Cx2DW4Bc.js → cli-api.ChbI1JU9.js} +412 -166
- package/dist/chunks/{config.d.Cy95HiCx.d.ts → config.d.Cr1Ep39N.d.ts} +13 -11
- package/dist/chunks/{console.Cf-YriPC.js → console.CNlG1KsP.js} +3 -2
- package/dist/chunks/{constants.D_Q9UYh-.js → constants.B63TT-Bl.js} +1 -1
- package/dist/chunks/coverage.tyqbzn4W.js +1001 -0
- package/dist/chunks/{creator.DAmOKTvJ.js → creator.yyCHuw5R.js} +33 -2
- package/dist/chunks/{global.d.B15mdLcR.d.ts → global.d.JeWMqlOm.d.ts} +1 -1
- package/dist/chunks/{globals.DOayXfHP.js → globals.C6Ecf1TO.js} +11 -10
- package/dist/chunks/{index.M8mOzt4Y.js → index.B-iBE_Gx.js} +21 -5
- package/dist/chunks/{coverage.AVPTjMgw.js → index.BCY_7LL2.js} +5 -959
- package/dist/chunks/{index.6Qv1eEA6.js → index.CAN630q3.js} +20 -8
- package/dist/chunks/{index.C5r1PdPD.js → index.CFulQRmC.js} +1 -1
- package/dist/chunks/{index.Z5E_ObnR.js → index.CouFDptX.js} +4 -2
- package/dist/chunks/{init-forks.BC6ZwHQN.js → init-forks.BnCXPazU.js} +1 -1
- package/dist/chunks/{init-threads.CxSxLC0N.js → init-threads.Cyh2PqXi.js} +1 -1
- package/dist/chunks/{init.C9kljSTm.js → init.B95Mm0Iz.js} +65 -12
- package/dist/chunks/native.mV0-490A.js +148 -0
- package/dist/chunks/nativeModuleMocker.D_q5sFv6.js +206 -0
- package/dist/chunks/nativeModuleRunner.BIakptoF.js +36 -0
- package/dist/chunks/{node.Ce0vMQM7.js → node.CrSEwhm4.js} +1 -1
- package/dist/chunks/{plugin.d.CtqpEehP.d.ts → plugin.d.C9o5bttz.d.ts} +1 -1
- package/dist/chunks/{reporters.d.CWXNI2jG.d.ts → reporters.d.7faYdkxy.d.ts} +146 -49
- package/dist/chunks/rpc.DcRWTy5G.js +148 -0
- package/dist/chunks/{rpc.d.RH3apGEf.d.ts → rpc.d.CM7x9-sm.d.ts} +1 -0
- package/dist/chunks/{setup-common.Cm-kSBVi.js → setup-common.cvFp-ao9.js} +2 -2
- package/dist/chunks/{startModuleRunner.DEj0jb3e.js → startVitestModuleRunner.BK-u7y4N.js} +182 -391
- package/dist/chunks/{vi.2VT5v0um.js → test.G82XYNFk.js} +505 -119
- package/dist/chunks/{utils.DvEY5TfP.js → utils.DT4VyRyl.js} +5 -1
- package/dist/chunks/{vm.CMjifoPa.js → vm.BdLtzhnj.js} +15 -11
- package/dist/chunks/{worker.d.Dyxm8DEL.d.ts → worker.d.CPzI2ZzJ.d.ts} +2 -2
- package/dist/cli.js +4 -3
- package/dist/config.d.ts +11 -11
- package/dist/config.js +1 -1
- package/dist/coverage.d.ts +10 -8
- package/dist/coverage.js +7 -4
- package/dist/environments.js +2 -0
- package/dist/index.d.ts +30 -23
- package/dist/index.js +9 -8
- package/dist/module-evaluator.d.ts +10 -1
- package/dist/module-evaluator.js +1 -5
- package/dist/node.d.ts +13 -12
- package/dist/node.js +27 -25
- package/dist/nodejs-worker-loader.js +41 -0
- package/dist/reporters.d.ts +8 -8
- package/dist/reporters.js +4 -2
- package/dist/runners.d.ts +24 -4
- package/dist/runners.js +6 -6
- package/dist/runtime.d.ts +6 -0
- package/dist/runtime.js +35 -0
- package/dist/snapshot.js +4 -2
- package/dist/suite.js +4 -2
- package/dist/worker.d.ts +8 -7
- package/dist/worker.js +25 -20
- package/dist/workers/forks.js +21 -16
- package/dist/workers/runVmTests.js +11 -13
- package/dist/workers/threads.js +21 -16
- package/dist/workers/vmForks.js +14 -11
- package/dist/workers/vmThreads.js +14 -11
- package/package.json +28 -29
- package/suppress-warnings.cjs +1 -0
- package/dist/chunks/date.Bq6ZW5rf.js +0 -73
- package/dist/chunks/rpc.BoxB0q7B.js +0 -76
- package/dist/chunks/test.B8ej_ZHS.js +0 -254
- package/dist/mocker.d.ts +0 -1
- package/dist/mocker.js +0 -1
- package/dist/module-runner.js +0 -17
|
@@ -1,249 +1,29 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { isBareImport } from '@vitest/utils/helpers';
|
|
3
3
|
import { i as isBuiltin, a as isBrowserExternal, t as toBuiltin } from './modules.BJuCwlRJ.js';
|
|
4
|
+
import { a as getSafeWorkerState } from './utils.DT4VyRyl.js';
|
|
4
5
|
import { pathToFileURL } from 'node:url';
|
|
5
|
-
import { normalize
|
|
6
|
+
import { normalize, join } from 'pathe';
|
|
6
7
|
import { distDir } from '../path.js';
|
|
7
|
-
import { serializeValue } from '@vitest/utils/serialize';
|
|
8
8
|
import { VitestModuleEvaluator, unwrapId } from '../module-evaluator.js';
|
|
9
|
-
import {
|
|
9
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
10
10
|
import vm from 'node:vm';
|
|
11
11
|
import { MockerRegistry, mockObject, RedirectedModule, AutomockedModule } from '@vitest/mocker';
|
|
12
|
-
import
|
|
12
|
+
import { findMockRedirect } from '@vitest/mocker/redirect';
|
|
13
13
|
import * as viteModuleRunner from 'vite/module-runner';
|
|
14
14
|
import { T as Traces } from './traces.CCmnQaNT.js';
|
|
15
15
|
|
|
16
|
-
class
|
|
17
|
-
constructor(options) {
|
|
18
|
-
this.options = options;
|
|
19
|
-
}
|
|
20
|
-
async invoke(event) {
|
|
21
|
-
if (event.type !== "custom") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support Vite HMR events.`) };
|
|
22
|
-
if (event.event !== "vite:invoke") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support ${event.event} event.`) };
|
|
23
|
-
const { name, data } = event.data;
|
|
24
|
-
if (name === "getBuiltins")
|
|
25
|
-
// we return an empty array here to avoid client-side builtin check,
|
|
26
|
-
// as we need builtins to go through `fetchModule`
|
|
27
|
-
return { result: [] };
|
|
28
|
-
if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) };
|
|
29
|
-
try {
|
|
30
|
-
return { result: await this.options.fetchModule(...data) };
|
|
31
|
-
} catch (error) {
|
|
32
|
-
return { error };
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
|
|
38
|
-
function normalizeWindowsPath(input = "") {
|
|
39
|
-
if (!input) return input;
|
|
40
|
-
return input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
|
|
41
|
-
}
|
|
42
|
-
const _UNC_REGEX = /^[/\\]{2}/;
|
|
43
|
-
const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
|
|
44
|
-
const _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
|
|
45
|
-
const _EXTNAME_RE = /.(\.[^./]+|\.)$/;
|
|
46
|
-
const normalize = function(path) {
|
|
47
|
-
if (path.length === 0) return ".";
|
|
48
|
-
path = normalizeWindowsPath(path);
|
|
49
|
-
const isUNCPath = path.match(_UNC_REGEX);
|
|
50
|
-
const isPathAbsolute = isAbsolute(path);
|
|
51
|
-
const trailingSeparator = path[path.length - 1] === "/";
|
|
52
|
-
path = normalizeString(path, !isPathAbsolute);
|
|
53
|
-
if (path.length === 0) {
|
|
54
|
-
if (isPathAbsolute) return "/";
|
|
55
|
-
return trailingSeparator ? "./" : ".";
|
|
56
|
-
}
|
|
57
|
-
if (trailingSeparator) path += "/";
|
|
58
|
-
if (_DRIVE_LETTER_RE.test(path)) path += "/";
|
|
59
|
-
if (isUNCPath) {
|
|
60
|
-
if (!isPathAbsolute) return `//./${path}`;
|
|
61
|
-
return `//${path}`;
|
|
62
|
-
}
|
|
63
|
-
return isPathAbsolute && !isAbsolute(path) ? `/${path}` : path;
|
|
64
|
-
};
|
|
65
|
-
const join = function(...segments) {
|
|
66
|
-
let path = "";
|
|
67
|
-
for (const seg of segments) {
|
|
68
|
-
if (!seg) continue;
|
|
69
|
-
if (path.length > 0) {
|
|
70
|
-
const pathTrailing = path[path.length - 1] === "/";
|
|
71
|
-
const segLeading = seg[0] === "/";
|
|
72
|
-
if (pathTrailing && segLeading) path += seg.slice(1);
|
|
73
|
-
else path += pathTrailing || segLeading ? seg : `/${seg}`;
|
|
74
|
-
} else path += seg;
|
|
75
|
-
}
|
|
76
|
-
return normalize(path);
|
|
77
|
-
};
|
|
78
|
-
function cwd$1() {
|
|
79
|
-
if (typeof process !== "undefined" && typeof process.cwd === "function") return process.cwd().replace(/\\/g, "/");
|
|
80
|
-
return "/";
|
|
81
|
-
}
|
|
82
|
-
const resolve = function(...arguments_) {
|
|
83
|
-
arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
|
|
84
|
-
let resolvedPath = "";
|
|
85
|
-
let resolvedAbsolute = false;
|
|
86
|
-
for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
|
|
87
|
-
const path = index >= 0 ? arguments_[index] : cwd$1();
|
|
88
|
-
if (!path || path.length === 0) continue;
|
|
89
|
-
resolvedPath = `${path}/${resolvedPath}`;
|
|
90
|
-
resolvedAbsolute = isAbsolute(path);
|
|
91
|
-
}
|
|
92
|
-
resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
|
|
93
|
-
if (resolvedAbsolute && !isAbsolute(resolvedPath)) return `/${resolvedPath}`;
|
|
94
|
-
return resolvedPath.length > 0 ? resolvedPath : ".";
|
|
95
|
-
};
|
|
96
|
-
function normalizeString(path, allowAboveRoot) {
|
|
97
|
-
let res = "";
|
|
98
|
-
let lastSegmentLength = 0;
|
|
99
|
-
let lastSlash = -1;
|
|
100
|
-
let dots = 0;
|
|
101
|
-
let char = null;
|
|
102
|
-
for (let index = 0; index <= path.length; ++index) {
|
|
103
|
-
if (index < path.length) char = path[index];
|
|
104
|
-
else if (char === "/") break;
|
|
105
|
-
else char = "/";
|
|
106
|
-
if (char === "/") {
|
|
107
|
-
if (lastSlash === index - 1 || dots === 1);
|
|
108
|
-
else if (dots === 2) {
|
|
109
|
-
if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
|
|
110
|
-
if (res.length > 2) {
|
|
111
|
-
const lastSlashIndex = res.lastIndexOf("/");
|
|
112
|
-
if (lastSlashIndex === -1) {
|
|
113
|
-
res = "";
|
|
114
|
-
lastSegmentLength = 0;
|
|
115
|
-
} else {
|
|
116
|
-
res = res.slice(0, lastSlashIndex);
|
|
117
|
-
lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
|
|
118
|
-
}
|
|
119
|
-
lastSlash = index;
|
|
120
|
-
dots = 0;
|
|
121
|
-
continue;
|
|
122
|
-
} else if (res.length > 0) {
|
|
123
|
-
res = "";
|
|
124
|
-
lastSegmentLength = 0;
|
|
125
|
-
lastSlash = index;
|
|
126
|
-
dots = 0;
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
if (allowAboveRoot) {
|
|
131
|
-
res += res.length > 0 ? "/.." : "..";
|
|
132
|
-
lastSegmentLength = 2;
|
|
133
|
-
}
|
|
134
|
-
} else {
|
|
135
|
-
if (res.length > 0) res += `/${path.slice(lastSlash + 1, index)}`;
|
|
136
|
-
else res = path.slice(lastSlash + 1, index);
|
|
137
|
-
lastSegmentLength = index - lastSlash - 1;
|
|
138
|
-
}
|
|
139
|
-
lastSlash = index;
|
|
140
|
-
dots = 0;
|
|
141
|
-
} else if (char === "." && dots !== -1) ++dots;
|
|
142
|
-
else dots = -1;
|
|
143
|
-
}
|
|
144
|
-
return res;
|
|
145
|
-
}
|
|
146
|
-
const isAbsolute = function(p) {
|
|
147
|
-
return _IS_ABSOLUTE_RE.test(p);
|
|
148
|
-
};
|
|
149
|
-
const extname = function(p) {
|
|
150
|
-
if (p === "..") return "";
|
|
151
|
-
const match = _EXTNAME_RE.exec(normalizeWindowsPath(p));
|
|
152
|
-
return match && match[1] || "";
|
|
153
|
-
};
|
|
154
|
-
const dirname = function(p) {
|
|
155
|
-
const segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1);
|
|
156
|
-
if (segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0])) segments[0] += "/";
|
|
157
|
-
return segments.join("/") || (isAbsolute(p) ? "/" : ".");
|
|
158
|
-
};
|
|
159
|
-
const basename = function(p, extension) {
|
|
160
|
-
const segments = normalizeWindowsPath(p).split("/");
|
|
161
|
-
let lastSegment = "";
|
|
162
|
-
for (let i = segments.length - 1; i >= 0; i--) {
|
|
163
|
-
const val = segments[i];
|
|
164
|
-
if (val) {
|
|
165
|
-
lastSegment = val;
|
|
166
|
-
break;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
const { existsSync, readdirSync, statSync } = fs;
|
|
173
|
-
function findMockRedirect(root, mockPath, external) {
|
|
174
|
-
const path = external || mockPath;
|
|
175
|
-
// it's a node_module alias
|
|
176
|
-
// all mocks should be inside <root>/__mocks__
|
|
177
|
-
if (external || isNodeBuiltin(mockPath) || !existsSync(mockPath)) {
|
|
178
|
-
const mockFolder = join(root, "__mocks__", dirname(path));
|
|
179
|
-
if (!existsSync(mockFolder)) return null;
|
|
180
|
-
const baseOriginal = basename(path);
|
|
181
|
-
function findFile(mockFolder, baseOriginal) {
|
|
182
|
-
const files = readdirSync(mockFolder);
|
|
183
|
-
for (const file of files) if (basename(file, extname(file)) === baseOriginal) {
|
|
184
|
-
const path = resolve(mockFolder, file);
|
|
185
|
-
// if the same name, return the file
|
|
186
|
-
if (statSync(path).isFile()) return path;
|
|
187
|
-
else {
|
|
188
|
-
// find folder/index.{js,ts}
|
|
189
|
-
const indexFile = findFile(path, "index");
|
|
190
|
-
if (indexFile) return indexFile;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
return findFile(mockFolder, baseOriginal);
|
|
196
|
-
}
|
|
197
|
-
const fullPath = resolve(dirname(path), "__mocks__", basename(path));
|
|
198
|
-
return existsSync(fullPath) ? fullPath : null;
|
|
199
|
-
}
|
|
200
|
-
const builtins = new Set([
|
|
201
|
-
...nodeModule.builtinModules,
|
|
202
|
-
"assert/strict",
|
|
203
|
-
"diagnostics_channel",
|
|
204
|
-
"dns/promises",
|
|
205
|
-
"fs/promises",
|
|
206
|
-
"path/posix",
|
|
207
|
-
"path/win32",
|
|
208
|
-
"readline/promises",
|
|
209
|
-
"stream/consumers",
|
|
210
|
-
"stream/promises",
|
|
211
|
-
"stream/web",
|
|
212
|
-
"timers/promises",
|
|
213
|
-
"util/types",
|
|
214
|
-
"wasi"
|
|
215
|
-
]);
|
|
216
|
-
// https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix
|
|
217
|
-
const prefixedBuiltins$1 = new Set([
|
|
218
|
-
"node:sea",
|
|
219
|
-
"node:sqlite",
|
|
220
|
-
"node:test",
|
|
221
|
-
"node:test/reporters"
|
|
222
|
-
]);
|
|
223
|
-
const NODE_BUILTIN_NAMESPACE = "node:";
|
|
224
|
-
function isNodeBuiltin(id) {
|
|
225
|
-
// Added in v18.6.0
|
|
226
|
-
if (nodeModule.isBuiltin) return nodeModule.isBuiltin(id);
|
|
227
|
-
if (prefixedBuiltins$1.has(id)) return true;
|
|
228
|
-
return builtins.has(id.startsWith(NODE_BUILTIN_NAMESPACE) ? id.slice(5) : id);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const spyModulePath = resolve$1(distDir, "spy.js");
|
|
232
|
-
class VitestMocker {
|
|
16
|
+
class BareModuleMocker {
|
|
233
17
|
static pendingIds = [];
|
|
234
18
|
spyModule;
|
|
235
19
|
primitives;
|
|
236
|
-
filterPublicKeys;
|
|
237
20
|
registries = /* @__PURE__ */ new Map();
|
|
238
21
|
mockContext = { callstack: null };
|
|
239
22
|
_otel;
|
|
240
|
-
constructor(
|
|
241
|
-
this.moduleRunner = moduleRunner;
|
|
23
|
+
constructor(options) {
|
|
242
24
|
this.options = options;
|
|
243
|
-
const context = this.options.context;
|
|
244
25
|
this._otel = options.traces;
|
|
245
|
-
|
|
246
|
-
else this.primitives = {
|
|
26
|
+
this.primitives = {
|
|
247
27
|
Object,
|
|
248
28
|
Error,
|
|
249
29
|
Function,
|
|
@@ -253,37 +33,13 @@ class VitestMocker {
|
|
|
253
33
|
Map
|
|
254
34
|
};
|
|
255
35
|
if (options.spyModule) this.spyModule = options.spyModule;
|
|
256
|
-
const Symbol = this.primitives.Symbol;
|
|
257
|
-
this.filterPublicKeys = [
|
|
258
|
-
"__esModule",
|
|
259
|
-
Symbol.asyncIterator,
|
|
260
|
-
Symbol.hasInstance,
|
|
261
|
-
Symbol.isConcatSpreadable,
|
|
262
|
-
Symbol.iterator,
|
|
263
|
-
Symbol.match,
|
|
264
|
-
Symbol.matchAll,
|
|
265
|
-
Symbol.replace,
|
|
266
|
-
Symbol.search,
|
|
267
|
-
Symbol.split,
|
|
268
|
-
Symbol.species,
|
|
269
|
-
Symbol.toPrimitive,
|
|
270
|
-
Symbol.toStringTag,
|
|
271
|
-
Symbol.unscopables
|
|
272
|
-
];
|
|
273
36
|
}
|
|
274
37
|
get root() {
|
|
275
38
|
return this.options.root;
|
|
276
39
|
}
|
|
277
|
-
get evaluatedModules() {
|
|
278
|
-
return this.moduleRunner.evaluatedModules;
|
|
279
|
-
}
|
|
280
40
|
get moduleDirectories() {
|
|
281
41
|
return this.options.moduleDirectories || [];
|
|
282
42
|
}
|
|
283
|
-
async initializeSpyModule() {
|
|
284
|
-
if (this.spyModule) return;
|
|
285
|
-
this.spyModule = await this.moduleRunner.import(spyModulePath);
|
|
286
|
-
}
|
|
287
43
|
getMockerRegistry() {
|
|
288
44
|
const suite = this.getSuiteFilepath();
|
|
289
45
|
if (!this.registries.has(suite)) this.registries.set(suite, new MockerRegistry());
|
|
@@ -292,13 +48,8 @@ class VitestMocker {
|
|
|
292
48
|
reset() {
|
|
293
49
|
this.registries.clear();
|
|
294
50
|
}
|
|
295
|
-
invalidateModuleById(
|
|
296
|
-
|
|
297
|
-
const node = this.evaluatedModules.getModuleById(mockId);
|
|
298
|
-
if (node) {
|
|
299
|
-
this.evaluatedModules.invalidateModule(node);
|
|
300
|
-
node.mockedExports = void 0;
|
|
301
|
-
}
|
|
51
|
+
invalidateModuleById(_id) {
|
|
52
|
+
// implemented by mockers that control the module runner
|
|
302
53
|
}
|
|
303
54
|
isModuleDirectory(path) {
|
|
304
55
|
return this.moduleDirectories.some((dir) => path.includes(dir));
|
|
@@ -335,7 +86,7 @@ class VitestMocker {
|
|
|
335
86
|
}
|
|
336
87
|
// external is node_module or unresolved module
|
|
337
88
|
// for example, some people mock "vscode" and don't have it installed
|
|
338
|
-
const external = !isAbsolute
|
|
89
|
+
const external = !isAbsolute(result.file) || this.isModuleDirectory(result.file) ? normalizeModuleId(rawId) : null;
|
|
339
90
|
const id = normalizeModuleId(result.id);
|
|
340
91
|
span.setAttributes({
|
|
341
92
|
"vitest.module.id": id,
|
|
@@ -350,51 +101,13 @@ class VitestMocker {
|
|
|
350
101
|
});
|
|
351
102
|
}
|
|
352
103
|
async resolveMocks() {
|
|
353
|
-
if (!
|
|
354
|
-
await Promise.all(
|
|
104
|
+
if (!BareModuleMocker.pendingIds.length) return;
|
|
105
|
+
await Promise.all(BareModuleMocker.pendingIds.map(async (mock) => {
|
|
355
106
|
const { id, url, external } = await this.resolveId(mock.id, mock.importer);
|
|
356
107
|
if (mock.action === "unmock") this.unmockPath(id);
|
|
357
108
|
if (mock.action === "mock") this.mockPath(mock.id, id, url, external, mock.type, mock.factory);
|
|
358
109
|
}));
|
|
359
|
-
|
|
360
|
-
}
|
|
361
|
-
ensureModule(id, url) {
|
|
362
|
-
const node = this.evaluatedModules.ensureModule(id, url);
|
|
363
|
-
// TODO
|
|
364
|
-
node.meta = {
|
|
365
|
-
id,
|
|
366
|
-
url,
|
|
367
|
-
code: "",
|
|
368
|
-
file: null,
|
|
369
|
-
invalidate: false
|
|
370
|
-
};
|
|
371
|
-
return node;
|
|
372
|
-
}
|
|
373
|
-
async callFunctionMock(id, url, mock) {
|
|
374
|
-
const node = this.ensureModule(id, url);
|
|
375
|
-
if (node.exports) return node.exports;
|
|
376
|
-
const exports$1 = await mock.resolve();
|
|
377
|
-
const moduleExports = new Proxy(exports$1, { get: (target, prop) => {
|
|
378
|
-
const val = target[prop];
|
|
379
|
-
// 'then' can exist on non-Promise objects, need nested instanceof check for logic to work
|
|
380
|
-
if (prop === "then") {
|
|
381
|
-
if (target instanceof Promise) return target.then.bind(target);
|
|
382
|
-
} else if (!(prop in target)) {
|
|
383
|
-
if (this.filterPublicKeys.includes(prop)) return;
|
|
384
|
-
throw this.createError(`[vitest] No "${String(prop)}" export is defined on the "${mock.raw}" mock. Did you forget to return it from "vi.mock"?
|
|
385
|
-
If you need to partially mock a module, you can use "importOriginal" helper inside:
|
|
386
|
-
`, `vi.mock(import("${mock.raw}"), async (importOriginal) => {
|
|
387
|
-
const actual = await importOriginal()
|
|
388
|
-
return {
|
|
389
|
-
...actual,
|
|
390
|
-
// your mocked methods
|
|
391
|
-
}
|
|
392
|
-
})`);
|
|
393
|
-
}
|
|
394
|
-
return val;
|
|
395
|
-
} });
|
|
396
|
-
node.exports = moduleExports;
|
|
397
|
-
return moduleExports;
|
|
110
|
+
BareModuleMocker.pendingIds = [];
|
|
398
111
|
}
|
|
399
112
|
// public method to avoid circular dependency
|
|
400
113
|
getMockContext() {
|
|
@@ -435,6 +148,151 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
|
|
|
435
148
|
// every time the mock is registered, we remove the previous one from the cache
|
|
436
149
|
this.invalidateModuleById(id);
|
|
437
150
|
}
|
|
151
|
+
async importActual(_rawId, _importer, _callstack) {
|
|
152
|
+
throw new Error(`importActual is not implemented`);
|
|
153
|
+
}
|
|
154
|
+
async importMock(_rawId, _importer, _callstack) {
|
|
155
|
+
throw new Error(`importMock is not implemented`);
|
|
156
|
+
}
|
|
157
|
+
queueMock(id, importer, factoryOrOptions) {
|
|
158
|
+
const mockType = getMockType(factoryOrOptions);
|
|
159
|
+
BareModuleMocker.pendingIds.push({
|
|
160
|
+
action: "mock",
|
|
161
|
+
id,
|
|
162
|
+
importer,
|
|
163
|
+
factory: typeof factoryOrOptions === "function" ? factoryOrOptions : void 0,
|
|
164
|
+
type: mockType
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
queueUnmock(id, importer) {
|
|
168
|
+
BareModuleMocker.pendingIds.push({
|
|
169
|
+
action: "unmock",
|
|
170
|
+
id,
|
|
171
|
+
importer
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function getMockType(factoryOrOptions) {
|
|
176
|
+
if (!factoryOrOptions) return "automock";
|
|
177
|
+
if (typeof factoryOrOptions === "function") return "manual";
|
|
178
|
+
return factoryOrOptions.spy ? "autospy" : "automock";
|
|
179
|
+
}
|
|
180
|
+
// unique id that is not available as "$bare_import" like "test"
|
|
181
|
+
// https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix
|
|
182
|
+
const prefixedBuiltins = new Set([
|
|
183
|
+
"node:sea",
|
|
184
|
+
"node:sqlite",
|
|
185
|
+
"node:test",
|
|
186
|
+
"node:test/reporters"
|
|
187
|
+
]);
|
|
188
|
+
const isWindows$1 = process.platform === "win32";
|
|
189
|
+
// transform file url to id
|
|
190
|
+
// virtual:custom -> virtual:custom
|
|
191
|
+
// \0custom -> \0custom
|
|
192
|
+
// /root/id -> /id
|
|
193
|
+
// /root/id.js -> /id.js
|
|
194
|
+
// C:/root/id.js -> /id.js
|
|
195
|
+
// C:\root\id.js -> /id.js
|
|
196
|
+
// TODO: expose this in vite/module-runner
|
|
197
|
+
function normalizeModuleId(file) {
|
|
198
|
+
if (prefixedBuiltins.has(file)) return file;
|
|
199
|
+
// if it's not in the root, keep it as a path, not a URL
|
|
200
|
+
return slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/");
|
|
201
|
+
}
|
|
202
|
+
const windowsSlashRE = /\\/g;
|
|
203
|
+
function slash(p) {
|
|
204
|
+
return p.replace(windowsSlashRE, "/");
|
|
205
|
+
}
|
|
206
|
+
const multipleSlashRe = /^\/+/;
|
|
207
|
+
// module-runner incorrectly replaces file:///path with `///path`
|
|
208
|
+
function fixLeadingSlashes(id) {
|
|
209
|
+
if (id.startsWith("//")) return id.replace(multipleSlashRe, "/");
|
|
210
|
+
return id;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const spyModulePath = resolve(distDir, "spy.js");
|
|
214
|
+
class VitestMocker extends BareModuleMocker {
|
|
215
|
+
filterPublicKeys;
|
|
216
|
+
constructor(moduleRunner, options) {
|
|
217
|
+
super(options);
|
|
218
|
+
this.moduleRunner = moduleRunner;
|
|
219
|
+
this.options = options;
|
|
220
|
+
const context = this.options.context;
|
|
221
|
+
if (context) this.primitives = vm.runInContext("({ Object, Error, Function, RegExp, Symbol, Array, Map })", context);
|
|
222
|
+
const Symbol = this.primitives.Symbol;
|
|
223
|
+
this.filterPublicKeys = [
|
|
224
|
+
"__esModule",
|
|
225
|
+
Symbol.asyncIterator,
|
|
226
|
+
Symbol.hasInstance,
|
|
227
|
+
Symbol.isConcatSpreadable,
|
|
228
|
+
Symbol.iterator,
|
|
229
|
+
Symbol.match,
|
|
230
|
+
Symbol.matchAll,
|
|
231
|
+
Symbol.replace,
|
|
232
|
+
Symbol.search,
|
|
233
|
+
Symbol.split,
|
|
234
|
+
Symbol.species,
|
|
235
|
+
Symbol.toPrimitive,
|
|
236
|
+
Symbol.toStringTag,
|
|
237
|
+
Symbol.unscopables
|
|
238
|
+
];
|
|
239
|
+
}
|
|
240
|
+
get evaluatedModules() {
|
|
241
|
+
return this.moduleRunner.evaluatedModules;
|
|
242
|
+
}
|
|
243
|
+
async initializeSpyModule() {
|
|
244
|
+
if (this.spyModule) return;
|
|
245
|
+
this.spyModule = await this.moduleRunner.import(spyModulePath);
|
|
246
|
+
}
|
|
247
|
+
reset() {
|
|
248
|
+
this.registries.clear();
|
|
249
|
+
}
|
|
250
|
+
invalidateModuleById(id) {
|
|
251
|
+
const mockId = this.getMockPath(id);
|
|
252
|
+
const node = this.evaluatedModules.getModuleById(mockId);
|
|
253
|
+
if (node) {
|
|
254
|
+
this.evaluatedModules.invalidateModule(node);
|
|
255
|
+
node.mockedExports = void 0;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
ensureModule(id, url) {
|
|
259
|
+
const node = this.evaluatedModules.ensureModule(id, url);
|
|
260
|
+
// TODO
|
|
261
|
+
node.meta = {
|
|
262
|
+
id,
|
|
263
|
+
url,
|
|
264
|
+
code: "",
|
|
265
|
+
file: null,
|
|
266
|
+
invalidate: false
|
|
267
|
+
};
|
|
268
|
+
return node;
|
|
269
|
+
}
|
|
270
|
+
async callFunctionMock(id, url, mock) {
|
|
271
|
+
const node = this.ensureModule(id, url);
|
|
272
|
+
if (node.exports) return node.exports;
|
|
273
|
+
const exports$1 = await mock.resolve();
|
|
274
|
+
const moduleExports = new Proxy(exports$1, { get: (target, prop) => {
|
|
275
|
+
const val = target[prop];
|
|
276
|
+
// 'then' can exist on non-Promise objects, need nested instanceof check for logic to work
|
|
277
|
+
if (prop === "then") {
|
|
278
|
+
if (target instanceof Promise) return target.then.bind(target);
|
|
279
|
+
} else if (!(prop in target)) {
|
|
280
|
+
if (this.filterPublicKeys.includes(prop)) return;
|
|
281
|
+
throw this.createError(`[vitest] No "${String(prop)}" export is defined on the "${mock.raw}" mock. Did you forget to return it from "vi.mock"?
|
|
282
|
+
If you need to partially mock a module, you can use "importOriginal" helper inside:
|
|
283
|
+
`, `vi.mock(import("${mock.raw}"), async (importOriginal) => {
|
|
284
|
+
const actual = await importOriginal()
|
|
285
|
+
return {
|
|
286
|
+
...actual,
|
|
287
|
+
// your mocked methods
|
|
288
|
+
}
|
|
289
|
+
})`);
|
|
290
|
+
}
|
|
291
|
+
return val;
|
|
292
|
+
} });
|
|
293
|
+
node.exports = moduleExports;
|
|
294
|
+
return moduleExports;
|
|
295
|
+
}
|
|
438
296
|
async importActual(rawId, importer, callstack) {
|
|
439
297
|
const { url } = await this.resolveId(rawId, importer);
|
|
440
298
|
const node = await this.moduleRunner.fetchModule(url, importer);
|
|
@@ -511,61 +369,28 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
|
|
|
511
369
|
if (!mock) return;
|
|
512
370
|
return this.requestWithMockedModule(url, evaluatedNode, callstack, mock);
|
|
513
371
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
importer,
|
|
520
|
-
factory: typeof factoryOrOptions === "function" ? factoryOrOptions : void 0,
|
|
521
|
-
type: mockType
|
|
522
|
-
});
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
class VitestTransport {
|
|
375
|
+
constructor(options) {
|
|
376
|
+
this.options = options;
|
|
523
377
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
378
|
+
async invoke(event) {
|
|
379
|
+
if (event.type !== "custom") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support Vite HMR events.`) };
|
|
380
|
+
if (event.event !== "vite:invoke") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support ${event.event} event.`) };
|
|
381
|
+
const { name, data } = event.data;
|
|
382
|
+
if (name === "getBuiltins")
|
|
383
|
+
// we return an empty array here to avoid client-side builtin check,
|
|
384
|
+
// as we need builtins to go through `fetchModule`
|
|
385
|
+
return { result: [] };
|
|
386
|
+
if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) };
|
|
387
|
+
try {
|
|
388
|
+
return { result: await this.options.fetchModule(...data) };
|
|
389
|
+
} catch (error) {
|
|
390
|
+
return { error };
|
|
391
|
+
}
|
|
530
392
|
}
|
|
531
393
|
}
|
|
532
|
-
function getMockType(factoryOrOptions) {
|
|
533
|
-
if (!factoryOrOptions) return "automock";
|
|
534
|
-
if (typeof factoryOrOptions === "function") return "manual";
|
|
535
|
-
return factoryOrOptions.spy ? "autospy" : "automock";
|
|
536
|
-
}
|
|
537
|
-
// unique id that is not available as "$bare_import" like "test"
|
|
538
|
-
// https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix
|
|
539
|
-
const prefixedBuiltins = new Set([
|
|
540
|
-
"node:sea",
|
|
541
|
-
"node:sqlite",
|
|
542
|
-
"node:test",
|
|
543
|
-
"node:test/reporters"
|
|
544
|
-
]);
|
|
545
|
-
const isWindows$1 = process.platform === "win32";
|
|
546
|
-
// transform file url to id
|
|
547
|
-
// virtual:custom -> virtual:custom
|
|
548
|
-
// \0custom -> \0custom
|
|
549
|
-
// /root/id -> /id
|
|
550
|
-
// /root/id.js -> /id.js
|
|
551
|
-
// C:/root/id.js -> /id.js
|
|
552
|
-
// C:\root\id.js -> /id.js
|
|
553
|
-
// TODO: expose this in vite/module-runner
|
|
554
|
-
function normalizeModuleId(file) {
|
|
555
|
-
if (prefixedBuiltins.has(file)) return file;
|
|
556
|
-
// if it's not in the root, keep it as a path, not a URL
|
|
557
|
-
return slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/");
|
|
558
|
-
}
|
|
559
|
-
const windowsSlashRE = /\\/g;
|
|
560
|
-
function slash(p) {
|
|
561
|
-
return p.replace(windowsSlashRE, "/");
|
|
562
|
-
}
|
|
563
|
-
const multipleSlashRe = /^\/+/;
|
|
564
|
-
// module-runner incorrectly replaces file:///path with `///path`
|
|
565
|
-
function fixLeadingSlashes(id) {
|
|
566
|
-
if (id.startsWith("//")) return id.replace(multipleSlashRe, "/");
|
|
567
|
-
return id;
|
|
568
|
-
}
|
|
569
394
|
|
|
570
395
|
const createNodeImportMeta = (modulePath) => {
|
|
571
396
|
if (!viteModuleRunner.createDefaultImportMeta) throw new Error(`createNodeImportMeta is not supported in this version of Vite.`);
|
|
@@ -684,7 +509,7 @@ class VitestModuleRunner extends viteModuleRunner.ModuleRunner {
|
|
|
684
509
|
}
|
|
685
510
|
|
|
686
511
|
const bareVitestRegexp = /^@?vitest(?:\/|$)/;
|
|
687
|
-
const normalizedDistDir = normalize
|
|
512
|
+
const normalizedDistDir = normalize(distDir);
|
|
688
513
|
const relativeIds = {};
|
|
689
514
|
const externalizeMap = /* @__PURE__ */ new Map();
|
|
690
515
|
// all Vitest imports always need to be externalized
|
|
@@ -707,7 +532,7 @@ function getCachedVitestImport(id, state) {
|
|
|
707
532
|
};
|
|
708
533
|
}
|
|
709
534
|
if (relativeRoot && relativeRoot !== "/" && id.startsWith(relativeRoot)) {
|
|
710
|
-
const externalize = pathToFileURL(join
|
|
535
|
+
const externalize = pathToFileURL(join(root, id)).toString();
|
|
711
536
|
externalizeMap.set(id, externalize);
|
|
712
537
|
return {
|
|
713
538
|
externalize,
|
|
@@ -724,48 +549,14 @@ function getCachedVitestImport(id, state) {
|
|
|
724
549
|
return null;
|
|
725
550
|
}
|
|
726
551
|
|
|
727
|
-
// Store globals in case tests overwrite them
|
|
728
|
-
const processListeners = process.listeners.bind(process);
|
|
729
|
-
const processOn = process.on.bind(process);
|
|
730
|
-
const processOff = process.off.bind(process);
|
|
731
|
-
const dispose = [];
|
|
732
|
-
function listenForErrors(state) {
|
|
733
|
-
dispose.forEach((fn) => fn());
|
|
734
|
-
dispose.length = 0;
|
|
735
|
-
function catchError(err, type, event) {
|
|
736
|
-
const worker = state();
|
|
737
|
-
// if there is another listener, assume that it's handled by user code
|
|
738
|
-
// one is Vitest's own listener
|
|
739
|
-
if (processListeners(event).length > 1) return;
|
|
740
|
-
const error = serializeValue(err);
|
|
741
|
-
if (typeof error === "object" && error != null) {
|
|
742
|
-
error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0;
|
|
743
|
-
if (worker.filepath) error.VITEST_TEST_PATH = worker.filepath;
|
|
744
|
-
}
|
|
745
|
-
state().rpc.onUnhandledError(error, type);
|
|
746
|
-
}
|
|
747
|
-
const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException");
|
|
748
|
-
const unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection");
|
|
749
|
-
processOn("uncaughtException", uncaughtException);
|
|
750
|
-
processOn("unhandledRejection", unhandledRejection);
|
|
751
|
-
dispose.push(() => {
|
|
752
|
-
processOff("uncaughtException", uncaughtException);
|
|
753
|
-
processOff("unhandledRejection", unhandledRejection);
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
|
|
757
552
|
const { readFileSync } = fs;
|
|
758
553
|
const VITEST_VM_CONTEXT_SYMBOL = "__vitest_vm_context__";
|
|
759
554
|
const cwd = process.cwd();
|
|
760
555
|
const isWindows = process.platform === "win32";
|
|
761
556
|
function startVitestModuleRunner(options) {
|
|
762
557
|
const traces = options.traces;
|
|
763
|
-
const state = () =>
|
|
558
|
+
const state = () => getSafeWorkerState() || options.state;
|
|
764
559
|
const rpc = () => state().rpc;
|
|
765
|
-
process.exit = (code = process.exitCode || 0) => {
|
|
766
|
-
throw new Error(`process.exit unexpectedly called with "${code}"`);
|
|
767
|
-
};
|
|
768
|
-
listenForErrors(state);
|
|
769
560
|
const environment = () => {
|
|
770
561
|
const environment = state().environment;
|
|
771
562
|
return environment.viteEnvironment || environment.name;
|
|
@@ -838,7 +629,7 @@ function startVitestModuleRunner(options) {
|
|
|
838
629
|
} catch (cause) {
|
|
839
630
|
// rethrow vite error if it cannot load the module because it's not resolved
|
|
840
631
|
if (typeof cause === "object" && cause != null && cause.code === "ERR_LOAD_URL" || typeof cause?.message === "string" && cause.message.includes("Failed to load url") || typeof cause?.message === "string" && cause.message.startsWith("Cannot find module '")) {
|
|
841
|
-
const error = new Error(`Cannot find ${isBareImport(id) ? "package" : "module"} '${id}'${importer ? ` imported from
|
|
632
|
+
const error = new Error(`Cannot find ${isBareImport(id) ? "package" : "module"} '${id}'${importer ? ` imported from ${importer}` : ""}`, { cause });
|
|
842
633
|
error.code = "ERR_MODULE_NOT_FOUND";
|
|
843
634
|
throw error;
|
|
844
635
|
}
|
|
@@ -858,4 +649,4 @@ function startVitestModuleRunner(options) {
|
|
|
858
649
|
return moduleRunner;
|
|
859
650
|
}
|
|
860
651
|
|
|
861
|
-
export {
|
|
652
|
+
export { BareModuleMocker as B, VITEST_VM_CONTEXT_SYMBOL as V, VitestModuleRunner as a, VitestTransport as b, createNodeImportMeta as c, normalizeModuleId as n, startVitestModuleRunner as s };
|