vitest 4.0.6 → 4.0.8

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 +1 -1
  2. package/dist/browser.d.ts +2 -2
  3. package/dist/browser.js +2 -2
  4. package/dist/chunks/base.BgTO2qAg.js +156 -0
  5. package/dist/chunks/{benchmark.DHKMYAts.js → benchmark.B3N2zMcH.js} +9 -4
  6. package/dist/chunks/{browser.d.ScGeWTou.d.ts → browser.d.DTTM2PTh.d.ts} +1 -1
  7. package/dist/chunks/{cac.BBqWH4nd.js → cac.CfkWq8Qy.js} +117 -43
  8. package/dist/chunks/{cli-api.UL3SwFUb.js → cli-api.BQ-bjcRi.js} +1870 -847
  9. package/dist/chunks/console.Cf-YriPC.js +146 -0
  10. package/dist/chunks/{coverage.DuCn_Tmx.js → coverage.NVjCOln1.js} +281 -103
  11. package/dist/chunks/{creator.cqqifzG7.js → creator.fzVyoMf3.js} +74 -30
  12. package/dist/chunks/{date.-jtEtIeV.js → date.Bq6ZW5rf.js} +17 -6
  13. package/dist/chunks/{git.BFNcloKD.js → git.Bm2pzPAa.js} +3 -3
  14. package/dist/chunks/{global.d.DdOkMiVb.d.ts → global.d.DVdCfKp5.d.ts} +1 -1
  15. package/dist/chunks/{globals.BGT_RUsD.js → globals.DOh96BiR.js} +5 -5
  16. package/dist/chunks/{resolveSnapshotEnvironment.BZzLjzkh.js → index.BY4-tcno.js} +42 -25
  17. package/dist/chunks/{index.Bgo3tNWt.js → index.DAL392Ss.js} +40 -15
  18. package/dist/chunks/{index.RwjEGCQ0.js → index.DIFZf73e.js} +2 -2
  19. package/dist/chunks/{index.DV0mQLEO.js → index.DfKyPFVi.js} +195 -64
  20. package/dist/chunks/{index.BL8Hg4Uk.js → index.kotH7DY7.js} +837 -380
  21. package/dist/chunks/{index.CpdwpN7L.js → index.op2Re5rn.js} +22 -12
  22. package/dist/chunks/{init-forks.CSGFj9zN.js → init-forks.2hx7cf78.js} +16 -5
  23. package/dist/chunks/{init-threads.CIJLeFO8.js → init-threads.Cm4OCIWA.js} +3 -2
  24. package/dist/chunks/{init.DUeOfNO9.js → init.DMDG-idf.js} +124 -54
  25. package/dist/chunks/{inspector.DLZxSeU3.js → inspector.CvyFGlXm.js} +25 -10
  26. package/dist/chunks/{moduleRunner.d.TP-w6tIQ.d.ts → moduleRunner.d.CzOZ_4wC.d.ts} +1 -1
  27. package/dist/chunks/{node.BwAWWjHZ.js → node.Ce0vMQM7.js} +1 -1
  28. package/dist/chunks/{plugin.d.lctzD3Wk.d.ts → plugin.d.D4RrtywJ.d.ts} +1 -1
  29. package/dist/chunks/{reporters.d.PEs0tXod.d.ts → reporters.d.Da1D1VbQ.d.ts} +19 -9
  30. package/dist/chunks/rpc.BUV7uWKJ.js +76 -0
  31. package/dist/chunks/{setup-common.DR1sucx6.js → setup-common.LGjNSzXp.js} +20 -8
  32. package/dist/chunks/{startModuleRunner.Di-EZqh0.js → startModuleRunner.BOmUtLIO.js} +228 -105
  33. package/dist/chunks/{test.CnspO-X4.js → test.ClrAtjMv.js} +48 -22
  34. package/dist/chunks/{utils.CG9h5ccR.js → utils.DvEY5TfP.js} +14 -5
  35. package/dist/chunks/{vi.BZvkKVkM.js → vi.Bgcdy3bQ.js} +261 -111
  36. package/dist/chunks/{vm.Co_lR2NL.js → vm.BIkCDs68.js} +177 -70
  37. package/dist/chunks/{worker.d.B4Hthdvt.d.ts → worker.d.DadbA89M.d.ts} +52 -6
  38. package/dist/cli.js +2 -2
  39. package/dist/config.d.ts +5 -5
  40. package/dist/coverage.d.ts +3 -3
  41. package/dist/coverage.js +1 -1
  42. package/dist/environments.js +2 -1
  43. package/dist/index.d.ts +5 -5
  44. package/dist/index.js +5 -5
  45. package/dist/module-evaluator.d.ts +2 -2
  46. package/dist/module-evaluator.js +85 -35
  47. package/dist/module-runner.js +2 -2
  48. package/dist/node.d.ts +7 -7
  49. package/dist/node.js +16 -12
  50. package/dist/reporters.d.ts +3 -3
  51. package/dist/reporters.js +2 -2
  52. package/dist/runners.js +7 -7
  53. package/dist/snapshot.js +2 -2
  54. package/dist/suite.js +2 -2
  55. package/dist/worker.d.ts +2 -1
  56. package/dist/worker.js +27 -27
  57. package/dist/workers/forks.js +34 -31
  58. package/dist/workers/runVmTests.js +41 -22
  59. package/dist/workers/threads.js +34 -31
  60. package/dist/workers/vmForks.js +14 -14
  61. package/dist/workers/vmThreads.js +14 -14
  62. package/package.json +20 -20
  63. package/dist/chunks/base.BAf_bYeI.js +0 -128
  64. package/dist/chunks/console.CTJL2nuH.js +0 -115
  65. package/dist/chunks/rpc.Dv1Jt3i2.js +0 -66
@@ -11,24 +11,62 @@ import vm from 'node:vm';
11
11
  import { MockerRegistry, mockObject, RedirectedModule, AutomockedModule } from '@vitest/mocker';
12
12
  import * as viteModuleRunner from 'vite/module-runner';
13
13
 
14
+ class VitestTransport {
15
+ constructor(options) {
16
+ this.options = options;
17
+ }
18
+ async invoke(event) {
19
+ if (event.type !== "custom") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support Vite HMR events.`) };
20
+ if (event.event !== "vite:invoke") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support ${event.event} event.`) };
21
+ const { name, data } = event.data;
22
+ if (name === "getBuiltins")
23
+ // we return an empty array here to avoid client-side builtin check,
24
+ // as we need builtins to go through `fetchModule`
25
+ return { result: [] };
26
+ if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) };
27
+ try {
28
+ return { result: await this.options.fetchModule(...data) };
29
+ } catch (error) {
30
+ return { error };
31
+ }
32
+ }
33
+ }
34
+
14
35
  const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
15
36
  function normalizeWindowsPath(input = "") {
16
- return input && input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
37
+ if (!input) return input;
38
+ return input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
17
39
  }
18
- const _UNC_REGEX = /^[/\\]{2}/, _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/, _DRIVE_LETTER_RE = /^[A-Za-z]:$/, _EXTNAME_RE = /.(\.[^./]+|\.)$/, normalize = function(path) {
40
+ const _UNC_REGEX = /^[/\\]{2}/;
41
+ const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
42
+ const _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
43
+ const _EXTNAME_RE = /.(\.[^./]+|\.)$/;
44
+ const normalize = function(path) {
19
45
  if (path.length === 0) return ".";
20
46
  path = normalizeWindowsPath(path);
21
- const isUNCPath = path.match(_UNC_REGEX), isPathAbsolute = isAbsolute(path), trailingSeparator = path[path.length - 1] === "/";
22
- if (path = normalizeString(path, !isPathAbsolute), path.length === 0) return isPathAbsolute ? "/" : trailingSeparator ? "./" : ".";
47
+ const isUNCPath = path.match(_UNC_REGEX);
48
+ const isPathAbsolute = isAbsolute(path);
49
+ const trailingSeparator = path[path.length - 1] === "/";
50
+ path = normalizeString(path, !isPathAbsolute);
51
+ if (path.length === 0) {
52
+ if (isPathAbsolute) return "/";
53
+ return trailingSeparator ? "./" : ".";
54
+ }
23
55
  if (trailingSeparator) path += "/";
24
56
  if (_DRIVE_LETTER_RE.test(path)) path += "/";
25
- return isUNCPath ? isPathAbsolute ? `//${path}` : `//./${path}` : isPathAbsolute && !isAbsolute(path) ? `/${path}` : path;
26
- }, join = function(...segments) {
57
+ if (isUNCPath) {
58
+ if (!isPathAbsolute) return `//./${path}`;
59
+ return `//${path}`;
60
+ }
61
+ return isPathAbsolute && !isAbsolute(path) ? `/${path}` : path;
62
+ };
63
+ const join = function(...segments) {
27
64
  let path = "";
28
65
  for (const seg of segments) {
29
66
  if (!seg) continue;
30
67
  if (path.length > 0) {
31
- const pathTrailing = path[path.length - 1] === "/", segLeading = seg[0] === "/";
68
+ const pathTrailing = path[path.length - 1] === "/";
69
+ const segLeading = seg[0] === "/";
32
70
  if (pathTrailing && segLeading) path += seg.slice(1);
33
71
  else path += pathTrailing || segLeading ? seg : `/${seg}`;
34
72
  } else path += seg;
@@ -36,19 +74,29 @@ const _UNC_REGEX = /^[/\\]{2}/, _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\
36
74
  return normalize(path);
37
75
  };
38
76
  function cwd$1() {
39
- return typeof process !== "undefined" && typeof process.cwd === "function" ? process.cwd().replace(/\\/g, "/") : "/";
77
+ if (typeof process !== "undefined" && typeof process.cwd === "function") return process.cwd().replace(/\\/g, "/");
78
+ return "/";
40
79
  }
41
80
  const resolve = function(...arguments_) {
42
81
  arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
43
- let resolvedPath = "", resolvedAbsolute = false;
82
+ let resolvedPath = "";
83
+ let resolvedAbsolute = false;
44
84
  for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
45
85
  const path = index >= 0 ? arguments_[index] : cwd$1();
46
- !path || path.length === 0 || (resolvedPath = `${path}/${resolvedPath}`, resolvedAbsolute = isAbsolute(path));
86
+ if (!path || path.length === 0) continue;
87
+ resolvedPath = `${path}/${resolvedPath}`;
88
+ resolvedAbsolute = isAbsolute(path);
47
89
  }
48
- return resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute), resolvedAbsolute && !isAbsolute(resolvedPath) ? `/${resolvedPath}` : resolvedPath.length > 0 ? resolvedPath : ".";
90
+ resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
91
+ if (resolvedAbsolute && !isAbsolute(resolvedPath)) return `/${resolvedPath}`;
92
+ return resolvedPath.length > 0 ? resolvedPath : ".";
49
93
  };
50
94
  function normalizeString(path, allowAboveRoot) {
51
- let res = "", lastSegmentLength = 0, lastSlash = -1, dots = 0, char = null;
95
+ let res = "";
96
+ let lastSegmentLength = 0;
97
+ let lastSlash = -1;
98
+ let dots = 0;
99
+ let char = null;
52
100
  for (let index = 0; index <= path.length; ++index) {
53
101
  if (index < path.length) char = path[index];
54
102
  else if (char === "/") break;
@@ -59,22 +107,35 @@ function normalizeString(path, allowAboveRoot) {
59
107
  if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
60
108
  if (res.length > 2) {
61
109
  const lastSlashIndex = res.lastIndexOf("/");
62
- if (lastSlashIndex === -1) res = "", lastSegmentLength = 0;
63
- else res = res.slice(0, lastSlashIndex), lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
64
- lastSlash = index, dots = 0;
110
+ if (lastSlashIndex === -1) {
111
+ res = "";
112
+ lastSegmentLength = 0;
113
+ } else {
114
+ res = res.slice(0, lastSlashIndex);
115
+ lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
116
+ }
117
+ lastSlash = index;
118
+ dots = 0;
65
119
  continue;
66
120
  } else if (res.length > 0) {
67
- res = "", lastSegmentLength = 0, lastSlash = index, dots = 0;
121
+ res = "";
122
+ lastSegmentLength = 0;
123
+ lastSlash = index;
124
+ dots = 0;
68
125
  continue;
69
126
  }
70
127
  }
71
- if (allowAboveRoot) res += res.length > 0 ? "/.." : "..", lastSegmentLength = 2;
128
+ if (allowAboveRoot) {
129
+ res += res.length > 0 ? "/.." : "..";
130
+ lastSegmentLength = 2;
131
+ }
72
132
  } else {
73
133
  if (res.length > 0) res += `/${path.slice(lastSlash + 1, index)}`;
74
134
  else res = path.slice(lastSlash + 1, index);
75
135
  lastSegmentLength = index - lastSlash - 1;
76
136
  }
77
- lastSlash = index, dots = 0;
137
+ lastSlash = index;
138
+ dots = 0;
78
139
  } else if (char === "." && dots !== -1) ++dots;
79
140
  else dots = -1;
80
141
  }
@@ -82,15 +143,18 @@ function normalizeString(path, allowAboveRoot) {
82
143
  }
83
144
  const isAbsolute = function(p) {
84
145
  return _IS_ABSOLUTE_RE.test(p);
85
- }, extname = function(p) {
146
+ };
147
+ const extname = function(p) {
86
148
  if (p === "..") return "";
87
149
  const match = _EXTNAME_RE.exec(normalizeWindowsPath(p));
88
150
  return match && match[1] || "";
89
- }, dirname = function(p) {
151
+ };
152
+ const dirname = function(p) {
90
153
  const segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1);
91
154
  if (segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0])) segments[0] += "/";
92
155
  return segments.join("/") || (isAbsolute(p) ? "/" : ".");
93
- }, basename = function(p, extension) {
156
+ };
157
+ const basename = function(p, extension) {
94
158
  const segments = normalizeWindowsPath(p).split("/");
95
159
  let lastSegment = "";
96
160
  for (let i = segments.length - 1; i >= 0; i--) {
@@ -109,7 +173,7 @@ function findMockRedirect(root, mockPath, external) {
109
173
  // it's a node_module alias
110
174
  // all mocks should be inside <root>/__mocks__
111
175
  if (external || isNodeBuiltin(mockPath) || !existsSync(mockPath)) {
112
- const mockDirname = dirname(path), mockFolder = join(root, "__mocks__", mockDirname);
176
+ const mockFolder = join(root, "__mocks__", dirname(path));
113
177
  if (!existsSync(mockFolder)) return null;
114
178
  const baseOriginal = basename(path);
115
179
  function findFile(mockFolder, baseOriginal) {
@@ -118,7 +182,7 @@ function findMockRedirect(root, mockPath, external) {
118
182
  const path = resolve(mockFolder, file);
119
183
  // if the same name, return the file
120
184
  if (statSync(path).isFile()) return path;
121
- {
185
+ else {
122
186
  // find folder/index.{js,ts}
123
187
  const indexFile = findFile(path, "index");
124
188
  if (indexFile) return indexFile;
@@ -128,7 +192,7 @@ function findMockRedirect(root, mockPath, external) {
128
192
  }
129
193
  return findFile(mockFolder, baseOriginal);
130
194
  }
131
- const dir = dirname(path), baseId = basename(path), fullPath = resolve(dir, "__mocks__", baseId);
195
+ const fullPath = resolve(dirname(path), "__mocks__", basename(path));
132
196
  return existsSync(fullPath) ? fullPath : null;
133
197
  }
134
198
  const builtins = new Set([
@@ -146,14 +210,20 @@ const builtins = new Set([
146
210
  "timers/promises",
147
211
  "util/types",
148
212
  "wasi"
149
- ]), prefixedBuiltins$1 = new Set([
213
+ ]);
214
+ // https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix
215
+ const prefixedBuiltins$1 = new Set([
150
216
  "node:sea",
151
217
  "node:sqlite",
152
218
  "node:test",
153
219
  "node:test/reporters"
154
- ]), NODE_BUILTIN_NAMESPACE = "node:";
220
+ ]);
221
+ const NODE_BUILTIN_NAMESPACE = "node:";
155
222
  function isNodeBuiltin(id) {
156
- return nodeModule.isBuiltin ? nodeModule.isBuiltin(id) : prefixedBuiltins$1.has(id) ? true : builtins.has(id.startsWith(NODE_BUILTIN_NAMESPACE) ? id.slice(5) : id);
223
+ // Added in v18.6.0
224
+ if (nodeModule.isBuiltin) return nodeModule.isBuiltin(id);
225
+ if (prefixedBuiltins$1.has(id)) return true;
226
+ return builtins.has(id.startsWith(NODE_BUILTIN_NAMESPACE) ? id.slice(5) : id);
157
227
  }
158
228
 
159
229
  const spyModulePath = resolve$1(distDir, "spy.js");
@@ -165,7 +235,8 @@ class VitestMocker {
165
235
  registries = /* @__PURE__ */ new Map();
166
236
  mockContext = { callstack: null };
167
237
  constructor(moduleRunner, options) {
168
- this.moduleRunner = moduleRunner, this.options = options;
238
+ this.moduleRunner = moduleRunner;
239
+ this.options = options;
169
240
  const context = this.options.context;
170
241
  if (context) this.primitives = vm.runInContext("({ Object, Error, Function, RegExp, Symbol, Array, Map })", context);
171
242
  else this.primitives = {
@@ -206,7 +277,8 @@ class VitestMocker {
206
277
  return this.options.moduleDirectories || [];
207
278
  }
208
279
  async initializeSpyModule() {
209
- this.spyModule ||= await this.moduleRunner.import(spyModulePath);
280
+ if (this.spyModule) return;
281
+ this.spyModule = await this.moduleRunner.import(spyModulePath);
210
282
  }
211
283
  getMockerRegistry() {
212
284
  const suite = this.getSuiteFilepath();
@@ -217,8 +289,12 @@ class VitestMocker {
217
289
  this.registries.clear();
218
290
  }
219
291
  invalidateModuleById(id) {
220
- const mockId = this.getMockPath(id), node = this.evaluatedModules.getModuleById(mockId);
221
- if (node) this.evaluatedModules.invalidateModule(node), node.mockedExports = void 0;
292
+ const mockId = this.getMockPath(id);
293
+ const node = this.evaluatedModules.getModuleById(mockId);
294
+ if (node) {
295
+ this.evaluatedModules.invalidateModule(node);
296
+ node.mockedExports = void 0;
297
+ }
222
298
  }
223
299
  isModuleDirectory(path) {
224
300
  return this.moduleDirectories.some((dir) => path.includes(dir));
@@ -227,8 +303,10 @@ class VitestMocker {
227
303
  return this.options.getCurrentTestFilepath() || "global";
228
304
  }
229
305
  createError(message, codeFrame) {
230
- const Error = this.primitives.Error, error = new Error(message);
231
- return Object.assign(error, { codeFrame }), error;
306
+ const Error = this.primitives.Error;
307
+ const error = new Error(message);
308
+ Object.assign(error, { codeFrame });
309
+ return error;
232
310
  }
233
311
  async resolveId(rawId, importer) {
234
312
  const result = await this.options.resolveId(rawId, importer);
@@ -250,26 +328,31 @@ class VitestMocker {
250
328
  };
251
329
  }
252
330
  async resolveMocks() {
253
- VitestMocker.pendingIds.length && (await Promise.all(VitestMocker.pendingIds.map(async (mock) => {
331
+ if (!VitestMocker.pendingIds.length) return;
332
+ await Promise.all(VitestMocker.pendingIds.map(async (mock) => {
254
333
  const { id, url, external } = await this.resolveId(mock.id, mock.importer);
255
334
  if (mock.action === "unmock") this.unmockPath(id);
256
335
  if (mock.action === "mock") this.mockPath(mock.id, id, url, external, mock.type, mock.factory);
257
- })), VitestMocker.pendingIds = []);
336
+ }));
337
+ VitestMocker.pendingIds = [];
258
338
  }
259
339
  ensureModule(id, url) {
260
340
  const node = this.evaluatedModules.ensureModule(id, url);
261
- return node.meta = {
341
+ // TODO
342
+ node.meta = {
262
343
  id,
263
344
  url,
264
345
  code: "",
265
346
  file: null,
266
347
  invalidate: false
267
- }, node;
348
+ };
349
+ return node;
268
350
  }
269
351
  async callFunctionMock(id, url, mock) {
270
352
  const node = this.ensureModule(id, url);
271
353
  if (node.exports) return node.exports;
272
- const exports = await mock.resolve(), moduleExports = new Proxy(exports, { get: (target, prop) => {
354
+ const exports = await mock.resolve();
355
+ const moduleExports = new Proxy(exports, { get: (target, prop) => {
273
356
  const val = target[prop];
274
357
  // 'then' can exist on non-Promise objects, need nested instanceof check for logic to work
275
358
  if (prop === "then") {
@@ -288,7 +371,8 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
288
371
  }
289
372
  return val;
290
373
  } });
291
- return node.exports = moduleExports, moduleExports;
374
+ node.exports = moduleExports;
375
+ return moduleExports;
292
376
  }
293
377
  // public method to avoid circular dependency
294
378
  getMockContext() {
@@ -314,7 +398,8 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
314
398
  }, object, mockExports);
315
399
  }
316
400
  unmockPath(id) {
317
- this.getMockerRegistry().deleteById(id), this.invalidateModuleById(id);
401
+ this.getMockerRegistry().deleteById(id);
402
+ this.invalidateModuleById(id);
318
403
  }
319
404
  mockPath(originalId, id, url, external, mockType, factory) {
320
405
  const registry = this.getMockerRegistry();
@@ -329,7 +414,8 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
329
414
  this.invalidateModuleById(id);
330
415
  }
331
416
  async importActual(rawId, importer, callstack) {
332
- const { url } = await this.resolveId(rawId, importer), node = await this.moduleRunner.fetchModule(url, importer);
417
+ const { url } = await this.resolveId(rawId, importer);
418
+ const node = await this.moduleRunner.fetchModule(url, importer);
333
419
  return await this.moduleRunner.cachedRequest(node.url, node, callstack || [importer], void 0, true);
334
420
  }
335
421
  async importMock(rawId, importer) {
@@ -341,7 +427,9 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
341
427
  else mock = new AutomockedModule(rawId, id, rawId);
342
428
  }
343
429
  if (mock.type === "automock" || mock.type === "autospy") {
344
- const node = await this.moduleRunner.fetchModule(url, importer), mod = await this.moduleRunner.cachedRequest(url, node, [importer], void 0, true), Object = this.primitives.Object;
430
+ const node = await this.moduleRunner.fetchModule(url, importer);
431
+ const mod = await this.moduleRunner.cachedRequest(url, node, [importer], void 0, true);
432
+ const Object = this.primitives.Object;
345
433
  return this.mockObject(mod, Object.create(Object.prototype), mock.type);
346
434
  }
347
435
  if (mock.type === "manual") return this.callFunctionMock(id, url, mock);
@@ -353,19 +441,30 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
353
441
  if (mock.type === "automock" || mock.type === "autospy") {
354
442
  const cache = this.evaluatedModules.getModuleById(mockId);
355
443
  if (cache && cache.mockedExports) return cache.mockedExports;
356
- const Object = this.primitives.Object, exports = Object.create(null);
444
+ const Object = this.primitives.Object;
445
+ // we have to define a separate object that will copy all properties into itself
446
+ // and can't just use the same `exports` define automatically by Vite before the evaluator
447
+ const exports = Object.create(null);
357
448
  Object.defineProperty(exports, Symbol.toStringTag, {
358
449
  value: "Module",
359
450
  configurable: true,
360
451
  writable: true
361
452
  });
362
453
  const node = this.ensureModule(mockId, this.getMockPath(evaluatedNode.url));
363
- node.meta = evaluatedNode.meta, node.file = evaluatedNode.file, node.mockedExports = exports;
454
+ node.meta = evaluatedNode.meta;
455
+ node.file = evaluatedNode.file;
456
+ node.mockedExports = exports;
364
457
  const mod = await this.moduleRunner.cachedRequest(url, node, callstack, void 0, true);
365
- return this.mockObject(mod, exports, mock.type), exports;
458
+ this.mockObject(mod, exports, mock.type);
459
+ return exports;
366
460
  }
367
461
  if (mock.type === "manual" && !callstack.includes(mockId) && !callstack.includes(url)) try {
368
- return callstack.push(mockId), this.mockContext.callstack = callstack, await this.callFunctionMock(mockId, this.getMockPath(url), mock);
462
+ callstack.push(mockId);
463
+ // this will not work if user does Promise.all(import(), import())
464
+ // we can also use AsyncLocalStorage to store callstack, but this won't work in the browser
465
+ // maybe we should improve mock API in the future?
466
+ this.mockContext.callstack = callstack;
467
+ return await this.callFunctionMock(mockId, this.getMockPath(url), mock);
369
468
  } finally {
370
469
  this.mockContext.callstack = null;
371
470
  const indexMock = callstack.indexOf(mockId);
@@ -375,7 +474,8 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
375
474
  }
376
475
  async mockedRequest(url, evaluatedNode, callstack) {
377
476
  const mock = this.getDependencyMock(evaluatedNode.id);
378
- if (mock) return this.requestWithMockedModule(url, evaluatedNode, callstack, mock);
477
+ if (!mock) return;
478
+ return this.requestWithMockedModule(url, evaluatedNode, callstack, mock);
379
479
  }
380
480
  queueMock(id, importer, factoryOrOptions) {
381
481
  const mockType = getMockType(factoryOrOptions);
@@ -396,7 +496,9 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
396
496
  }
397
497
  }
398
498
  function getMockType(factoryOrOptions) {
399
- return factoryOrOptions ? typeof factoryOrOptions === "function" ? "manual" : factoryOrOptions.spy ? "autospy" : "automock" : "automock";
499
+ if (!factoryOrOptions) return "automock";
500
+ if (typeof factoryOrOptions === "function") return "manual";
501
+ return factoryOrOptions.spy ? "autospy" : "automock";
400
502
  }
401
503
  // unique id that is not available as "$bare_import" like "test"
402
504
  // https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix
@@ -405,7 +507,8 @@ const prefixedBuiltins = new Set([
405
507
  "node:sqlite",
406
508
  "node:test",
407
509
  "node:test/reporters"
408
- ]), isWindows$1 = process.platform === "win32";
510
+ ]);
511
+ const isWindows$1 = process.platform === "win32";
409
512
  // transform file url to id
410
513
  // virtual:custom -> virtual:custom
411
514
  // \0custom -> \0custom
@@ -415,8 +518,9 @@ const prefixedBuiltins = new Set([
415
518
  // C:\root\id.js -> /id.js
416
519
  // TODO: expose this in vite/module-runner
417
520
  function normalizeModuleId(file) {
521
+ if (prefixedBuiltins.has(file)) return file;
418
522
  // if it's not in the root, keep it as a path, not a URL
419
- return prefixedBuiltins.has(file) ? file : slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/");
523
+ return slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/");
420
524
  }
421
525
  const windowsSlashRE = /\\/g;
422
526
  function slash(p) {
@@ -425,33 +529,15 @@ function slash(p) {
425
529
  const multipleSlashRe = /^\/+/;
426
530
  // module-runner incorrectly replaces file:///path with `///path`
427
531
  function fixLeadingSlashes(id) {
428
- return id.startsWith("//") ? id.replace(multipleSlashRe, "/") : id;
429
- }
430
-
431
- class VitestTransport {
432
- constructor(options) {
433
- this.options = options;
434
- }
435
- async invoke(event) {
436
- if (event.type !== "custom") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support Vite HMR events.`) };
437
- if (event.event !== "vite:invoke") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support ${event.event} event.`) };
438
- const { name, data } = event.data;
439
- if (name === "getBuiltins")
440
- // we return an empty array here to avoid client-side builtin check,
441
- // as we need builtins to go through `fetchModule`
442
- return { result: [] };
443
- if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) };
444
- try {
445
- return { result: await this.options.fetchModule(...data) };
446
- } catch (error) {
447
- return { error };
448
- }
449
- }
532
+ if (id.startsWith("//")) return id.replace(multipleSlashRe, "/");
533
+ return id;
450
534
  }
451
535
 
452
536
  const createNodeImportMeta = (modulePath) => {
453
537
  if (!viteModuleRunner.createDefaultImportMeta) throw new Error(`createNodeImportMeta is not supported in this version of Vite.`);
454
- const defaultMeta = viteModuleRunner.createDefaultImportMeta(modulePath), href = defaultMeta.url, importMetaResolver = createImportMetaResolver();
538
+ const defaultMeta = viteModuleRunner.createDefaultImportMeta(modulePath);
539
+ const href = defaultMeta.url;
540
+ const importMetaResolver = createImportMetaResolver();
455
541
  return {
456
542
  ...defaultMeta,
457
543
  main: false,
@@ -461,21 +547,27 @@ const createNodeImportMeta = (modulePath) => {
461
547
  };
462
548
  };
463
549
  function createImportMetaResolver() {
464
- if (import.meta.resolve) return (specifier, importer) => import.meta.resolve(specifier, importer);
550
+ if (!import.meta.resolve) return;
551
+ return (specifier, importer) => import.meta.resolve(specifier, importer);
465
552
  }
466
553
  // @ts-expect-error overriding private method
467
554
  class VitestModuleRunner extends viteModuleRunner.ModuleRunner {
468
555
  mocker;
469
556
  moduleExecutionInfo;
470
557
  constructor(vitestOptions) {
471
- const options = vitestOptions, transport = new VitestTransport(options.transport), evaluatedModules = options.evaluatedModules;
472
- if (super({
558
+ const options = vitestOptions;
559
+ const transport = new VitestTransport(options.transport);
560
+ const evaluatedModules = options.evaluatedModules;
561
+ super({
473
562
  transport,
474
563
  hmr: false,
475
564
  evaluatedModules,
476
565
  sourcemapInterceptor: "prepareStackTrace",
477
566
  createImportMeta: vitestOptions.createImportMeta
478
- }, options.evaluator), this.vitestOptions = vitestOptions, this.moduleExecutionInfo = options.getWorkerState().moduleExecutionInfo, this.mocker = options.mocker || new VitestMocker(this, {
567
+ }, options.evaluator);
568
+ this.vitestOptions = vitestOptions;
569
+ this.moduleExecutionInfo = options.getWorkerState().moduleExecutionInfo;
570
+ this.mocker = options.mocker || new VitestMocker(this, {
479
571
  spyModule: options.spyModule,
480
572
  context: options.vm?.context,
481
573
  resolveId: options.transport.resolveId,
@@ -488,7 +580,8 @@ class VitestModuleRunner extends viteModuleRunner.ModuleRunner {
488
580
  getCurrentTestFilepath() {
489
581
  return options.getWorkerState().filepath;
490
582
  }
491
- }), options.vm) options.vm.context.__vitest_mocker__ = this.mocker;
583
+ });
584
+ if (options.vm) options.vm.context.__vitest_mocker__ = this.mocker;
492
585
  else Object.defineProperty(globalThis, "__vitest_mocker__", {
493
586
  configurable: true,
494
587
  writable: true,
@@ -528,7 +621,8 @@ class VitestModuleRunner extends viteModuleRunner.ModuleRunner {
528
621
  const node = await this.fetchModule(mocked);
529
622
  return this._cachedRequest(mocked, node, callstack, metadata);
530
623
  }
531
- return mocked != null && typeof mocked === "object" ? mocked : this._cachedRequest(url, mod, callstack, metadata);
624
+ if (mocked != null && typeof mocked === "object") return mocked;
625
+ return this._cachedRequest(url, mod, callstack, metadata);
532
626
  }
533
627
  /** @internal */
534
628
  _invalidateSubTreeById(ids, invalidated = /* @__PURE__ */ new Set()) {
@@ -544,7 +638,10 @@ class VitestModuleRunner extends viteModuleRunner.ModuleRunner {
544
638
  }
545
639
  }
546
640
 
547
- const bareVitestRegexp = /^@?vitest(?:\/|$)/, normalizedDistDir = normalize$1(distDir), relativeIds = {}, externalizeMap = /* @__PURE__ */ new Map();
641
+ const bareVitestRegexp = /^@?vitest(?:\/|$)/;
642
+ const normalizedDistDir = normalize$1(distDir);
643
+ const relativeIds = {};
644
+ const externalizeMap = /* @__PURE__ */ new Map();
548
645
  // all Vitest imports always need to be externalized
549
646
  function getCachedVitestImport(id, state) {
550
647
  if (id.startsWith("/@fs/") || id.startsWith("\\@fs\\")) id = id.slice(process.platform === "win32" ? 5 : 4);
@@ -554,63 +651,86 @@ function getCachedVitestImport(id, state) {
554
651
  };
555
652
  // always externalize Vitest because we import from there before running tests
556
653
  // so we already have it cached by Node.js
557
- const root = state().config.root, relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length));
654
+ const root = state().config.root;
655
+ const relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length));
558
656
  if (id.includes(distDir) || id.includes(normalizedDistDir)) {
559
657
  const externalize = id.startsWith("file://") ? id : pathToFileURL(id).toString();
560
- return externalizeMap.set(id, externalize), {
658
+ externalizeMap.set(id, externalize);
659
+ return {
561
660
  externalize,
562
661
  type: "module"
563
662
  };
564
663
  }
565
664
  if (relativeRoot && relativeRoot !== "/" && id.startsWith(relativeRoot)) {
566
- const path = join$1(root, id), externalize = pathToFileURL(path).toString();
567
- return externalizeMap.set(id, externalize), {
665
+ const externalize = pathToFileURL(join$1(root, id)).toString();
666
+ externalizeMap.set(id, externalize);
667
+ return {
568
668
  externalize,
569
669
  type: "module"
570
670
  };
571
671
  }
572
- return bareVitestRegexp.test(id) ? (externalizeMap.set(id, id), {
573
- externalize: id,
574
- type: "module"
575
- }) : null;
672
+ if (bareVitestRegexp.test(id)) {
673
+ externalizeMap.set(id, id);
674
+ return {
675
+ externalize: id,
676
+ type: "module"
677
+ };
678
+ }
679
+ return null;
576
680
  }
577
681
 
682
+ // Store globals in case tests overwrite them
683
+ const processListeners = process.listeners.bind(process);
684
+ const processOn = process.on.bind(process);
685
+ const processOff = process.off.bind(process);
578
686
  const dispose = [];
579
687
  function listenForErrors(state) {
580
- dispose.forEach((fn) => fn()), dispose.length = 0;
688
+ dispose.forEach((fn) => fn());
689
+ dispose.length = 0;
581
690
  function catchError(err, type, event) {
582
691
  const worker = state();
583
692
  // if there is another listener, assume that it's handled by user code
584
693
  // one is Vitest's own listener
585
- if (process.listeners(event).length > 1) return;
694
+ if (processListeners(event).length > 1) return;
586
695
  const error = serializeValue(err);
587
696
  if (typeof error === "object" && error != null) {
588
- if (error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0, worker.filepath) error.VITEST_TEST_PATH = worker.filepath;
589
- error.VITEST_AFTER_ENV_TEARDOWN = worker.environmentTeardownRun;
697
+ error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0;
698
+ if (worker.filepath) error.VITEST_TEST_PATH = worker.filepath;
590
699
  }
591
700
  state().rpc.onUnhandledError(error, type);
592
701
  }
593
- const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException"), unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection");
594
- process.on("uncaughtException", uncaughtException), process.on("unhandledRejection", unhandledRejection), dispose.push(() => {
595
- process.off("uncaughtException", uncaughtException), process.off("unhandledRejection", unhandledRejection);
702
+ const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException");
703
+ const unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection");
704
+ processOn("uncaughtException", uncaughtException);
705
+ processOn("unhandledRejection", unhandledRejection);
706
+ dispose.push(() => {
707
+ processOff("uncaughtException", uncaughtException);
708
+ processOff("unhandledRejection", unhandledRejection);
596
709
  });
597
710
  }
598
711
 
599
- const { readFileSync } = fs, browserExternalId = "__vite-browser-external", browserExternalLength = 24;
712
+ const { readFileSync } = fs;
713
+ const browserExternalId = "__vite-browser-external";
714
+ const browserExternalLength = 24;
600
715
  const VITEST_VM_CONTEXT_SYMBOL = "__vitest_vm_context__";
601
- const cwd = process.cwd(), isWindows = process.platform === "win32";
716
+ const cwd = process.cwd();
717
+ const isWindows = process.platform === "win32";
602
718
  function startVitestModuleRunner(options) {
603
- const state = () => globalThis.__vitest_worker__ || options.state, rpc = () => state().rpc;
719
+ const state = () => globalThis.__vitest_worker__ || options.state;
720
+ const rpc = () => state().rpc;
604
721
  process.exit = (code = process.exitCode || 0) => {
605
722
  throw new Error(`process.exit unexpectedly called with "${code}"`);
606
- }, listenForErrors(state);
723
+ };
724
+ listenForErrors(state);
607
725
  const environment = () => {
608
726
  const environment = state().environment;
609
727
  return environment.viteEnvironment || environment.name;
610
- }, vm = options.context && options.externalModulesExecutor ? {
728
+ };
729
+ const vm = options.context && options.externalModulesExecutor ? {
611
730
  context: options.context,
612
731
  externalModulesExecutor: options.externalModulesExecutor
613
- } : void 0, evaluator = options.evaluator || new VitestModuleEvaluator(vm, {
732
+ } : void 0;
733
+ const evaluator = options.evaluator || new VitestModuleEvaluator(vm, {
614
734
  get moduleExecutionInfo() {
615
735
  return state().moduleExecutionInfo;
616
736
  },
@@ -618,7 +738,8 @@ function startVitestModuleRunner(options) {
618
738
  return state().config.deps.interopDefault;
619
739
  },
620
740
  getCurrentTestFilepath: () => state().filepath
621
- }), moduleRunner = new VitestModuleRunner({
741
+ });
742
+ const moduleRunner = new VitestModuleRunner({
622
743
  spyModule: options.spyModule,
623
744
  evaluatedModules: options.evaluatedModules,
624
745
  evaluator,
@@ -654,15 +775,17 @@ function startVitestModuleRunner(options) {
654
775
  type: "builtin"
655
776
  };
656
777
  const result = await rpc().fetch(id, importer, environment(), options);
657
- return "cached" in result ? {
778
+ if ("cached" in result) return {
658
779
  code: readFileSync(result.tmp, "utf-8"),
659
780
  ...result
660
- } : result;
781
+ };
782
+ return result;
661
783
  } catch (cause) {
662
784
  // rethrow vite error if it cannot load the module because it's not resolved
663
785
  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 '")) {
664
786
  const error = new Error(`Cannot find ${isBareImport(id) ? "package" : "module"} '${id}'${importer ? ` imported from '${importer}'` : ""}`, { cause });
665
- throw error.code = "ERR_MODULE_NOT_FOUND", error;
787
+ error.code = "ERR_MODULE_NOT_FOUND";
788
+ throw error;
666
789
  }
667
790
  throw cause;
668
791
  } finally {