vitest 4.0.17 → 4.1.0-beta.2

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