vitest 4.1.0-beta.1 → 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.CBRNZa3k.js → base.DiopZV8F.js} +48 -14
- package/dist/chunks/{benchmark.B3N2zMcH.js → benchmark.BoqSLF53.js} +1 -1
- package/dist/chunks/{browser.d.8hOapKZr.d.ts → browser.d.BE4kbYok.d.ts} +2 -1
- package/dist/chunks/{cac.B1v3xxoC.js → cac.C4jjt2RX.js} +797 -13
- package/dist/chunks/{cli-api.B4CqEpI6.js → cli-api.ChbI1JU9.js} +322 -124
- package/dist/chunks/{config.d.idH22YSr.d.ts → config.d.Cr1Ep39N.d.ts} +6 -1
- package/dist/chunks/{console.uGgdMhyZ.js → console.CNlG1KsP.js} +2 -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.C7WwjkuR.js → creator.yyCHuw5R.js} +1 -1
- package/dist/chunks/{global.d.B15mdLcR.d.ts → global.d.JeWMqlOm.d.ts} +1 -1
- package/dist/chunks/{globals.DjuGMoMc.js → globals.C6Ecf1TO.js} +6 -6
- package/dist/chunks/{index.Dm4xqZ0s.js → index.B-iBE_Gx.js} +20 -4
- package/dist/chunks/{coverage.BMlOMIWl.js → index.BCY_7LL2.js} +5 -969
- package/dist/chunks/{index.BiOAd_ki.js → index.CAN630q3.js} +7 -7
- package/dist/chunks/{index.DyBZXrH3.js → index.CFulQRmC.js} +1 -1
- package/dist/chunks/{index.BEFi2-_3.js → index.CouFDptX.js} +2 -2
- package/dist/chunks/{init-forks.CHeQ9Moq.js → init-forks.BnCXPazU.js} +1 -1
- package/dist/chunks/{init-threads.uZiNAuPk.js → init-threads.Cyh2PqXi.js} +1 -1
- package/dist/chunks/{init.DVtKdFty.js → init.B95Mm0Iz.js} +47 -9
- 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.D8KU2PY_.d.ts → plugin.d.C9o5bttz.d.ts} +1 -1
- package/dist/chunks/{reporters.d.Db3MiIWX.d.ts → reporters.d.7faYdkxy.d.ts} +120 -51
- package/dist/chunks/{rpc.HLmECnw_.js → rpc.DcRWTy5G.js} +1 -1
- package/dist/chunks/{rpc.d.RH3apGEf.d.ts → rpc.d.CM7x9-sm.d.ts} +1 -0
- package/dist/chunks/{setup-common.BcqLPsn5.js → setup-common.cvFp-ao9.js} +2 -2
- package/dist/chunks/{startModuleRunner.C5CcWyXW.js → startVitestModuleRunner.BK-u7y4N.js} +163 -372
- package/dist/chunks/{test.prxIahgM.js → test.G82XYNFk.js} +9 -4
- package/dist/chunks/{utils.DvEY5TfP.js → utils.DT4VyRyl.js} +5 -1
- package/dist/chunks/{vm.CrifS09m.js → vm.BdLtzhnj.js} +13 -6
- package/dist/chunks/{worker.d.Bji1eq5g.d.ts → worker.d.CPzI2ZzJ.d.ts} +2 -2
- package/dist/cli.js +4 -3
- package/dist/config.d.ts +8 -8
- package/dist/config.js +1 -1
- package/dist/coverage.d.ts +7 -5
- package/dist/coverage.js +5 -4
- package/dist/index.d.ts +18 -23
- package/dist/index.js +5 -5
- package/dist/module-evaluator.d.ts +10 -1
- package/dist/node.d.ts +9 -9
- package/dist/node.js +18 -16
- package/dist/nodejs-worker-loader.js +41 -0
- package/dist/reporters.d.ts +5 -5
- package/dist/reporters.js +2 -2
- package/dist/runners.d.ts +2 -1
- package/dist/runners.js +4 -4
- package/dist/runtime.js +4 -5
- package/dist/snapshot.js +2 -2
- package/dist/suite.js +2 -2
- package/dist/worker.d.ts +6 -6
- package/dist/worker.js +25 -18
- package/dist/workers/forks.js +21 -14
- package/dist/workers/runVmTests.js +7 -7
- package/dist/workers/threads.js +21 -14
- package/dist/workers/vmForks.js +14 -10
- package/dist/workers/vmThreads.js +14 -10
- package/package.json +17 -14
- package/suppress-warnings.cjs +1 -0
|
@@ -1,228 +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
|
-
|
|
17
|
-
function normalizeWindowsPath(input = "") {
|
|
18
|
-
if (!input) return input;
|
|
19
|
-
return input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
|
|
20
|
-
}
|
|
21
|
-
const _UNC_REGEX = /^[/\\]{2}/;
|
|
22
|
-
const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
|
|
23
|
-
const _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
|
|
24
|
-
const _EXTNAME_RE = /.(\.[^./]+|\.)$/;
|
|
25
|
-
const normalize = function(path) {
|
|
26
|
-
if (path.length === 0) return ".";
|
|
27
|
-
path = normalizeWindowsPath(path);
|
|
28
|
-
const isUNCPath = path.match(_UNC_REGEX);
|
|
29
|
-
const isPathAbsolute = isAbsolute(path);
|
|
30
|
-
const trailingSeparator = path[path.length - 1] === "/";
|
|
31
|
-
path = normalizeString(path, !isPathAbsolute);
|
|
32
|
-
if (path.length === 0) {
|
|
33
|
-
if (isPathAbsolute) return "/";
|
|
34
|
-
return trailingSeparator ? "./" : ".";
|
|
35
|
-
}
|
|
36
|
-
if (trailingSeparator) path += "/";
|
|
37
|
-
if (_DRIVE_LETTER_RE.test(path)) path += "/";
|
|
38
|
-
if (isUNCPath) {
|
|
39
|
-
if (!isPathAbsolute) return `//./${path}`;
|
|
40
|
-
return `//${path}`;
|
|
41
|
-
}
|
|
42
|
-
return isPathAbsolute && !isAbsolute(path) ? `/${path}` : path;
|
|
43
|
-
};
|
|
44
|
-
const join = function(...segments) {
|
|
45
|
-
let path = "";
|
|
46
|
-
for (const seg of segments) {
|
|
47
|
-
if (!seg) continue;
|
|
48
|
-
if (path.length > 0) {
|
|
49
|
-
const pathTrailing = path[path.length - 1] === "/";
|
|
50
|
-
const segLeading = seg[0] === "/";
|
|
51
|
-
if (pathTrailing && segLeading) path += seg.slice(1);
|
|
52
|
-
else path += pathTrailing || segLeading ? seg : `/${seg}`;
|
|
53
|
-
} else path += seg;
|
|
54
|
-
}
|
|
55
|
-
return normalize(path);
|
|
56
|
-
};
|
|
57
|
-
function cwd$1() {
|
|
58
|
-
if (typeof process !== "undefined" && typeof process.cwd === "function") return process.cwd().replace(/\\/g, "/");
|
|
59
|
-
return "/";
|
|
60
|
-
}
|
|
61
|
-
const resolve = function(...arguments_) {
|
|
62
|
-
arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
|
|
63
|
-
let resolvedPath = "";
|
|
64
|
-
let resolvedAbsolute = false;
|
|
65
|
-
for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
|
|
66
|
-
const path = index >= 0 ? arguments_[index] : cwd$1();
|
|
67
|
-
if (!path || path.length === 0) continue;
|
|
68
|
-
resolvedPath = `${path}/${resolvedPath}`;
|
|
69
|
-
resolvedAbsolute = isAbsolute(path);
|
|
70
|
-
}
|
|
71
|
-
resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
|
|
72
|
-
if (resolvedAbsolute && !isAbsolute(resolvedPath)) return `/${resolvedPath}`;
|
|
73
|
-
return resolvedPath.length > 0 ? resolvedPath : ".";
|
|
74
|
-
};
|
|
75
|
-
function normalizeString(path, allowAboveRoot) {
|
|
76
|
-
let res = "";
|
|
77
|
-
let lastSegmentLength = 0;
|
|
78
|
-
let lastSlash = -1;
|
|
79
|
-
let dots = 0;
|
|
80
|
-
let char = null;
|
|
81
|
-
for (let index = 0; index <= path.length; ++index) {
|
|
82
|
-
if (index < path.length) char = path[index];
|
|
83
|
-
else if (char === "/") break;
|
|
84
|
-
else char = "/";
|
|
85
|
-
if (char === "/") {
|
|
86
|
-
if (lastSlash === index - 1 || dots === 1);
|
|
87
|
-
else if (dots === 2) {
|
|
88
|
-
if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
|
|
89
|
-
if (res.length > 2) {
|
|
90
|
-
const lastSlashIndex = res.lastIndexOf("/");
|
|
91
|
-
if (lastSlashIndex === -1) {
|
|
92
|
-
res = "";
|
|
93
|
-
lastSegmentLength = 0;
|
|
94
|
-
} else {
|
|
95
|
-
res = res.slice(0, lastSlashIndex);
|
|
96
|
-
lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
|
|
97
|
-
}
|
|
98
|
-
lastSlash = index;
|
|
99
|
-
dots = 0;
|
|
100
|
-
continue;
|
|
101
|
-
} else if (res.length > 0) {
|
|
102
|
-
res = "";
|
|
103
|
-
lastSegmentLength = 0;
|
|
104
|
-
lastSlash = index;
|
|
105
|
-
dots = 0;
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (allowAboveRoot) {
|
|
110
|
-
res += res.length > 0 ? "/.." : "..";
|
|
111
|
-
lastSegmentLength = 2;
|
|
112
|
-
}
|
|
113
|
-
} else {
|
|
114
|
-
if (res.length > 0) res += `/${path.slice(lastSlash + 1, index)}`;
|
|
115
|
-
else res = path.slice(lastSlash + 1, index);
|
|
116
|
-
lastSegmentLength = index - lastSlash - 1;
|
|
117
|
-
}
|
|
118
|
-
lastSlash = index;
|
|
119
|
-
dots = 0;
|
|
120
|
-
} else if (char === "." && dots !== -1) ++dots;
|
|
121
|
-
else dots = -1;
|
|
122
|
-
}
|
|
123
|
-
return res;
|
|
124
|
-
}
|
|
125
|
-
const isAbsolute = function(p) {
|
|
126
|
-
return _IS_ABSOLUTE_RE.test(p);
|
|
127
|
-
};
|
|
128
|
-
const extname = function(p) {
|
|
129
|
-
if (p === "..") return "";
|
|
130
|
-
const match = _EXTNAME_RE.exec(normalizeWindowsPath(p));
|
|
131
|
-
return match && match[1] || "";
|
|
132
|
-
};
|
|
133
|
-
const dirname = function(p) {
|
|
134
|
-
const segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1);
|
|
135
|
-
if (segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0])) segments[0] += "/";
|
|
136
|
-
return segments.join("/") || (isAbsolute(p) ? "/" : ".");
|
|
137
|
-
};
|
|
138
|
-
const basename = function(p, extension) {
|
|
139
|
-
const segments = normalizeWindowsPath(p).split("/");
|
|
140
|
-
let lastSegment = "";
|
|
141
|
-
for (let i = segments.length - 1; i >= 0; i--) {
|
|
142
|
-
const val = segments[i];
|
|
143
|
-
if (val) {
|
|
144
|
-
lastSegment = val;
|
|
145
|
-
break;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const { existsSync, readdirSync, statSync } = fs;
|
|
152
|
-
function findMockRedirect(root, mockPath, external) {
|
|
153
|
-
const path = external || mockPath;
|
|
154
|
-
// it's a node_module alias
|
|
155
|
-
// all mocks should be inside <root>/__mocks__
|
|
156
|
-
if (external || isNodeBuiltin(mockPath) || !existsSync(mockPath)) {
|
|
157
|
-
const mockFolder = join(root, "__mocks__", dirname(path));
|
|
158
|
-
if (!existsSync(mockFolder)) return null;
|
|
159
|
-
const baseOriginal = basename(path);
|
|
160
|
-
function findFile(mockFolder, baseOriginal) {
|
|
161
|
-
const files = readdirSync(mockFolder);
|
|
162
|
-
for (const file of files) if (basename(file, extname(file)) === baseOriginal) {
|
|
163
|
-
const path = resolve(mockFolder, file);
|
|
164
|
-
// if the same name, return the file
|
|
165
|
-
if (statSync(path).isFile()) return path;
|
|
166
|
-
else {
|
|
167
|
-
// find folder/index.{js,ts}
|
|
168
|
-
const indexFile = findFile(path, "index");
|
|
169
|
-
if (indexFile) return indexFile;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
return findFile(mockFolder, baseOriginal);
|
|
175
|
-
}
|
|
176
|
-
const fullPath = resolve(dirname(path), "__mocks__", basename(path));
|
|
177
|
-
return existsSync(fullPath) ? fullPath : null;
|
|
178
|
-
}
|
|
179
|
-
const builtins = new Set([
|
|
180
|
-
...nodeModule.builtinModules,
|
|
181
|
-
"assert/strict",
|
|
182
|
-
"diagnostics_channel",
|
|
183
|
-
"dns/promises",
|
|
184
|
-
"fs/promises",
|
|
185
|
-
"path/posix",
|
|
186
|
-
"path/win32",
|
|
187
|
-
"readline/promises",
|
|
188
|
-
"stream/consumers",
|
|
189
|
-
"stream/promises",
|
|
190
|
-
"stream/web",
|
|
191
|
-
"timers/promises",
|
|
192
|
-
"util/types",
|
|
193
|
-
"wasi"
|
|
194
|
-
]);
|
|
195
|
-
// https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix
|
|
196
|
-
const prefixedBuiltins$1 = new Set([
|
|
197
|
-
"node:sea",
|
|
198
|
-
"node:sqlite",
|
|
199
|
-
"node:test",
|
|
200
|
-
"node:test/reporters"
|
|
201
|
-
]);
|
|
202
|
-
const NODE_BUILTIN_NAMESPACE = "node:";
|
|
203
|
-
function isNodeBuiltin(id) {
|
|
204
|
-
// Added in v18.6.0
|
|
205
|
-
if (nodeModule.isBuiltin) return nodeModule.isBuiltin(id);
|
|
206
|
-
if (prefixedBuiltins$1.has(id)) return true;
|
|
207
|
-
return builtins.has(id.startsWith(NODE_BUILTIN_NAMESPACE) ? id.slice(5) : id);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const spyModulePath = resolve$1(distDir, "spy.js");
|
|
211
|
-
class VitestMocker {
|
|
16
|
+
class BareModuleMocker {
|
|
212
17
|
static pendingIds = [];
|
|
213
18
|
spyModule;
|
|
214
19
|
primitives;
|
|
215
|
-
filterPublicKeys;
|
|
216
20
|
registries = /* @__PURE__ */ new Map();
|
|
217
21
|
mockContext = { callstack: null };
|
|
218
22
|
_otel;
|
|
219
|
-
constructor(
|
|
220
|
-
this.moduleRunner = moduleRunner;
|
|
23
|
+
constructor(options) {
|
|
221
24
|
this.options = options;
|
|
222
|
-
const context = this.options.context;
|
|
223
25
|
this._otel = options.traces;
|
|
224
|
-
|
|
225
|
-
else this.primitives = {
|
|
26
|
+
this.primitives = {
|
|
226
27
|
Object,
|
|
227
28
|
Error,
|
|
228
29
|
Function,
|
|
@@ -232,37 +33,13 @@ class VitestMocker {
|
|
|
232
33
|
Map
|
|
233
34
|
};
|
|
234
35
|
if (options.spyModule) this.spyModule = options.spyModule;
|
|
235
|
-
const Symbol = this.primitives.Symbol;
|
|
236
|
-
this.filterPublicKeys = [
|
|
237
|
-
"__esModule",
|
|
238
|
-
Symbol.asyncIterator,
|
|
239
|
-
Symbol.hasInstance,
|
|
240
|
-
Symbol.isConcatSpreadable,
|
|
241
|
-
Symbol.iterator,
|
|
242
|
-
Symbol.match,
|
|
243
|
-
Symbol.matchAll,
|
|
244
|
-
Symbol.replace,
|
|
245
|
-
Symbol.search,
|
|
246
|
-
Symbol.split,
|
|
247
|
-
Symbol.species,
|
|
248
|
-
Symbol.toPrimitive,
|
|
249
|
-
Symbol.toStringTag,
|
|
250
|
-
Symbol.unscopables
|
|
251
|
-
];
|
|
252
36
|
}
|
|
253
37
|
get root() {
|
|
254
38
|
return this.options.root;
|
|
255
39
|
}
|
|
256
|
-
get evaluatedModules() {
|
|
257
|
-
return this.moduleRunner.evaluatedModules;
|
|
258
|
-
}
|
|
259
40
|
get moduleDirectories() {
|
|
260
41
|
return this.options.moduleDirectories || [];
|
|
261
42
|
}
|
|
262
|
-
async initializeSpyModule() {
|
|
263
|
-
if (this.spyModule) return;
|
|
264
|
-
this.spyModule = await this.moduleRunner.import(spyModulePath);
|
|
265
|
-
}
|
|
266
43
|
getMockerRegistry() {
|
|
267
44
|
const suite = this.getSuiteFilepath();
|
|
268
45
|
if (!this.registries.has(suite)) this.registries.set(suite, new MockerRegistry());
|
|
@@ -271,13 +48,8 @@ class VitestMocker {
|
|
|
271
48
|
reset() {
|
|
272
49
|
this.registries.clear();
|
|
273
50
|
}
|
|
274
|
-
invalidateModuleById(
|
|
275
|
-
|
|
276
|
-
const node = this.evaluatedModules.getModuleById(mockId);
|
|
277
|
-
if (node) {
|
|
278
|
-
this.evaluatedModules.invalidateModule(node);
|
|
279
|
-
node.mockedExports = void 0;
|
|
280
|
-
}
|
|
51
|
+
invalidateModuleById(_id) {
|
|
52
|
+
// implemented by mockers that control the module runner
|
|
281
53
|
}
|
|
282
54
|
isModuleDirectory(path) {
|
|
283
55
|
return this.moduleDirectories.some((dir) => path.includes(dir));
|
|
@@ -314,7 +86,7 @@ class VitestMocker {
|
|
|
314
86
|
}
|
|
315
87
|
// external is node_module or unresolved module
|
|
316
88
|
// for example, some people mock "vscode" and don't have it installed
|
|
317
|
-
const external = !isAbsolute
|
|
89
|
+
const external = !isAbsolute(result.file) || this.isModuleDirectory(result.file) ? normalizeModuleId(rawId) : null;
|
|
318
90
|
const id = normalizeModuleId(result.id);
|
|
319
91
|
span.setAttributes({
|
|
320
92
|
"vitest.module.id": id,
|
|
@@ -329,51 +101,13 @@ class VitestMocker {
|
|
|
329
101
|
});
|
|
330
102
|
}
|
|
331
103
|
async resolveMocks() {
|
|
332
|
-
if (!
|
|
333
|
-
await Promise.all(
|
|
104
|
+
if (!BareModuleMocker.pendingIds.length) return;
|
|
105
|
+
await Promise.all(BareModuleMocker.pendingIds.map(async (mock) => {
|
|
334
106
|
const { id, url, external } = await this.resolveId(mock.id, mock.importer);
|
|
335
107
|
if (mock.action === "unmock") this.unmockPath(id);
|
|
336
108
|
if (mock.action === "mock") this.mockPath(mock.id, id, url, external, mock.type, mock.factory);
|
|
337
109
|
}));
|
|
338
|
-
|
|
339
|
-
}
|
|
340
|
-
ensureModule(id, url) {
|
|
341
|
-
const node = this.evaluatedModules.ensureModule(id, url);
|
|
342
|
-
// TODO
|
|
343
|
-
node.meta = {
|
|
344
|
-
id,
|
|
345
|
-
url,
|
|
346
|
-
code: "",
|
|
347
|
-
file: null,
|
|
348
|
-
invalidate: false
|
|
349
|
-
};
|
|
350
|
-
return node;
|
|
351
|
-
}
|
|
352
|
-
async callFunctionMock(id, url, mock) {
|
|
353
|
-
const node = this.ensureModule(id, url);
|
|
354
|
-
if (node.exports) return node.exports;
|
|
355
|
-
const exports$1 = await mock.resolve();
|
|
356
|
-
const moduleExports = new Proxy(exports$1, { get: (target, prop) => {
|
|
357
|
-
const val = target[prop];
|
|
358
|
-
// 'then' can exist on non-Promise objects, need nested instanceof check for logic to work
|
|
359
|
-
if (prop === "then") {
|
|
360
|
-
if (target instanceof Promise) return target.then.bind(target);
|
|
361
|
-
} else if (!(prop in target)) {
|
|
362
|
-
if (this.filterPublicKeys.includes(prop)) return;
|
|
363
|
-
throw this.createError(`[vitest] No "${String(prop)}" export is defined on the "${mock.raw}" mock. Did you forget to return it from "vi.mock"?
|
|
364
|
-
If you need to partially mock a module, you can use "importOriginal" helper inside:
|
|
365
|
-
`, `vi.mock(import("${mock.raw}"), async (importOriginal) => {
|
|
366
|
-
const actual = await importOriginal()
|
|
367
|
-
return {
|
|
368
|
-
...actual,
|
|
369
|
-
// your mocked methods
|
|
370
|
-
}
|
|
371
|
-
})`);
|
|
372
|
-
}
|
|
373
|
-
return val;
|
|
374
|
-
} });
|
|
375
|
-
node.exports = moduleExports;
|
|
376
|
-
return moduleExports;
|
|
110
|
+
BareModuleMocker.pendingIds = [];
|
|
377
111
|
}
|
|
378
112
|
// public method to avoid circular dependency
|
|
379
113
|
getMockContext() {
|
|
@@ -414,6 +148,151 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
|
|
|
414
148
|
// every time the mock is registered, we remove the previous one from the cache
|
|
415
149
|
this.invalidateModuleById(id);
|
|
416
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
|
+
}
|
|
417
296
|
async importActual(rawId, importer, callstack) {
|
|
418
297
|
const { url } = await this.resolveId(rawId, importer);
|
|
419
298
|
const node = await this.moduleRunner.fetchModule(url, importer);
|
|
@@ -490,60 +369,6 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
|
|
|
490
369
|
if (!mock) return;
|
|
491
370
|
return this.requestWithMockedModule(url, evaluatedNode, callstack, mock);
|
|
492
371
|
}
|
|
493
|
-
queueMock(id, importer, factoryOrOptions) {
|
|
494
|
-
const mockType = getMockType(factoryOrOptions);
|
|
495
|
-
VitestMocker.pendingIds.push({
|
|
496
|
-
action: "mock",
|
|
497
|
-
id,
|
|
498
|
-
importer,
|
|
499
|
-
factory: typeof factoryOrOptions === "function" ? factoryOrOptions : void 0,
|
|
500
|
-
type: mockType
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
queueUnmock(id, importer) {
|
|
504
|
-
VitestMocker.pendingIds.push({
|
|
505
|
-
action: "unmock",
|
|
506
|
-
id,
|
|
507
|
-
importer
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
function getMockType(factoryOrOptions) {
|
|
512
|
-
if (!factoryOrOptions) return "automock";
|
|
513
|
-
if (typeof factoryOrOptions === "function") return "manual";
|
|
514
|
-
return factoryOrOptions.spy ? "autospy" : "automock";
|
|
515
|
-
}
|
|
516
|
-
// unique id that is not available as "$bare_import" like "test"
|
|
517
|
-
// https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix
|
|
518
|
-
const prefixedBuiltins = new Set([
|
|
519
|
-
"node:sea",
|
|
520
|
-
"node:sqlite",
|
|
521
|
-
"node:test",
|
|
522
|
-
"node:test/reporters"
|
|
523
|
-
]);
|
|
524
|
-
const isWindows$1 = process.platform === "win32";
|
|
525
|
-
// transform file url to id
|
|
526
|
-
// virtual:custom -> virtual:custom
|
|
527
|
-
// \0custom -> \0custom
|
|
528
|
-
// /root/id -> /id
|
|
529
|
-
// /root/id.js -> /id.js
|
|
530
|
-
// C:/root/id.js -> /id.js
|
|
531
|
-
// C:\root\id.js -> /id.js
|
|
532
|
-
// TODO: expose this in vite/module-runner
|
|
533
|
-
function normalizeModuleId(file) {
|
|
534
|
-
if (prefixedBuiltins.has(file)) return file;
|
|
535
|
-
// if it's not in the root, keep it as a path, not a URL
|
|
536
|
-
return slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/");
|
|
537
|
-
}
|
|
538
|
-
const windowsSlashRE = /\\/g;
|
|
539
|
-
function slash(p) {
|
|
540
|
-
return p.replace(windowsSlashRE, "/");
|
|
541
|
-
}
|
|
542
|
-
const multipleSlashRe = /^\/+/;
|
|
543
|
-
// module-runner incorrectly replaces file:///path with `///path`
|
|
544
|
-
function fixLeadingSlashes(id) {
|
|
545
|
-
if (id.startsWith("//")) return id.replace(multipleSlashRe, "/");
|
|
546
|
-
return id;
|
|
547
372
|
}
|
|
548
373
|
|
|
549
374
|
class VitestTransport {
|
|
@@ -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 { VITEST_VM_CONTEXT_SYMBOL as V, VitestModuleRunner as a, VitestTransport as b, createNodeImportMeta as c, startVitestModuleRunner as s };
|
|
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 };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getCurrentTest, updateTask, createTaskCollector, getCurrentSuite, getHooks, getFn } from '@vitest/runner';
|
|
2
2
|
import { assertTypes, createSimpleStackTrace, createDefer } from '@vitest/utils/helpers';
|
|
3
3
|
import { getSafeTimers, delay } from '@vitest/utils/timers';
|
|
4
|
-
import { a as getBenchOptions, g as getBenchFn } from './benchmark.
|
|
5
|
-
import { g as getWorkerState, i as isChildProcess, w as waitForImportsToResolve, r as resetModules } from './utils.
|
|
4
|
+
import { a as getBenchOptions, g as getBenchFn } from './benchmark.BoqSLF53.js';
|
|
5
|
+
import { g as getWorkerState, i as isChildProcess, w as waitForImportsToResolve, r as resetModules } from './utils.DT4VyRyl.js';
|
|
6
6
|
import { chai, equals, iterableEquality, subsetEquality, JestExtend, JestChaiExpect, ChaiStyleAssertions, JestAsymmetricMatchers, GLOBAL_EXPECT, ASYMMETRIC_MATCHERS_OBJECT, getState, setState, addCustomEqualityTesters, customMatchers } from '@vitest/expect';
|
|
7
7
|
import { getNames, getTests, getTestName, createChainable } from '@vitest/runner/utils';
|
|
8
8
|
import { processError } from '@vitest/utils/error';
|
|
@@ -12,7 +12,7 @@ import { fn, spyOn, restoreAllMocks, resetAllMocks, clearAllMocks, isMockFunctio
|
|
|
12
12
|
import '@vitest/utils/offset';
|
|
13
13
|
import { parseSingleStack } from '@vitest/utils/source-map';
|
|
14
14
|
import { c as commonjsGlobal } from './_commonjsHelpers.D26ty3Ew.js';
|
|
15
|
-
import { R as RealDate, b as resetDate, m as mockDate, r as rpc } from './rpc.
|
|
15
|
+
import { R as RealDate, b as resetDate, m as mockDate, r as rpc } from './rpc.DcRWTy5G.js';
|
|
16
16
|
|
|
17
17
|
// these matchers are not supported because they don't make sense with poll
|
|
18
18
|
const unsupported = [
|
|
@@ -4153,17 +4153,22 @@ class TestRunner {
|
|
|
4153
4153
|
pool = this.workerState.ctx.pool;
|
|
4154
4154
|
_otel;
|
|
4155
4155
|
viteEnvironment;
|
|
4156
|
+
viteModuleRunner;
|
|
4156
4157
|
constructor(config) {
|
|
4157
4158
|
this.config = config;
|
|
4158
4159
|
const environment = this.workerState.environment;
|
|
4159
4160
|
this.viteEnvironment = environment.viteEnvironment || environment.name;
|
|
4161
|
+
this.viteModuleRunner = config.experimental.viteModuleRunner;
|
|
4160
4162
|
}
|
|
4161
4163
|
importFile(filepath, source) {
|
|
4162
4164
|
if (source === "setup") {
|
|
4163
4165
|
const moduleNode = this.workerState.evaluatedModules.getModuleById(filepath);
|
|
4164
4166
|
if (moduleNode) this.workerState.evaluatedModules.invalidateModule(moduleNode);
|
|
4165
4167
|
}
|
|
4166
|
-
return this._otel.$(`vitest.module.import_${source === "setup" ? "setup" : "spec"}`, { attributes: { "code.file.path": filepath } }, () =>
|
|
4168
|
+
return this._otel.$(`vitest.module.import_${source === "setup" ? "setup" : "spec"}`, { attributes: { "code.file.path": filepath } }, () => {
|
|
4169
|
+
if (!this.viteModuleRunner) filepath = `${filepath}?vitest=${Date.now()}`;
|
|
4170
|
+
return this.moduleRunner.import(filepath);
|
|
4171
|
+
});
|
|
4167
4172
|
}
|
|
4168
4173
|
onCollectStart(file) {
|
|
4169
4174
|
this.workerState.current = file;
|