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.
Files changed (65) hide show
  1. package/LICENSE.md +36 -0
  2. package/dist/browser.d.ts +1 -1
  3. package/dist/browser.js +2 -2
  4. package/dist/chunks/acorn.B2iPLyUM.js +5958 -0
  5. package/dist/chunks/{base.CBRNZa3k.js → base.DiopZV8F.js} +48 -14
  6. package/dist/chunks/{benchmark.B3N2zMcH.js → benchmark.BoqSLF53.js} +1 -1
  7. package/dist/chunks/{browser.d.8hOapKZr.d.ts → browser.d.BE4kbYok.d.ts} +2 -1
  8. package/dist/chunks/{cac.B1v3xxoC.js → cac.C4jjt2RX.js} +797 -13
  9. package/dist/chunks/{cli-api.B4CqEpI6.js → cli-api.ChbI1JU9.js} +322 -124
  10. package/dist/chunks/{config.d.idH22YSr.d.ts → config.d.Cr1Ep39N.d.ts} +6 -1
  11. package/dist/chunks/{console.uGgdMhyZ.js → console.CNlG1KsP.js} +2 -2
  12. package/dist/chunks/{constants.D_Q9UYh-.js → constants.B63TT-Bl.js} +1 -1
  13. package/dist/chunks/coverage.tyqbzn4W.js +1001 -0
  14. package/dist/chunks/{creator.C7WwjkuR.js → creator.yyCHuw5R.js} +1 -1
  15. package/dist/chunks/{global.d.B15mdLcR.d.ts → global.d.JeWMqlOm.d.ts} +1 -1
  16. package/dist/chunks/{globals.DjuGMoMc.js → globals.C6Ecf1TO.js} +6 -6
  17. package/dist/chunks/{index.Dm4xqZ0s.js → index.B-iBE_Gx.js} +20 -4
  18. package/dist/chunks/{coverage.BMlOMIWl.js → index.BCY_7LL2.js} +5 -969
  19. package/dist/chunks/{index.BiOAd_ki.js → index.CAN630q3.js} +7 -7
  20. package/dist/chunks/{index.DyBZXrH3.js → index.CFulQRmC.js} +1 -1
  21. package/dist/chunks/{index.BEFi2-_3.js → index.CouFDptX.js} +2 -2
  22. package/dist/chunks/{init-forks.CHeQ9Moq.js → init-forks.BnCXPazU.js} +1 -1
  23. package/dist/chunks/{init-threads.uZiNAuPk.js → init-threads.Cyh2PqXi.js} +1 -1
  24. package/dist/chunks/{init.DVtKdFty.js → init.B95Mm0Iz.js} +47 -9
  25. package/dist/chunks/native.mV0-490A.js +148 -0
  26. package/dist/chunks/nativeModuleMocker.D_q5sFv6.js +206 -0
  27. package/dist/chunks/nativeModuleRunner.BIakptoF.js +36 -0
  28. package/dist/chunks/{node.Ce0vMQM7.js → node.CrSEwhm4.js} +1 -1
  29. package/dist/chunks/{plugin.d.D8KU2PY_.d.ts → plugin.d.C9o5bttz.d.ts} +1 -1
  30. package/dist/chunks/{reporters.d.Db3MiIWX.d.ts → reporters.d.7faYdkxy.d.ts} +120 -51
  31. package/dist/chunks/{rpc.HLmECnw_.js → rpc.DcRWTy5G.js} +1 -1
  32. package/dist/chunks/{rpc.d.RH3apGEf.d.ts → rpc.d.CM7x9-sm.d.ts} +1 -0
  33. package/dist/chunks/{setup-common.BcqLPsn5.js → setup-common.cvFp-ao9.js} +2 -2
  34. package/dist/chunks/{startModuleRunner.C5CcWyXW.js → startVitestModuleRunner.BK-u7y4N.js} +163 -372
  35. package/dist/chunks/{test.prxIahgM.js → test.G82XYNFk.js} +9 -4
  36. package/dist/chunks/{utils.DvEY5TfP.js → utils.DT4VyRyl.js} +5 -1
  37. package/dist/chunks/{vm.CrifS09m.js → vm.BdLtzhnj.js} +13 -6
  38. package/dist/chunks/{worker.d.Bji1eq5g.d.ts → worker.d.CPzI2ZzJ.d.ts} +2 -2
  39. package/dist/cli.js +4 -3
  40. package/dist/config.d.ts +8 -8
  41. package/dist/config.js +1 -1
  42. package/dist/coverage.d.ts +7 -5
  43. package/dist/coverage.js +5 -4
  44. package/dist/index.d.ts +18 -23
  45. package/dist/index.js +5 -5
  46. package/dist/module-evaluator.d.ts +10 -1
  47. package/dist/node.d.ts +9 -9
  48. package/dist/node.js +18 -16
  49. package/dist/nodejs-worker-loader.js +41 -0
  50. package/dist/reporters.d.ts +5 -5
  51. package/dist/reporters.js +2 -2
  52. package/dist/runners.d.ts +2 -1
  53. package/dist/runners.js +4 -4
  54. package/dist/runtime.js +4 -5
  55. package/dist/snapshot.js +2 -2
  56. package/dist/suite.js +2 -2
  57. package/dist/worker.d.ts +6 -6
  58. package/dist/worker.js +25 -18
  59. package/dist/workers/forks.js +21 -14
  60. package/dist/workers/runVmTests.js +7 -7
  61. package/dist/workers/threads.js +21 -14
  62. package/dist/workers/vmForks.js +14 -10
  63. package/dist/workers/vmThreads.js +14 -10
  64. package/package.json +17 -14
  65. 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 as normalize$1, join as join$1 } from 'pathe';
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 { resolve as resolve$1, isAbsolute as isAbsolute$1 } from 'node:path';
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 nodeModule from 'node:module';
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
- const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
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(moduleRunner, options) {
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
- if (context) this.primitives = vm.runInContext("({ Object, Error, Function, RegExp, Symbol, Array, Map })", context);
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(id) {
275
- const mockId = this.getMockPath(id);
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$1(result.file) || this.isModuleDirectory(result.file) ? normalizeModuleId(rawId) : null;
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 (!VitestMocker.pendingIds.length) return;
333
- await Promise.all(VitestMocker.pendingIds.map(async (mock) => {
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
- VitestMocker.pendingIds = [];
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$1(distDir);
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$1(root, id)).toString();
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 = () => globalThis.__vitest_worker__ || options.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 '${importer}'` : ""}`, { cause });
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.B3N2zMcH.js';
5
- import { g as getWorkerState, i as isChildProcess, w as waitForImportsToResolve, r as resetModules } from './utils.DvEY5TfP.js';
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.HLmECnw_.js';
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 } }, () => this.moduleRunner.import(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;