vitest 3.2.0-beta.2 → 3.2.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 (72) hide show
  1. package/LICENSE.md +29 -0
  2. package/dist/browser.d.ts +3 -3
  3. package/dist/browser.js +2 -2
  4. package/dist/chunks/{base.DwtwORaC.js → base.Cg0miDlQ.js} +11 -14
  5. package/dist/chunks/{benchmark.BoF7jW0Q.js → benchmark.CYdenmiT.js} +4 -6
  6. package/dist/chunks/{cac.I9MLYfT-.js → cac.6rXCxFY1.js} +76 -143
  7. package/dist/chunks/{cli-api.d6IK1pnk.js → cli-api.Cej3MBjA.js} +1460 -1344
  8. package/dist/chunks/{config.d.UqE-KR0o.d.ts → config.d.D2ROskhv.d.ts} +2 -0
  9. package/dist/chunks/{console.K1NMVOSc.js → console.CtFJOzRO.js} +25 -45
  10. package/dist/chunks/{constants.BZZyIeIE.js → constants.DnKduX2e.js} +1 -0
  11. package/dist/chunks/{coverage.0iPg4Wrz.js → coverage.DVF1vEu8.js} +4 -12
  12. package/dist/chunks/{coverage.OGU09Jbh.js → coverage.EIiagJJP.js} +578 -993
  13. package/dist/chunks/{creator.DGAdZ4Hj.js → creator.GK6I-cL4.js} +39 -83
  14. package/dist/chunks/date.Bq6ZW5rf.js +73 -0
  15. package/dist/chunks/{defaults.DSxsTG0h.js → defaults.B7q_naMc.js} +2 -1
  16. package/dist/chunks/{env.Dq0hM4Xv.js → env.D4Lgay0q.js} +1 -1
  17. package/dist/chunks/{environment.d.D8YDy2v5.d.ts → environment.d.cL3nLXbE.d.ts} +1 -0
  18. package/dist/chunks/{execute.JlGHLJZT.js → execute.B7h3T_Hc.js} +126 -217
  19. package/dist/chunks/{git.DXfdBEfR.js → git.BVQ8w_Sw.js} +1 -3
  20. package/dist/chunks/{global.d.BPa1eL3O.d.ts → global.d.MAmajcmJ.d.ts} +5 -1
  21. package/dist/chunks/{globals.CpxW8ccg.js → globals.DEHgCU4V.js} +7 -6
  22. package/dist/chunks/{index.CV36oG_L.js → index.BZ0g1JD2.js} +430 -625
  23. package/dist/chunks/{index.DswW_LEs.js → index.BbB8_kAK.js} +25 -24
  24. package/dist/chunks/{index.CmC5OK9L.js → index.CIyJn3t1.js} +38 -82
  25. package/dist/chunks/{index.CfXMNXHg.js → index.CdQS2e2Q.js} +4 -2
  26. package/dist/chunks/{index.DFXFpH3w.js → index.CmSc2RE5.js} +85 -105
  27. package/dist/chunks/index.D3XRDfWc.js +213 -0
  28. package/dist/chunks/{inspector.DbDkSkFn.js → inspector.C914Efll.js} +4 -1
  29. package/dist/chunks/{node.3xsWotC9.js → node.fjCdwEIl.js} +1 -1
  30. package/dist/chunks/{reporters.d.CLC9rhKy.d.ts → reporters.d.C1ogPriE.d.ts} +47 -9
  31. package/dist/chunks/{rpc.D9_013TY.js → rpc.Iovn4oWe.js} +10 -19
  32. package/dist/chunks/{runBaseTests.Dn2vyej_.js → runBaseTests.Dd85QTll.js} +27 -31
  33. package/dist/chunks/{setup-common.CYo3Y0dD.js → setup-common.Dd054P77.js} +16 -42
  34. package/dist/chunks/{typechecker.DnTrplSJ.js → typechecker.DRKU1-1g.js} +163 -186
  35. package/dist/chunks/{utils.BfxieIyZ.js → utils.CAioKnHs.js} +9 -14
  36. package/dist/chunks/{utils.CgTj3MsC.js → utils.XdZDrNZV.js} +6 -13
  37. package/dist/chunks/{vi.BFR5YIgu.js → vi.bdSIJ99Y.js} +137 -263
  38. package/dist/chunks/{vite.d.CBZ3M_ru.d.ts → vite.d.DqE4-hhK.d.ts} +3 -1
  39. package/dist/chunks/{vm.C1HHjtNS.js → vm.BThCzidc.js} +164 -212
  40. package/dist/chunks/{worker.d.D5Xdi-Zr.d.ts → worker.d.DvqK5Vmu.d.ts} +1 -1
  41. package/dist/chunks/{worker.d.CoCI7hzP.d.ts → worker.d.tQu2eJQy.d.ts} +5 -3
  42. package/dist/cli.js +5 -5
  43. package/dist/config.cjs +3 -1
  44. package/dist/config.d.ts +7 -6
  45. package/dist/config.js +3 -3
  46. package/dist/coverage.d.ts +4 -4
  47. package/dist/coverage.js +7 -7
  48. package/dist/environments.d.ts +6 -2
  49. package/dist/environments.js +1 -1
  50. package/dist/execute.d.ts +9 -3
  51. package/dist/execute.js +1 -1
  52. package/dist/index.d.ts +28 -15
  53. package/dist/index.js +5 -5
  54. package/dist/node.d.ts +18 -10
  55. package/dist/node.js +17 -17
  56. package/dist/reporters.d.ts +4 -4
  57. package/dist/reporters.js +4 -4
  58. package/dist/runners.d.ts +6 -3
  59. package/dist/runners.js +59 -80
  60. package/dist/snapshot.js +2 -2
  61. package/dist/suite.js +2 -2
  62. package/dist/worker.js +39 -41
  63. package/dist/workers/forks.js +6 -4
  64. package/dist/workers/runVmTests.js +20 -21
  65. package/dist/workers/threads.js +4 -4
  66. package/dist/workers/vmForks.js +6 -6
  67. package/dist/workers/vmThreads.js +6 -6
  68. package/dist/workers.d.ts +4 -4
  69. package/dist/workers.js +10 -10
  70. package/package.json +21 -19
  71. package/dist/chunks/date.CDOsz-HY.js +0 -53
  72. package/dist/chunks/index.CK1YOQaa.js +0 -143
package/dist/runners.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as tinybench from 'tinybench';
2
- import { VitestRunner, VitestRunnerImportSource, Suite, File, Task, CancelReason, TestContext } from '@vitest/runner';
2
+ import { VitestRunner, VitestRunnerImportSource, Suite, File, Task, CancelReason, Test, TestContext, ImportDuration } from '@vitest/runner';
3
3
  export { VitestRunner } from '@vitest/runner';
4
- import { a as SerializedConfig } from './chunks/config.d.UqE-KR0o.js';
4
+ import { a as SerializedConfig } from './chunks/config.d.D2ROskhv.js';
5
5
  import '@vitest/pretty-format';
6
6
  import '@vitest/snapshot';
7
7
  import '@vitest/snapshot/environment';
@@ -28,7 +28,9 @@ declare class VitestTestRunner implements VitestRunner {
28
28
  constructor(config: SerializedConfig);
29
29
  importFile(filepath: string, source: VitestRunnerImportSource): unknown;
30
30
  onCollectStart(file: File): void;
31
+ onCleanupWorkerContext(listener: () => unknown): void;
31
32
  onAfterRunFiles(): void;
33
+ getWorkerContext(): Record<string, unknown>;
32
34
  onAfterRunSuite(suite: Suite): Promise<void>;
33
35
  onAfterRunTask(test: Task): void;
34
36
  cancel(_reason: CancelReason): void;
@@ -36,8 +38,9 @@ declare class VitestTestRunner implements VitestRunner {
36
38
  onBeforeRunTask(test: Task): Promise<void>;
37
39
  onBeforeRunSuite(suite: Suite): Promise<void>;
38
40
  onBeforeTryTask(test: Task): void;
39
- onAfterTryTask(test: Task): void;
41
+ onAfterTryTask(test: Test): void;
40
42
  extendTaskContext(context: TestContext): TestContext;
43
+ getImportDurations(): Record<string, ImportDuration>;
41
44
  }
42
45
 
43
46
  export { NodeBenchmarkRunner, VitestTestRunner };
package/dist/runners.js CHANGED
@@ -1,18 +1,19 @@
1
1
  import { updateTask } from '@vitest/runner';
2
2
  import { createDefer, getSafeTimers } from '@vitest/utils';
3
- import { a as getBenchOptions, g as getBenchFn } from './chunks/benchmark.BoF7jW0Q.js';
4
- import { g as getWorkerState } from './chunks/utils.CgTj3MsC.js';
3
+ import { a as getBenchOptions, g as getBenchFn } from './chunks/benchmark.CYdenmiT.js';
4
+ import { g as getWorkerState } from './chunks/utils.XdZDrNZV.js';
5
5
  import { setState, GLOBAL_EXPECT, getState } from '@vitest/expect';
6
6
  import { getTests, getNames, getTestName } from '@vitest/runner/utils';
7
- import { g as getSnapshotClient, i as inject, c as createExpect, v as vi } from './chunks/vi.BFR5YIgu.js';
8
- import { r as rpc } from './chunks/rpc.D9_013TY.js';
7
+ import { normalize } from 'pathe';
8
+ import { g as getSnapshotClient, i as inject, c as createExpect, v as vi } from './chunks/vi.bdSIJ99Y.js';
9
+ import { r as rpc } from './chunks/rpc.Iovn4oWe.js';
9
10
  import 'chai';
10
11
  import './chunks/_commonjsHelpers.BFTU3MAI.js';
11
12
  import '@vitest/snapshot';
12
13
  import '@vitest/utils/error';
13
14
  import '@vitest/spy';
14
15
  import '@vitest/utils/source-map';
15
- import './chunks/date.CDOsz-HY.js';
16
+ import './chunks/date.Bq6ZW5rf.js';
16
17
  import './chunks/index.CJ0plNrh.js';
17
18
 
18
19
  function createBenchmarkResult(name) {
@@ -23,25 +24,19 @@ function createBenchmarkResult(name) {
23
24
  samples: []
24
25
  };
25
26
  }
26
- const benchmarkTasks = new WeakMap();
27
+ const benchmarkTasks = /* @__PURE__ */ new WeakMap();
27
28
  async function runBenchmarkSuite(suite, runner) {
28
29
  const { Task, Bench } = await runner.importTinybench();
29
30
  const start = performance.now();
30
31
  const benchmarkGroup = [];
31
32
  const benchmarkSuiteGroup = [];
32
33
  for (const task of suite.tasks) {
33
- if (task.mode !== "run" && task.mode !== "queued") {
34
- continue;
35
- }
36
- if (task.meta?.benchmark) {
37
- benchmarkGroup.push(task);
38
- } else if (task.type === "suite") {
39
- benchmarkSuiteGroup.push(task);
40
- }
41
- }
42
- for (const subSuite of benchmarkSuiteGroup) {
43
- await runBenchmarkSuite(subSuite, runner);
34
+ if (task.mode !== "run" && task.mode !== "queued") continue;
35
+ if (task.meta?.benchmark) benchmarkGroup.push(task);
36
+ else if (task.type === "suite") benchmarkSuiteGroup.push(task);
44
37
  }
38
+ // run sub suites sequentially
39
+ for (const subSuite of benchmarkSuiteGroup) await runBenchmarkSuite(subSuite, runner);
45
40
  if (benchmarkGroup.length) {
46
41
  const defer = createDefer();
47
42
  suite.result = {
@@ -57,12 +52,11 @@ async function runBenchmarkSuite(suite, runner) {
57
52
  const result = benchmark.result.benchmark;
58
53
  benchmark.result.state = "pass";
59
54
  Object.assign(result, taskRes);
55
+ // compute extra stats and free raw samples as early as possible
60
56
  const samples = result.samples;
61
57
  result.sampleCount = samples.length;
62
58
  result.median = samples.length % 2 ? samples[Math.floor(samples.length / 2)] : (samples[samples.length / 2] + samples[samples.length / 2 - 1]) / 2;
63
- if (!runner.config.benchmark?.includeSamples) {
64
- result.samples.length = 0;
65
- }
59
+ if (!runner.config.benchmark?.includeSamples) result.samples.length = 0;
66
60
  updateTask$1("test-finished", benchmark);
67
61
  }, { once: true });
68
62
  task.addEventListener("error", (e) => {
@@ -112,9 +106,7 @@ class NodeBenchmarkRunner {
112
106
  return await import('tinybench');
113
107
  }
114
108
  importFile(filepath, source) {
115
- if (source === "setup") {
116
- getWorkerState().moduleCache.delete(filepath);
117
- }
109
+ if (source === "setup") getWorkerState().moduleCache.delete(filepath);
118
110
  return this.__vitest_executor.executeId(filepath);
119
111
  }
120
112
  async runSuite(suite) {
@@ -125,39 +117,42 @@ class NodeBenchmarkRunner {
125
117
  }
126
118
  }
127
119
 
120
+ // worker context is shared between all tests
121
+ const workerContext = Object.create(null);
128
122
  class VitestTestRunner {
129
123
  snapshotClient = getSnapshotClient();
130
124
  workerState = getWorkerState();
131
125
  __vitest_executor;
132
126
  cancelRun = false;
133
- assertionsErrors = new WeakMap();
127
+ assertionsErrors = /* @__PURE__ */ new WeakMap();
134
128
  pool = this.workerState.ctx.pool;
135
129
  constructor(config) {
136
130
  this.config = config;
137
131
  }
138
132
  importFile(filepath, source) {
139
- if (source === "setup") {
140
- this.workerState.moduleCache.delete(filepath);
141
- }
133
+ if (source === "setup") this.workerState.moduleCache.delete(filepath);
142
134
  return this.__vitest_executor.executeId(filepath);
143
135
  }
144
136
  onCollectStart(file) {
145
137
  this.workerState.current = file;
146
138
  }
139
+ onCleanupWorkerContext(listener) {
140
+ this.workerState.onCleanup(listener);
141
+ }
147
142
  onAfterRunFiles() {
148
143
  this.snapshotClient.clear();
149
- this.workerState.current = undefined;
144
+ this.workerState.current = void 0;
145
+ }
146
+ getWorkerContext() {
147
+ return workerContext;
150
148
  }
151
149
  async onAfterRunSuite(suite) {
152
- if (this.config.logHeapUsage && typeof process !== "undefined") {
153
- suite.result.heap = process.memoryUsage().heapUsed;
154
- }
150
+ if (this.config.logHeapUsage && typeof process !== "undefined") suite.result.heap = process.memoryUsage().heapUsed;
155
151
  if (suite.mode !== "skip" && "filepath" in suite) {
156
- for (const test of getTests(suite)) {
157
- if (test.mode === "skip") {
158
- const name = getNames(test).slice(1).join(" > ");
159
- this.snapshotClient.skipTest(suite.file.filepath, name);
160
- }
152
+ // mark snapshots in skipped tests as not obsolete
153
+ for (const test of getTests(suite)) if (test.mode === "skip") {
154
+ const name = getNames(test).slice(1).join(" > ");
155
+ this.snapshotClient.skipTest(suite.file.filepath, name);
161
156
  }
162
157
  const result = await this.snapshotClient.finish(suite.file.filepath);
163
158
  await rpc().snapshotSaved(result);
@@ -165,33 +160,26 @@ class VitestTestRunner {
165
160
  this.workerState.current = suite.suite || suite.file;
166
161
  }
167
162
  onAfterRunTask(test) {
168
- if (this.config.logHeapUsage && typeof process !== "undefined") {
169
- test.result.heap = process.memoryUsage().heapUsed;
170
- }
163
+ if (this.config.logHeapUsage && typeof process !== "undefined") test.result.heap = process.memoryUsage().heapUsed;
171
164
  this.workerState.current = test.suite || test.file;
172
165
  }
173
166
  cancel(_reason) {
174
167
  this.cancelRun = true;
175
168
  }
176
169
  injectValue(key) {
170
+ // inject has a very limiting type controlled by ProvidedContext
171
+ // some tests override it which causes the build to fail
177
172
  return inject(key);
178
173
  }
179
174
  async onBeforeRunTask(test) {
180
- if (this.cancelRun) {
181
- test.mode = "skip";
182
- }
183
- if (test.mode !== "run" && test.mode !== "queued") {
184
- return;
185
- }
175
+ if (this.cancelRun) test.mode = "skip";
176
+ if (test.mode !== "run" && test.mode !== "queued") return;
186
177
  this.workerState.current = test;
187
178
  }
188
179
  async onBeforeRunSuite(suite) {
189
- if (this.cancelRun) {
190
- suite.mode = "skip";
191
- }
192
- if (suite.mode !== "skip" && "filepath" in suite) {
193
- await this.snapshotClient.setup(suite.file.filepath, this.workerState.config.snapshotOptions);
194
- }
180
+ if (this.cancelRun) suite.mode = "skip";
181
+ // initialize snapshot state before running file suite
182
+ if (suite.mode !== "skip" && "filepath" in suite) await this.snapshotClient.setup(suite.file.filepath, this.workerState.config.snapshotOptions);
195
183
  this.workerState.current = suite;
196
184
  }
197
185
  onBeforeTryTask(test) {
@@ -208,26 +196,17 @@ class VitestTestRunner {
208
196
  }, globalThis[GLOBAL_EXPECT]);
209
197
  }
210
198
  onAfterTryTask(test) {
211
- const { assertionCalls, expectedAssertionsNumber, expectedAssertionsNumberErrorGen, isExpectingAssertions, isExpectingAssertionsError } = "context" in test && test.context._local ? test.context.expect.getState() : getState(globalThis[GLOBAL_EXPECT]);
212
- if (expectedAssertionsNumber !== null && assertionCalls !== expectedAssertionsNumber) {
213
- throw expectedAssertionsNumberErrorGen();
214
- }
215
- if (isExpectingAssertions === true && assertionCalls === 0) {
216
- throw isExpectingAssertionsError;
217
- }
218
- if (this.config.expect.requireAssertions && assertionCalls === 0) {
219
- throw this.assertionsErrors.get(test);
220
- }
199
+ const { assertionCalls, expectedAssertionsNumber, expectedAssertionsNumberErrorGen, isExpectingAssertions, isExpectingAssertionsError } = test.context._local ? test.context.expect.getState() : getState(globalThis[GLOBAL_EXPECT]);
200
+ if (expectedAssertionsNumber !== null && assertionCalls !== expectedAssertionsNumber) throw expectedAssertionsNumberErrorGen();
201
+ if (isExpectingAssertions === true && assertionCalls === 0) throw isExpectingAssertionsError;
202
+ if (this.config.expect.requireAssertions && assertionCalls === 0) throw this.assertionsErrors.get(test);
221
203
  }
222
204
  extendTaskContext(context) {
223
- if (this.config.expect.requireAssertions) {
224
- this.assertionsErrors.set(context.task, new Error("expected any number of assertion, but got none"));
225
- }
205
+ // create error during the test initialization so we have a nice stack trace
206
+ if (this.config.expect.requireAssertions) this.assertionsErrors.set(context.task, new Error("expected any number of assertion, but got none"));
226
207
  let _expect;
227
208
  Object.defineProperty(context, "expect", { get() {
228
- if (!_expect) {
229
- _expect = createExpect(context.task);
230
- }
209
+ if (!_expect) _expect = createExpect(context.task);
231
210
  return _expect;
232
211
  } });
233
212
  Object.defineProperty(context, "_local", { get() {
@@ -235,22 +214,22 @@ class VitestTestRunner {
235
214
  } });
236
215
  return context;
237
216
  }
217
+ getImportDurations() {
218
+ const entries = [...this.workerState.moduleExecutionInfo?.entries() ?? []];
219
+ return Object.fromEntries(entries.map(([filepath, { duration, selfTime }]) => [normalize(filepath), {
220
+ selfTime,
221
+ totalTime: duration
222
+ }]));
223
+ }
238
224
  }
239
225
  function clearModuleMocks(config) {
240
226
  const { clearMocks, mockReset, restoreMocks, unstubEnvs, unstubGlobals } = config;
241
- if (restoreMocks) {
242
- vi.restoreAllMocks();
243
- } else if (mockReset) {
244
- vi.resetAllMocks();
245
- } else if (clearMocks) {
246
- vi.clearAllMocks();
247
- }
248
- if (unstubEnvs) {
249
- vi.unstubAllEnvs();
250
- }
251
- if (unstubGlobals) {
252
- vi.unstubAllGlobals();
253
- }
227
+ // since each function calls another, we can just call one
228
+ if (restoreMocks) vi.restoreAllMocks();
229
+ else if (mockReset) vi.resetAllMocks();
230
+ else if (clearMocks) vi.clearAllMocks();
231
+ if (unstubEnvs) vi.unstubAllEnvs();
232
+ if (unstubGlobals) vi.unstubAllGlobals();
254
233
  }
255
234
 
256
235
  export { NodeBenchmarkRunner, VitestTestRunner };
package/dist/snapshot.js CHANGED
@@ -1,4 +1,4 @@
1
- export { VitestNodeSnapshotEnvironment as VitestSnapshotEnvironment } from './chunks/node.3xsWotC9.js';
1
+ export { VitestNodeSnapshotEnvironment as VitestSnapshotEnvironment } from './chunks/node.fjCdwEIl.js';
2
2
  import '@vitest/snapshot/environment';
3
- import './chunks/utils.CgTj3MsC.js';
3
+ import './chunks/utils.XdZDrNZV.js';
4
4
  import '@vitest/utils';
package/dist/suite.js CHANGED
@@ -1,5 +1,5 @@
1
- export { g as getBenchFn, a as getBenchOptions } from './chunks/benchmark.BoF7jW0Q.js';
1
+ export { g as getBenchFn, a as getBenchOptions } from './chunks/benchmark.CYdenmiT.js';
2
2
  export { createTaskCollector, getCurrentSuite, getCurrentTest, getFn, getHooks, setFn, setHooks } from '@vitest/runner';
3
3
  export { createChainable } from '@vitest/runner/utils';
4
4
  import '@vitest/utils';
5
- import './chunks/utils.CgTj3MsC.js';
5
+ import './chunks/utils.XdZDrNZV.js';
package/dist/worker.js CHANGED
@@ -4,11 +4,11 @@ import { workerId } from 'tinypool';
4
4
  import { ViteNodeRunner, ModuleCacheMap } from 'vite-node/client';
5
5
  import { readFileSync } from 'node:fs';
6
6
  import { resolve, normalize } from 'pathe';
7
- import { e as environments } from './chunks/index.DFXFpH3w.js';
8
- import { s as setupInspect } from './chunks/inspector.DbDkSkFn.js';
9
- import { c as createRuntimeRpc, a as rpcDone } from './chunks/rpc.D9_013TY.js';
10
- import { i as isChildProcess, s as setProcessTitle } from './chunks/utils.CgTj3MsC.js';
11
- import { d as disposeInternalListeners } from './chunks/utils.BfxieIyZ.js';
7
+ import { e as environments } from './chunks/index.CmSc2RE5.js';
8
+ import { s as setupInspect } from './chunks/inspector.C914Efll.js';
9
+ import { c as createRuntimeRpc, a as rpcDone } from './chunks/rpc.Iovn4oWe.js';
10
+ import { i as isChildProcess, s as setProcessTitle } from './chunks/utils.XdZDrNZV.js';
11
+ import { d as disposeInternalListeners } from './chunks/utils.CAioKnHs.js';
12
12
  import 'node:console';
13
13
  import 'node:module';
14
14
  import '@vitest/utils';
@@ -17,7 +17,7 @@ import './chunks/index.CJ0plNrh.js';
17
17
  function isBuiltinEnvironment(env) {
18
18
  return env in environments;
19
19
  }
20
- const _loaders = new Map();
20
+ const _loaders = /* @__PURE__ */ new Map();
21
21
  async function createEnvironmentLoader(options) {
22
22
  if (!_loaders.has(options.root)) {
23
23
  const loader = new ViteNodeRunner(options);
@@ -28,42 +28,44 @@ async function createEnvironmentLoader(options) {
28
28
  }
29
29
  async function loadEnvironment(ctx, rpc) {
30
30
  const name = ctx.environment.name;
31
- if (isBuiltinEnvironment(name)) {
32
- return environments[name];
33
- }
31
+ if (isBuiltinEnvironment(name)) return environments[name];
34
32
  const loader = await createEnvironmentLoader({
35
33
  root: ctx.config.root,
36
34
  fetchModule: async (id) => {
37
35
  const result = await rpc.fetch(id, "ssr");
38
- if (result.id) {
39
- return { code: readFileSync(result.id, "utf-8") };
40
- }
36
+ if (result.id) return { code: readFileSync(result.id, "utf-8") };
41
37
  return result;
42
38
  },
43
39
  resolveId: (id, importer) => rpc.resolveId(id, importer, "ssr")
44
40
  });
45
41
  const root = loader.root;
46
- const packageId = name[0] === "." || name[0] === "/" ? resolve(root, name) : (await rpc.resolveId(`vitest-environment-${name}`, undefined, "ssr"))?.id ?? resolve(root, name);
42
+ const packageId = name[0] === "." || name[0] === "/" ? resolve(root, name) : (await rpc.resolveId(`vitest-environment-${name}`, void 0, "ssr"))?.id ?? resolve(root, name);
47
43
  const pkg = await loader.executeId(normalize(packageId));
48
- if (!pkg || !pkg.default || typeof pkg.default !== "object") {
49
- throw new TypeError(`Environment "${name}" is not a valid environment. ` + `Path "${packageId}" should export default object with a "setup" or/and "setupVM" method.`);
50
- }
44
+ 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.`);
51
45
  const environment = pkg.default;
52
- if (environment.transformMode !== "web" && environment.transformMode !== "ssr") {
53
- 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".`);
54
- }
46
+ if (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".`);
55
47
  return environment;
56
48
  }
57
49
 
50
+ const listeners = /* @__PURE__ */ new Set();
51
+ function addCleanupListener(listener) {
52
+ listeners.add(listener);
53
+ }
54
+ async function cleanup() {
55
+ const promises = [...listeners].map((l) => l());
56
+ await Promise.all(promises);
57
+ }
58
+
58
59
  if (isChildProcess()) {
59
60
  setProcessTitle(`vitest ${workerId}`);
60
61
  const isProfiling = process.execArgv.some((execArg) => execArg.startsWith("--prof") || execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"));
61
- if (isProfiling) {
62
- process.on("SIGTERM", () => {
63
- process.exit();
64
- });
65
- }
62
+ if (isProfiling)
63
+ // Work-around for nodejs/node#55094
64
+ process.on("SIGTERM", () => {
65
+ process.exit();
66
+ });
66
67
  }
68
+ // this is what every pool executes when running tests
67
69
  async function execute(method, ctx) {
68
70
  disposeInternalListeners();
69
71
  const prepareStart = performance.now();
@@ -71,28 +73,22 @@ async function execute(method, ctx) {
71
73
  process.env.VITEST_WORKER_ID = String(ctx.workerId);
72
74
  process.env.VITEST_POOL_ID = String(workerId);
73
75
  try {
74
- if (ctx.worker[0] === ".") {
75
- throw new Error(`Path to the test runner cannot be relative, received "${ctx.worker}"`);
76
- }
76
+ // worker is a filepath or URL to a file that exposes a default export with "getRpcOptions" and "runTests" methods
77
+ if (ctx.worker[0] === ".") throw new Error(`Path to the test runner cannot be relative, received "${ctx.worker}"`);
77
78
  const file = ctx.worker.startsWith("file:") ? ctx.worker : pathToFileURL(ctx.worker).toString();
78
79
  const testRunnerModule = await import(file);
79
- if (!testRunnerModule.default || typeof testRunnerModule.default !== "object") {
80
- throw new TypeError(`Test worker object should be exposed as a default export. Received "${typeof testRunnerModule.default}"`);
81
- }
80
+ if (!testRunnerModule.default || typeof testRunnerModule.default !== "object") throw new TypeError(`Test worker object should be exposed as a default export. Received "${typeof testRunnerModule.default}"`);
82
81
  const worker = testRunnerModule.default;
83
- if (!worker.getRpcOptions || typeof worker.getRpcOptions !== "function") {
84
- throw new TypeError(`Test worker should expose "getRpcOptions" method. Received "${typeof worker.getRpcOptions}".`);
85
- }
82
+ if (!worker.getRpcOptions || typeof worker.getRpcOptions !== "function") throw new TypeError(`Test worker should expose "getRpcOptions" method. Received "${typeof worker.getRpcOptions}".`);
83
+ // RPC is used to communicate between worker (be it a thread worker or child process or a custom implementation) and the main thread
86
84
  const { rpc, onCancel } = createRuntimeRpc(worker.getRpcOptions(ctx));
87
85
  const beforeEnvironmentTime = performance.now();
88
86
  const environment = await loadEnvironment(ctx, rpc);
89
- if (ctx.environment.transformMode) {
90
- environment.transformMode = ctx.environment.transformMode;
91
- }
87
+ if (ctx.environment.transformMode) environment.transformMode = ctx.environment.transformMode;
92
88
  const state = {
93
89
  ctx,
94
90
  moduleCache: new ModuleCacheMap(),
95
- moduleExecutionInfo: new Map(),
91
+ moduleExecutionInfo: /* @__PURE__ */ new Map(),
96
92
  config: ctx.config,
97
93
  onCancel,
98
94
  environment,
@@ -101,15 +97,14 @@ async function execute(method, ctx) {
101
97
  prepare: prepareStart
102
98
  },
103
99
  rpc,
100
+ onCleanup: (listener) => addCleanupListener(listener),
104
101
  providedContext: ctx.providedContext,
105
102
  onFilterStackTrace(stack) {
106
103
  return createStackString(parseStacktrace(stack));
107
104
  }
108
105
  };
109
106
  const methodName = method === "collect" ? "collectTests" : "runTests";
110
- if (!worker[methodName] || typeof worker[methodName] !== "function") {
111
- throw new TypeError(`Test worker should expose "runTests" method. Received "${typeof worker.runTests}".`);
112
- }
107
+ if (!worker[methodName] || typeof worker[methodName] !== "function") throw new TypeError(`Test worker should expose "runTests" method. Received "${typeof worker.runTests}".`);
113
108
  await worker[methodName](state);
114
109
  } finally {
115
110
  await rpcDone().catch(() => {});
@@ -122,5 +117,8 @@ function run(ctx) {
122
117
  function collect(ctx) {
123
118
  return execute("collect", ctx);
124
119
  }
120
+ async function teardown() {
121
+ return cleanup();
122
+ }
125
123
 
126
- export { collect, run };
124
+ export { collect, run, teardown };
@@ -1,8 +1,8 @@
1
1
  import v8 from 'node:v8';
2
- import { r as runBaseTests } from '../chunks/base.DwtwORaC.js';
3
- import { c as createForksRpcOptions, u as unwrapSerializableConfig } from '../chunks/utils.BfxieIyZ.js';
2
+ import { r as runBaseTests } from '../chunks/base.Cg0miDlQ.js';
3
+ import { c as createForksRpcOptions, u as unwrapSerializableConfig } from '../chunks/utils.CAioKnHs.js';
4
4
  import 'vite-node/client';
5
- import '../chunks/execute.JlGHLJZT.js';
5
+ import '../chunks/execute.B7h3T_Hc.js';
6
6
  import 'node:fs';
7
7
  import 'node:url';
8
8
  import 'node:vm';
@@ -14,13 +14,15 @@ import 'node:path';
14
14
  import '@vitest/mocker';
15
15
  import 'node:module';
16
16
  import '@vitest/utils';
17
- import '../chunks/utils.CgTj3MsC.js';
17
+ import '../chunks/utils.XdZDrNZV.js';
18
18
 
19
19
  class ForksBaseWorker {
20
20
  getRpcOptions() {
21
21
  return createForksRpcOptions(v8);
22
22
  }
23
23
  async executeTests(method, state) {
24
+ // TODO: don't rely on reassigning process.exit
25
+ // https://github.com/vitest-dev/vitest/pull/4441#discussion_r1443771486
24
26
  const exit = process.exit;
25
27
  state.ctx.config = unwrapSerializableConfig(state.ctx.config);
26
28
  try {
@@ -6,29 +6,29 @@ import util from 'node:util';
6
6
  import { startTests, collectTests } from '@vitest/runner';
7
7
  import { KNOWN_ASSET_TYPES } from 'vite-node/constants';
8
8
  import { installSourcemapsSupport } from 'vite-node/source-map';
9
- import { s as setupChaiConfig, r as resolveTestRunner, a as resolveSnapshotEnvironment } from '../chunks/index.DswW_LEs.js';
10
- import { c as setupCommonEnv, s as startCoverageInsideWorker, a as stopCoverageInsideWorker } from '../chunks/setup-common.CYo3Y0dD.js';
11
- import { V as VitestIndex } from '../chunks/index.CfXMNXHg.js';
12
- import { c as closeInspector } from '../chunks/inspector.DbDkSkFn.js';
13
- import { g as getWorkerState } from '../chunks/utils.CgTj3MsC.js';
9
+ import { s as setupChaiConfig, r as resolveTestRunner, a as resolveSnapshotEnvironment } from '../chunks/index.BbB8_kAK.js';
10
+ import { c as setupCommonEnv, s as startCoverageInsideWorker, a as stopCoverageInsideWorker } from '../chunks/setup-common.Dd054P77.js';
11
+ import { V as VitestIndex } from '../chunks/index.CdQS2e2Q.js';
12
+ import { c as closeInspector } from '../chunks/inspector.C914Efll.js';
13
+ import { g as getWorkerState } from '../chunks/utils.XdZDrNZV.js';
14
14
  import 'chai';
15
15
  import 'node:path';
16
16
  import '../path.js';
17
17
  import 'node:url';
18
- import '../chunks/rpc.D9_013TY.js';
18
+ import '../chunks/rpc.Iovn4oWe.js';
19
19
  import '@vitest/utils';
20
20
  import '../chunks/index.CJ0plNrh.js';
21
- import '../chunks/coverage.0iPg4Wrz.js';
21
+ import '../chunks/coverage.DVF1vEu8.js';
22
22
  import '@vitest/snapshot';
23
- import '../chunks/vi.BFR5YIgu.js';
23
+ import '../chunks/vi.bdSIJ99Y.js';
24
24
  import '@vitest/expect';
25
25
  import '@vitest/runner/utils';
26
26
  import '../chunks/_commonjsHelpers.BFTU3MAI.js';
27
27
  import '@vitest/utils/error';
28
28
  import '@vitest/spy';
29
29
  import '@vitest/utils/source-map';
30
- import '../chunks/date.CDOsz-HY.js';
31
- import '../chunks/benchmark.BoF7jW0Q.js';
30
+ import '../chunks/date.Bq6ZW5rf.js';
31
+ import '../chunks/benchmark.CYdenmiT.js';
32
32
  import 'expect-type';
33
33
 
34
34
  async function run(method, files, config, executor) {
@@ -40,17 +40,18 @@ async function run(method, files, config, executor) {
40
40
  });
41
41
  if (workerState.environment.transformMode === "web") {
42
42
  const _require = createRequire(import.meta.url);
43
+ // always mock "required" `css` files, because we cannot process them
43
44
  _require.extensions[".css"] = resolveCss;
44
45
  _require.extensions[".scss"] = resolveCss;
45
46
  _require.extensions[".sass"] = resolveCss;
46
47
  _require.extensions[".less"] = resolveCss;
48
+ // since we are using Vite, we can assume how these will be resolved
47
49
  KNOWN_ASSET_TYPES.forEach((type) => {
48
50
  _require.extensions[`.${type}`] = resolveAsset;
49
51
  });
50
52
  process.env.SSR = "";
51
- } else {
52
- process.env.SSR = "1";
53
- }
53
+ } else process.env.SSR = "1";
54
+ // @ts-expect-error not typed global for patched timers
54
55
  globalThis.__vitest_required__ = {
55
56
  util,
56
57
  timers,
@@ -58,11 +59,10 @@ async function run(method, files, config, executor) {
58
59
  };
59
60
  installSourcemapsSupport({ getSourceMap: (source) => workerState.moduleCache.getSourceMap(source) });
60
61
  await startCoverageInsideWorker(config.coverage, executor, { isolate: false });
61
- if (config.chaiConfig) {
62
- setupChaiConfig(config.chaiConfig);
63
- }
62
+ if (config.chaiConfig) setupChaiConfig(config.chaiConfig);
64
63
  const [runner, snapshotEnvironment] = await Promise.all([resolveTestRunner(config, executor), resolveSnapshotEnvironment(config, executor)]);
65
64
  config.snapshotOptions.snapshotEnvironment = snapshotEnvironment;
65
+ runner.getWorkerContext = void 0;
66
66
  workerState.onCancel.then((reason) => {
67
67
  closeInspector(config);
68
68
  runner.cancel?.(reason);
@@ -71,12 +71,11 @@ async function run(method, files, config, executor) {
71
71
  const { vi } = VitestIndex;
72
72
  for (const file of files) {
73
73
  workerState.filepath = file.filepath;
74
- if (method === "run") {
75
- await startTests([file], runner);
76
- } else {
77
- await collectTests([file], runner);
78
- }
74
+ if (method === "run") await startTests([file], runner);
75
+ else await collectTests([file], runner);
76
+ // reset after tests, because user might call `vi.setConfig` in setupFile
79
77
  vi.resetConfig();
78
+ // mocks should not affect different files
80
79
  vi.restoreAllMocks();
81
80
  }
82
81
  await stopCoverageInsideWorker(config.coverage, executor, { isolate: false });
@@ -1,7 +1,7 @@
1
- import { r as runBaseTests } from '../chunks/base.DwtwORaC.js';
2
- import { a as createThreadsRpcOptions } from '../chunks/utils.BfxieIyZ.js';
1
+ import { r as runBaseTests } from '../chunks/base.Cg0miDlQ.js';
2
+ import { a as createThreadsRpcOptions } from '../chunks/utils.CAioKnHs.js';
3
3
  import 'vite-node/client';
4
- import '../chunks/execute.JlGHLJZT.js';
4
+ import '../chunks/execute.B7h3T_Hc.js';
5
5
  import 'node:fs';
6
6
  import 'node:url';
7
7
  import 'node:vm';
@@ -13,7 +13,7 @@ import 'node:path';
13
13
  import '@vitest/mocker';
14
14
  import 'node:module';
15
15
  import '@vitest/utils';
16
- import '../chunks/utils.CgTj3MsC.js';
16
+ import '../chunks/utils.XdZDrNZV.js';
17
17
 
18
18
  class ThreadsBaseWorker {
19
19
  getRpcOptions(ctx) {
@@ -1,19 +1,19 @@
1
1
  import v8 from 'node:v8';
2
- import { c as createForksRpcOptions, u as unwrapSerializableConfig } from '../chunks/utils.BfxieIyZ.js';
3
- import { r as runVmTests } from '../chunks/vm.C1HHjtNS.js';
2
+ import { c as createForksRpcOptions, u as unwrapSerializableConfig } from '../chunks/utils.CAioKnHs.js';
3
+ import { r as runVmTests } from '../chunks/vm.BThCzidc.js';
4
4
  import '@vitest/utils';
5
5
  import 'node:url';
6
6
  import 'node:vm';
7
7
  import 'pathe';
8
8
  import '../path.js';
9
9
  import 'node:path';
10
- import '../chunks/console.K1NMVOSc.js';
10
+ import '../chunks/console.CtFJOzRO.js';
11
11
  import 'node:console';
12
12
  import 'node:stream';
13
13
  import 'tinyrainbow';
14
- import '../chunks/date.CDOsz-HY.js';
15
- import '../chunks/utils.CgTj3MsC.js';
16
- import '../chunks/execute.JlGHLJZT.js';
14
+ import '../chunks/date.Bq6ZW5rf.js';
15
+ import '../chunks/utils.XdZDrNZV.js';
16
+ import '../chunks/execute.B7h3T_Hc.js';
17
17
  import 'node:fs';
18
18
  import '@vitest/utils/error';
19
19
  import 'vite-node/client';
@@ -1,18 +1,18 @@
1
- import { a as createThreadsRpcOptions } from '../chunks/utils.BfxieIyZ.js';
2
- import { r as runVmTests } from '../chunks/vm.C1HHjtNS.js';
1
+ import { a as createThreadsRpcOptions } from '../chunks/utils.CAioKnHs.js';
2
+ import { r as runVmTests } from '../chunks/vm.BThCzidc.js';
3
3
  import '@vitest/utils';
4
4
  import 'node:url';
5
5
  import 'node:vm';
6
6
  import 'pathe';
7
7
  import '../path.js';
8
8
  import 'node:path';
9
- import '../chunks/console.K1NMVOSc.js';
9
+ import '../chunks/console.CtFJOzRO.js';
10
10
  import 'node:console';
11
11
  import 'node:stream';
12
12
  import 'tinyrainbow';
13
- import '../chunks/date.CDOsz-HY.js';
14
- import '../chunks/utils.CgTj3MsC.js';
15
- import '../chunks/execute.JlGHLJZT.js';
13
+ import '../chunks/date.Bq6ZW5rf.js';
14
+ import '../chunks/utils.XdZDrNZV.js';
15
+ import '../chunks/execute.B7h3T_Hc.js';
16
16
  import 'node:fs';
17
17
  import '@vitest/utils/error';
18
18
  import 'vite-node/client';