vitest 4.0.0-beta.8 → 4.0.0

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 (85) hide show
  1. package/LICENSE.md +86 -102
  2. package/browser/context.d.ts +7 -0
  3. package/browser/context.js +20 -0
  4. package/dist/browser.d.ts +26 -9
  5. package/dist/browser.js +17 -7
  6. package/dist/chunks/base.CtHM3ryk.js +128 -0
  7. package/dist/chunks/{benchmark.UW6Ezvxy.js → benchmark.DHKMYAts.js} +2 -2
  8. package/dist/chunks/{browser.d.DOMmqJQx.d.ts → browser.d.B9iJzZyn.d.ts} +3 -3
  9. package/dist/chunks/{cac.By1HvRIk.js → cac.B99MQg-w.js} +47 -91
  10. package/dist/chunks/{cli-api.C-JHgQgp.js → cli-api.PwHwIMss.js} +1544 -310
  11. package/dist/chunks/{config.d._GBBbReY.d.ts → config.d.u2CUDWwS.d.ts} +6 -19
  12. package/dist/chunks/{console.B0quX7yH.js → console.CTJL2nuH.js} +4 -6
  13. package/dist/chunks/{coverage.DarITf6U.js → coverage.FU3w4IrQ.js} +128 -1142
  14. package/dist/chunks/{creator.KEg6n5IC.js → creator.DucAaYBz.js} +10 -37
  15. package/dist/chunks/{defaults.CXFFjsi8.js → defaults.BOqNVLsY.js} +0 -1
  16. package/dist/chunks/environment.d.CrsxCzP1.d.ts +29 -0
  17. package/dist/chunks/evaluatedModules.Dg1zASAC.js +17 -0
  18. package/dist/chunks/{global.d.K6uBQHzY.d.ts → global.d.BgJSTpgQ.d.ts} +2 -17
  19. package/dist/chunks/{globals.lgsmH00r.js → globals.BGT_RUsD.js} +12 -9
  20. package/dist/chunks/{index.BuwjkI-q.js → index.BdSLhLDZ.js} +3 -3
  21. package/dist/chunks/{index.DfviD7lX.js → index.CbWINfS7.js} +49 -21
  22. package/dist/chunks/{index.AzwzFtyi.js → index.CcRZ6fUh.js} +1493 -114
  23. package/dist/chunks/{index.X0nbfr6-.js → index.Dc3xnDvT.js} +48 -289
  24. package/dist/chunks/{index.AR8aAkCC.js → index.RwjEGCQ0.js} +7 -8
  25. package/dist/chunks/init-forks.DSafeltJ.js +54 -0
  26. package/dist/chunks/init-threads.SUtZ-067.js +17 -0
  27. package/dist/chunks/init.B2EESLQM.js +213 -0
  28. package/dist/chunks/{inspector.CvQD-Nie.js → inspector.DLZxSeU3.js} +2 -6
  29. package/dist/chunks/{moduleRunner.d.CX4DuqOx.d.ts → moduleRunner.d.YtNsMIoJ.d.ts} +12 -14
  30. package/dist/chunks/{node.BOqcT2jW.js → node.BwAWWjHZ.js} +3 -4
  31. package/dist/chunks/{plugin.d.CHe6slQs.d.ts → plugin.d.DQU1R5px.d.ts} +1 -1
  32. package/dist/chunks/{reporters.d.37tJQ2uV.d.ts → reporters.d.BMKt7f6I.d.ts} +1066 -1030
  33. package/dist/chunks/{index.CsFXYRkW.js → resolveSnapshotEnvironment.DJJKMKxb.js} +18 -24
  34. package/dist/chunks/{rpc.RpPylpp0.js → rpc.cD77ENhU.js} +13 -14
  35. package/dist/chunks/{setup-common.hLGRxhC8.js → setup-common.DR1sucx6.js} +8 -8
  36. package/dist/chunks/{startModuleRunner.C8TW8zTN.js → startModuleRunner.C2tTvmF9.js} +131 -110
  37. package/dist/chunks/test.C3RPt8JR.js +214 -0
  38. package/dist/chunks/{utils.C7__0Iv5.js → utils.CG9h5ccR.js} +3 -15
  39. package/dist/chunks/{vi.BfdOiD4j.js → vi.BZvkKVkM.js} +73 -176
  40. package/dist/chunks/{vm.BHBje7cC.js → vm.DBeOXrP9.js} +29 -33
  41. package/dist/chunks/{worker.d.DYlqbejz.d.ts → worker.d.BFk-vvBU.d.ts} +42 -6
  42. package/dist/cli.js +12 -11
  43. package/dist/config.cjs +0 -1
  44. package/dist/config.d.ts +12 -14
  45. package/dist/config.js +1 -1
  46. package/dist/coverage.d.ts +8 -7
  47. package/dist/coverage.js +3 -14
  48. package/dist/environments.d.ts +3 -6
  49. package/dist/environments.js +1 -1
  50. package/dist/index.d.ts +24 -30
  51. package/dist/index.js +12 -11
  52. package/dist/module-evaluator.d.ts +6 -4
  53. package/dist/module-evaluator.js +14 -16
  54. package/dist/module-runner.js +5 -5
  55. package/dist/node.d.ts +83 -27
  56. package/dist/node.js +23 -20
  57. package/dist/reporters.d.ts +11 -10
  58. package/dist/reporters.js +12 -11
  59. package/dist/runners.d.ts +1 -1
  60. package/dist/runners.js +14 -216
  61. package/dist/snapshot.js +3 -3
  62. package/dist/suite.js +4 -3
  63. package/dist/worker.d.ts +26 -0
  64. package/dist/worker.js +45 -166
  65. package/dist/workers/forks.js +41 -35
  66. package/dist/workers/runVmTests.js +25 -22
  67. package/dist/workers/threads.js +41 -23
  68. package/dist/workers/vmForks.js +26 -39
  69. package/dist/workers/vmThreads.js +26 -29
  70. package/package.json +48 -35
  71. package/worker.d.ts +1 -0
  72. package/browser.d.ts +0 -1
  73. package/dist/chunks/base.BXI97p6t.js +0 -39
  74. package/dist/chunks/environment.d.2fYMoz3o.d.ts +0 -66
  75. package/dist/chunks/moduleTransport.I-bgQy0S.js +0 -19
  76. package/dist/chunks/resolver.Bx6lE0iq.js +0 -119
  77. package/dist/chunks/runBaseTests.D6sfuWBM.js +0 -99
  78. package/dist/chunks/typechecker.DSo_maXz.js +0 -762
  79. package/dist/chunks/utils.C2YI6McM.js +0 -52
  80. package/dist/chunks/worker.d.BKu8cnnX.d.ts +0 -8
  81. package/dist/workers.d.ts +0 -38
  82. package/dist/workers.js +0 -31
  83. package/execute.d.ts +0 -1
  84. package/utils.d.ts +0 -1
  85. package/workers.d.ts +0 -1
@@ -1,36 +1,21 @@
1
- import * as chai from 'chai';
2
- import { resolve, join } from 'node:path';
3
- import { l as loadDiffConfig, b as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.hLGRxhC8.js';
4
- import { distDir } from '../path.js';
5
- import { r as rpc } from './rpc.RpPylpp0.js';
6
- import { g as getWorkerState } from './utils.C7__0Iv5.js';
1
+ import { chai } from '@vitest/expect';
2
+ import { l as loadDiffConfig, b as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.DR1sucx6.js';
3
+ import { r as rpc } from './rpc.cD77ENhU.js';
4
+ import { g as getWorkerState } from './utils.CG9h5ccR.js';
5
+ import { V as VitestTestRunner, N as NodeBenchmarkRunner } from './test.C3RPt8JR.js';
7
6
 
8
7
  function setupChaiConfig(config) {
9
8
  Object.assign(chai.config, config);
10
9
  }
11
10
 
12
- async function resolveSnapshotEnvironment(config, executor) {
13
- if (!config.snapshotEnvironment) {
14
- const { VitestNodeSnapshotEnvironment } = await import('./node.BOqcT2jW.js');
15
- return new VitestNodeSnapshotEnvironment();
16
- }
17
- const mod = await executor.import(config.snapshotEnvironment);
18
- if (typeof mod.default !== "object" || !mod.default) throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`");
19
- return mod.default;
20
- }
21
-
22
- const runnersFile = resolve(distDir, "runners.js");
23
11
  async function getTestRunnerConstructor(config, moduleRunner) {
24
- if (!config.runner) {
25
- const { VitestTestRunner, NodeBenchmarkRunner } = await moduleRunner.import(join("/@fs/", runnersFile));
26
- return config.mode === "test" ? VitestTestRunner : NodeBenchmarkRunner;
27
- }
12
+ if (!config.runner) return config.mode === "test" ? VitestTestRunner : NodeBenchmarkRunner;
28
13
  const mod = await moduleRunner.import(config.runner);
29
14
  if (!mod.default && typeof mod.default !== "function") throw new Error(`Runner must export a default function, but got ${typeof mod.default} imported from ${config.runner}`);
30
15
  return mod.default;
31
16
  }
32
17
  async function resolveTestRunner(config, moduleRunner) {
33
- const TestRunner = await getTestRunnerConstructor(config, moduleRunner), testRunner = new TestRunner(config);
18
+ const testRunner = new (await (getTestRunnerConstructor(config, moduleRunner)))(config);
34
19
  if (Object.defineProperty(testRunner, "moduleRunner", {
35
20
  value: moduleRunner,
36
21
  enumerable: false,
@@ -76,11 +61,20 @@ async function resolveTestRunner(config, moduleRunner) {
76
61
  const originalOnAfterRunTask = testRunner.onAfterRunTask;
77
62
  return testRunner.onAfterRunTask = async (test) => {
78
63
  if (config.bail && test.result?.state === "fail") {
79
- const previousFailures = await rpc().getCountOfFailedTests(), currentFailures = 1 + previousFailures;
80
- if (currentFailures >= config.bail) rpc().onCancel("test-failure"), testRunner.cancel?.("test-failure");
64
+ if (1 + await rpc().getCountOfFailedTests() >= config.bail) rpc().onCancel("test-failure"), testRunner.cancel?.("test-failure");
81
65
  }
82
66
  await originalOnAfterRunTask?.call(testRunner, test);
83
67
  }, testRunner;
84
68
  }
85
69
 
70
+ async function resolveSnapshotEnvironment(config, executor) {
71
+ if (!config.snapshotEnvironment) {
72
+ const { VitestNodeSnapshotEnvironment } = await import('./node.BwAWWjHZ.js');
73
+ return new VitestNodeSnapshotEnvironment();
74
+ }
75
+ const mod = await executor.import(config.snapshotEnvironment);
76
+ if (typeof mod.default !== "object" || !mod.default) throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`");
77
+ return mod.default;
78
+ }
79
+
86
80
  export { resolveSnapshotEnvironment as a, resolveTestRunner as r, setupChaiConfig as s };
@@ -1,6 +1,6 @@
1
- import { getSafeTimers } from '@vitest/utils';
1
+ import { getSafeTimers } from '@vitest/utils/timers';
2
2
  import { c as createBirpc } from './index.Bgo3tNWt.js';
3
- import { g as getWorkerState } from './utils.C7__0Iv5.js';
3
+ import { g as getWorkerState } from './utils.CG9h5ccR.js';
4
4
 
5
5
  const { get } = Reflect;
6
6
  function withSafeTimers(fn) {
@@ -9,8 +9,7 @@ function withSafeTimers(fn) {
9
9
  if (globalThis.setTimeout = setTimeout, globalThis.clearTimeout = clearTimeout, setImmediate) globalThis.setImmediate = setImmediate;
10
10
  if (clearImmediate) globalThis.clearImmediate = clearImmediate;
11
11
  if (globalThis.process && nextTick) globalThis.process.nextTick = nextTick;
12
- const result = fn();
13
- return result;
12
+ return fn();
14
13
  } finally {
15
14
  if (globalThis.setTimeout = currentSetTimeout, globalThis.clearTimeout = currentClearTimeout, globalThis.setImmediate = currentSetImmediate, globalThis.clearImmediate = currentClearImmediate, globalThis.process && nextTick) nextTick(() => {
16
15
  globalThis.process.nextTick = currentNextTick;
@@ -27,17 +26,17 @@ function createRuntimeRpc(options) {
27
26
  let setCancel = (_reason) => {};
28
27
  const onCancel = new Promise((resolve) => {
29
28
  setCancel = resolve;
30
- }), rpc = createSafeRpc(createBirpc({ onCancel: setCancel }, {
31
- eventNames: [
32
- "onUserConsoleLog",
33
- "onCollected",
34
- "onCancel"
35
- ],
36
- timeout: -1,
37
- ...options
38
- }));
29
+ });
39
30
  return {
40
- rpc,
31
+ rpc: createSafeRpc(createBirpc({ onCancel: setCancel }, {
32
+ eventNames: [
33
+ "onUserConsoleLog",
34
+ "onCollected",
35
+ "onCancel"
36
+ ],
37
+ timeout: -1,
38
+ ...options
39
+ })),
41
40
  onCancel
42
41
  };
43
42
  }
@@ -1,7 +1,7 @@
1
1
  import { r as resolveCoverageProviderModule } from './coverage.D_JHT54q.js';
2
2
  import { addSerializer } from '@vitest/snapshot';
3
- import { setSafeTimers } from '@vitest/utils';
4
- import { g as getWorkerState } from './utils.C7__0Iv5.js';
3
+ import { setSafeTimers } from '@vitest/utils/timers';
4
+ import { g as getWorkerState } from './utils.CG9h5ccR.js';
5
5
 
6
6
  async function startCoverageInsideWorker(options, loader, runtimeOptions) {
7
7
  const coverageModule = await resolveCoverageProviderModule(options, loader);
@@ -18,10 +18,10 @@ async function stopCoverageInsideWorker(options, loader, runtimeOptions) {
18
18
 
19
19
  let globalSetup = false;
20
20
  async function setupCommonEnv(config) {
21
- if (setupDefines(config.defines), setupEnv(config.env), !globalSetup && (globalSetup = true, setSafeTimers(), config.globals)) (await import('./globals.lgsmH00r.js')).registerApiGlobally();
21
+ if (setupDefines(config), setupEnv(config.env), !globalSetup && (globalSetup = true, setSafeTimers(), config.globals)) (await import('./globals.BGT_RUsD.js')).registerApiGlobally();
22
22
  }
23
- function setupDefines(defines) {
24
- for (const key in defines) globalThis[key] = defines[key];
23
+ function setupDefines(config) {
24
+ for (const key in config.defines) globalThis[key] = config.defines[key];
25
25
  }
26
26
  function setupEnv(env) {
27
27
  const state = getWorkerState(), { PROD, DEV,...restEnvs } = env;
@@ -35,14 +35,14 @@ async function loadDiffConfig(config, moduleRunner) {
35
35
  throw new Error(`invalid diff config file ${config.diff}. Must have a default export with config object`);
36
36
  }
37
37
  async function loadSnapshotSerializers(config, moduleRunner) {
38
- const files = config.snapshotSerializers, snapshotSerializers = await Promise.all(files.map(async (file) => {
38
+ const files = config.snapshotSerializers;
39
+ (await Promise.all(files.map(async (file) => {
39
40
  const mo = await moduleRunner.import(file);
40
41
  if (!mo || typeof mo.default !== "object" || mo.default === null) throw new Error(`invalid snapshot serializer file ${file}. Must export a default object`);
41
42
  const config = mo.default;
42
43
  if (typeof config.test !== "function" || typeof config.serialize !== "function" && typeof config.print !== "function") throw new TypeError(`invalid snapshot serializer in ${file}. Must have a 'test' method along with either a 'serialize' or 'print' method.`);
43
44
  return config;
44
- }));
45
- snapshotSerializers.forEach((serializer) => addSerializer(serializer));
45
+ }))).forEach((serializer) => addSerializer(serializer));
46
46
  }
47
47
 
48
48
  export { stopCoverageInsideWorker as a, loadSnapshotSerializers as b, setupCommonEnv as c, loadDiffConfig as l, startCoverageInsideWorker as s, takeCoverageInsideWorker as t };
@@ -1,68 +1,15 @@
1
1
  import fs from 'node:fs';
2
- import { builtinModules, isBuiltin } from 'node:module';
3
- import { highlight, isBareImport } from '@vitest/utils';
2
+ import nodeModule, { builtinModules, isBuiltin } from 'node:module';
3
+ import { isBareImport } from '@vitest/utils/helpers';
4
4
  import { pathToFileURL } from 'node:url';
5
5
  import { normalize as normalize$1, join as join$1 } from 'pathe';
6
6
  import { distDir } from '../path.js';
7
- import { processError } from '@vitest/utils/error';
7
+ import { serializeValue } from '@vitest/utils/serialize';
8
8
  import { VitestModuleEvaluator, unwrapId } from '../module-evaluator.js';
9
9
  import { resolve as resolve$1, isAbsolute as isAbsolute$1 } from 'node:path';
10
10
  import vm from 'node:vm';
11
11
  import { MockerRegistry, mockObject, RedirectedModule, AutomockedModule } from '@vitest/mocker';
12
- import { ModuleRunner } from 'vite/module-runner';
13
- import { V as VitestTransport } from './moduleTransport.I-bgQy0S.js';
14
-
15
- const bareVitestRegexp = /^@?vitest(?:\/|$)/, normalizedDistDir = normalize$1(distDir), relativeIds = {}, externalizeMap = /* @__PURE__ */ new Map();
16
- // all Vitest imports always need to be externalized
17
- function getCachedVitestImport(id, state) {
18
- if (id.startsWith("/@fs/") || id.startsWith("\\@fs\\")) id = id.slice(process.platform === "win32" ? 5 : 4);
19
- if (externalizeMap.has(id)) return {
20
- externalize: externalizeMap.get(id),
21
- type: "module"
22
- };
23
- // always externalize Vitest because we import from there before running tests
24
- // so we already have it cached by Node.js
25
- const root = state().config.root, relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length));
26
- if (id.includes(distDir) || id.includes(normalizedDistDir)) {
27
- const externalize = id.startsWith("file://") ? id : pathToFileURL(id).toString();
28
- return externalizeMap.set(id, externalize), {
29
- externalize,
30
- type: "module"
31
- };
32
- }
33
- if (relativeRoot && relativeRoot !== "/" && id.startsWith(relativeRoot)) {
34
- const path = join$1(root, id), externalize = pathToFileURL(path).toString();
35
- return externalizeMap.set(id, externalize), {
36
- externalize,
37
- type: "module"
38
- };
39
- }
40
- return bareVitestRegexp.test(id) ? (externalizeMap.set(id, id), {
41
- externalize: id,
42
- type: "module"
43
- }) : null;
44
- }
45
-
46
- const dispose = [];
47
- function listenForErrors(state) {
48
- dispose.forEach((fn) => fn()), dispose.length = 0;
49
- function catchError(err, type, event) {
50
- const worker = state(), listeners = process.listeners(event);
51
- // if there is another listener, assume that it's handled by user code
52
- // one is Vitest's own listener
53
- if (listeners.length > 1) return;
54
- const error = processError(err);
55
- if (typeof error === "object" && error != null) {
56
- if (error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0, worker.filepath) error.VITEST_TEST_PATH = worker.filepath;
57
- error.VITEST_AFTER_ENV_TEARDOWN = worker.environmentTeardownRun;
58
- }
59
- state().rpc.onUnhandledError(error, type);
60
- }
61
- const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException"), unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection");
62
- process.on("uncaughtException", uncaughtException), process.on("unhandledRejection", unhandledRejection), dispose.push(() => {
63
- process.off("uncaughtException", uncaughtException), process.off("unhandledRejection", unhandledRejection);
64
- });
65
- }
12
+ import * as viteModuleRunner from 'vite/module-runner';
66
13
 
67
14
  const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
68
15
  function normalizeWindowsPath(input = "") {
@@ -81,8 +28,8 @@ const _UNC_REGEX = /^[/\\]{2}/, _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\
81
28
  for (const seg of segments) {
82
29
  if (!seg) continue;
83
30
  if (path.length > 0) {
84
- const pathTrailing = path[path.length - 1] === "/", segLeading = seg[0] === "/", both = pathTrailing && segLeading;
85
- if (both) path += seg.slice(1);
31
+ const pathTrailing = path[path.length - 1] === "/", segLeading = seg[0] === "/";
32
+ if (pathTrailing && segLeading) path += seg.slice(1);
86
33
  else path += pathTrailing || segLeading ? seg : `/${seg}`;
87
34
  } else path += seg;
88
35
  }
@@ -167,17 +114,14 @@ function findMockRedirect(root, mockPath, external) {
167
114
  const baseOriginal = basename(path);
168
115
  function findFile(mockFolder, baseOriginal) {
169
116
  const files = readdirSync(mockFolder);
170
- for (const file of files) {
171
- const baseFile = basename(file, extname(file));
172
- if (baseFile === baseOriginal) {
173
- const path = resolve(mockFolder, file);
174
- // if the same name, return the file
175
- if (statSync(path).isFile()) return path;
176
- {
177
- // find folder/index.{js,ts}
178
- const indexFile = findFile(path, "index");
179
- if (indexFile) return indexFile;
180
- }
117
+ for (const file of files) if (basename(file, extname(file)) === baseOriginal) {
118
+ const path = resolve(mockFolder, file);
119
+ // if the same name, return the file
120
+ if (statSync(path).isFile()) return path;
121
+ {
122
+ // find folder/index.{js,ts}
123
+ const indexFile = findFile(path, "index");
124
+ if (indexFile) return indexFile;
181
125
  }
182
126
  }
183
127
  return null;
@@ -188,7 +132,7 @@ function findMockRedirect(root, mockPath, external) {
188
132
  return existsSync(fullPath) ? fullPath : null;
189
133
  }
190
134
  const builtins = new Set([
191
- ...builtinModules,
135
+ ...nodeModule.builtinModules,
192
136
  "assert/strict",
193
137
  "diagnostics_channel",
194
138
  "dns/promises",
@@ -209,7 +153,7 @@ const builtins = new Set([
209
153
  "node:test/reporters"
210
154
  ]), NODE_BUILTIN_NAMESPACE = "node:";
211
155
  function isNodeBuiltin(id) {
212
- return prefixedBuiltins$1.has(id) ? true : builtins.has(id.startsWith(NODE_BUILTIN_NAMESPACE) ? id.slice(5) : id);
156
+ return nodeModule.isBuiltin ? nodeModule.isBuiltin(id) : prefixedBuiltins$1.has(id) ? true : builtins.has(id.startsWith(NODE_BUILTIN_NAMESPACE) ? id.slice(5) : id);
213
157
  }
214
158
 
215
159
  const spyModulePath = resolve$1(distDir, "spy.js");
@@ -233,6 +177,7 @@ class VitestMocker {
233
177
  Array,
234
178
  Map
235
179
  };
180
+ if (options.spyModule) this.spyModule = options.spyModule;
236
181
  const Symbol = this.primitives.Symbol;
237
182
  this.filterPublicKeys = [
238
183
  "__esModule",
@@ -330,16 +275,16 @@ class VitestMocker {
330
275
  if (prop === "then") {
331
276
  if (target instanceof Promise) return target.then.bind(target);
332
277
  } else if (!(prop in target)) {
333
- if (this.filterPublicKeys.includes(prop)) return void 0;
278
+ if (this.filterPublicKeys.includes(prop)) return;
334
279
  throw this.createError(`[vitest] No "${String(prop)}" export is defined on the "${mock.raw}" mock. Did you forget to return it from "vi.mock"?
335
280
  If you need to partially mock a module, you can use "importOriginal" helper inside:
336
- `, highlight(`vi.mock(import("${mock.raw}"), async (importOriginal) => {
281
+ `, `vi.mock(import("${mock.raw}"), async (importOriginal) => {
337
282
  const actual = await importOriginal()
338
283
  return {
339
284
  ...actual,
340
285
  // your mocked methods
341
286
  }
342
- })`));
287
+ })`);
343
288
  }
344
289
  return val;
345
290
  } });
@@ -354,8 +299,7 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
354
299
  return `mock:${dep}`;
355
300
  }
356
301
  getDependencyMock(id) {
357
- const registry = this.getMockerRegistry();
358
- return registry.getById(fixLeadingSlashes(id));
302
+ return this.getMockerRegistry().getById(fixLeadingSlashes(id));
359
303
  }
360
304
  findMockRedirect(mockPath, external) {
361
305
  return findMockRedirect(this.root, mockPath, external);
@@ -370,8 +314,7 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
370
314
  }, object, mockExports);
371
315
  }
372
316
  unmockPath(id) {
373
- const registry = this.getMockerRegistry();
374
- registry.deleteById(id), this.invalidateModuleById(id);
317
+ this.getMockerRegistry().deleteById(id), this.invalidateModuleById(id);
375
318
  }
376
319
  mockPath(originalId, id, url, external, mockType, factory) {
377
320
  const registry = this.getMockerRegistry();
@@ -386,8 +329,8 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
386
329
  this.invalidateModuleById(id);
387
330
  }
388
331
  async importActual(rawId, importer, callstack) {
389
- const { url } = await this.resolveId(rawId, importer), node = await this.moduleRunner.fetchModule(url, importer), result = await this.moduleRunner.cachedRequest(node.url, node, callstack || [importer], void 0, true);
390
- return result;
332
+ const { url } = await this.resolveId(rawId, importer), node = await this.moduleRunner.fetchModule(url, importer);
333
+ return await this.moduleRunner.cachedRequest(node.url, node, callstack || [importer], void 0, true);
391
334
  }
392
335
  async importMock(rawId, importer) {
393
336
  const { id, url, external } = await this.resolveId(rawId, importer);
@@ -472,11 +415,8 @@ const prefixedBuiltins = new Set([
472
415
  // C:\root\id.js -> /id.js
473
416
  // TODO: expose this in vite/module-runner
474
417
  function normalizeModuleId(file) {
475
- if (prefixedBuiltins.has(file)) return file;
476
- // unix style, but Windows path still starts with the drive letter to check the root
477
- const unixFile = slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/");
478
418
  // if it's not in the root, keep it as a path, not a URL
479
- return unixFile.replace(/^file:\//, "/");
419
+ return prefixedBuiltins.has(file) ? file : slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/");
480
420
  }
481
421
  const windowsSlashRE = /\\/g;
482
422
  function slash(p) {
@@ -488,18 +428,53 @@ function fixLeadingSlashes(id) {
488
428
  return id.startsWith("//") ? id.replace(multipleSlashRe, "/") : id;
489
429
  }
490
430
 
431
+ const nodeBuiltins = builtinModules.filter((id) => !id.includes(":"));
432
+ class VitestTransport {
433
+ constructor(options) {
434
+ this.options = options;
435
+ }
436
+ async invoke(event) {
437
+ if (event.type !== "custom") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support Vite HMR events.`) };
438
+ if (event.event !== "vite:invoke") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support ${event.event} event.`) };
439
+ const { name, data } = event.data;
440
+ if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) };
441
+ if (name === "getBuiltins") return { result: [...nodeBuiltins, /^node:/] };
442
+ try {
443
+ return { result: await this.options.fetchModule(...data) };
444
+ } catch (error) {
445
+ return { error };
446
+ }
447
+ }
448
+ }
449
+
450
+ const createNodeImportMeta = (modulePath) => {
451
+ if (!viteModuleRunner.createDefaultImportMeta) throw new Error(`createNodeImportMeta is not supported in this version of Vite.`);
452
+ const defaultMeta = viteModuleRunner.createDefaultImportMeta(modulePath), href = defaultMeta.url, importMetaResolver = createImportMetaResolver();
453
+ return {
454
+ ...defaultMeta,
455
+ main: false,
456
+ resolve(id, parent) {
457
+ return (importMetaResolver ?? defaultMeta.resolve)(id, parent ?? href);
458
+ }
459
+ };
460
+ };
461
+ function createImportMetaResolver() {
462
+ if (import.meta.resolve) return (specifier, importer) => import.meta.resolve(specifier, importer);
463
+ }
491
464
  // @ts-expect-error overriding private method
492
- class VitestModuleRunner extends ModuleRunner {
465
+ class VitestModuleRunner extends viteModuleRunner.ModuleRunner {
493
466
  mocker;
494
467
  moduleExecutionInfo;
495
- constructor(options) {
496
- const transport = new VitestTransport(options.transport), evaluatedModules = options.evaluatedModules;
468
+ constructor(vitestOptions) {
469
+ const options = vitestOptions, transport = new VitestTransport(options.transport), evaluatedModules = options.evaluatedModules;
497
470
  if (super({
498
471
  transport,
499
472
  hmr: false,
500
473
  evaluatedModules,
501
- sourcemapInterceptor: "prepareStackTrace"
502
- }, options.evaluator), this.options = options, this.moduleExecutionInfo = options.getWorkerState().moduleExecutionInfo, this.mocker = options.mocker || new VitestMocker(this, {
474
+ sourcemapInterceptor: "prepareStackTrace",
475
+ createImportMeta: vitestOptions.createImportMeta
476
+ }, options.evaluator), this.vitestOptions = vitestOptions, this.moduleExecutionInfo = options.getWorkerState().moduleExecutionInfo, this.mocker = options.mocker || new VitestMocker(this, {
477
+ spyModule: options.spyModule,
503
478
  context: options.vm?.context,
504
479
  resolveId: options.transport.resolveId,
505
480
  get root() {
@@ -519,12 +494,11 @@ class VitestModuleRunner extends ModuleRunner {
519
494
  });
520
495
  }
521
496
  async import(rawId) {
522
- const resolved = await this.options.transport.resolveId(rawId);
523
- return resolved ? super.import(resolved.url) : super.import(rawId);
497
+ const resolved = await this.vitestOptions.transport.resolveId(rawId);
498
+ return super.import(resolved ? resolved.url : rawId);
524
499
  }
525
500
  async fetchModule(url, importer) {
526
- const module = await this.cachedModule(url, importer);
527
- return module;
501
+ return await this.cachedModule(url, importer);
528
502
  }
529
503
  _cachedRequest(url, module, callstack = [], metadata) {
530
504
  // @ts-expect-error "cachedRequest" is private
@@ -558,10 +532,62 @@ class VitestModuleRunner extends ModuleRunner {
558
532
  }
559
533
  }
560
534
 
535
+ const bareVitestRegexp = /^@?vitest(?:\/|$)/, normalizedDistDir = normalize$1(distDir), relativeIds = {}, externalizeMap = /* @__PURE__ */ new Map();
536
+ // all Vitest imports always need to be externalized
537
+ function getCachedVitestImport(id, state) {
538
+ if (id.startsWith("/@fs/") || id.startsWith("\\@fs\\")) id = id.slice(process.platform === "win32" ? 5 : 4);
539
+ if (externalizeMap.has(id)) return {
540
+ externalize: externalizeMap.get(id),
541
+ type: "module"
542
+ };
543
+ // always externalize Vitest because we import from there before running tests
544
+ // so we already have it cached by Node.js
545
+ const root = state().config.root, relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length));
546
+ if (id.includes(distDir) || id.includes(normalizedDistDir)) {
547
+ const externalize = id.startsWith("file://") ? id : pathToFileURL(id).toString();
548
+ return externalizeMap.set(id, externalize), {
549
+ externalize,
550
+ type: "module"
551
+ };
552
+ }
553
+ if (relativeRoot && relativeRoot !== "/" && id.startsWith(relativeRoot)) {
554
+ const path = join$1(root, id), externalize = pathToFileURL(path).toString();
555
+ return externalizeMap.set(id, externalize), {
556
+ externalize,
557
+ type: "module"
558
+ };
559
+ }
560
+ return bareVitestRegexp.test(id) ? (externalizeMap.set(id, id), {
561
+ externalize: id,
562
+ type: "module"
563
+ }) : null;
564
+ }
565
+
566
+ const dispose = [];
567
+ function listenForErrors(state) {
568
+ dispose.forEach((fn) => fn()), dispose.length = 0;
569
+ function catchError(err, type, event) {
570
+ const worker = state();
571
+ // if there is another listener, assume that it's handled by user code
572
+ // one is Vitest's own listener
573
+ if (process.listeners(event).length > 1) return;
574
+ const error = serializeValue(err);
575
+ if (typeof error === "object" && error != null) {
576
+ if (error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0, worker.filepath) error.VITEST_TEST_PATH = worker.filepath;
577
+ error.VITEST_AFTER_ENV_TEARDOWN = worker.environmentTeardownRun;
578
+ }
579
+ state().rpc.onUnhandledError(error, type);
580
+ }
581
+ const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException"), unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection");
582
+ process.on("uncaughtException", uncaughtException), process.on("unhandledRejection", unhandledRejection), dispose.push(() => {
583
+ process.off("uncaughtException", uncaughtException), process.off("unhandledRejection", unhandledRejection);
584
+ });
585
+ }
586
+
561
587
  const { readFileSync } = fs, browserExternalId = "__vite-browser-external", browserExternalLength = 24;
562
588
  const VITEST_VM_CONTEXT_SYMBOL = "__vitest_vm_context__";
563
589
  const cwd = process.cwd(), isWindows = process.platform === "win32";
564
- async function startVitestModuleRunner(options) {
590
+ function startVitestModuleRunner(options) {
565
591
  const state = () => globalThis.__vitest_worker__ || options.state, rpc = () => state().rpc;
566
592
  process.exit = (code = process.exitCode || 0) => {
567
593
  throw new Error(`process.exit unexpectedly called with "${code}"`);
@@ -581,6 +607,7 @@ async function startVitestModuleRunner(options) {
581
607
  },
582
608
  getCurrentTestFilepath: () => state().filepath
583
609
  }), moduleRunner = new VitestModuleRunner({
610
+ spyModule: options.spyModule,
584
611
  evaluatedModules: options.evaluatedModules,
585
612
  evaluator,
586
613
  mocker: options.mocker,
@@ -590,10 +617,7 @@ async function startVitestModuleRunner(options) {
590
617
  if (isWindows) {
591
618
  if (id[1] === ":") {
592
619
  // The drive letter is different for whatever reason, we need to normalize it to CWD
593
- if (id[0] !== cwd[0] && id[0].toUpperCase() === cwd[0].toUpperCase()) {
594
- const isUpperCase = cwd[0].toUpperCase() === cwd[0];
595
- id = (isUpperCase ? id[0].toUpperCase() : id[0].toLowerCase()) + id.slice(1);
596
- }
620
+ if (id[0] !== cwd[0] && id[0].toUpperCase() === cwd[0].toUpperCase()) id = (cwd[0].toUpperCase() === cwd[0] ? id[0].toUpperCase() : id[0].toLowerCase()) + id.slice(1);
597
621
  // always mark absolute windows paths, otherwise Vite will externalize it
598
622
  id = `/@id/${id}`;
599
623
  }
@@ -618,14 +642,10 @@ async function startVitestModuleRunner(options) {
618
642
  type: "builtin"
619
643
  };
620
644
  const result = await rpc().fetch(id, importer, environment(), options);
621
- if ("cached" in result) {
622
- const code = readFileSync(result.tmp, "utf-8");
623
- return {
624
- code,
625
- ...result
626
- };
627
- }
628
- return result;
645
+ return "cached" in result ? {
646
+ code: readFileSync(result.tmp, "utf-8"),
647
+ ...result
648
+ } : result;
629
649
  } catch (cause) {
630
650
  // rethrow vite error if it cannot load the module because it's not resolved
631
651
  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 '")) {
@@ -642,9 +662,10 @@ async function startVitestModuleRunner(options) {
642
662
  }
643
663
  },
644
664
  getWorkerState: state,
645
- vm
665
+ vm,
666
+ createImportMeta: options.createImportMeta
646
667
  });
647
- return await moduleRunner.import("/@vite/env"), await moduleRunner.mocker.initializeSpyModule(), moduleRunner;
668
+ return moduleRunner;
648
669
  }
649
670
  function toBuiltin(id) {
650
671
  if (id.startsWith(browserExternalId)) id = id.slice(browserExternalLength);
@@ -652,4 +673,4 @@ function toBuiltin(id) {
652
673
  return id;
653
674
  }
654
675
 
655
- export { VitestModuleRunner as V, VITEST_VM_CONTEXT_SYMBOL as a, startVitestModuleRunner as s };
676
+ export { VitestModuleRunner as V, VITEST_VM_CONTEXT_SYMBOL as a, VitestTransport as b, createNodeImportMeta as c, startVitestModuleRunner as s };