vitest 5.0.4 → 5.0.5

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 (30) hide show
  1. package/dist/browser.js +2 -2
  2. package/dist/chunks/{base.CYbb9pQW.js → base.CzXt2BO_.js} +8 -7
  3. package/dist/chunks/{cac.DTXWs6Ni.js → cac.CLrZKo1g.js} +5 -5
  4. package/dist/chunks/{cli-api.Bx28WXzL.js → cli-api.De07GUeT.js} +24 -9
  5. package/dist/chunks/{creator.CLL8QFMS.js → creator.C5g4egeG.js} +3 -3
  6. package/dist/chunks/{doctor.Bqc8NDDb.js → doctor.BK86Cncq.js} +1 -1
  7. package/dist/chunks/{globals.CTWMSIPL.js → globals.CXEE6_2C.js} +2 -2
  8. package/dist/chunks/{index.B8VfM7Mf.js → index.1TqnEahn.js} +108 -81
  9. package/dist/chunks/{index.CPNMO3h-.js → index.CK-t0WMg.js} +6 -7
  10. package/dist/chunks/{index.GYMZ12wH.js → index.CoUIxZd4.js} +4 -2
  11. package/dist/chunks/{index.uwTEEBsB.js → index.aTZaPVhf.js} +1 -1
  12. package/dist/chunks/{init-forks.CbYYa5xq.js → init-forks.CRxIPOJR.js} +1 -1
  13. package/dist/chunks/{init-threads.DtjdvxPl.js → init-threads.Dv3kwST_.js} +1 -1
  14. package/dist/chunks/{init.DrHtV5zd.js → init.PvxYpuCm.js} +1 -1
  15. package/dist/chunks/{nativeModuleMocker.D8f4cW4A.js → nativeModuleMocker.BxrHJNAF.js} +25 -4
  16. package/dist/chunks/{run.Cm2sd7-x.js → run.BPv-BBRv.js} +37 -28
  17. package/dist/chunks/{setup-common.BABL3z3m.js → setup-common.HGAqWOnX.js} +1 -1
  18. package/dist/chunks/{vm.Uo_C9Uld.js → vm.FGl2rw_t.js} +3 -3
  19. package/dist/cli.js +1 -1
  20. package/dist/index.js +2 -2
  21. package/dist/module-evaluator.js +16 -12
  22. package/dist/node.js +5 -5
  23. package/dist/runtime.js +2 -2
  24. package/dist/worker.js +7 -7
  25. package/dist/workers/forks.js +8 -8
  26. package/dist/workers/runVmTests.js +5 -4
  27. package/dist/workers/threads.js +8 -8
  28. package/dist/workers/vmForks.js +5 -5
  29. package/dist/workers/vmThreads.js +5 -5
  30. package/package.json +12 -12
package/dist/browser.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { s as startCoverageInsideWorker, a as stopCoverageInsideWorker, t as takeCoverageInsideWorker } from './chunks/coverage.-bm5IxnW.js';
2
- export { p as collectTests, a as processError, s as startTests } from './chunks/run.Cm2sd7-x.js';
3
- export { l as loadDiffConfig, a as loadSnapshotSerializers, s as setupCommonEnv, b as setupEnv } from './chunks/setup-common.BABL3z3m.js';
2
+ export { p as collectTests, a as processError, s as startTests } from './chunks/run.BPv-BBRv.js';
3
+ export { l as loadDiffConfig, a as loadSnapshotSerializers, s as setupCommonEnv, b as setupEnv } from './chunks/setup-common.HGAqWOnX.js';
4
4
  export { s as SpyModule } from './chunks/spy.DDMXghXv.js';
5
5
  export { f as format, i as inspect, s as stringify } from './chunks/display.BlTmubjj.js';
6
6
  export { g as getType } from './chunks/pathe.M-eThtNZ.Ba-7h1rE.js';
@@ -1,22 +1,22 @@
1
1
  import { runInThisContext } from 'node:vm';
2
2
  import { s as spyModule } from './spy.DDMXghXv.js';
3
- import { r as resolveTestRunner, a as resolveSnapshotEnvironment, d as detectAsyncLeaks, s as setupChaiConfig } from './index.GYMZ12wH.js';
4
- import { l as loadEnvironment, e as emitModuleRunner, a as listenForErrors } from './init.DrHtV5zd.js';
3
+ import { r as resolveTestRunner, a as resolveSnapshotEnvironment, d as detectAsyncLeaks, s as setupChaiConfig } from './index.CoUIxZd4.js';
4
+ import { l as loadEnvironment, e as emitModuleRunner, a as listenForErrors } from './init.PvxYpuCm.js';
5
5
  import { n as nativeImports, g as getEvaluatedImports, c as collectDependencies } from './module-dependencies.CwNPkcV4.js';
6
6
  import { Traces } from '../traces.js';
7
7
  import { V as VitestEvaluatedModules } from './rpc.DpkUyY1N.js';
8
- import { s as startVitestModuleRunner, c as createNodeImportMeta } from './index.CPNMO3h-.js';
8
+ import { s as startVitestModuleRunner, c as createNodeImportMeta } from './index.CK-t0WMg.js';
9
9
  import { performance as performance$1 } from 'node:perf_hooks';
10
10
  import { s as startCoverageInsideWorker, a as stopCoverageInsideWorker } from './coverage.-bm5IxnW.js';
11
- import { i as index, g as globalExpect, v as vi } from './index.uwTEEBsB.js';
11
+ import { i as index, g as globalExpect, v as vi } from './index.aTZaPVhf.js';
12
12
  import { c as closeInspector } from './inspector.CvyFGlXm.js';
13
- import { s as startTests, p as publicCollect } from './run.Cm2sd7-x.js';
13
+ import { s as startTests, p as publicCollect } from './run.BPv-BBRv.js';
14
14
  import { createRequire } from 'node:module';
15
15
  import timers from 'node:timers';
16
16
  import timersPromises from 'node:timers/promises';
17
17
  import util from 'node:util';
18
18
  import { K as KNOWN_ASSET_TYPES } from './pathe.M-eThtNZ.Ba-7h1rE.js';
19
- import { s as setupCommonEnv, b as setupEnv } from './setup-common.BABL3z3m.js';
19
+ import { s as setupCommonEnv, b as setupEnv } from './setup-common.HGAqWOnX.js';
20
20
  import { g as getWorkerState, r as resetModules, p as provideWorkerState, a as getSafeWorkerState } from './utils.DYj33du9.js';
21
21
 
22
22
  // this should only be used in Node
@@ -102,6 +102,7 @@ async function run(method, files, config, moduleRunner, environment, traces) {
102
102
  vi.resetConfig();
103
103
  // mocks should not affect different files
104
104
  vi.restoreAllMocks();
105
+ moduleRunner.mocker?.reset();
105
106
  }
106
107
  });
107
108
  } finally {
@@ -126,7 +127,7 @@ async function startModuleRunner(options) {
126
127
  let mocker;
127
128
  if (options.state.config.experimental.nodeLoader !== false) {
128
129
  // this additionally imports acorn/magic-string
129
- const { NativeModuleMocker } = await import('./nativeModuleMocker.D8f4cW4A.js');
130
+ const { NativeModuleMocker } = await import('./nativeModuleMocker.BxrHJNAF.js');
130
131
  mocker = new NativeModuleMocker({
131
132
  async resolveId(id, importer) {
132
133
  // TODO: use import.meta.resolve instead
@@ -620,7 +620,7 @@ class CAC extends EventEmitter {
620
620
 
621
621
  const cac = (name = "") => new CAC(name);
622
622
 
623
- var version = "5.0.4";
623
+ var version = "5.0.5";
624
624
 
625
625
  const apiConfig = (port) => ({
626
626
  port: {
@@ -2364,7 +2364,7 @@ function normalizeCliOptions(cliFilters, argv) {
2364
2364
  }
2365
2365
  async function start(cliFilters, options) {
2366
2366
  try {
2367
- const { startVitest } = await import('./cli-api.Bx28WXzL.js').then(function (n) { return n.g; });
2367
+ const { startVitest } = await import('./cli-api.De07GUeT.js').then(function (n) { return n.g; });
2368
2368
  const ctx = await startVitest(cliFilters.map(normalize), normalizeCliOptions(cliFilters, options));
2369
2369
  if (!ctx.shouldKeepServer()) await ctx.exit();
2370
2370
  } catch (e) {
@@ -2378,7 +2378,7 @@ async function start(cliFilters, options) {
2378
2378
  }
2379
2379
  async function doctorCommand(cliFilters, options) {
2380
2380
  try {
2381
- const { doctor } = await import('./doctor.Bqc8NDDb.js');
2381
+ const { doctor } = await import('./doctor.BK86Cncq.js');
2382
2382
  await doctor(cliFilters.map(normalize), normalizeCliOptions(cliFilters, options));
2383
2383
  process.exit();
2384
2384
  } catch (e) {
@@ -2395,12 +2395,12 @@ async function init(project) {
2395
2395
  console.error(/* @__PURE__ */ new Error("Only the \"browser\" project is supported. Use \"vitest init browser\" to create a new project."));
2396
2396
  process.exit(1);
2397
2397
  }
2398
- const { create } = await import('./creator.CLL8QFMS.js');
2398
+ const { create } = await import('./creator.C5g4egeG.js');
2399
2399
  await create();
2400
2400
  }
2401
2401
  async function collect(cliFilters, options) {
2402
2402
  try {
2403
- const { prepareVitest, processCollected, outputFileList } = await import('./cli-api.Bx28WXzL.js').then(function (n) { return n.g; });
2403
+ const { prepareVitest, processCollected, outputFileList } = await import('./cli-api.De07GUeT.js').then(function (n) { return n.g; });
2404
2404
  const ctx = await prepareVitest({
2405
2405
  ...normalizeCliOptions(cliFilters, options),
2406
2406
  watch: false,
@@ -1,12 +1,12 @@
1
1
  import * as fs from 'node:fs';
2
2
  import fs__default, { promises, existsSync, writeFileSync, mkdirSync, readFileSync, statSync, readdirSync } from 'node:fs';
3
3
  import { r as resolveCoverageProviderModule, g as getCoverageFilesDirectory, C as CoverageProviderMap } from './coverage.cTDc4uSS.js';
4
- import { o as parse, s as stringify, k as isFileServingAllowed, f as createDebugger, q as hash, t as resolveCoverageReporters, u as createIndexLocationsMap, v as getOutputFile, w as groupBy, x as generateCodeFrame, y as printStack, z as getSpecificationDocblock, A as resolveStaticMocks, C as getStaticMocks, R as RangeLocationFilterProvidedError, I as IncludeTaskLocationDisabledError, D as LocationFilterFileNotFoundError, E as GitCommandError, G as GitNotFoundError, H as VitestResolver, M as ModuleTransformService, l as resolveConfig$1, J as createClusterServer, S as ServerModuleRunner, K as attachProjectsFromEntries, N as TestProject, O as resolveAndAttachProjects, Q as RandomSequencer, b as FilesNotFoundError, U as createPool, W as astCollectTests, X as createFailedFileTask, Y as matchesProjectFilter, Z as nanoid, L as Logger, V as VitestPackageInstaller, P as PluginHarness, _ as stdout, p as prompt } from './index.B8VfM7Mf.js';
4
+ import { o as parse, s as stringify, k as isFileServingAllowed, f as createDebugger, q as hash, t as resolveCoverageReporters, u as createIndexLocationsMap, v as getOutputFile, w as groupBy, x as generateCodeFrame, y as printStack, z as getSpecificationDocblock, A as resolveStaticMocks, C as getStaticMocks, R as RangeLocationFilterProvidedError, I as IncludeTaskLocationDisabledError, D as LocationFilterFileNotFoundError, E as GitCommandError, G as GitNotFoundError, H as VitestResolver, M as ModuleTransformService, l as resolveConfig$1, J as createClusterServer, S as ServerModuleRunner, K as attachProjectsFromEntries, N as TestProject, O as resolveAndAttachProjects, Q as RandomSequencer, b as FilesNotFoundError, U as createPool, W as astCollectTests, X as createFailedFileTask, Y as matchesProjectFilter, Z as nanoid, L as Logger, V as VitestPackageInstaller, P as PluginHarness, _ as stdout, p as prompt } from './index.1TqnEahn.js';
5
5
  import { rm, readFile, writeFile, rename, stat, unlink, mkdir, readdir, copyFile } from 'node:fs/promises';
6
6
  import os__default, { tmpdir, hostname } from 'node:os';
7
7
  import { j as join, b as basename, d as dirname, i as isAbsolute, r as resolve, D as noop, e as createDefer, a as relative, c as cleanUrl, s as slash, F as sanitizeFilePath, t as toArray, G as deepMerge, m as isPrimitive, f as extname, n as normalize, p as deepClone } from './pathe.M-eThtNZ.Ba-7h1rE.js';
8
8
  import { T as TraceMap, o as originalPositionFor, p as parseStacktrace, e as parseErrorStacktrace, b as serializeValue } from './source-map.DdKI5IHB.js';
9
- import { v as version } from './cac.DTXWs6Ni.js';
9
+ import { v as version } from './cac.CLrZKo1g.js';
10
10
  import { performance as performance$1 } from 'node:perf_hooks';
11
11
  import { c as createBirpc } from './index.DmDMHCg8.js';
12
12
  import require$$0$3 from 'events';
@@ -25,7 +25,7 @@ import { A as API_PATH, d as defaultBrowserPort } from './constants.-juJ8b_4.js'
25
25
  import { i as isBuiltin } from './modules.BJuCwlRJ.js';
26
26
  import crypto, { createHash } from 'node:crypto';
27
27
  import { distDir } from '../path.js';
28
- import { z as limitConcurrency, A as createTagsFilter } from './run.Cm2sd7-x.js';
28
+ import { z as limitConcurrency, A as createTagsFilter } from './run.BPv-BBRv.js';
29
29
  import { N as NativeModuleRunner } from './nativeModuleRunner.xi64Afb2.js';
30
30
  import { getTestName, hasFailed, hasFailedSnapshot, getTests, getSuites, getTasks, getFullName, createFileTask, generateFileHash, interpretTaskModes, convertTasksToEvents } from '../task-utils.js';
31
31
  import { Traces } from '../traces.js';
@@ -5485,12 +5485,19 @@ class WebSocketReporter {
5485
5485
  class BrowserSessions {
5486
5486
  sessions = /* @__PURE__ */ new Map();
5487
5487
  sessionIds = /* @__PURE__ */ new Set();
5488
+ // a page can outlive the close of its session and reconnect
5489
+ closedSessionIds = /* @__PURE__ */ new Set();
5488
5490
  getSession(sessionId) {
5489
5491
  return this.sessions.get(sessionId);
5490
5492
  }
5491
5493
  destroySession(sessionId) {
5492
5494
  this.sessions.delete(sessionId);
5493
5495
  }
5496
+ close(sessionId) {
5497
+ this.sessions.delete(sessionId);
5498
+ this.sessionIds.delete(sessionId);
5499
+ this.closedSessionIds.add(sessionId);
5500
+ }
5494
5501
  createSession(sessionId, project, pool, options) {
5495
5502
  // this promise waits until the orchestrator is ready to accept RPC calls
5496
5503
  const defer = createDefer();
@@ -11796,7 +11803,7 @@ class TestRun {
11796
11803
  }
11797
11804
  hasFailed(modules) {
11798
11805
  if (!modules.length) return !this.vitest.config.passWithNoTests;
11799
- return modules.some((m) => !m.ok());
11806
+ return modules.some((m) => !m.ok() || m.state() === "pending");
11800
11807
  }
11801
11808
  // make sure the error always has a "stacks" property
11802
11809
  syncUpdateStacks(update) {
@@ -11906,7 +11913,7 @@ class GitVCSProvider {
11906
11913
  if (error instanceof NonZeroExitError) throw new GitCommandError(args, error.output?.stderr.trim() || error.message);
11907
11914
  throw error;
11908
11915
  }
11909
- return result.stdout.split("\n").filter((s) => s !== "").map((changedPath) => resolve(this.root, changedPath));
11916
+ return result.stdout.split("\0").filter((s) => s !== "").map((changedPath) => resolve(this.root, changedPath));
11910
11917
  }
11911
11918
  async findChangedFiles(options) {
11912
11919
  const root = this.root || await this.getRoot(options.root);
@@ -11932,6 +11939,7 @@ class GitVCSProvider {
11932
11939
  return this.resolveFilesWithGitCommand([
11933
11940
  "diff",
11934
11941
  "--name-only",
11942
+ "-z",
11935
11943
  `${hash}...HEAD`
11936
11944
  ]);
11937
11945
  }
@@ -11939,12 +11947,14 @@ class GitVCSProvider {
11939
11947
  return this.resolveFilesWithGitCommand([
11940
11948
  "diff",
11941
11949
  "--cached",
11942
- "--name-only"
11950
+ "--name-only",
11951
+ "-z"
11943
11952
  ]);
11944
11953
  }
11945
11954
  getUnstagedFiles() {
11946
11955
  return this.resolveFilesWithGitCommand([
11947
11956
  "ls-files",
11957
+ "-z",
11948
11958
  "--other",
11949
11959
  "--modified",
11950
11960
  "--exclude-standard"
@@ -13210,11 +13220,16 @@ class Vitest {
13210
13220
  // after the caller already cleaned up the test files
13211
13221
  clearTimeout(this._rerunTimer);
13212
13222
  await this.runningPromise?.catch(noop);
13213
- const teardownProjects = [...this.projects];
13214
- if (this.coreWorkspaceProject && !teardownProjects.includes(this.coreWorkspaceProject)) teardownProjects.push(this.coreWorkspaceProject);
13223
+ const teardownProjects = /* @__PURE__ */ new Set();
13224
+ for (const project of this.projects) {
13225
+ // the project that declares browser instances runs their global setup
13226
+ if (project._instanceParent) teardownProjects.add(project._instanceParent);
13227
+ teardownProjects.add(project);
13228
+ }
13229
+ if (this.coreWorkspaceProject) teardownProjects.add(this.coreWorkspaceProject);
13215
13230
  const teardownErrors = [];
13216
13231
  // do teardown before closing the server
13217
- for (const project of teardownProjects.reverse()) await project._teardownGlobalSetup().catch((error) => {
13232
+ for (const project of [...teardownProjects].reverse()) await project._teardownGlobalSetup().catch((error) => {
13218
13233
  teardownErrors.push(error);
13219
13234
  });
13220
13235
  // close the pool (and the browser pages with it) BEFORE the Vite
@@ -2,7 +2,7 @@ import { existsSync, writeFileSync, readFileSync } from 'node:fs';
2
2
  import { mkdir, writeFile } from 'node:fs/promises';
3
3
  import { resolve, dirname, relative } from 'node:path';
4
4
  import { detectPackageManager, installPackage } from './index.BoyTG_B7.js';
5
- import { p as prompt, n as findConfigFile } from './index.B8VfM7Mf.js';
5
+ import { p as prompt, n as findConfigFile } from './index.1TqnEahn.js';
6
6
  import { x } from 'tinyexec';
7
7
  import { $ } from './tinyrainbow.Do8I1XRG.js';
8
8
  import 'node:process';
@@ -32,7 +32,7 @@ import './display.BlTmubjj.js';
32
32
  import './index.D0heQG4v.js';
33
33
  import 'node:perf_hooks';
34
34
  import './source-map.DdKI5IHB.js';
35
- import './run.Cm2sd7-x.js';
35
+ import './run.BPv-BBRv.js';
36
36
  import '../task-utils.js';
37
37
  import 'obug';
38
38
  import './resolver.CtCcxIy1.js';
@@ -48,7 +48,7 @@ import 'node:events';
48
48
  import './index.DmDMHCg8.js';
49
49
  import 'node:child_process';
50
50
  import 'node:worker_threads';
51
- import './cac.DTXWs6Ni.js';
51
+ import './cac.CLrZKo1g.js';
52
52
  import 'events';
53
53
  import 'readline';
54
54
 
@@ -100,7 +100,7 @@ function log(...args) {
100
100
  console.log(...args);
101
101
  }
102
102
  async function doctor(cliFilters, options) {
103
- const { prepareVitest } = await import('./cli-api.Bx28WXzL.js').then(function (n) { return n.g; });
103
+ const { prepareVitest } = await import('./cli-api.De07GUeT.js').then(function (n) { return n.g; });
104
104
  log();
105
105
  log($.inverse($.bold($.blue(" DOCTOR "))), "resolving the current configuration...");
106
106
  const ctx = await prepareVitest({
@@ -1,6 +1,6 @@
1
1
  import { g as globalApis } from './constants.-juJ8b_4.js';
2
- import { i as index } from './index.uwTEEBsB.js';
3
- import './run.Cm2sd7-x.js';
2
+ import { i as index } from './index.aTZaPVhf.js';
3
+ import './run.BPv-BBRv.js';
4
4
  import './index.D0heQG4v.js';
5
5
  import './tinyrainbow.Do8I1XRG.js';
6
6
  import './display.BlTmubjj.js';
@@ -1,4 +1,4 @@
1
- import { promises, existsSync, mkdirSync, readFileSync, writeFileSync, linkSync, renameSync, rmSync, chmodSync, statfsSync, realpathSync, statSync, readdirSync } from 'node:fs';
1
+ import { promises, existsSync, mkdirSync, writeFileSync, linkSync, renameSync, rmSync, chmodSync, readFileSync, statfsSync, realpathSync, statSync, readdirSync } from 'node:fs';
2
2
  import url, { pathToFileURL, fileURLToPath } from 'node:url';
3
3
  import { c as cleanUrl, r as resolve, f as extname, d as dirname, j as join, h as KNOWN_ASSET_RE, H as withTrailingSlash, I as wrapId, i as isAbsolute, J as isExternalUrl, L as unwrapId, a as relative, z as unique, s as slash, t as toArray, b as basename, m as isPrimitive, n as normalize, G as deepMerge, e as createDefer, p as deepClone } from './pathe.M-eThtNZ.Ba-7h1rE.js';
4
4
  import { N as NativeModuleRunner, i as isPackageExists, r as resolveModule } from './nativeModuleRunner.xi64Afb2.js';
@@ -24,7 +24,7 @@ import { i as inspect } from './display.BlTmubjj.js';
24
24
  import { performance as performance$1 } from 'node:perf_hooks';
25
25
  import { T as TraceMap, o as originalPositionFor, i as generatedPositionFor, j as eachMapping, k as stackIgnorePatterns, e as parseErrorStacktrace } from './source-map.DdKI5IHB.js';
26
26
  import { x } from 'tinyexec';
27
- import { B as validateTags, z as limitConcurrency, C as shuffle } from './run.Cm2sd7-x.js';
27
+ import { B as validateTags, z as limitConcurrency, C as shuffle } from './run.BPv-BBRv.js';
28
28
  import { createDebug } from 'obug';
29
29
  import { createFileTask as createFileTask$1, createTaskName, calculateSuiteHash, convertTasksToEvents, hasFailed, generateFileHash } from '../task-utils.js';
30
30
  import { readFile, mkdir, writeFile, rm, stat } from 'node:fs/promises';
@@ -45,7 +45,7 @@ import EventEmitter$1, { EventEmitter } from 'node:events';
45
45
  import { c as createBirpc } from './index.DmDMHCg8.js';
46
46
  import { fork } from 'node:child_process';
47
47
  import { Worker } from 'node:worker_threads';
48
- import { v as version$1 } from './cac.DTXWs6Ni.js';
48
+ import { v as version$1 } from './cac.CLrZKo1g.js';
49
49
  import { g as getDefaultExportFromCjs } from './index.D0heQG4v.js';
50
50
  import require$$0 from 'readline';
51
51
  import require$$0$1 from 'events';
@@ -1865,7 +1865,12 @@ async function createClusterServer(vitest, viteConfig, config, children) {
1865
1865
  // listen on startup only for `api`/`ui`, otherwise on the first browser launch
1866
1866
  // (collect-only processes never listen, so Vite never starts a dependency scan)
1867
1867
  if (config._apiRequested) await server.listen(config.api.port);
1868
- else deferredListen.set(server, { port: config.api.port });
1868
+ else {
1869
+ deferredListen.set(server, { port: config.api.port });
1870
+ // Vite runs plugin buildStart hooks on listen; global setup and --changed
1871
+ // transform modules before the first browser launch
1872
+ await server.environments.client.pluginContainer.buildStart();
1873
+ }
1869
1874
  contribution.setupRpc(parent);
1870
1875
  return {
1871
1876
  server,
@@ -1883,6 +1888,70 @@ function generateScopedClassName(strategy, name, filename) {
1883
1888
  return `_${name}_${generateCssFilenameHash(filename)}`;
1884
1889
  }
1885
1890
 
1891
+ const API_TOKEN_FILE = ".vitest-secret-token";
1892
+ // Follows env-paths' user data directory conventions:
1893
+ // https://github.com/sindresorhus/env-paths/blob/v4.0.0/index.js
1894
+ function getUserDataDir() {
1895
+ if (process.platform === "win32") return process.env.LOCALAPPDATA || join(homedir(), "AppData/Local");
1896
+ if (process.platform === "darwin") return join(homedir(), "Library/Application Support");
1897
+ return process.env.XDG_DATA_HOME || join(homedir(), ".local/share");
1898
+ }
1899
+ function readPublishedToken(tokenPath) {
1900
+ try {
1901
+ return readFileSync(tokenPath, "utf-8").trim() || void 0;
1902
+ } catch {
1903
+ return;
1904
+ }
1905
+ }
1906
+ function resolveTokenFromPath(tokenPath) {
1907
+ const published = readPublishedToken(tokenPath);
1908
+ if (published) return {
1909
+ token: published,
1910
+ tokenCreated: false
1911
+ };
1912
+ const dir = dirname(tokenPath);
1913
+ mkdirSync(dir, {
1914
+ recursive: true,
1915
+ mode: 448
1916
+ });
1917
+ const token = crypto.randomUUID();
1918
+ const pendingPath = join(dir, `${API_TOKEN_FILE}.${process.pid}.${crypto.randomUUID()}`);
1919
+ writeFileSync(pendingPath, `${token}\n`, { mode: 384 });
1920
+ let tokenCreated = true;
1921
+ try {
1922
+ // linking fails when another process already published, which keeps a single winner
1923
+ linkSync(pendingPath, tokenPath);
1924
+ } catch (error) {
1925
+ if (error.code === "EEXIST") tokenCreated = false;
1926
+ else renameSync(pendingPath, tokenPath);
1927
+ } finally {
1928
+ rmSync(pendingPath, { force: true });
1929
+ }
1930
+ const winner = readPublishedToken(tokenPath);
1931
+ if (!tokenCreated && !winner) {
1932
+ writeFileSync(tokenPath, `${token}\n`, { mode: 384 });
1933
+ tokenCreated = true;
1934
+ }
1935
+ try {
1936
+ chmodSync(dir, 448);
1937
+ chmodSync(tokenPath, 384);
1938
+ } catch {}
1939
+ return {
1940
+ token: (tokenCreated ? token : winner) ?? token,
1941
+ tokenCreated
1942
+ };
1943
+ }
1944
+ function resolveApiToken(root) {
1945
+ const tokenPaths = [join(getUserDataDir(), "vitest", API_TOKEN_FILE), join(searchForWorkspaceRoot(root), "node_modules/.vitest", API_TOKEN_FILE)];
1946
+ for (const tokenPath of tokenPaths) try {
1947
+ return {
1948
+ ...resolveTokenFromPath(tokenPath),
1949
+ tokenPath
1950
+ };
1951
+ } catch {}
1952
+ throw new Error(`Failed to create Vitest API token at ${tokenPaths.join(" or ")}`);
1953
+ }
1954
+
1886
1955
  function resolveTestCacheDir(root, testConfig, viteCacheDir) {
1887
1956
  const name = testConfig.name;
1888
1957
  const label = typeof name === "string" ? name : name?.label || "";
@@ -1976,6 +2045,23 @@ function deleteDefineConfig(viteConfig) {
1976
2045
  scriptDefines
1977
2046
  };
1978
2047
  }
2048
+ // TODO: use Vite's own defaults once they are exported (request upstream)
2049
+ // copied from Vite 8.3 https://github.com/vitejs/vite/blob/v8.3.4/packages/vite/src/node/server/index.ts#L1254-L1261
2050
+ const VITE_DEFAULT_FS_DENY = [
2051
+ ".env",
2052
+ ".env.*",
2053
+ "*.{crt,pem,key,p12,pfx,cer,der}",
2054
+ ".npmrc",
2055
+ ".yarnrc.yml",
2056
+ "**/.git/**"
2057
+ ];
2058
+ // Vite drops its default `server.fs.deny` once any value is set,
2059
+ // so the defaults are kept explicitly when the user didn't set one.
2060
+ function appendApiTokenFsDeny(viteConfig) {
2061
+ viteConfig.server ??= {};
2062
+ viteConfig.server.fs ??= {};
2063
+ viteConfig.server.fs.deny = [...viteConfig.server.fs.deny ?? VITE_DEFAULT_FS_DENY, API_TOKEN_FILE];
2064
+ }
1979
2065
  function resolveFsAllow(projectRoot, rootConfigFile) {
1980
2066
  if (!rootConfigFile) return [searchForWorkspaceRoot(projectRoot), rootDir];
1981
2067
  return [
@@ -3558,6 +3644,7 @@ function VitestCorePlugin(harness) {
3558
3644
  order: "post",
3559
3645
  handler(viteConfig) {
3560
3646
  const root = resolve(viteConfig.test?.root || viteConfig.root || process.cwd());
3647
+ appendApiTokenFsDeny(viteConfig);
3561
3648
  return {
3562
3649
  base: "/",
3563
3650
  root,
@@ -3783,70 +3870,6 @@ function processWildcard(dep, moduleDirectories) {
3783
3870
  return dep;
3784
3871
  }
3785
3872
 
3786
- const API_TOKEN_FILE = ".vitest-secret-token";
3787
- // Follows env-paths' user data directory conventions:
3788
- // https://github.com/sindresorhus/env-paths/blob/v4.0.0/index.js
3789
- function getUserDataDir() {
3790
- if (process.platform === "win32") return process.env.LOCALAPPDATA || join(homedir(), "AppData/Local");
3791
- if (process.platform === "darwin") return join(homedir(), "Library/Application Support");
3792
- return process.env.XDG_DATA_HOME || join(homedir(), ".local/share");
3793
- }
3794
- function readPublishedToken(tokenPath) {
3795
- try {
3796
- return readFileSync(tokenPath, "utf-8").trim() || void 0;
3797
- } catch {
3798
- return;
3799
- }
3800
- }
3801
- function resolveTokenFromPath(tokenPath) {
3802
- const published = readPublishedToken(tokenPath);
3803
- if (published) return {
3804
- token: published,
3805
- tokenCreated: false
3806
- };
3807
- const dir = dirname(tokenPath);
3808
- mkdirSync(dir, {
3809
- recursive: true,
3810
- mode: 448
3811
- });
3812
- const token = crypto.randomUUID();
3813
- const pendingPath = join(dir, `${API_TOKEN_FILE}.${process.pid}.${crypto.randomUUID()}`);
3814
- writeFileSync(pendingPath, `${token}\n`, { mode: 384 });
3815
- let tokenCreated = true;
3816
- try {
3817
- // linking fails when another process already published, which keeps a single winner
3818
- linkSync(pendingPath, tokenPath);
3819
- } catch (error) {
3820
- if (error.code === "EEXIST") tokenCreated = false;
3821
- else renameSync(pendingPath, tokenPath);
3822
- } finally {
3823
- rmSync(pendingPath, { force: true });
3824
- }
3825
- const winner = readPublishedToken(tokenPath);
3826
- if (!tokenCreated && !winner) {
3827
- writeFileSync(tokenPath, `${token}\n`, { mode: 384 });
3828
- tokenCreated = true;
3829
- }
3830
- try {
3831
- chmodSync(dir, 448);
3832
- chmodSync(tokenPath, 384);
3833
- } catch {}
3834
- return {
3835
- token: (tokenCreated ? token : winner) ?? token,
3836
- tokenCreated
3837
- };
3838
- }
3839
- function resolveApiToken(root) {
3840
- const tokenPaths = [join(getUserDataDir(), "vitest", API_TOKEN_FILE), join(searchForWorkspaceRoot(root), "node_modules/.vitest", API_TOKEN_FILE)];
3841
- for (const tokenPath of tokenPaths) try {
3842
- return {
3843
- ...resolveTokenFromPath(tokenPath),
3844
- tokenPath
3845
- };
3846
- } catch {}
3847
- throw new Error(`Failed to create Vitest API token at ${tokenPaths.join(" or ")}`);
3848
- }
3849
-
3850
3873
  function ProjectRootPlugin(projectRoot) {
3851
3874
  return {
3852
3875
  name: "vitest:project-root",
@@ -3872,16 +3895,14 @@ function WorkspaceVitestPlugin(harness, globalViteConfig) {
3872
3895
  config(viteConfig) {
3873
3896
  const testConfig = viteConfig.test || {};
3874
3897
  const root = testConfig.root || viteConfig.root;
3898
+ appendApiTokenFsDeny(viteConfig);
3875
3899
  return {
3876
3900
  base: "/",
3877
3901
  root,
3878
3902
  cacheDir: resolveTestCacheDir(resolve(root || process.cwd()), testConfig, viteConfig.cacheDir),
3879
3903
  server: {
3880
3904
  open: false,
3881
- fs: {
3882
- allow: globalViteConfig.server.fs.allow,
3883
- deny: [API_TOKEN_FILE]
3884
- }
3905
+ fs: { allow: globalViteConfig.server.fs.allow }
3885
3906
  }
3886
3907
  };
3887
3908
  },
@@ -4272,7 +4293,7 @@ class RangeLocationFilterProvidedError extends Error {
4272
4293
  }
4273
4294
 
4274
4295
  const debug$1 = createDebugger("vitest:browser:pool");
4275
- const PROVIDER_CLOSE_TIMEOUT = 1e4;
4296
+ const PROVIDER_CLOSE_TIMEOUT = 3e4;
4276
4297
  function createBrowserPool(vitest) {
4277
4298
  // every browser instance is a worker; at most `maxWorkers` of them are open
4278
4299
  const workers = /* @__PURE__ */ new Map();
@@ -4420,7 +4441,9 @@ function createBrowserPool(vitest) {
4420
4441
  await Promise.all([...stopping, ...exitPromises]);
4421
4442
  // pages can be opened outside of the pool (`vitest.standalone`)
4422
4443
  await Promise.all(vitest.projects.map((project) => closeProvider(project)));
4423
- vitest._browserSessions.sessionIds.clear();
4444
+ vitest._browserSessions.sessionIds.forEach((sessionId) => {
4445
+ vitest._browserSessions.close(sessionId);
4446
+ });
4424
4447
  vitest.projects.forEach((project) => {
4425
4448
  project.browser?.state.orchestrators.forEach((orchestrator) => {
4426
4449
  orchestrator.$close();
@@ -4638,8 +4661,7 @@ class BrowserWorker {
4638
4661
  this.busySessions.clear();
4639
4662
  this.readySessions.clear();
4640
4663
  await closeProvider(this.project, options);
4641
- // the pages are closed now, so a late reconnect is not reported as an unknown session
4642
- sessionIds.forEach((sessionId) => sessions.sessionIds.delete(sessionId));
4664
+ sessionIds.forEach((sessionId) => sessions.close(sessionId));
4643
4665
  orchestrators.forEach((orchestrator) => orchestrator?.$close());
4644
4666
  }
4645
4667
  async openPage(sessionId, options) {
@@ -6478,10 +6500,8 @@ class TestProject {
6478
6500
  */
6479
6501
  getProvidedContext() {
6480
6502
  if (this.isRootProject()) return this._provided;
6481
- // globalSetup can run even if core workspace is not part of the test run
6482
- // so we need to inherit its provided context
6483
6503
  return {
6484
- ...this.vitest.getRootProject().getProvidedContext(),
6504
+ ...(this._instanceParent ?? this.vitest.getRootProject()).getProvidedContext(),
6485
6505
  ...this._provided
6486
6506
  };
6487
6507
  }
@@ -6534,10 +6554,14 @@ class TestProject {
6534
6554
  /** @internal */
6535
6555
  async _initializeGlobalSetup() {
6536
6556
  if (this._globalSetups) return;
6557
+ // the project that declares browser instances runs their inherited global setup once
6558
+ const parent = this._instanceParent;
6559
+ await parent?._initializeGlobalSetup();
6560
+ const globalSetup = parent ? toArray(this.config.globalSetup).filter((file) => !parent.config.globalSetup.includes(file)) : this.config.globalSetup;
6537
6561
  const native = this.runner instanceof NativeModuleRunner;
6538
6562
  // global setup is imported by this process, so its imports are only known to a resolve hook
6539
6563
  const canRecord = !native || !this.vitest.config.experimental.recordDependencies || !this.config.globalSetup.length || trackNativeImports();
6540
- this._globalSetups = await loadGlobalSetupFiles(this.runner, this.config.globalSetup);
6564
+ this._globalSetups = await loadGlobalSetupFiles(this.runner, globalSetup);
6541
6565
  if (canRecord) this.vitest.cache._dependencies.recordGlobalSetup(this, collectDependencies(native ? nativeImports.getImports : getEvaluatedImports(this.runner.evaluatedModules), this.config.globalSetup));
6542
6566
  for (const globalSetupFile of this._globalSetups) {
6543
6567
  const teardown = await globalSetupFile.setup?.(this);
@@ -6655,6 +6679,10 @@ class TestProject {
6655
6679
  _parentBrowser;
6656
6680
  /** @internal */
6657
6681
  _parent;
6682
+ /** @internal */
6683
+ get _instanceParent() {
6684
+ return this._parent?._parentBrowser ? this._parent : void 0;
6685
+ }
6658
6686
  /**
6659
6687
  * Closes the project and all associated resources. This can only be called once; the closing promise is cached until the server restarts.
6660
6688
  * If the resources are needed again, create a new project.
@@ -9242,7 +9270,6 @@ async function resolveConfig(options = {}, viteOverrides = {}, pluginsHarness =
9242
9270
  const rootConfig = resolveTestConfig(pluginsHarness.logger, rootViteConfig.test || {}, rootViteConfig);
9243
9271
  rootViteConfig.test = rootConfig;
9244
9272
  rootViteConfig.server.fs.allow.push(...resolveFsAllow(rootViteConfig.root, rootViteConfig.configFile));
9245
- rootViteConfig.server.fs.deny.push(API_TOKEN_FILE);
9246
9273
  // the server has been created, we don't need to override vite.server options
9247
9274
  const { token, tokenCreated } = resolveApiToken(rootViteConfig.root);
9248
9275
  rootConfig.api.token = token;
@@ -48,7 +48,9 @@ class BareModuleMocker {
48
48
  return this.registries.get(suite);
49
49
  }
50
50
  reset() {
51
+ for (const registry of this.registries.values()) for (const url of registry.keys()) this.invalidateModuleById(registry.get(url).id);
51
52
  this.registries.clear();
53
+ BareModuleMocker.pendingIds = [];
52
54
  }
53
55
  invalidateModuleById(_id) {
54
56
  // implemented by mockers that control the module runner
@@ -304,9 +306,6 @@ class VitestMocker extends BareModuleMocker {
304
306
  if (this.spyModule) return;
305
307
  this.spyModule = await this.moduleRunner.import(spyModulePath);
306
308
  }
307
- reset() {
308
- this.registries.clear();
309
- }
310
309
  invalidateModuleById(id) {
311
310
  const mockId = this.getMockPath(id);
312
311
  const node = this.evaluatedModules.getModuleById(mockId);
@@ -373,7 +372,7 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
373
372
  const Object = this.primitives.Object;
374
373
  return this.mockObject(mod, Object.create(Object.prototype), mock.type);
375
374
  }
376
- if (mock.type === "manual") return this.callFunctionMock(id, url, mock);
375
+ if (mock.type === "manual") return this.callFunctionMock(this.getMockPath(id), this.getMockPath(url), mock);
377
376
  const node = await this.moduleRunner.fetchModule(mock.redirect);
378
377
  return this.moduleRunner.cachedRequest(mock.redirect, node, [importer], void 0, true);
379
378
  }
@@ -578,7 +577,6 @@ class VitestModuleRunner extends viteModuleRunner.ModuleRunner {
578
577
  if (ignoreMock) return this._cachedRequest(url, mod, callstack, metadata);
579
578
  let mocked;
580
579
  if (mod.meta && "mockedModule" in mod.meta) {
581
- const mockedModule = mod.meta.mockedModule;
582
580
  const mockId = this.mocker.getMockPath(mod.id);
583
581
  const currentMock = this.mocker.getDependencyMock(mod.id);
584
582
  // bypass mock and force "importActual" behavior when:
@@ -591,7 +589,7 @@ class VitestModuleRunner extends viteModuleRunner.ModuleRunner {
591
589
  const node = await this.fetchModule(injectQuery(url, "_vitest_original"));
592
590
  return this._cachedRequest(node.url, node, callstack, metadata);
593
591
  }
594
- if ((currentMock.type === "automock" || currentMock.type === "autospy") && currentMock !== mockedModule) {
592
+ if (currentMock.type === "automock" || currentMock.type === "autospy") {
595
593
  const freshNode = await this.fetchModule(injectQuery(url, "_vitest_original"));
596
594
  mocked = await this.mocker.requestWithMockedModule(url, freshNode, callstack, currentMock);
597
595
  } else mocked = await this.mocker.requestWithMockedModule(url, mod, callstack, currentMock);
@@ -769,7 +767,8 @@ function startVitestModuleRunner(options) {
769
767
  id: resolvedMock.id,
770
768
  url: resolvedMock.url,
771
769
  invalidate: false,
772
- mockedModule: resolvedMock
770
+ // the module node outlives the test file, so it must not keep the mock factory alive
771
+ mockedModule: true
773
772
  };
774
773
  }
775
774
  if (isBuiltin(rawId)) return {
@@ -2,9 +2,9 @@ import * as chai from 'chai';
2
2
  import { createHook } from 'node:async_hooks';
3
3
  import { t as takeCoverageInsideWorker } from './coverage.-bm5IxnW.js';
4
4
  import { r as rpc } from './rpc.DpkUyY1N.js';
5
- import { l as loadDiffConfig, a as loadSnapshotSerializers } from './setup-common.BABL3z3m.js';
5
+ import { l as loadDiffConfig, a as loadSnapshotSerializers } from './setup-common.HGAqWOnX.js';
6
6
  import { g as getWorkerState } from './utils.DYj33du9.js';
7
- import { T as TestRunner } from './index.uwTEEBsB.js';
7
+ import { T as TestRunner } from './index.aTZaPVhf.js';
8
8
 
9
9
  function setupChaiConfig(config) {
10
10
  Object.assign(chai.config, config);
@@ -50,6 +50,8 @@ function detectAsyncLeaks(testFile, projectName) {
50
50
  } finally {
51
51
  Error.stackTraceLimit = limit;
52
52
  }
53
+ // a builtin loaded on first use can create pending promises at the module level
54
+ if (stack.includes("node:internal/bootstrap/realm")) return;
53
55
  if (!stack.includes(testFile)) {
54
56
  const trigger = resources.get(triggerAsyncId);
55
57
  if (!trigger) return;
@@ -1,4 +1,4 @@
1
- import { b as printDiffOrStringify, d as diff, a as processError, T as TestSyntaxError, g as getCurrentTest, c as createTaskCollector, e as getCurrentSuite, f as createChainable, h as getHooks, i as getFn, m as matchesTags, j as afterAll, k as afterEach, l as aroundAll, n as aroundEach, o as beforeAll, q as beforeEach, r as describe, t as it, u as onTestFailed, v as onTestFinished, w as recordArtifact, x as suite, y as test } from './run.Cm2sd7-x.js';
1
+ import { b as printDiffOrStringify, d as diff, a as processError, T as TestSyntaxError, g as getCurrentTest, c as createTaskCollector, e as getCurrentSuite, f as createChainable, h as getHooks, i as getFn, m as matchesTags, j as afterAll, k as afterEach, l as aroundAll, n as aroundEach, o as beforeAll, q as beforeEach, r as describe, t as it, u as onTestFailed, v as onTestFinished, w as recordArtifact, x as suite, y as test } from './run.BPv-BBRv.js';
2
2
  import { i as isChildProcess, r as resetModules, g as getWorkerState } from './utils.DYj33du9.js';
3
3
  import { e as parseErrorStacktrace, a as getSafeTimers, f as parseSingleStack, h as delay } from './source-map.DdKI5IHB.js';
4
4
  import { i as isMockFunction, f as fn, a as spyOn, r as restoreAllMocks, b as resetAllMocks, c as clearAllMocks } from './spy.DDMXghXv.js';
@@ -1,4 +1,4 @@
1
- import { i as init } from './init.DrHtV5zd.js';
1
+ import { i as init } from './init.PvxYpuCm.js';
2
2
 
3
3
  if (!process.send) throw new Error("Expected worker to be run in node:child_process");
4
4
  // Store globals in case tests overwrite them
@@ -1,5 +1,5 @@
1
1
  import { isMainThread, parentPort } from 'node:worker_threads';
2
- import { i as init } from './init.DrHtV5zd.js';
2
+ import { i as init } from './init.PvxYpuCm.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) {