vitest 4.0.6 → 4.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/LICENSE.md +1 -1
  2. package/dist/browser.d.ts +2 -2
  3. package/dist/browser.js +2 -2
  4. package/dist/chunks/base.BgTO2qAg.js +156 -0
  5. package/dist/chunks/{benchmark.DHKMYAts.js → benchmark.B3N2zMcH.js} +9 -4
  6. package/dist/chunks/{browser.d.ScGeWTou.d.ts → browser.d.DTTM2PTh.d.ts} +1 -1
  7. package/dist/chunks/{cac.BBqWH4nd.js → cac.CfkWq8Qy.js} +117 -43
  8. package/dist/chunks/{cli-api.UL3SwFUb.js → cli-api.BQ-bjcRi.js} +1870 -847
  9. package/dist/chunks/console.Cf-YriPC.js +146 -0
  10. package/dist/chunks/{coverage.DuCn_Tmx.js → coverage.NVjCOln1.js} +281 -103
  11. package/dist/chunks/{creator.cqqifzG7.js → creator.fzVyoMf3.js} +74 -30
  12. package/dist/chunks/{date.-jtEtIeV.js → date.Bq6ZW5rf.js} +17 -6
  13. package/dist/chunks/{git.BFNcloKD.js → git.Bm2pzPAa.js} +3 -3
  14. package/dist/chunks/{global.d.DdOkMiVb.d.ts → global.d.DVdCfKp5.d.ts} +1 -1
  15. package/dist/chunks/{globals.BGT_RUsD.js → globals.DOh96BiR.js} +5 -5
  16. package/dist/chunks/{resolveSnapshotEnvironment.BZzLjzkh.js → index.BY4-tcno.js} +42 -25
  17. package/dist/chunks/{index.Bgo3tNWt.js → index.DAL392Ss.js} +40 -15
  18. package/dist/chunks/{index.RwjEGCQ0.js → index.DIFZf73e.js} +2 -2
  19. package/dist/chunks/{index.DV0mQLEO.js → index.DfKyPFVi.js} +195 -64
  20. package/dist/chunks/{index.BL8Hg4Uk.js → index.kotH7DY7.js} +837 -380
  21. package/dist/chunks/{index.CpdwpN7L.js → index.op2Re5rn.js} +22 -12
  22. package/dist/chunks/{init-forks.CSGFj9zN.js → init-forks.2hx7cf78.js} +16 -5
  23. package/dist/chunks/{init-threads.CIJLeFO8.js → init-threads.Cm4OCIWA.js} +3 -2
  24. package/dist/chunks/{init.DUeOfNO9.js → init.DMDG-idf.js} +124 -54
  25. package/dist/chunks/{inspector.DLZxSeU3.js → inspector.CvyFGlXm.js} +25 -10
  26. package/dist/chunks/{moduleRunner.d.TP-w6tIQ.d.ts → moduleRunner.d.CzOZ_4wC.d.ts} +1 -1
  27. package/dist/chunks/{node.BwAWWjHZ.js → node.Ce0vMQM7.js} +1 -1
  28. package/dist/chunks/{plugin.d.lctzD3Wk.d.ts → plugin.d.D4RrtywJ.d.ts} +1 -1
  29. package/dist/chunks/{reporters.d.PEs0tXod.d.ts → reporters.d.Da1D1VbQ.d.ts} +19 -9
  30. package/dist/chunks/rpc.BUV7uWKJ.js +76 -0
  31. package/dist/chunks/{setup-common.DR1sucx6.js → setup-common.LGjNSzXp.js} +20 -8
  32. package/dist/chunks/{startModuleRunner.Di-EZqh0.js → startModuleRunner.BOmUtLIO.js} +228 -105
  33. package/dist/chunks/{test.CnspO-X4.js → test.ClrAtjMv.js} +48 -22
  34. package/dist/chunks/{utils.CG9h5ccR.js → utils.DvEY5TfP.js} +14 -5
  35. package/dist/chunks/{vi.BZvkKVkM.js → vi.Bgcdy3bQ.js} +261 -111
  36. package/dist/chunks/{vm.Co_lR2NL.js → vm.BIkCDs68.js} +177 -70
  37. package/dist/chunks/{worker.d.B4Hthdvt.d.ts → worker.d.DadbA89M.d.ts} +52 -6
  38. package/dist/cli.js +2 -2
  39. package/dist/config.d.ts +5 -5
  40. package/dist/coverage.d.ts +3 -3
  41. package/dist/coverage.js +1 -1
  42. package/dist/environments.js +2 -1
  43. package/dist/index.d.ts +5 -5
  44. package/dist/index.js +5 -5
  45. package/dist/module-evaluator.d.ts +2 -2
  46. package/dist/module-evaluator.js +85 -35
  47. package/dist/module-runner.js +2 -2
  48. package/dist/node.d.ts +7 -7
  49. package/dist/node.js +16 -12
  50. package/dist/reporters.d.ts +3 -3
  51. package/dist/reporters.js +2 -2
  52. package/dist/runners.js +7 -7
  53. package/dist/snapshot.js +2 -2
  54. package/dist/suite.js +2 -2
  55. package/dist/worker.d.ts +2 -1
  56. package/dist/worker.js +27 -27
  57. package/dist/workers/forks.js +34 -31
  58. package/dist/workers/runVmTests.js +41 -22
  59. package/dist/workers/threads.js +34 -31
  60. package/dist/workers/vmForks.js +14 -14
  61. package/dist/workers/vmThreads.js +14 -14
  62. package/package.json +20 -20
  63. package/dist/chunks/base.BAf_bYeI.js +0 -128
  64. package/dist/chunks/console.CTJL2nuH.js +0 -115
  65. package/dist/chunks/rpc.Dv1Jt3i2.js +0 -66
@@ -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.BL8Hg4Uk.js';
5
+ import { g as getStateSymbol, t as truncateString, F as F_RIGHT, D as DefaultReporter, f as formatProjectName, s as separator } from './index.kotH7DY7.js';
6
6
  import { stripVTControlCharacters } from 'node:util';
7
7
  import { notNullish } from '@vitest/utils/helpers';
8
8
 
@@ -98,16 +98,19 @@ function renderBenchmark(result, widths) {
98
98
  ].join(" ");
99
99
  }
100
100
  function renderTable(options) {
101
- const output = [], benchMap = {};
101
+ const output = [];
102
+ const benchMap = {};
102
103
  for (const task of options.tasks) if (task.meta.benchmark && task.result?.benchmark) benchMap[task.id] = {
103
104
  current: task.result.benchmark,
104
105
  baseline: options.compare?.[task.id]
105
106
  };
106
- const benchCount = Object.entries(benchMap).length, columnWidths = computeColumnWidths(Object.values(benchMap).flatMap((v) => [v.current, v.baseline]).filter(notNullish));
107
+ const benchCount = Object.entries(benchMap).length;
108
+ const columnWidths = computeColumnWidths(Object.values(benchMap).flatMap((v) => [v.current, v.baseline]).filter(notNullish));
107
109
  let idx = 0;
108
110
  const padding = " ".repeat(1 );
109
111
  for (const task of options.tasks) {
110
- const duration = task.result?.duration, bench = benchMap[task.id];
112
+ const duration = task.result?.duration;
113
+ const bench = benchMap[task.id];
111
114
  let prefix = "";
112
115
  if (idx === 0 && task.meta?.benchmark) prefix += `${renderTableHead(columnWidths)}\n${padding}`;
113
116
  prefix += ` ${getStateSymbol(task)} `;
@@ -123,7 +126,8 @@ function renderTable(options) {
123
126
  let body = renderBenchmark(bench.current, columnWidths);
124
127
  if (options.compare && bench.baseline) {
125
128
  if (bench.current.hz) {
126
- const diff = bench.current.hz / bench.baseline.hz, diffFixed = diff.toFixed(2);
129
+ const diff = bench.current.hz / bench.baseline.hz;
130
+ const diffFixed = diff.toFixed(2);
127
131
  if (diffFixed === "1.0.0") body += c.gray(` [${diffFixed}x]`);
128
132
  if (diff > 1) body += c.blue(` [${diffFixed}x] ⇑`);
129
133
  else body += c.red(` [${diffFixed}x] ⇓`);
@@ -140,7 +144,8 @@ function renderTable(options) {
140
144
  if (task.result?.state !== "pass" && outputMap.get(task) != null) {
141
145
  let data = outputMap.get(task);
142
146
  if (typeof data === "string") {
143
- if (data = stripVTControlCharacters(data.trim().split("\n").filter(Boolean).pop()), data === "") data = void 0;
147
+ data = stripVTControlCharacters(data.trim().split("\n").filter(Boolean).pop());
148
+ if (data === "") data = void 0;
144
149
  }
145
150
  if (data != null) {
146
151
  const out = ` ${" ".repeat(options.level)}${F_RIGHT} ${data}`;
@@ -155,7 +160,8 @@ function renderTable(options) {
155
160
  class BenchmarkReporter extends DefaultReporter {
156
161
  compare;
157
162
  async onInit(ctx) {
158
- if (super.onInit(ctx), this.ctx.config.benchmark?.compare) {
163
+ super.onInit(ctx);
164
+ if (this.ctx.config.benchmark?.compare) {
159
165
  const compareFile = pathe.resolve(this.ctx.config.root, this.ctx.config.benchmark?.compare);
160
166
  try {
161
167
  this.compare = flattenFormattedBenchmarkReport(JSON.parse(await fs.promises.readFile(compareFile, "utf-8")));
@@ -173,7 +179,8 @@ class BenchmarkReporter extends DefaultReporter {
173
179
  }
174
180
  }
175
181
  onTestSuiteResult(testSuite) {
176
- super.onTestSuiteResult(testSuite), this.printSuiteTable(testSuite);
182
+ super.onTestSuiteResult(testSuite);
183
+ this.printSuiteTable(testSuite);
177
184
  }
178
185
  printTestModule(testModule) {
179
186
  this.printSuiteTable(testModule);
@@ -181,11 +188,13 @@ class BenchmarkReporter extends DefaultReporter {
181
188
  printSuiteTable(testTask) {
182
189
  const state = testTask.state();
183
190
  if (state === "pending" || state === "queued") return;
184
- const benches = testTask.task.tasks.filter((t) => t.meta.benchmark), duration = testTask.task.result?.duration || 0;
191
+ const benches = testTask.task.tasks.filter((t) => t.meta.benchmark);
192
+ const duration = testTask.task.result?.duration || 0;
185
193
  if (benches.length > 0 && benches.every((t) => t.result?.state !== "run" && t.result?.state !== "queued")) {
186
194
  let title = `\n ${getStateSymbol(testTask.task)} ${formatProjectName(testTask.project)}${getFullName(testTask.task, separator)}`;
187
195
  if (duration != null && duration > this.ctx.config.slowTestThreshold) title += c.yellow(` ${Math.round(duration)}${c.dim("ms")}`);
188
- this.log(title), this.log(renderTable({
196
+ this.log(title);
197
+ this.log(renderTable({
189
198
  tasks: benches,
190
199
  level: 1,
191
200
  columns: this.ctx.logger.getColumns(),
@@ -203,8 +212,9 @@ class BenchmarkReporter extends DefaultReporter {
203
212
  outputFile = pathe.resolve(this.ctx.config.root, outputFile);
204
213
  const outputDirectory = pathe.dirname(outputFile);
205
214
  if (!fs.existsSync(outputDirectory)) await fs.promises.mkdir(outputDirectory, { recursive: true });
206
- const files = testModules.map((t) => t.task.file), output = createBenchmarkJsonReport(files);
207
- await fs.promises.writeFile(outputFile, JSON.stringify(output, null, 2)), this.log(`Benchmark report written to ${outputFile}`);
215
+ const output = createBenchmarkJsonReport(testModules.map((t) => t.task.file));
216
+ await fs.promises.writeFile(outputFile, JSON.stringify(output, null, 2));
217
+ this.log(`Benchmark report written to ${outputFile}`);
208
218
  }
209
219
  }
210
220
  }
@@ -1,9 +1,13 @@
1
1
  import v8 from 'node:v8';
2
- import { i as init } from './init.DUeOfNO9.js';
2
+ import { i as init } from './init.DMDG-idf.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
6
- const processExit = process.exit.bind(process), processSend = process.send.bind(process), processOn = process.on.bind(process), processOff = process.off.bind(process), processRemoveAllListeners = process.removeAllListeners.bind(process);
6
+ const processExit = process.exit.bind(process);
7
+ const processSend = process.send.bind(process);
8
+ const processOn = process.on.bind(process);
9
+ const processOff = process.off.bind(process);
10
+ const processRemoveAllListeners = process.removeAllListeners.bind(process);
7
11
  // Work-around for nodejs/node#55094
8
12
  if (process.execArgv.some((execArg) => execArg.startsWith("--prof") || execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"))) processOn("SIGTERM", () => processExit());
9
13
  function workerInit(options) {
@@ -16,7 +20,8 @@ function workerInit(options) {
16
20
  serialize: v8.serialize,
17
21
  deserialize: (v) => v8.deserialize(Buffer.from(v)),
18
22
  runTests: (state) => executeTests("run", state),
19
- collectTests: (state) => executeTests("collect", state)
23
+ collectTests: (state) => executeTests("collect", state),
24
+ setup: options.setup
20
25
  });
21
26
  async function executeTests(method, state) {
22
27
  state.ctx.config = unwrapSerializableConfig(state.ctx.config);
@@ -36,7 +41,8 @@ function unwrapSerializableConfig(config) {
36
41
  if (testNamePattern.startsWith("$$vitest:")) config.testNamePattern = parseRegexp(testNamePattern.slice(9));
37
42
  }
38
43
  if (config.defines && Array.isArray(config.defines.keys) && config.defines.original) {
39
- const { keys, original } = config.defines, defines = {};
44
+ const { keys, original } = config.defines;
45
+ const defines = {};
40
46
  // Apply all keys from the original. Entries which had undefined value are missing from original now
41
47
  for (const key of keys) defines[key] = original[key];
42
48
  config.defines = defines;
@@ -47,8 +53,13 @@ function parseRegexp(input) {
47
53
  // Parse input
48
54
  // eslint-disable-next-line regexp/no-misleading-capturing-group
49
55
  const m = input.match(/(\/?)(.+)\1([a-z]*)/i);
56
+ // match nothing
57
+ if (!m) return /$^/;
58
+ // Invalid flags
59
+ // eslint-disable-next-line regexp/optimal-quantifier-concatenation
60
+ if (m[3] && !/^(?!.*?(.).*?\1)[gmixXsuUAJ]+$/.test(m[3])) return new RegExp(input);
50
61
  // Create the regular expression
51
- return m ? m[3] && !/^(?!.*?(.).*?\1)[gmixXsuUAJ]+$/.test(m[3]) ? new RegExp(input) : new RegExp(m[2], m[3]) : /$^/;
62
+ return new RegExp(m[2], m[3]);
52
63
  }
53
64
 
54
65
  export { workerInit as w };
@@ -1,5 +1,5 @@
1
1
  import { isMainThread, parentPort } from 'node:worker_threads';
2
- import { i as init } from './init.DUeOfNO9.js';
2
+ import { i as init } from './init.DMDG-idf.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,20 +1,21 @@
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.Di-EZqh0.js';
9
- import { e as environments } from './index.DV0mQLEO.js';
10
- import { s as setupInspect } from './inspector.DLZxSeU3.js';
6
+ import { b as VitestTransport } from './startModuleRunner.BOmUtLIO.js';
7
+ import { e as environments } from './index.DfKyPFVi.js';
8
+ import { serializeError } from '@vitest/utils/error';
9
+ import { o as onCancel, a as rpcDone, c as createRuntimeRpc } from './rpc.BUV7uWKJ.js';
10
+ import { createStackString, parseStacktrace } from '@vitest/utils/source-map';
11
+ import { s as setupInspect } from './inspector.CvyFGlXm.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;
16
16
  }
17
- const isWindows = process.platform === "win32", _loaders = /* @__PURE__ */ new Map();
17
+ const isWindows = process.platform === "win32";
18
+ const _loaders = /* @__PURE__ */ new Map();
18
19
  async function createEnvironmentLoader(root, rpc) {
19
20
  const cachedLoader = _loaders.get(root);
20
21
  if (!cachedLoader || cachedLoader.isClosed()) {
@@ -40,32 +41,37 @@ async function createEnvironmentLoader(root, rpc) {
40
41
  }
41
42
  })
42
43
  });
43
- _loaders.set(root, moduleRunner), await moduleRunner.import("/@vite/env");
44
+ _loaders.set(root, moduleRunner);
45
+ await moduleRunner.import("/@vite/env");
44
46
  }
45
47
  return _loaders.get(root);
46
48
  }
47
- async function loadEnvironment(ctx, rpc) {
48
- const name = ctx.environment.name;
49
+ async function loadEnvironment(name, root, rpc) {
49
50
  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);
51
+ const loader = await createEnvironmentLoader(root, rpc);
52
+ const packageId = name[0] === "." || name[0] === "/" ? resolve(root, name) : (await rpc.resolve(`vitest-environment-${name}`, void 0, "__vitest__"))?.id ?? resolve(root, name);
53
+ const pkg = await loader.import(packageId);
51
54
  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
55
  const environment = pkg.default;
53
56
  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}".`);
54
- if (environment.transformMode)
55
- // keep for backwards compat
56
- console.warn(`The Vitest environment ${environment.name} defines the "transformMode". This options was deprecated in Vitest 4 and will be removed in the next major version. Please, use "viteEnvironment" instead.`), environment.viteEnvironment ??= environment.transformMode === "ssr" ? "ssr" : "client";
57
+ if (environment.transformMode) {
58
+ console.warn(`The Vitest environment ${environment.name} defines the "transformMode". This options was deprecated in Vitest 4 and will be removed in the next major version. Please, use "viteEnvironment" instead.`);
59
+ // keep for backwards compat
60
+ environment.viteEnvironment ??= environment.transformMode === "ssr" ? "ssr" : "client";
61
+ }
57
62
  return {
58
63
  environment,
59
64
  loader
60
65
  };
61
66
  }
62
67
 
63
- const resolvingModules = /* @__PURE__ */ new Set(), globalListeners = /* @__PURE__ */ new Set();
68
+ const resolvingModules = /* @__PURE__ */ new Set();
69
+ const globalListeners = /* @__PURE__ */ new Set();
64
70
  async function execute(method, ctx, worker) {
65
- const prepareStart = performance.now(), cleanups = [setupInspect(ctx)];
66
- let environmentLoader;
71
+ const prepareStart = performance.now();
72
+ const cleanups = [setupInspect(ctx)];
67
73
  // 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);
74
+ const rpc = ctx.rpc;
69
75
  try {
70
76
  // do not close the RPC channel so that we can get the error messages sent to the main thread
71
77
  cleanups.push(async () => {
@@ -73,32 +79,32 @@ async function execute(method, ctx, worker) {
73
79
  reject(/* @__PURE__ */ new Error(`[vitest-worker]: Closing rpc while "${method}" was pending`));
74
80
  }));
75
81
  });
76
- const beforeEnvironmentTime = performance.now(), { environment, loader } = await loadEnvironment(ctx, rpc);
77
- environmentLoader = loader;
78
82
  const state = {
79
83
  ctx,
80
84
  evaluatedModules: new VitestEvaluatedModules(),
81
85
  resolvingModules,
82
86
  moduleExecutionInfo: /* @__PURE__ */ new Map(),
83
87
  config: ctx.config,
84
- onCancel,
85
- environment,
88
+ environment: null,
86
89
  durations: {
87
- environment: beforeEnvironmentTime,
90
+ environment: 0,
88
91
  prepare: prepareStart
89
92
  },
90
93
  rpc,
94
+ onCancel,
91
95
  onCleanup: (listener) => globalListeners.add(listener),
92
96
  providedContext: ctx.providedContext,
93
97
  onFilterStackTrace(stack) {
94
98
  return createStackString(parseStacktrace(stack));
95
99
  },
96
100
  metaEnv: createImportMetaEnvProxy()
97
- }, methodName = method === "collect" ? "collectTests" : "runTests";
101
+ };
102
+ const methodName = method === "collect" ? "collectTests" : "runTests";
98
103
  if (!worker[methodName] || typeof worker[methodName] !== "function") throw new TypeError(`Test worker should expose "runTests" method. Received "${typeof worker.runTests}".`);
99
104
  await worker[methodName](state);
100
105
  } finally {
101
- await rpcDone().catch(() => {}), await Promise.all(cleanups.map((fn) => fn())).catch(() => {}), await environmentLoader?.close();
106
+ await rpcDone().catch(() => {});
107
+ await Promise.all(cleanups.map((fn) => fn())).catch(() => {});
102
108
  }
103
109
  }
104
110
  function run(ctx, worker) {
@@ -110,6 +116,7 @@ function collect(ctx, worker) {
110
116
  async function teardown() {
111
117
  await Promise.all([...globalListeners].map((l) => l()));
112
118
  }
119
+ const env = process.env;
113
120
  function createImportMetaEnvProxy() {
114
121
  // packages/vitest/src/node/plugins/index.ts:146
115
122
  const booleanKeys = [
@@ -117,9 +124,11 @@ function createImportMetaEnvProxy() {
117
124
  "PROD",
118
125
  "SSR"
119
126
  ];
120
- return new Proxy(process.env, {
127
+ return new Proxy(env, {
121
128
  get(_, key) {
122
- if (typeof key === "string") return booleanKeys.includes(key) ? !!process.env[key] : process.env[key];
129
+ if (typeof key !== "string") return;
130
+ if (booleanKeys.includes(key)) return !!process.env[key];
131
+ return process.env[key];
123
132
  },
124
133
  set(_, key, value) {
125
134
  if (typeof key !== "string") return true;
@@ -130,24 +139,48 @@ function createImportMetaEnvProxy() {
130
139
  });
131
140
  }
132
141
 
133
- const __vitest_worker_response__ = true, memoryUsage = process.memoryUsage.bind(process);
142
+ const __vitest_worker_response__ = true;
143
+ const memoryUsage = process.memoryUsage.bind(process);
134
144
  let reportMemory = false;
135
145
  /** @experimental */
136
146
  function init(worker) {
137
147
  worker.on(onMessage);
138
- let runPromise, isRunning = false;
148
+ let runPromise;
149
+ let isRunning = false;
150
+ let workerTeardown;
151
+ let setupContext;
139
152
  function send(response) {
140
153
  worker.post(worker.serialize ? worker.serialize(response) : response);
141
154
  }
142
155
  async function onMessage(rawMessage) {
143
156
  const message = worker.deserialize ? worker.deserialize(rawMessage) : rawMessage;
144
- 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
- });
157
+ if (message?.__vitest_worker_request__ !== true) return;
158
+ switch (message.type) {
159
+ case "start": {
160
+ reportMemory = message.options.reportMemory;
161
+ const { environment, config, pool } = message.context;
162
+ try {
163
+ setupContext = {
164
+ environment,
165
+ config,
166
+ pool,
167
+ rpc: createRuntimeRpc(worker),
168
+ projectName: config.name || ""
169
+ };
170
+ workerTeardown = await worker.setup?.(setupContext);
171
+ send({
172
+ type: "started",
173
+ __vitest_worker_response__
174
+ });
175
+ } catch (error) {
176
+ send({
177
+ type: "started",
178
+ __vitest_worker_response__,
179
+ error: serializeError(error)
180
+ });
181
+ }
150
182
  break;
183
+ }
151
184
  case "run":
152
185
  // Prevent concurrent execution if worker is already running
153
186
  if (isRunning) {
@@ -158,18 +191,32 @@ function init(worker) {
158
191
  });
159
192
  return;
160
193
  }
161
- isRunning = true, process.env.VITEST_POOL_ID = String(message.poolId), process.env.VITEST_WORKER_ID = String(message.context.workerId);
162
194
  try {
163
- runPromise = run(message.context, worker).catch((error) => serializeError(error));
164
- const error = await runPromise;
195
+ process.env.VITEST_POOL_ID = String(message.poolId);
196
+ process.env.VITEST_WORKER_ID = String(message.context.workerId);
197
+ } catch (error) {
198
+ return send({
199
+ type: "testfileFinished",
200
+ __vitest_worker_response__,
201
+ error: serializeError(error),
202
+ usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
203
+ });
204
+ }
205
+ isRunning = true;
206
+ try {
207
+ runPromise = run({
208
+ ...setupContext,
209
+ ...message.context
210
+ }, worker).catch((error) => serializeError(error));
165
211
  send({
166
212
  type: "testfileFinished",
167
213
  __vitest_worker_response__,
168
- error,
214
+ error: await runPromise,
169
215
  usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
170
216
  });
171
217
  } finally {
172
- runPromise = void 0, isRunning = false;
218
+ runPromise = void 0;
219
+ isRunning = false;
173
220
  }
174
221
  break;
175
222
  case "collect":
@@ -182,32 +229,55 @@ function init(worker) {
182
229
  });
183
230
  return;
184
231
  }
185
- isRunning = true, process.env.VITEST_POOL_ID = String(message.poolId), process.env.VITEST_WORKER_ID = String(message.context.workerId);
186
232
  try {
187
- runPromise = collect(message.context, worker).catch((error) => serializeError(error));
188
- const error = await runPromise;
233
+ process.env.VITEST_POOL_ID = String(message.poolId);
234
+ process.env.VITEST_WORKER_ID = String(message.context.workerId);
235
+ } catch (error) {
236
+ return send({
237
+ type: "testfileFinished",
238
+ __vitest_worker_response__,
239
+ error: serializeError(error),
240
+ usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
241
+ });
242
+ }
243
+ isRunning = true;
244
+ try {
245
+ runPromise = collect({
246
+ ...setupContext,
247
+ ...message.context
248
+ }, worker).catch((error) => serializeError(error));
189
249
  send({
190
250
  type: "testfileFinished",
191
251
  __vitest_worker_response__,
192
- error,
252
+ error: await runPromise,
193
253
  usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
194
254
  });
195
255
  } finally {
196
- runPromise = void 0, isRunning = false;
256
+ runPromise = void 0;
257
+ isRunning = false;
197
258
  }
198
259
  break;
199
- case "stop": {
260
+ case "stop":
200
261
  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?.();
262
+ try {
263
+ const error = await teardown().catch((error) => serializeError(error));
264
+ await workerTeardown?.();
265
+ send({
266
+ type: "stopped",
267
+ error,
268
+ __vitest_worker_response__
269
+ });
270
+ } catch (error) {
271
+ send({
272
+ type: "stopped",
273
+ error: serializeError(error),
274
+ __vitest_worker_response__
275
+ });
276
+ }
277
+ worker.teardown?.();
207
278
  break;
208
- }
209
279
  }
210
280
  }
211
281
  }
212
282
 
213
- export { init as i };
283
+ export { init as i, loadEnvironment as l };
@@ -2,33 +2,48 @@ import { createRequire } from 'node:module';
2
2
  import { pathToFileURL } from 'node:url';
3
3
 
4
4
  const __require = createRequire(import.meta.url);
5
- let inspector, session;
5
+ let inspector;
6
+ let session;
6
7
  /**
7
8
  * Enables debugging inside `worker_threads` and `child_process`.
8
9
  * Should be called as early as possible when worker/process has been set up.
9
10
  */
10
11
  function setupInspect(ctx) {
11
- const config = ctx.config, isEnabled = config.inspector.enabled;
12
+ const config = ctx.config;
13
+ const isEnabled = config.inspector.enabled;
12
14
  if (isEnabled) {
13
- if (inspector = __require("node:inspector"), !(inspector.url() !== void 0)) {
14
- if (inspector.open(config.inspector.port, config.inspector.host, config.inspector.waitForDebugger), config.inspectBrk) {
15
+ inspector = __require("node:inspector");
16
+ if (!(inspector.url() !== void 0)) {
17
+ inspector.open(config.inspector.port, config.inspector.host, config.inspector.waitForDebugger);
18
+ if (config.inspectBrk) {
15
19
  const firstTestFile = typeof ctx.files[0] === "string" ? ctx.files[0] : ctx.files[0].filepath;
16
20
  // Stop at first test file
17
- if (firstTestFile) session = new inspector.Session(), session.connect(), session.post("Debugger.enable"), session.post("Debugger.setBreakpointByUrl", {
18
- lineNumber: 0,
19
- url: pathToFileURL(firstTestFile)
20
- });
21
+ if (firstTestFile) {
22
+ session = new inspector.Session();
23
+ session.connect();
24
+ session.post("Debugger.enable");
25
+ session.post("Debugger.setBreakpointByUrl", {
26
+ lineNumber: 0,
27
+ url: pathToFileURL(firstTestFile)
28
+ });
29
+ }
21
30
  }
22
31
  }
23
32
  }
24
33
  const keepOpen = shouldKeepOpen(config);
25
34
  return function cleanup() {
26
- if (isEnabled && !keepOpen && inspector) inspector.close(), session?.disconnect();
35
+ if (isEnabled && !keepOpen && inspector) {
36
+ inspector.close();
37
+ session?.disconnect();
38
+ }
27
39
  };
28
40
  }
29
41
  function closeInspector(config) {
30
42
  const keepOpen = shouldKeepOpen(config);
31
- if (inspector && !keepOpen) inspector.close(), session?.disconnect();
43
+ if (inspector && !keepOpen) {
44
+ inspector.close();
45
+ session?.disconnect();
46
+ }
32
47
  }
33
48
  function shouldKeepOpen(config) {
34
49
  // In watch mode the inspector can persist re-runs if isolation is disabled and a single worker is used
@@ -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.B4Hthdvt.js';
5
+ import { R as RuntimeRPC, e as ResolveFunctionResult, W as WorkerGlobalState } from './worker.d.DadbA89M.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,5 +1,5 @@
1
1
  import { NodeSnapshotEnvironment } from '@vitest/snapshot/environment';
2
- import { g as getWorkerState } from './utils.CG9h5ccR.js';
2
+ import { g as getWorkerState } from './utils.DvEY5TfP.js';
3
3
  import '@vitest/utils/timers';
4
4
 
5
5
  class VitestNodeSnapshotEnvironment extends NodeSnapshotEnvironment {
@@ -1,4 +1,4 @@
1
- import { V as Vitest, T as TestProject, a as TestProjectConfiguration } from './reporters.d.PEs0tXod.js';
1
+ import { V as Vitest, T as TestProject, a as TestProjectConfiguration } from './reporters.d.Da1D1VbQ.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.B4Hthdvt.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.DadbA89M.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
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.ScGeWTou.js';
10
+ import { S as SerializedTestSpecification, B as BrowserTesterOptions } from './browser.d.DTTM2PTh.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
  /**
@@ -1533,7 +1535,7 @@ interface BrowserConfigOptions {
1533
1535
  /**
1534
1536
  * Commands that will be executed on the server
1535
1537
  * via the browser `import("vitest/browser").commands` API.
1536
- * @see {@link https://vitest.dev/guide/browser/commands}
1538
+ * @see {@link https://vitest.dev/api/browser/commands}
1537
1539
  */
1538
1540
  commands?: Record<string, BrowserCommand<any>>;
1539
1541
  /**
@@ -1694,7 +1696,7 @@ type ToMatchScreenshotResolvePath = (data: {
1694
1696
  platform: NodeJS.Platform;
1695
1697
  /**
1696
1698
  * The value provided to
1697
- * {@linkcode https://vitest.dev/guide/browser/config#browser-screenshotdirectory|browser.screenshotDirectory},
1699
+ * {@linkcode https://vitest.dev/config/browser/screenshotdirectory|browser.screenshotDirectory},
1698
1700
  * if none is provided, its default value.
1699
1701
  */
1700
1702
  screenshotDirectory: string;
@@ -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;
@@ -2443,9 +2452,10 @@ interface InlineConfig {
2443
2452
  */
2444
2453
  benchmark?: BenchmarkUserOptions;
2445
2454
  /**
2446
- * Include globs for test files
2455
+ * A list of [glob patterns](https://superchupu.dev/tinyglobby/comparison) that match your test files.
2447
2456
  *
2448
2457
  * @default ['**\/*.{test,spec}.?(c|m)[jt]s?(x)']
2458
+ * @see {@link https://vitest.dev/config/include}
2449
2459
  */
2450
2460
  include?: string[];
2451
2461
  /**