vitest 4.0.5 → 4.0.7

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 (45) hide show
  1. package/dist/browser.d.ts +3 -3
  2. package/dist/chunks/{base.RFExFinv.js → base.D3GxgUMI.js} +43 -50
  3. package/dist/chunks/{browser.d.B9iJzZyn.d.ts → browser.d.-LKfRopd.d.ts} +1 -1
  4. package/dist/chunks/{cac.Be29vze6.js → cac.G9DAn-c7.js} +8 -7
  5. package/dist/chunks/{cli-api.6GYRwzrM.js → cli-api.Csks4as1.js} +32 -28
  6. package/dist/chunks/{config.d.u2CUDWwS.d.ts → config.d.BTfZNUu9.d.ts} +0 -1
  7. package/dist/chunks/{coverage.DT47gDHj.js → coverage.C2LA1DSL.js} +17 -14
  8. package/dist/chunks/{global.d.BgJSTpgQ.d.ts → global.d.DxtanrNO.d.ts} +1 -1
  9. package/dist/chunks/{index.CcRZ6fUh.js → index.CVpyv-Zg.js} +9 -10
  10. package/dist/chunks/{index.DON9WL-E.js → index.CWIFvlX5.js} +57 -11
  11. package/dist/chunks/{resolveSnapshotEnvironment.BZzLjzkh.js → index.DEPqWSIZ.js} +12 -12
  12. package/dist/chunks/{index.BdSLhLDZ.js → index.jMQYiEWE.js} +1 -1
  13. package/dist/chunks/{init-forks.WSf5dRNP.js → init-forks.IU-xQ2_X.js} +3 -2
  14. package/dist/chunks/{init-threads.CgZguQvI.js → init-threads.C_NWvZkU.js} +3 -2
  15. package/dist/chunks/{init.CpZMjXJJ.js → init.fmH9J833.js} +85 -38
  16. package/dist/chunks/{moduleRunner.d.YtNsMIoJ.d.ts → moduleRunner.d.DEkTotCv.d.ts} +1 -1
  17. package/dist/chunks/{plugin.d.D8LgBgbU.d.ts → plugin.d.Cpes8Bt6.d.ts} +1 -1
  18. package/dist/chunks/{reporters.d.D-el0219.d.ts → reporters.d.CSNcMDxF.d.ts} +17 -9
  19. package/dist/chunks/{rpc.Dv1Jt3i2.js → rpc.D38ahn14.js} +8 -11
  20. package/dist/chunks/{startModuleRunner.BqQUfEjB.js → startModuleRunner.Cn7hCL7D.js} +36 -26
  21. package/dist/chunks/{test.CnspO-X4.js → test.B6aJd6T3.js} +1 -1
  22. package/dist/chunks/{vm.CqZQkf-M.js → vm.BL7_zzOr.js} +6 -5
  23. package/dist/chunks/{worker.d.BFk-vvBU.d.ts → worker.d.D25zYZ7N.d.ts} +23 -5
  24. package/dist/cli.js +2 -2
  25. package/dist/config.d.ts +6 -6
  26. package/dist/coverage.d.ts +4 -4
  27. package/dist/coverage.js +1 -1
  28. package/dist/environments.js +2 -1
  29. package/dist/index.d.ts +8 -8
  30. package/dist/module-evaluator.d.ts +3 -3
  31. package/dist/module-runner.js +1 -1
  32. package/dist/node.d.ts +8 -8
  33. package/dist/node.js +7 -7
  34. package/dist/reporters.d.ts +4 -4
  35. package/dist/reporters.js +2 -2
  36. package/dist/runners.d.ts +1 -1
  37. package/dist/runners.js +2 -2
  38. package/dist/worker.d.ts +3 -2
  39. package/dist/worker.js +21 -21
  40. package/dist/workers/forks.js +27 -24
  41. package/dist/workers/runVmTests.js +4 -4
  42. package/dist/workers/threads.js +27 -24
  43. package/dist/workers/vmForks.js +10 -10
  44. package/dist/workers/vmThreads.js +10 -10
  45. package/package.json +12 -12
@@ -1,3 +1,4 @@
1
+ import { URL } from 'node:url';
1
2
  import { Console } from 'node:console';
2
3
 
3
4
  // SEE https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/interfaces.js
@@ -136,13 +137,13 @@ const LIVING_KEYS = [
136
137
  "Plugin",
137
138
  "MimeType",
138
139
  "FileReader",
140
+ "FormData",
139
141
  "Blob",
140
142
  "File",
141
143
  "FileList",
142
144
  "ValidityState",
143
145
  "DOMParser",
144
146
  "XMLSerializer",
145
- "FormData",
146
147
  "XMLHttpRequestEventTarget",
147
148
  "XMLHttpRequestUpload",
148
149
  "XMLHttpRequest",
@@ -247,10 +248,10 @@ function isClassLikeName(name) {
247
248
  return name[0] === name[0].toUpperCase();
248
249
  }
249
250
  function populateGlobal(global, win, options = {}) {
250
- const { bindFunctions = false } = options, keys = getWindowKeys(global, win, options.additionalKeys), originals = /* @__PURE__ */ new Map(), overrideObject = /* @__PURE__ */ new Map();
251
+ const { bindFunctions = false } = options, keys = getWindowKeys(global, win, options.additionalKeys), originals = /* @__PURE__ */ new Map(), overridenKeys = new Set([...KEYS, ...options.additionalKeys || []]), overrideObject = /* @__PURE__ */ new Map();
251
252
  for (const key of keys) {
252
253
  const boundFunction = bindFunctions && typeof win[key] === "function" && !isClassLikeName(key) && win[key].bind(win);
253
- if (KEYS.includes(key) && key in global) originals.set(key, global[key]);
254
+ if (overridenKeys.has(key) && key in global) originals.set(key, global[key]);
254
255
  Object.defineProperty(global, key, {
255
256
  get() {
256
257
  return overrideObject.has(key) ? overrideObject.get(key) : boundFunction || win[key];
@@ -354,7 +355,8 @@ var happy = {
354
355
  "AbortController",
355
356
  "AbortSignal",
356
357
  "URL",
357
- "URLSearchParams"
358
+ "URLSearchParams",
359
+ "FormData"
358
360
  ]
359
361
  });
360
362
  return { async teardown(global) {
@@ -366,7 +368,7 @@ var happy = {
366
368
  function catchWindowErrors(window) {
367
369
  let userErrorListenerCount = 0;
368
370
  function throwUnhandlerError(e) {
369
- if (userErrorListenerCount === 0 && e.error != null) process.emit("uncaughtException", e.error);
371
+ if (userErrorListenerCount === 0 && e.error != null) e.preventDefault(), process.emit("uncaughtException", e.error);
370
372
  }
371
373
  const addEventListener = window.addEventListener.bind(window), removeEventListener = window.removeEventListener.bind(window);
372
374
  return window.addEventListener("error", throwUnhandlerError), window.addEventListener = function(...args) {
@@ -379,10 +381,12 @@ function catchWindowErrors(window) {
379
381
  window.removeEventListener("error", throwUnhandlerError);
380
382
  };
381
383
  }
384
+ let NodeFormData_, NodeBlob_, NodeRequest_;
382
385
  var jsdom = {
383
386
  name: "jsdom",
384
387
  viteEnvironment: "client",
385
388
  async setupVM({ jsdom = {} }) {
389
+ NodeFormData_ = globalThis.FormData, NodeBlob_ = globalThis.Blob, NodeRequest_ = globalThis.Request;
386
390
  const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom'), { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false,...restOptions } = jsdom;
387
391
  let dom = new JSDOM(html, {
388
392
  pretendToBeVisual,
@@ -396,8 +400,8 @@ var jsdom = {
396
400
  userAgent,
397
401
  ...restOptions
398
402
  });
399
- const clearAddEventListenerPatch = patchAddEventListener(dom.window), clearWindowErrors = catchWindowErrors(dom.window);
400
- dom.window.Buffer = Buffer, dom.window.jsdom = dom;
403
+ const clearAddEventListenerPatch = patchAddEventListener(dom.window), clearWindowErrors = catchWindowErrors(dom.window), utils = createCompatUtils(dom.window);
404
+ dom.window.Buffer = Buffer, dom.window.jsdom = dom, dom.window.Request = createCompatRequest(utils), dom.window.URL = createJSDOMCompatURL(utils);
401
405
  for (const name of [
402
406
  "structuredClone",
403
407
  "BroadcastChannel",
@@ -411,12 +415,10 @@ var jsdom = {
411
415
  }
412
416
  for (const name of [
413
417
  "fetch",
414
- "Request",
415
418
  "Response",
416
419
  "Headers",
417
420
  "AbortController",
418
421
  "AbortSignal",
419
- "URL",
420
422
  "URLSearchParams"
421
423
  ]) {
422
424
  const value = globalThis[name];
@@ -432,6 +434,7 @@ var jsdom = {
432
434
  };
433
435
  },
434
436
  async setup(global, { jsdom = {} }) {
437
+ NodeFormData_ = globalThis.FormData, NodeBlob_ = globalThis.Blob, NodeRequest_ = globalThis.Request;
435
438
  const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom'), { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false,...restOptions } = jsdom, dom = new JSDOM(html, {
436
439
  pretendToBeVisual,
437
440
  resources: resources ?? (userAgent ? new ResourceLoader({ userAgent }) : void 0),
@@ -443,12 +446,55 @@ var jsdom = {
443
446
  contentType,
444
447
  userAgent,
445
448
  ...restOptions
446
- }), clearAddEventListenerPatch = patchAddEventListener(dom.window), { keys, originals } = populateGlobal(global, dom.window, { bindFunctions: true }), clearWindowErrors = catchWindowErrors(global);
447
- return global.jsdom = dom, { teardown(global) {
449
+ }), clearAddEventListenerPatch = patchAddEventListener(dom.window), { keys, originals } = populateGlobal(global, dom.window, { bindFunctions: true }), clearWindowErrors = catchWindowErrors(global), utils = createCompatUtils(dom.window);
450
+ return global.jsdom = dom, global.Request = createCompatRequest(utils), global.URL = createJSDOMCompatURL(utils), { teardown(global) {
448
451
  clearAddEventListenerPatch(), clearWindowErrors(), dom.window.close(), delete global.jsdom, keys.forEach((key) => delete global[key]), originals.forEach((v, k) => global[k] = v);
449
452
  } };
450
453
  }
451
454
  };
455
+ function createCompatRequest(utils) {
456
+ return class Request extends NodeRequest_ {
457
+ constructor(...args) {
458
+ const [input, init] = args;
459
+ if (init?.body != null) {
460
+ const compatInit = { ...init };
461
+ if (init.body instanceof utils.window.Blob) compatInit.body = utils.makeCompatBlob(init.body);
462
+ if (init.body instanceof utils.window.FormData) compatInit.body = utils.makeCompatFormData(init.body);
463
+ super(input, compatInit);
464
+ } else super(...args);
465
+ }
466
+ };
467
+ }
468
+ function createJSDOMCompatURL(utils) {
469
+ return class URL$1 extends URL {
470
+ static createObjectURL(blob) {
471
+ if (blob instanceof utils.window.Blob) {
472
+ const compatBlob = utils.makeCompatBlob(blob);
473
+ return URL.createObjectURL(compatBlob);
474
+ }
475
+ return URL.createObjectURL(blob);
476
+ }
477
+ };
478
+ }
479
+ function createCompatUtils(window) {
480
+ // this returns a hidden Symbol(impl)
481
+ // this is cursed, and jsdom should just implement fetch API itself
482
+ const implSymbol = Object.getOwnPropertySymbols(Object.getOwnPropertyDescriptors(new window.Blob()))[0], utils = {
483
+ window,
484
+ makeCompatFormData(formData) {
485
+ const nodeFormData = new NodeFormData_();
486
+ return formData.forEach((value, key) => {
487
+ if (value instanceof window.Blob) nodeFormData.append(key, utils.makeCompatBlob(value));
488
+ else nodeFormData.append(key, value);
489
+ }), nodeFormData;
490
+ },
491
+ makeCompatBlob(blob) {
492
+ const buffer = blob[implSymbol]._buffer;
493
+ return new NodeBlob_([buffer], { type: blob.type });
494
+ }
495
+ };
496
+ return utils;
497
+ }
452
498
  function patchAddEventListener(window) {
453
499
  const JSDOMAbortSignal = window.AbortSignal, JSDOMAbortController = window.AbortController, originalAddEventListener = window.EventTarget.prototype.addEventListener;
454
500
  return window.EventTarget.prototype.addEventListener = function addEventListener(type, callback, options) {
@@ -1,13 +1,23 @@
1
1
  import { chai } from '@vitest/expect';
2
2
  import { l as loadDiffConfig, b as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.DR1sucx6.js';
3
- import { r as rpc } from './rpc.Dv1Jt3i2.js';
3
+ import { r as rpc } from './rpc.D38ahn14.js';
4
4
  import { g as getWorkerState } from './utils.CG9h5ccR.js';
5
- import { V as VitestTestRunner, N as NodeBenchmarkRunner } from './test.CnspO-X4.js';
5
+ import { V as VitestTestRunner, N as NodeBenchmarkRunner } from './test.B6aJd6T3.js';
6
6
 
7
7
  function setupChaiConfig(config) {
8
8
  Object.assign(chai.config, config);
9
9
  }
10
10
 
11
+ async function resolveSnapshotEnvironment(config, executor) {
12
+ if (!config.snapshotEnvironment) {
13
+ const { VitestNodeSnapshotEnvironment } = await import('./node.BwAWWjHZ.js');
14
+ return new VitestNodeSnapshotEnvironment();
15
+ }
16
+ const mod = await executor.import(config.snapshotEnvironment);
17
+ if (typeof mod.default !== "object" || !mod.default) throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`");
18
+ return mod.default;
19
+ }
20
+
11
21
  async function getTestRunnerConstructor(config, moduleRunner) {
12
22
  if (!config.runner) return config.mode === "test" ? VitestTestRunner : NodeBenchmarkRunner;
13
23
  const mod = await moduleRunner.import(config.runner);
@@ -67,14 +77,4 @@ async function resolveTestRunner(config, moduleRunner) {
67
77
  }, testRunner;
68
78
  }
69
79
 
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
-
80
80
  export { resolveSnapshotEnvironment as a, resolveTestRunner as r, setupChaiConfig as s };
@@ -2,7 +2,7 @@ import fs from 'node:fs';
2
2
  import { getTasks, getFullName, getTests } from '@vitest/runner/utils';
3
3
  import * as pathe from 'pathe';
4
4
  import c from 'tinyrainbow';
5
- import { g as getStateSymbol, t as truncateString, F as F_RIGHT, D as DefaultReporter, f as formatProjectName, s as separator } from './index.CcRZ6fUh.js';
5
+ import { g as getStateSymbol, t as truncateString, F as F_RIGHT, D as DefaultReporter, f as formatProjectName, s as separator } from './index.CVpyv-Zg.js';
6
6
  import { stripVTControlCharacters } from 'node:util';
7
7
  import { notNullish } from '@vitest/utils/helpers';
8
8
 
@@ -1,5 +1,5 @@
1
1
  import v8 from 'node:v8';
2
- import { i as init } from './init.CpZMjXJJ.js';
2
+ import { i as init } from './init.fmH9J833.js';
3
3
 
4
4
  if (!process.send) throw new Error("Expected worker to be run in node:child_process");
5
5
  // Store globals in case tests overwrite them
@@ -16,7 +16,8 @@ function workerInit(options) {
16
16
  serialize: v8.serialize,
17
17
  deserialize: (v) => v8.deserialize(Buffer.from(v)),
18
18
  runTests: (state) => executeTests("run", state),
19
- collectTests: (state) => executeTests("collect", state)
19
+ collectTests: (state) => executeTests("collect", state),
20
+ setup: options.setup
20
21
  });
21
22
  async function executeTests(method, state) {
22
23
  state.ctx.config = unwrapSerializableConfig(state.ctx.config);
@@ -1,5 +1,5 @@
1
1
  import { isMainThread, parentPort } from 'node:worker_threads';
2
- import { i as init } from './init.CpZMjXJJ.js';
2
+ import { i as init } from './init.fmH9J833.js';
3
3
 
4
4
  if (isMainThread || !parentPort) throw new Error("Expected worker to be run in node:worker_threads");
5
5
  function workerInit(options) {
@@ -10,7 +10,8 @@ function workerInit(options) {
10
10
  off: (callback) => parentPort.off("message", callback),
11
11
  teardown: () => parentPort.removeAllListeners("message"),
12
12
  runTests: async (state) => runTests("run", state),
13
- collectTests: async (state) => runTests("collect", state)
13
+ collectTests: async (state) => runTests("collect", state),
14
+ setup: options.setup
14
15
  });
15
16
  }
16
17
 
@@ -1,15 +1,15 @@
1
- import { serializeError } from '@vitest/utils/error';
2
- import { createStackString, parseStacktrace } from '@vitest/utils/source-map';
3
1
  import { readFileSync } from 'node:fs';
4
2
  import { isBuiltin } from 'node:module';
5
3
  import { pathToFileURL } from 'node:url';
6
4
  import { resolve } from 'pathe';
7
5
  import { ModuleRunner } from 'vite/module-runner';
8
- import { b as VitestTransport } from './startModuleRunner.BqQUfEjB.js';
9
- import { e as environments } from './index.DON9WL-E.js';
6
+ import { b as VitestTransport } from './startModuleRunner.Cn7hCL7D.js';
7
+ import { e as environments } from './index.CWIFvlX5.js';
8
+ import { serializeError } from '@vitest/utils/error';
9
+ import { o as onCancel, a as rpcDone, c as createRuntimeRpc } from './rpc.D38ahn14.js';
10
+ import { createStackString, parseStacktrace } from '@vitest/utils/source-map';
10
11
  import { s as setupInspect } from './inspector.DLZxSeU3.js';
11
12
  import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js';
12
- import { c as createRuntimeRpc, a as rpcDone } from './rpc.Dv1Jt3i2.js';
13
13
 
14
14
  function isBuiltinEnvironment(env) {
15
15
  return env in environments;
@@ -44,10 +44,9 @@ async function createEnvironmentLoader(root, rpc) {
44
44
  }
45
45
  return _loaders.get(root);
46
46
  }
47
- async function loadEnvironment(ctx, rpc) {
48
- const name = ctx.environment.name;
47
+ async function loadEnvironment(name, root, rpc) {
49
48
  if (isBuiltinEnvironment(name)) return { environment: environments[name] };
50
- const root = ctx.config.root, loader = await createEnvironmentLoader(root, rpc), packageId = name[0] === "." || name[0] === "/" ? resolve(root, name) : (await rpc.resolve(`vitest-environment-${name}`, void 0, "__vitest__"))?.id ?? resolve(root, name), pkg = await loader.import(packageId);
49
+ const loader = await createEnvironmentLoader(root, rpc), packageId = name[0] === "." || name[0] === "/" ? resolve(root, name) : (await rpc.resolve(`vitest-environment-${name}`, void 0, "__vitest__"))?.id ?? resolve(root, name), pkg = await loader.import(packageId);
51
50
  if (!pkg || !pkg.default || typeof pkg.default !== "object") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "setup" or/and "setupVM" method.`);
52
51
  const environment = pkg.default;
53
52
  if (environment.transformMode != null && environment.transformMode !== "web" && environment.transformMode !== "ssr") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "transformMode" method equal to "ssr" or "web", received "${environment.transformMode}".`);
@@ -62,10 +61,7 @@ async function loadEnvironment(ctx, rpc) {
62
61
 
63
62
  const resolvingModules = /* @__PURE__ */ new Set(), globalListeners = /* @__PURE__ */ new Set();
64
63
  async function execute(method, ctx, worker) {
65
- const prepareStart = performance.now(), cleanups = [setupInspect(ctx)];
66
- let environmentLoader;
67
- // RPC is used to communicate between worker (be it a thread worker or child process or a custom implementation) and the main thread
68
- const { rpc, onCancel } = createRuntimeRpc(worker);
64
+ const prepareStart = performance.now(), cleanups = [setupInspect(ctx)], rpc = ctx.rpc;
69
65
  try {
70
66
  // do not close the RPC channel so that we can get the error messages sent to the main thread
71
67
  cleanups.push(async () => {
@@ -73,21 +69,19 @@ async function execute(method, ctx, worker) {
73
69
  reject(/* @__PURE__ */ new Error(`[vitest-worker]: Closing rpc while "${method}" was pending`));
74
70
  }));
75
71
  });
76
- const beforeEnvironmentTime = performance.now(), { environment, loader } = await loadEnvironment(ctx, rpc);
77
- environmentLoader = loader;
78
72
  const state = {
79
73
  ctx,
80
74
  evaluatedModules: new VitestEvaluatedModules(),
81
75
  resolvingModules,
82
76
  moduleExecutionInfo: /* @__PURE__ */ new Map(),
83
77
  config: ctx.config,
84
- onCancel,
85
- environment,
78
+ environment: null,
86
79
  durations: {
87
- environment: beforeEnvironmentTime,
80
+ environment: 0,
88
81
  prepare: prepareStart
89
82
  },
90
83
  rpc,
84
+ onCancel,
91
85
  onCleanup: (listener) => globalListeners.add(listener),
92
86
  providedContext: ctx.providedContext,
93
87
  onFilterStackTrace(stack) {
@@ -98,7 +92,7 @@ async function execute(method, ctx, worker) {
98
92
  if (!worker[methodName] || typeof worker[methodName] !== "function") throw new TypeError(`Test worker should expose "runTests" method. Received "${typeof worker.runTests}".`);
99
93
  await worker[methodName](state);
100
94
  } finally {
101
- await rpcDone().catch(() => {}), await Promise.all(cleanups.map((fn) => fn())).catch(() => {}), await environmentLoader?.close();
95
+ await rpcDone().catch(() => {}), await Promise.all(cleanups.map((fn) => fn())).catch(() => {});
102
96
  }
103
97
  }
104
98
  function run(ctx, worker) {
@@ -110,6 +104,7 @@ function collect(ctx, worker) {
110
104
  async function teardown() {
111
105
  await Promise.all([...globalListeners].map((l) => l()));
112
106
  }
107
+ const env = process.env;
113
108
  function createImportMetaEnvProxy() {
114
109
  // packages/vitest/src/node/plugins/index.ts:146
115
110
  const booleanKeys = [
@@ -117,7 +112,7 @@ function createImportMetaEnvProxy() {
117
112
  "PROD",
118
113
  "SSR"
119
114
  ];
120
- return new Proxy(process.env, {
115
+ return new Proxy(env, {
121
116
  get(_, key) {
122
117
  if (typeof key === "string") return booleanKeys.includes(key) ? !!process.env[key] : process.env[key];
123
118
  },
@@ -135,19 +130,37 @@ let reportMemory = false;
135
130
  /** @experimental */
136
131
  function init(worker) {
137
132
  worker.on(onMessage);
138
- let runPromise, isRunning = false;
133
+ let runPromise, isRunning = false, workerTeardown, setupContext;
139
134
  function send(response) {
140
135
  worker.post(worker.serialize ? worker.serialize(response) : response);
141
136
  }
142
137
  async function onMessage(rawMessage) {
143
138
  const message = worker.deserialize ? worker.deserialize(rawMessage) : rawMessage;
144
139
  if (message?.__vitest_worker_request__ === true) switch (message.type) {
145
- case "start":
146
- reportMemory = message.options.reportMemory, send({
147
- type: "started",
148
- __vitest_worker_response__
149
- });
140
+ case "start": {
141
+ reportMemory = message.options.reportMemory;
142
+ const { environment, config, pool } = message.context;
143
+ try {
144
+ const rpc = createRuntimeRpc(worker);
145
+ setupContext = {
146
+ environment,
147
+ config,
148
+ pool,
149
+ rpc,
150
+ projectName: config.name || ""
151
+ }, workerTeardown = await worker.setup?.(setupContext), send({
152
+ type: "started",
153
+ __vitest_worker_response__
154
+ });
155
+ } catch (error) {
156
+ send({
157
+ type: "started",
158
+ __vitest_worker_response__,
159
+ error: serializeError(error)
160
+ });
161
+ }
150
162
  break;
163
+ }
151
164
  case "run":
152
165
  // Prevent concurrent execution if worker is already running
153
166
  if (isRunning) {
@@ -158,9 +171,22 @@ function init(worker) {
158
171
  });
159
172
  return;
160
173
  }
161
- isRunning = true, process.env.VITEST_POOL_ID = String(message.poolId), process.env.VITEST_WORKER_ID = String(message.context.workerId);
162
174
  try {
163
- runPromise = run(message.context, worker).catch((error) => serializeError(error));
175
+ process.env.VITEST_POOL_ID = String(message.poolId), process.env.VITEST_WORKER_ID = String(message.context.workerId);
176
+ } catch (error) {
177
+ return send({
178
+ type: "testfileFinished",
179
+ __vitest_worker_response__,
180
+ error: serializeError(error),
181
+ usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
182
+ });
183
+ }
184
+ isRunning = true;
185
+ try {
186
+ runPromise = run({
187
+ ...setupContext,
188
+ ...message.context
189
+ }, worker).catch((error) => serializeError(error));
164
190
  const error = await runPromise;
165
191
  send({
166
192
  type: "testfileFinished",
@@ -182,9 +208,22 @@ function init(worker) {
182
208
  });
183
209
  return;
184
210
  }
185
- isRunning = true, process.env.VITEST_POOL_ID = String(message.poolId), process.env.VITEST_WORKER_ID = String(message.context.workerId);
186
211
  try {
187
- runPromise = collect(message.context, worker).catch((error) => serializeError(error));
212
+ process.env.VITEST_POOL_ID = String(message.poolId), process.env.VITEST_WORKER_ID = String(message.context.workerId);
213
+ } catch (error) {
214
+ return send({
215
+ type: "testfileFinished",
216
+ __vitest_worker_response__,
217
+ error: serializeError(error),
218
+ usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
219
+ });
220
+ }
221
+ isRunning = true;
222
+ try {
223
+ runPromise = collect({
224
+ ...setupContext,
225
+ ...message.context
226
+ }, worker).catch((error) => serializeError(error));
188
227
  const error = await runPromise;
189
228
  send({
190
229
  type: "testfileFinished",
@@ -196,18 +235,26 @@ function init(worker) {
196
235
  runPromise = void 0, isRunning = false;
197
236
  }
198
237
  break;
199
- case "stop": {
238
+ case "stop":
200
239
  await runPromise;
201
- const error = await teardown().catch((error) => serializeError(error));
202
- send({
203
- type: "stopped",
204
- error,
205
- __vitest_worker_response__
206
- }), worker.teardown?.();
240
+ try {
241
+ const error = await teardown().catch((error) => serializeError(error));
242
+ await workerTeardown?.(), send({
243
+ type: "stopped",
244
+ error,
245
+ __vitest_worker_response__
246
+ });
247
+ } catch (error) {
248
+ send({
249
+ type: "stopped",
250
+ error: serializeError(error),
251
+ __vitest_worker_response__
252
+ });
253
+ }
254
+ worker.teardown?.();
207
255
  break;
208
- }
209
256
  }
210
257
  }
211
258
  }
212
259
 
213
- export { init as i };
260
+ export { init as i, loadEnvironment as l };
@@ -2,7 +2,7 @@ import * as _vitest_spy from '@vitest/spy';
2
2
  import vm from 'node:vm';
3
3
  import * as viteModuleRunner from 'vite/module-runner';
4
4
  import { ModuleEvaluator, ModuleRunnerImportMeta, ModuleRunnerContext, EvaluatedModuleNode, FetchFunction, EvaluatedModules } from 'vite/module-runner';
5
- import { R as RuntimeRPC, d as ResolveFunctionResult, W as WorkerGlobalState } from './worker.d.BFk-vvBU.js';
5
+ import { R as RuntimeRPC, e as ResolveFunctionResult, W as WorkerGlobalState } from './worker.d.D25zYZ7N.js';
6
6
  import { MockedModule, MockedModuleType } from '@vitest/mocker';
7
7
  import { P as PendingSuiteMock, b as MockFactory, a as MockOptions } from './mocker.d.BE_2ls6u.js';
8
8
 
@@ -1,4 +1,4 @@
1
- import { V as Vitest, T as TestProject, a as TestProjectConfiguration } from './reporters.d.D-el0219.js';
1
+ import { V as Vitest, T as TestProject, a as TestProjectConfiguration } from './reporters.d.CSNcMDxF.js';
2
2
 
3
3
  interface VitestPluginContext {
4
4
  vitest: Vitest;
@@ -1,13 +1,13 @@
1
1
  import { TaskMeta, Suite, File, TestAnnotation, ImportDuration, Test, Task, TaskResultPack, FileSpecification, CancelReason, SequenceSetupFiles, SequenceHooks } from '@vitest/runner';
2
2
  import { TestError, SerializedError, Arrayable, ParsedStack, Awaitable } from '@vitest/utils';
3
- import { A as AfterSuiteRunMeta, U as UserConsoleLog, P as ProvidedContext, C as ContextRPC, L as LabelColor } from './worker.d.BFk-vvBU.js';
3
+ import { A as AfterSuiteRunMeta, U as UserConsoleLog, P as ProvidedContext, d as ContextTestEnvironment, f as WorkerTestEnvironment, g as WorkerExecuteContext, L as LabelColor } from './worker.d.D25zYZ7N.js';
4
4
  import { Writable } from 'node:stream';
5
5
  import { TransformResult as TransformResult$1, ViteDevServer, Plugin, UserConfig as UserConfig$1, DepOptimizationConfig, ServerOptions, ConfigEnv, AliasOptions } from 'vite';
6
6
  import { MockedModule } from '@vitest/mocker';
7
7
  import { StackTraceParserOptions } from '@vitest/utils/source-map';
8
8
  import { BrowserCommands } from 'vitest/browser';
9
- import { B as BrowserTraceViewMode, S as SerializedConfig, F as FakeTimerInstallOpts } from './config.d.u2CUDWwS.js';
10
- import { S as SerializedTestSpecification, B as BrowserTesterOptions } from './browser.d.B9iJzZyn.js';
9
+ import { B as BrowserTraceViewMode, S as SerializedConfig, F as FakeTimerInstallOpts } from './config.d.BTfZNUu9.js';
10
+ import { S as SerializedTestSpecification, B as BrowserTesterOptions } from './browser.d.-LKfRopd.js';
11
11
  import { PrettyFormatOptions } from '@vitest/pretty-format';
12
12
  import { SnapshotSummary, SnapshotStateOptions } from '@vitest/snapshot';
13
13
  import { SerializedDiffOptions } from '@vitest/utils/diff';
@@ -1445,6 +1445,7 @@ interface BrowserConfigOptions {
1445
1445
  * Isolate test environment after each test
1446
1446
  *
1447
1447
  * @default true
1448
+ * @deprecated use top-level `isolate` instead
1448
1449
  */
1449
1450
  isolate?: boolean;
1450
1451
  /**
@@ -1452,6 +1453,7 @@ interface BrowserConfigOptions {
1452
1453
  * This option only has effect in headless mode (enabled in CI by default)
1453
1454
  *
1454
1455
  * @default // Same as "test.fileParallelism"
1456
+ * @deprecated use top-level `fileParallelism` instead
1455
1457
  */
1456
1458
  fileParallelism?: boolean;
1457
1459
  /**
@@ -1866,7 +1868,7 @@ interface PoolOptions {
1866
1868
  project: TestProject;
1867
1869
  method: "run" | "collect";
1868
1870
  cacheFs?: boolean;
1869
- environment: string;
1871
+ environment: ContextTestEnvironment;
1870
1872
  execArgv: string[];
1871
1873
  env: Partial<NodeJS.ProcessEnv>;
1872
1874
  }
@@ -1901,7 +1903,8 @@ interface PoolTask {
1901
1903
  * so modifying it once will modify it for every task.
1902
1904
  */
1903
1905
  execArgv: string[];
1904
- context: ContextRPC;
1906
+ context: WorkerExecuteContext;
1907
+ environment: ContextTestEnvironment;
1905
1908
  memoryLimit: number | null;
1906
1909
  }
1907
1910
  type WorkerRequest = {
@@ -1911,15 +1914,20 @@ type WorkerRequest = {
1911
1914
  options: {
1912
1915
  reportMemory: boolean;
1913
1916
  };
1917
+ context: {
1918
+ environment: WorkerTestEnvironment;
1919
+ config: SerializedConfig;
1920
+ pool: string;
1921
+ };
1914
1922
  } | {
1915
1923
  type: "stop";
1916
1924
  } | {
1917
1925
  type: "run";
1918
- context: ContextRPC;
1926
+ context: WorkerExecuteContext;
1919
1927
  poolId: number;
1920
1928
  } | {
1921
1929
  type: "collect";
1922
- context: ContextRPC;
1930
+ context: WorkerExecuteContext;
1923
1931
  poolId: number;
1924
1932
  } | {
1925
1933
  type: "cancel";
@@ -1928,6 +1936,7 @@ type WorkerResponse = {
1928
1936
  __vitest_worker_response__: true;
1929
1937
  } & ({
1930
1938
  type: "started";
1939
+ error?: unknown;
1931
1940
  } | {
1932
1941
  type: "stopped";
1933
1942
  error?: unknown;
@@ -3071,7 +3080,7 @@ interface UserConfig extends InlineConfig {
3071
3080
  type OnUnhandledErrorCallback = (error: (TestError | Error) & {
3072
3081
  type: string;
3073
3082
  }) => boolean | void;
3074
- interface ResolvedConfig extends Omit<Required<UserConfig>, "project" | "config" | "filters" | "browser" | "coverage" | "testNamePattern" | "related" | "api" | "reporters" | "resolveSnapshotPath" | "benchmark" | "shard" | "cache" | "sequence" | "typecheck" | "runner" | "pool" | "cliExclude" | "diff" | "setupFiles" | "snapshotEnvironment" | "bail" | "name" | "vmMemoryLimit"> {
3083
+ interface ResolvedConfig extends Omit<Required<UserConfig>, "project" | "config" | "filters" | "browser" | "coverage" | "testNamePattern" | "related" | "api" | "reporters" | "resolveSnapshotPath" | "benchmark" | "shard" | "cache" | "sequence" | "typecheck" | "runner" | "pool" | "cliExclude" | "diff" | "setupFiles" | "snapshotEnvironment" | "bail" | "name" | "vmMemoryLimit" | "fileParallelism"> {
3075
3084
  mode: VitestRunMode;
3076
3085
  name: ProjectName["label"];
3077
3086
  color?: ProjectName["color"];
@@ -3153,7 +3162,6 @@ type ProjectConfig = Omit<InlineConfig, NonProjectOptions | "sequencer" | "deps"
3153
3162
  mode?: string;
3154
3163
  sequencer?: Omit<SequenceOptions, "sequencer" | "seed">;
3155
3164
  deps?: Omit<DepsOptions, "moduleDirectories">;
3156
- fileParallelism?: boolean;
3157
3165
  };
3158
3166
  type ResolvedProjectConfig = Omit<ResolvedConfig, Exclude<NonProjectOptions, "coverage" | "watch">>;
3159
3167
  interface UserWorkspaceConfig extends UserConfig$1 {
@@ -22,13 +22,14 @@ async function rpcDone() {
22
22
  const awaitable = Array.from(promises);
23
23
  return Promise.all(awaitable);
24
24
  }
25
- let previousRpc;
25
+ const onCancelCallbacks = [];
26
+ function onCancel(callback) {
27
+ onCancelCallbacks.push(callback);
28
+ }
26
29
  function createRuntimeRpc(options) {
27
- if (previousRpc) previousRpc.$close(), previousRpc = void 0;
28
- let setCancel = (_reason) => {};
29
- const onCancel = new Promise((resolve) => {
30
- setCancel = resolve;
31
- }), rpc = createSafeRpc(createBirpc({ onCancel: setCancel }, {
30
+ return createSafeRpc(createBirpc({ async onCancel(reason) {
31
+ await Promise.all(onCancelCallbacks.map((fn) => fn(reason)));
32
+ } }, {
32
33
  eventNames: [
33
34
  "onUserConsoleLog",
34
35
  "onCollected",
@@ -37,10 +38,6 @@ function createRuntimeRpc(options) {
37
38
  timeout: -1,
38
39
  ...options
39
40
  }));
40
- return previousRpc = rpc, {
41
- rpc,
42
- onCancel
43
- };
44
41
  }
45
42
  function createSafeRpc(rpc) {
46
43
  return new Proxy(rpc, { get(target, p, handler) {
@@ -63,4 +60,4 @@ function rpc() {
63
60
  return rpc;
64
61
  }
65
62
 
66
- export { rpcDone as a, createRuntimeRpc as c, rpc as r };
63
+ export { rpcDone as a, createRuntimeRpc as c, onCancel as o, rpc as r };