vitest 4.0.0-beta.9 → 4.0.1

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 (83) hide show
  1. package/LICENSE.md +86 -102
  2. package/browser/context.d.ts +7 -0
  3. package/browser/context.js +20 -0
  4. package/dist/browser.d.ts +24 -7
  5. package/dist/browser.js +15 -5
  6. package/dist/chunks/{base.CA5N8Af0.js → base.BYPMk0VN.js} +36 -36
  7. package/dist/chunks/{benchmark.CJUa-Hsa.js → benchmark.DHKMYAts.js} +2 -2
  8. package/dist/chunks/{browser.d.DtfyY9yS.d.ts → browser.d.B9iJzZyn.d.ts} +3 -3
  9. package/dist/chunks/{cac.Dt7e1TIu.js → cac.DrF4Gm0S.js} +47 -73
  10. package/dist/chunks/{cli-api.eAzsLIxz.js → cli-api.W2Q-JQoO.js} +1524 -296
  11. package/dist/chunks/{config.d.DacWrqWe.d.ts → config.d.u2CUDWwS.d.ts} +5 -19
  12. package/dist/chunks/{console.7h5kHUIf.js → console.CTJL2nuH.js} +4 -6
  13. package/dist/chunks/{coverage.CDRAMTt7.js → coverage.FU3w4IrQ.js} +125 -1108
  14. package/dist/chunks/{creator.KEg6n5IC.js → creator.DucAaYBz.js} +10 -37
  15. package/dist/chunks/{defaults.CXFFjsi8.js → defaults.BOqNVLsY.js} +0 -1
  16. package/dist/chunks/environment.d.CrsxCzP1.d.ts +29 -0
  17. package/dist/chunks/evaluatedModules.Dg1zASAC.js +17 -0
  18. package/dist/chunks/{global.d.K6uBQHzY.d.ts → global.d.BgJSTpgQ.d.ts} +2 -17
  19. package/dist/chunks/{globals.CJrTTbxC.js → globals.BGT_RUsD.js} +11 -7
  20. package/dist/chunks/{index.BjKEiSn0.js → index.BdSLhLDZ.js} +3 -3
  21. package/dist/chunks/{index.DfviD7lX.js → index.CbWINfS7.js} +49 -21
  22. package/dist/chunks/{index.BIP7prJq.js → index.CcRZ6fUh.js} +1493 -114
  23. package/dist/chunks/{index.X0nbfr6-.js → index.Dc3xnDvT.js} +48 -289
  24. package/dist/chunks/{index.C832ioot.js → index.RwjEGCQ0.js} +4 -4
  25. package/dist/chunks/init-forks.WglB-sfY.js +54 -0
  26. package/dist/chunks/init-threads.Czek6eA5.js +17 -0
  27. package/dist/chunks/init.94FWN9pW.js +213 -0
  28. package/dist/chunks/{inspector.CvQD-Nie.js → inspector.DLZxSeU3.js} +2 -6
  29. package/dist/chunks/{moduleRunner.d.DxTLreRD.d.ts → moduleRunner.d.YtNsMIoJ.d.ts} +9 -14
  30. package/dist/chunks/{node.CyipiPvJ.js → node.BwAWWjHZ.js} +3 -4
  31. package/dist/chunks/{plugin.d.CIk0YiKb.d.ts → plugin.d.DQU1R5px.d.ts} +1 -1
  32. package/dist/chunks/{reporters.d.DmP-iHLr.d.ts → reporters.d.BMKt7f6I.d.ts} +1064 -1021
  33. package/dist/chunks/{resolveSnapshotEnvironment.Bvv2zr69.js → resolveSnapshotEnvironment.DJJKMKxb.js} +7 -8
  34. package/dist/chunks/{rpc.BKr6mtxz.js → rpc.cD77ENhU.js} +13 -14
  35. package/dist/chunks/{setup-common.B7I37Tji.js → setup-common.DR1sucx6.js} +6 -6
  36. package/dist/chunks/{startModuleRunner.BDRvKSdz.js → startModuleRunner.iF1E9Bt4.js} +126 -110
  37. package/dist/chunks/{test.BAlBebnP.js → test.C3RPt8JR.js} +7 -7
  38. package/dist/chunks/{utils.D2R2NiOH.js → utils.CG9h5ccR.js} +2 -5
  39. package/dist/chunks/{vi.BB37KeLx.js → vi.BZvkKVkM.js} +61 -164
  40. package/dist/chunks/{vm.CjLTDaST.js → vm.CuMWYx_F.js} +20 -29
  41. package/dist/chunks/{worker.d.B2r4Ln6p.d.ts → worker.d.BFk-vvBU.d.ts} +42 -6
  42. package/dist/cli.js +12 -11
  43. package/dist/config.cjs +0 -1
  44. package/dist/config.d.ts +11 -13
  45. package/dist/config.js +1 -1
  46. package/dist/coverage.d.ts +7 -6
  47. package/dist/coverage.js +3 -14
  48. package/dist/environments.d.ts +3 -6
  49. package/dist/environments.js +1 -1
  50. package/dist/index.d.ts +20 -25
  51. package/dist/index.js +11 -7
  52. package/dist/module-evaluator.d.ts +5 -4
  53. package/dist/module-evaluator.js +11 -13
  54. package/dist/module-runner.js +5 -5
  55. package/dist/node.d.ts +82 -25
  56. package/dist/node.js +23 -20
  57. package/dist/reporters.d.ts +10 -9
  58. package/dist/reporters.js +12 -11
  59. package/dist/runners.d.ts +1 -1
  60. package/dist/runners.js +9 -7
  61. package/dist/snapshot.js +3 -3
  62. package/dist/suite.js +4 -3
  63. package/dist/worker.d.ts +26 -0
  64. package/dist/worker.js +45 -165
  65. package/dist/workers/forks.js +26 -43
  66. package/dist/workers/runVmTests.js +16 -12
  67. package/dist/workers/threads.js +26 -31
  68. package/dist/workers/vmForks.js +26 -39
  69. package/dist/workers/vmThreads.js +26 -29
  70. package/package.json +48 -32
  71. package/worker.d.ts +1 -0
  72. package/browser.d.ts +0 -1
  73. package/dist/chunks/environment.d.2fYMoz3o.d.ts +0 -66
  74. package/dist/chunks/moduleTransport.I-bgQy0S.js +0 -19
  75. package/dist/chunks/resolver.Bx6lE0iq.js +0 -119
  76. package/dist/chunks/typechecker.DB-fIMaH.js +0 -805
  77. package/dist/chunks/utils.C2YI6McM.js +0 -52
  78. package/dist/chunks/worker.d.DJ6qxO2w.d.ts +0 -8
  79. package/dist/workers.d.ts +0 -38
  80. package/dist/workers.js +0 -49
  81. package/execute.d.ts +0 -1
  82. package/utils.d.ts +0 -1
  83. package/workers.d.ts +0 -1
@@ -1,58 +1,26 @@
1
- import fs, { statSync, realpathSync, promises as promises$1, mkdirSync, existsSync, readdirSync, writeFileSync } from 'node:fs';
2
- import path, { win32, dirname, join, resolve } from 'node:path';
3
- import { isExternalUrl, unwrapId, nanoid, withTrailingSlash as withTrailingSlash$1, cleanUrl, wrapId, createDefer, slash, shuffle, toArray } from '@vitest/utils';
4
- import { isAbsolute, join as join$1, dirname as dirname$1, resolve as resolve$1, relative, normalize } from 'pathe';
1
+ import fs, { statSync, realpathSync, existsSync, promises, readdirSync, writeFileSync } from 'node:fs';
2
+ import path, { win32, dirname, join } from 'node:path';
3
+ import { slash, shuffle, toArray, cleanUrl } from '@vitest/utils/helpers';
4
+ import { isAbsolute, resolve, relative, normalize } from 'pathe';
5
5
  import pm from 'picomatch';
6
6
  import { glob } from 'tinyglobby';
7
7
  import c from 'tinyrainbow';
8
- import { c as configDefaults, e as benchmarkConfigDefaults, a as coverageConfigDefaults } from './defaults.CXFFjsi8.js';
8
+ import { c as configDefaults, e as benchmarkConfigDefaults, a as coverageConfigDefaults } from './defaults.BOqNVLsY.js';
9
9
  import crypto from 'node:crypto';
10
10
  import { builtinModules, createRequire } from 'node:module';
11
11
  import process$1 from 'node:process';
12
- import fs$1, { writeFile, rename, stat, unlink } from 'node:fs/promises';
12
+ import fs$1 from 'node:fs/promises';
13
13
  import { fileURLToPath as fileURLToPath$1, pathToFileURL as pathToFileURL$1, URL as URL$1 } from 'node:url';
14
14
  import assert from 'node:assert';
15
15
  import v8 from 'node:v8';
16
16
  import { format, inspect } from 'node:util';
17
- import { fetchModule, version, mergeConfig } from 'vite';
17
+ import { mergeConfig } from 'vite';
18
18
  import { c as configFiles, d as defaultBrowserPort, b as defaultInspectPort, a as defaultPort } from './constants.D_Q9UYh-.js';
19
- import { a as isWindows } from './env.D4Lgay0q.js';
20
- import * as nodeos from 'node:os';
21
- import nodeos__default, { tmpdir } from 'node:os';
22
- import { isatty } from 'node:tty';
23
- import EventEmitter from 'node:events';
24
- import { c as createBirpc } from './index.Bgo3tNWt.js';
25
- import Tinypool$1, { Tinypool } from 'tinypool';
26
- import { w as wrapSerializableConfig, a as Typechecker } from './typechecker.DB-fIMaH.js';
27
- import { MessageChannel } from 'node:worker_threads';
28
- import { hasFailed } from '@vitest/runner/utils';
29
- import { rootDir } from '../path.js';
19
+ import './env.D4Lgay0q.js';
20
+ import nodeos__default from 'node:os';
30
21
  import { isCI, provider } from 'std-env';
31
22
  import { r as resolveCoverageProviderModule } from './coverage.D_JHT54q.js';
32
23
 
33
- function groupBy(collection, iteratee) {
34
- return collection.reduce((acc, item) => {
35
- const key = iteratee(item);
36
- return acc[key] ||= [], acc[key].push(item), acc;
37
- }, {});
38
- }
39
- function stdout() {
40
- // @ts-expect-error Node.js maps process.stdout to console._stdout
41
- // eslint-disable-next-line no-console
42
- return console._stdout || process.stdout;
43
- }
44
- function escapeRegExp(s) {
45
- // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
46
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
47
- }
48
- function wildcardPatternToRegExp(pattern) {
49
- const negated = pattern.startsWith("!");
50
- if (negated) pattern = pattern.slice(1);
51
- let regexp = `${pattern.split("*").map(escapeRegExp).join(".*")}$`;
52
- if (negated) regexp = `(?!${regexp})`;
53
- return new RegExp(`^${regexp}`, "i");
54
- }
55
-
56
24
  const hash = crypto.hash ?? ((algorithm, data, outputEncoding) => crypto.createHash(algorithm).update(data).digest(outputEncoding));
57
25
 
58
26
  const JOIN_LEADING_SLASH_RE = /^\.?\//;
@@ -2014,7 +1982,7 @@ function normalizeid(id) {
2014
1982
  if (typeof id !== "string") {
2015
1983
  id = id.toString();
2016
1984
  }
2017
- if (/(node|data|http|https|file):/.test(id)) {
1985
+ if (/(?:node|data|http|https|file):/.test(id)) {
2018
1986
  return id;
2019
1987
  }
2020
1988
  if (BUILTIN_MODULES.has(id)) {
@@ -2048,7 +2016,7 @@ function _resolve$1(id, options = {}) {
2048
2016
  throw new TypeError("input must be a `string` or `URL`");
2049
2017
  }
2050
2018
  }
2051
- if (/(node|data|http|https):/.test(id)) {
2019
+ if (/(?:node|data|http|https):/.test(id)) {
2052
2020
  return id;
2053
2021
  }
2054
2022
  if (BUILTIN_MODULES.has(id)) {
@@ -2386,970 +2354,6 @@ function getWorkersCountByPercentage(percent) {
2386
2354
  return Math.max(1, Math.min(maxWorkersCount, workersCountByPercentage));
2387
2355
  }
2388
2356
 
2389
- const envsOrder = [
2390
- "node",
2391
- "jsdom",
2392
- "happy-dom",
2393
- "edge-runtime"
2394
- ];
2395
- async function groupFilesByEnv(files) {
2396
- const filesWithEnv = await Promise.all(files.map(async ({ moduleId: filepath, project, testLines }) => {
2397
- const code = await promises$1.readFile(filepath, "utf-8");
2398
- // 1. Check for control comments in the file
2399
- let env = code.match(/@(?:vitest|jest)-environment\s+([\w-]+)\b/)?.[1];
2400
- // 2. Fallback to global env
2401
- env ||= project.config.environment || "node";
2402
- let envOptionsJson = code.match(/@(?:vitest|jest)-environment-options\s+(.+)/)?.[1];
2403
- if (envOptionsJson?.endsWith("*/"))
2404
- // Trim closing Docblock characters the above regex might have captured
2405
- envOptionsJson = envOptionsJson.slice(0, -2);
2406
- const envOptions = JSON.parse(envOptionsJson || "null"), envKey = env === "happy-dom" ? "happyDOM" : env, environment = {
2407
- name: env,
2408
- options: envOptions ? { [envKey]: envOptions } : null
2409
- };
2410
- return {
2411
- file: {
2412
- filepath,
2413
- testLocations: testLines
2414
- },
2415
- project,
2416
- environment
2417
- };
2418
- }));
2419
- return groupBy(filesWithEnv, ({ environment }) => environment.name);
2420
- }
2421
-
2422
- const created = /* @__PURE__ */ new Set(), promises = /* @__PURE__ */ new Map();
2423
- function createFetchModuleFunction(resolver, cacheFs = false, tmpDir = join$1(tmpdir(), nanoid())) {
2424
- const cachedFsResults = /* @__PURE__ */ new Map();
2425
- return async (url, importer, environment, options) => {
2426
- // We are copy pasting Vite's externalization logic from `fetchModule` because
2427
- // we instead rely on our own `shouldExternalize` method because Vite
2428
- // doesn't support `resolve.external` in non SSR environments (jsdom/happy-dom)
2429
- if (url.startsWith("data:")) return {
2430
- externalize: url,
2431
- type: "builtin"
2432
- };
2433
- if (url === "/@vite/client" || url === "@vite/client")
2434
- // this will be stubbed
2435
- return {
2436
- externalize: "/@vite/client",
2437
- type: "module"
2438
- };
2439
- const isFileUrl = url.startsWith("file://");
2440
- if (isExternalUrl(url) && !isFileUrl) return {
2441
- externalize: url,
2442
- type: "network"
2443
- };
2444
- // Vite does the same in `fetchModule`, but we want to externalize modules ourselves,
2445
- // so we do this first to resolve the module and check its `id`. The next call of
2446
- // `ensureEntryFromUrl` inside `fetchModule` is cached and should take no time
2447
- // This also makes it so externalized modules are inside the module graph.
2448
- const moduleGraphModule = await environment.moduleGraph.ensureEntryFromUrl(unwrapId(url)), cached = !!moduleGraphModule.transformResult;
2449
- // if url is already cached, we can just confirm it's also cached on the server
2450
- if (options?.cached && cached) return { cache: true };
2451
- if (moduleGraphModule.id) {
2452
- const externalize = await resolver.shouldExternalize(moduleGraphModule.id);
2453
- if (externalize) return {
2454
- externalize,
2455
- type: "module"
2456
- };
2457
- }
2458
- const moduleRunnerModule = await fetchModule(environment, url, importer, {
2459
- ...options,
2460
- inlineSourceMap: false
2461
- }).catch(handleRollupError), result = processResultSource(environment, moduleRunnerModule);
2462
- if (!cacheFs || !("code" in result)) return result;
2463
- const code = result.code;
2464
- // to avoid serialising large chunks of code,
2465
- // we store them in a tmp file and read in the test thread
2466
- if (cachedFsResults.has(result.id)) return getCachedResult(result, cachedFsResults);
2467
- const dir = join$1(tmpDir, environment.name), name = hash("sha1", result.id, "hex"), tmp = join$1(dir, name);
2468
- if (!created.has(dir)) mkdirSync(dir, { recursive: true }), created.add(dir);
2469
- return promises.has(tmp) ? (await promises.get(tmp), cachedFsResults.set(result.id, tmp), getCachedResult(result, cachedFsResults)) : (promises.set(tmp, atomicWriteFile(tmp, code).catch(() => writeFile(tmp, code, "utf-8")).finally(() => promises.delete(tmp))), await promises.get(tmp), cachedFsResults.set(result.id, tmp), getCachedResult(result, cachedFsResults));
2470
- };
2471
- }
2472
- let SOURCEMAPPING_URL = "sourceMa";
2473
- SOURCEMAPPING_URL += "ppingURL";
2474
- const MODULE_RUNNER_SOURCEMAPPING_SOURCE = "//# sourceMappingSource=vite-generated";
2475
- function processResultSource(environment, result) {
2476
- if (!("code" in result)) return result;
2477
- const node = environment.moduleGraph.getModuleById(result.id);
2478
- if (node?.transformResult)
2479
- // this also overrides node.transformResult.code which is also what the module
2480
- // runner does under the hood by default (we disable source maps inlining)
2481
- inlineSourceMap(node.transformResult);
2482
- return {
2483
- ...result,
2484
- code: node?.transformResult?.code || result.code
2485
- };
2486
- }
2487
- const OTHER_SOURCE_MAP_REGEXP = new RegExp(`//# ${SOURCEMAPPING_URL}=data:application/json[^,]+base64,([A-Za-z0-9+/=]+)$`, "gm");
2488
- // we have to inline the source map ourselves, because
2489
- // - we don't need //# sourceURL since we are running code in VM
2490
- // - important in stack traces and the V8 coverage
2491
- // - we need to inject an empty line for --inspect-brk
2492
- function inlineSourceMap(result) {
2493
- const map = result.map;
2494
- let code = result.code;
2495
- if (!map || !("version" in map) || code.includes(MODULE_RUNNER_SOURCEMAPPING_SOURCE)) return result;
2496
- if (OTHER_SOURCE_MAP_REGEXP.lastIndex = 0, OTHER_SOURCE_MAP_REGEXP.test(code)) code = code.replace(OTHER_SOURCE_MAP_REGEXP, "");
2497
- const sourceMap = { ...map };
2498
- // If the first line is not present on source maps, add simple 1:1 mapping ([0,0,0,0], [1,0,0,0])
2499
- // so that debuggers can be set to break on first line
2500
- if (sourceMap.mappings.startsWith(";")) sourceMap.mappings = `AAAA,CAAA${sourceMap.mappings}`;
2501
- return result.code = `${code.trimEnd()}\n${MODULE_RUNNER_SOURCEMAPPING_SOURCE}\n//# ${SOURCEMAPPING_URL}=${genSourceMapUrl(sourceMap)}\n`, result;
2502
- }
2503
- function genSourceMapUrl(map) {
2504
- if (typeof map !== "string") map = JSON.stringify(map);
2505
- return `data:application/json;base64,${Buffer.from(map).toString("base64")}`;
2506
- }
2507
- function getCachedResult(result, cachedFsResults) {
2508
- const tmp = cachedFsResults.get(result.id);
2509
- if (!tmp) throw new Error(`The cached result was returned too early for ${result.id}.`);
2510
- return {
2511
- cached: true,
2512
- file: result.file,
2513
- id: result.id,
2514
- tmp,
2515
- url: result.url,
2516
- invalidate: result.invalidate
2517
- };
2518
- }
2519
- // serialize rollup error on server to preserve details as a test error
2520
- function handleRollupError(e) {
2521
- throw e instanceof Error && ("plugin" in e || "frame" in e || "id" in e) ? {
2522
- name: e.name,
2523
- message: e.message,
2524
- stack: e.stack,
2525
- cause: e.cause,
2526
- __vitest_rollup_error__: {
2527
- plugin: e.plugin,
2528
- id: e.id,
2529
- loc: e.loc,
2530
- frame: e.frame
2531
- }
2532
- } : e;
2533
- }
2534
- /**
2535
- * Performs an atomic write operation using the write-then-rename pattern.
2536
- *
2537
- * Why we need this:
2538
- * - Ensures file integrity by never leaving partially written files on disk
2539
- * - Prevents other processes from reading incomplete data during writes
2540
- * - Particularly important for test files where incomplete writes could cause test failures
2541
- *
2542
- * The implementation writes to a temporary file first, then renames it to the target path.
2543
- * This rename operation is atomic on most filesystems (including POSIX-compliant ones),
2544
- * guaranteeing that other processes will only ever see the complete file.
2545
- *
2546
- * Added in https://github.com/vitest-dev/vitest/pull/7531
2547
- */
2548
- async function atomicWriteFile(realFilePath, data) {
2549
- const dir = dirname$1(realFilePath), tmpFilePath = join$1(dir, `.tmp-${Date.now()}-${Math.random().toString(36).slice(2)}`);
2550
- try {
2551
- await writeFile(tmpFilePath, data, "utf-8"), await rename(tmpFilePath, realFilePath);
2552
- } finally {
2553
- try {
2554
- if (await stat(tmpFilePath)) await unlink(tmpFilePath);
2555
- } catch {}
2556
- }
2557
- }
2558
-
2559
- // this is copy pasted from vite
2560
- function normalizeResolvedIdToUrl(environment, resolvedId) {
2561
- const root = environment.config.root, depsOptimizer = environment.depsOptimizer;
2562
- let url;
2563
- // normalize all imports into resolved URLs
2564
- // e.g. `import 'foo'` -> `import '/@fs/.../node_modules/foo/index.js'`
2565
- if (resolvedId.startsWith(withTrailingSlash$1(root)))
2566
- // in root: infer short absolute path from root
2567
- url = resolvedId.slice(root.length);
2568
- else if (depsOptimizer?.isOptimizedDepFile(resolvedId) || resolvedId !== "/@react-refresh" && path.isAbsolute(resolvedId) && existsSync(cleanUrl(resolvedId)))
2569
- // an optimized deps may not yet exists in the filesystem, or
2570
- // a regular file exists but is out of root: rewrite to absolute /@fs/ paths
2571
- url = path.posix.join("/@fs/", resolvedId);
2572
- else url = resolvedId;
2573
- // if the resolved id is not a valid browser import specifier,
2574
- // prefix it to make it valid. We will strip this before feeding it
2575
- // back into the transform pipeline
2576
- if (url[0] !== "." && url[0] !== "/") url = wrapId(resolvedId);
2577
- return url;
2578
- }
2579
-
2580
- function createMethodsRPC(project, options = {}) {
2581
- const ctx = project.vitest, cacheFs = options.cacheFs ?? false, fetch = createFetchModuleFunction(project._resolver, cacheFs, project.tmpDir);
2582
- return {
2583
- async fetch(url, importer, environmentName, options) {
2584
- const environment = project.vite.environments[environmentName];
2585
- if (!environment) throw new Error(`The environment ${environmentName} was not defined in the Vite config.`);
2586
- const start = performance.now();
2587
- try {
2588
- return await fetch(url, importer, environment, options);
2589
- } finally {
2590
- project.vitest.state.transformTime += performance.now() - start;
2591
- }
2592
- },
2593
- async resolve(id, importer, environmentName) {
2594
- const environment = project.vite.environments[environmentName];
2595
- if (!environment) throw new Error(`The environment ${environmentName} was not defined in the Vite config.`);
2596
- const resolved = await environment.pluginContainer.resolveId(id, importer);
2597
- return resolved ? {
2598
- file: cleanUrl(resolved.id),
2599
- url: normalizeResolvedIdToUrl(environment, resolved.id),
2600
- id: resolved.id
2601
- } : null;
2602
- },
2603
- snapshotSaved(snapshot) {
2604
- ctx.snapshot.add(snapshot);
2605
- },
2606
- resolveSnapshotPath(testPath) {
2607
- return ctx.snapshot.resolvePath(testPath, { config: project.serializedConfig });
2608
- },
2609
- async transform(id) {
2610
- const environment = project.vite.environments.__vitest_vm__;
2611
- if (!environment) throw new Error(`The VM environment was not defined in the Vite config. This is a bug in Vitest. Please, open a new issue with reproduction.`);
2612
- const url = normalizeResolvedIdToUrl(environment, fileURLToPath$1(id)), result = await environment.transformRequest(url).catch(handleRollupError);
2613
- return { code: result?.code };
2614
- },
2615
- async onQueued(file) {
2616
- if (options.collect) ctx.state.collectFiles(project, [file]);
2617
- else await ctx._testRun.enqueued(project, file);
2618
- },
2619
- async onCollected(files) {
2620
- if (options.collect) ctx.state.collectFiles(project, files);
2621
- else await ctx._testRun.collected(project, files);
2622
- },
2623
- onAfterSuiteRun(meta) {
2624
- ctx.coverageProvider?.onAfterSuiteRun(meta);
2625
- },
2626
- async onTaskAnnotate(testId, annotation) {
2627
- return ctx._testRun.annotate(testId, annotation);
2628
- },
2629
- async onTaskUpdate(packs, events) {
2630
- if (options.collect) ctx.state.updateTasks(packs);
2631
- else await ctx._testRun.updated(packs, events);
2632
- },
2633
- async onUserConsoleLog(log) {
2634
- if (options.collect) ctx.state.updateUserLog(log);
2635
- else await ctx._testRun.log(log);
2636
- },
2637
- onUnhandledError(err, type) {
2638
- ctx.state.catchError(err, type);
2639
- },
2640
- onCancel(reason) {
2641
- ctx.cancelCurrentRun(reason);
2642
- },
2643
- getCountOfFailedTests() {
2644
- return ctx.state.getCountOfFailedTests();
2645
- }
2646
- };
2647
- }
2648
-
2649
- function createChildProcessChannel$1(project, collect = false) {
2650
- const emitter = new EventEmitter(), events = {
2651
- message: "message",
2652
- response: "response"
2653
- }, rpc = createBirpc(createMethodsRPC(project, {
2654
- cacheFs: true,
2655
- collect
2656
- }), {
2657
- eventNames: ["onCancel"],
2658
- serialize: v8.serialize,
2659
- deserialize: (v) => {
2660
- try {
2661
- return v8.deserialize(Buffer.from(v));
2662
- } catch (error) {
2663
- let stringified = "";
2664
- try {
2665
- stringified = `\nReceived value: ${JSON.stringify(v)}`;
2666
- } catch {}
2667
- throw new Error(`[vitest-pool]: Unexpected call to process.send(). Make sure your test cases are not interfering with process's channel.${stringified}`, { cause: error });
2668
- }
2669
- },
2670
- post(v) {
2671
- emitter.emit(events.message, v);
2672
- },
2673
- on(fn) {
2674
- emitter.on(events.response, fn);
2675
- },
2676
- timeout: -1
2677
- });
2678
- project.vitest.onCancel((reason) => rpc.onCancel(reason));
2679
- const channel = {
2680
- onMessage: (callback) => emitter.on(events.message, callback),
2681
- postMessage: (message) => emitter.emit(events.response, message),
2682
- onClose: () => {
2683
- emitter.removeAllListeners(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
2684
- }
2685
- };
2686
- return channel;
2687
- }
2688
- function createForksPool(vitest, { execArgv, env }, specifications) {
2689
- const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length, threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1), recommendedCount = vitest.config.watch ? threadsCount : Math.min(threadsCount, specifications.length), poolOptions = vitest.config.poolOptions?.forks ?? {}, maxThreads = poolOptions.maxForks ?? vitest.config.maxWorkers ?? recommendedCount, minThreads = vitest.config.watch ? Math.min(recommendedCount, maxThreads) : 0, worker = resolve(vitest.distPath, "workers/forks.js"), options = {
2690
- runtime: "child_process",
2691
- filename: resolve(vitest.distPath, "worker.js"),
2692
- teardown: "teardown",
2693
- maxThreads,
2694
- minThreads,
2695
- env,
2696
- execArgv: [...poolOptions.execArgv ?? [], ...execArgv],
2697
- terminateTimeout: vitest.config.teardownTimeout,
2698
- concurrentTasksPerWorker: 1
2699
- }, isolated = poolOptions.isolate ?? true;
2700
- if (isolated) options.isolateWorkers = true;
2701
- if (poolOptions.singleFork || !vitest.config.fileParallelism) options.maxThreads = 1, options.minThreads = 1;
2702
- const pool = new Tinypool(options), runWithFiles = (name) => {
2703
- let id = 0;
2704
- async function runFiles(project, config, files, environment, invalidates = []) {
2705
- const paths = files.map((f) => f.filepath);
2706
- vitest.state.clearFiles(project, paths);
2707
- const channel = createChildProcessChannel$1(project, name === "collect"), workerId = ++id, data = {
2708
- pool: "forks",
2709
- worker,
2710
- config,
2711
- files,
2712
- invalidates,
2713
- environment,
2714
- workerId,
2715
- projectName: project.name,
2716
- providedContext: project.getProvidedContext()
2717
- };
2718
- try {
2719
- await pool.run(data, {
2720
- name,
2721
- channel
2722
- });
2723
- } catch (error) {
2724
- // Worker got stuck and won't terminate - this may cause process to hang
2725
- if (error instanceof Error && /Failed to terminate worker/.test(error.message)) vitest.state.addProcessTimeoutCause(`Failed to terminate worker while running ${paths.join(", ")}.`);
2726
- else if (vitest.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) vitest.state.cancelFiles(paths, project);
2727
- else throw error;
2728
- }
2729
- }
2730
- return async (specs, invalidates) => {
2731
- // Cancel pending tasks from pool when possible
2732
- vitest.onCancel(() => pool.cancelPendingTasks());
2733
- const configs = /* @__PURE__ */ new WeakMap(), getConfig = (project) => {
2734
- if (configs.has(project)) return configs.get(project);
2735
- const _config = project.serializedConfig, config = wrapSerializableConfig(_config);
2736
- return configs.set(project, config), config;
2737
- }, singleFork = specs.filter((spec) => spec.project.config.poolOptions?.forks?.singleFork), multipleForks = specs.filter((spec) => !spec.project.config.poolOptions?.forks?.singleFork);
2738
- if (multipleForks.length) {
2739
- const filesByEnv = await groupFilesByEnv(multipleForks), files = Object.values(filesByEnv).flat(), results = [];
2740
- if (isolated) results.push(...await Promise.allSettled(files.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))));
2741
- else {
2742
- // When isolation is disabled, we still need to isolate environments and workspace projects from each other.
2743
- // Tasks are still running parallel but environments are isolated between tasks.
2744
- const grouped = groupBy(files, ({ project, environment }) => project.name + environment.name + JSON.stringify(environment.options));
2745
- for (const group of Object.values(grouped)) results.push(...await Promise.allSettled(group.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)))), await new Promise((resolve) => pool.queueSize === 0 ? resolve() : pool.once("drain", resolve)), await pool.recycleWorkers();
2746
- }
2747
- const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
2748
- if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
2749
- }
2750
- if (singleFork.length) {
2751
- const filesByEnv = await groupFilesByEnv(singleFork), envs = envsOrder.concat(Object.keys(filesByEnv).filter((env) => !envsOrder.includes(env)));
2752
- for (const env of envs) {
2753
- const files = filesByEnv[env];
2754
- if (!files?.length) continue;
2755
- const filesByOptions = groupBy(files, ({ project, environment }) => project.name + JSON.stringify(environment.options));
2756
- for (const files of Object.values(filesByOptions)) {
2757
- // Always run environments isolated between each other
2758
- await pool.recycleWorkers();
2759
- const filenames = files.map((f) => f.file);
2760
- await runFiles(files[0].project, getConfig(files[0].project), filenames, files[0].environment, invalidates);
2761
- }
2762
- }
2763
- }
2764
- };
2765
- };
2766
- return {
2767
- name: "forks",
2768
- runTests: runWithFiles("run"),
2769
- collectTests: runWithFiles("collect"),
2770
- close: () => pool.destroy()
2771
- };
2772
- }
2773
-
2774
- function createWorkerChannel$1(project, collect) {
2775
- const channel = new MessageChannel(), port = channel.port2, workerPort = channel.port1, rpc = createBirpc(createMethodsRPC(project, { collect }), {
2776
- eventNames: ["onCancel"],
2777
- post(v) {
2778
- port.postMessage(v);
2779
- },
2780
- on(fn) {
2781
- port.on("message", fn);
2782
- },
2783
- timeout: -1
2784
- });
2785
- project.vitest.onCancel((reason) => rpc.onCancel(reason));
2786
- const onClose = () => {
2787
- port.close(), workerPort.close(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
2788
- };
2789
- return {
2790
- workerPort,
2791
- port,
2792
- onClose
2793
- };
2794
- }
2795
- function createThreadsPool(vitest, { execArgv, env }, specifications) {
2796
- const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length, threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1), recommendedCount = vitest.config.watch ? threadsCount : Math.min(threadsCount, specifications.length), poolOptions = vitest.config.poolOptions?.threads ?? {}, maxThreads = poolOptions.maxThreads ?? vitest.config.maxWorkers ?? recommendedCount, minThreads = vitest.config.watch ? Math.min(recommendedCount, maxThreads) : 0, worker = resolve(vitest.distPath, "workers/threads.js"), options = {
2797
- filename: resolve(vitest.distPath, "worker.js"),
2798
- teardown: "teardown",
2799
- useAtomics: poolOptions.useAtomics ?? false,
2800
- maxThreads,
2801
- minThreads,
2802
- env,
2803
- execArgv: [...poolOptions.execArgv ?? [], ...execArgv],
2804
- terminateTimeout: vitest.config.teardownTimeout,
2805
- concurrentTasksPerWorker: 1
2806
- }, isolated = poolOptions.isolate ?? true;
2807
- if (isolated) options.isolateWorkers = true;
2808
- if (poolOptions.singleThread || !vitest.config.fileParallelism) options.maxThreads = 1, options.minThreads = 1;
2809
- const pool = new Tinypool$1(options), runWithFiles = (name) => {
2810
- let id = 0;
2811
- async function runFiles(project, config, files, environment, invalidates = []) {
2812
- const paths = files.map((f) => f.filepath);
2813
- vitest.state.clearFiles(project, paths);
2814
- const { workerPort, onClose } = createWorkerChannel$1(project, name === "collect"), workerId = ++id, data = {
2815
- pool: "threads",
2816
- worker,
2817
- port: workerPort,
2818
- config,
2819
- files,
2820
- invalidates,
2821
- environment,
2822
- workerId,
2823
- projectName: project.name,
2824
- providedContext: project.getProvidedContext()
2825
- };
2826
- try {
2827
- await pool.run(data, {
2828
- transferList: [workerPort],
2829
- name,
2830
- channel: { onClose }
2831
- });
2832
- } catch (error) {
2833
- // Worker got stuck and won't terminate - this may cause process to hang
2834
- if (error instanceof Error && /Failed to terminate worker/.test(error.message)) vitest.state.addProcessTimeoutCause(`Failed to terminate worker while running ${paths.join(", ")}. \nSee https://vitest.dev/guide/common-errors.html#failed-to-terminate-worker for troubleshooting.`);
2835
- else if (vitest.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) vitest.state.cancelFiles(paths, project);
2836
- else throw error;
2837
- }
2838
- }
2839
- return async (specs, invalidates) => {
2840
- // Cancel pending tasks from pool when possible
2841
- vitest.onCancel(() => pool.cancelPendingTasks());
2842
- const configs = /* @__PURE__ */ new WeakMap(), getConfig = (project) => {
2843
- if (configs.has(project)) return configs.get(project);
2844
- const config = project.serializedConfig;
2845
- return configs.set(project, config), config;
2846
- }, singleThreads = specs.filter((spec) => spec.project.config.poolOptions?.threads?.singleThread), multipleThreads = specs.filter((spec) => !spec.project.config.poolOptions?.threads?.singleThread);
2847
- if (multipleThreads.length) {
2848
- const filesByEnv = await groupFilesByEnv(multipleThreads), files = Object.values(filesByEnv).flat(), results = [];
2849
- if (isolated) results.push(...await Promise.allSettled(files.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))));
2850
- else {
2851
- // When isolation is disabled, we still need to isolate environments and workspace projects from each other.
2852
- // Tasks are still running parallel but environments are isolated between tasks.
2853
- const grouped = groupBy(files, ({ project, environment }) => project.name + environment.name + JSON.stringify(environment.options));
2854
- for (const group of Object.values(grouped)) results.push(...await Promise.allSettled(group.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)))), await new Promise((resolve) => pool.queueSize === 0 ? resolve() : pool.once("drain", resolve)), await pool.recycleWorkers();
2855
- }
2856
- const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
2857
- if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
2858
- }
2859
- if (singleThreads.length) {
2860
- const filesByEnv = await groupFilesByEnv(singleThreads), envs = envsOrder.concat(Object.keys(filesByEnv).filter((env) => !envsOrder.includes(env)));
2861
- for (const env of envs) {
2862
- const files = filesByEnv[env];
2863
- if (!files?.length) continue;
2864
- const filesByOptions = groupBy(files, ({ project, environment }) => project.name + JSON.stringify(environment.options));
2865
- for (const files of Object.values(filesByOptions)) {
2866
- // Always run environments isolated between each other
2867
- await pool.recycleWorkers();
2868
- const filenames = files.map((f) => f.file);
2869
- await runFiles(files[0].project, getConfig(files[0].project), filenames, files[0].environment, invalidates);
2870
- }
2871
- }
2872
- }
2873
- };
2874
- };
2875
- return {
2876
- name: "threads",
2877
- runTests: runWithFiles("run"),
2878
- collectTests: runWithFiles("collect"),
2879
- close: () => pool.destroy()
2880
- };
2881
- }
2882
-
2883
- function createTypecheckPool(vitest) {
2884
- const promisesMap = /* @__PURE__ */ new WeakMap(), rerunTriggered = /* @__PURE__ */ new WeakSet();
2885
- async function onParseEnd(project, { files, sourceErrors }) {
2886
- const checker = project.typechecker, { packs, events } = checker.getTestPacksAndEvents();
2887
- if (await vitest._testRun.updated(packs, events), !project.config.typecheck.ignoreSourceErrors) sourceErrors.forEach((error) => vitest.state.catchError(error, "Unhandled Source Error"));
2888
- const processError = !hasFailed(files) && !sourceErrors.length && checker.getExitCode();
2889
- if (processError) {
2890
- const error = new Error(checker.getOutput());
2891
- error.stack = "", vitest.state.catchError(error, "Typecheck Error");
2892
- }
2893
- // triggered by TSC watcher, not Vitest watcher, so we need to emulate what Vitest does in this case
2894
- if (promisesMap.get(project)?.resolve(), rerunTriggered.delete(project), vitest.config.watch && !vitest.runningPromise) {
2895
- const modules = files.map((file) => vitest.state.getReportedEntity(file)).filter((e) => e?.type === "module"), state = vitest.isCancelling ? "interrupted" : modules.some((m) => !m.ok()) ? "failed" : "passed";
2896
- await vitest.report("onTestRunEnd", modules, [], state), await vitest.report("onWatcherStart", files, [...project.config.typecheck.ignoreSourceErrors ? [] : sourceErrors, ...vitest.state.getUnhandledErrors()]);
2897
- }
2898
- }
2899
- async function createWorkspaceTypechecker(project, files) {
2900
- const checker = project.typechecker ?? new Typechecker(project);
2901
- return project.typechecker ? checker : (project.typechecker = checker, checker.setFiles(files), checker.onParseStart(async () => {
2902
- const files = checker.getTestFiles();
2903
- for (const file of files) await vitest._testRun.enqueued(project, file);
2904
- await vitest._testRun.collected(project, files);
2905
- }), checker.onParseEnd((result) => onParseEnd(project, result)), checker.onWatcherRerun(async () => {
2906
- if (rerunTriggered.add(project), !vitest.runningPromise) vitest.state.clearErrors(), await vitest.report("onWatcherRerun", files, "File change detected. Triggering rerun.");
2907
- await checker.collectTests();
2908
- const testFiles = checker.getTestFiles();
2909
- for (const file of testFiles) await vitest._testRun.enqueued(project, file);
2910
- await vitest._testRun.collected(project, testFiles);
2911
- const { packs, events } = checker.getTestPacksAndEvents();
2912
- await vitest._testRun.updated(packs, events);
2913
- }), checker);
2914
- }
2915
- async function startTypechecker(project, files) {
2916
- if (project.typechecker) return;
2917
- const checker = await createWorkspaceTypechecker(project, files);
2918
- await checker.collectTests(), await checker.start();
2919
- }
2920
- async function collectTests(specs) {
2921
- const specsByProject = groupBy(specs, (spec) => spec.project.name);
2922
- for (const name in specsByProject) {
2923
- const project = specsByProject[name][0].project, files = specsByProject[name].map((spec) => spec.moduleId), checker = await createWorkspaceTypechecker(project, files);
2924
- checker.setFiles(files), await checker.collectTests();
2925
- const testFiles = checker.getTestFiles();
2926
- vitest.state.collectFiles(project, testFiles);
2927
- }
2928
- }
2929
- async function runTests(specs) {
2930
- const specsByProject = groupBy(specs, (spec) => spec.project.name), promises = [];
2931
- for (const name in specsByProject) {
2932
- const project = specsByProject[name][0].project, files = specsByProject[name].map((spec) => spec.moduleId), promise = createDefer(), _p = new Promise((resolve) => {
2933
- const _i = setInterval(() => {
2934
- if (!project.typechecker || rerunTriggered.has(project)) resolve(true), clearInterval(_i);
2935
- });
2936
- setTimeout(() => {
2937
- resolve(false), clearInterval(_i);
2938
- }, 500).unref();
2939
- }), triggered = await _p;
2940
- if (project.typechecker && !triggered) {
2941
- const testFiles = project.typechecker.getTestFiles();
2942
- for (const file of testFiles) await vitest._testRun.enqueued(project, file);
2943
- await vitest._testRun.collected(project, testFiles), await onParseEnd(project, project.typechecker.getResult());
2944
- continue;
2945
- }
2946
- promises.push(promise), promisesMap.set(project, promise), promises.push(startTypechecker(project, files));
2947
- }
2948
- await Promise.all(promises);
2949
- }
2950
- return {
2951
- name: "typescript",
2952
- runTests,
2953
- collectTests,
2954
- async close() {
2955
- const promises = vitest.projects.map((project) => project.typechecker?.stop());
2956
- await Promise.all(promises);
2957
- }
2958
- };
2959
- }
2960
-
2961
- function getDefaultThreadsCount(config) {
2962
- const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length;
2963
- return config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
2964
- }
2965
- function getWorkerMemoryLimit(config, pool) {
2966
- if (pool === "vmForks") {
2967
- const opts = config.poolOptions?.vmForks ?? {};
2968
- if (opts.memoryLimit) return opts.memoryLimit;
2969
- const workers = opts.maxForks ?? getDefaultThreadsCount(config);
2970
- return 1 / workers;
2971
- } else {
2972
- const opts = config.poolOptions?.vmThreads ?? {};
2973
- if (opts.memoryLimit) return opts.memoryLimit;
2974
- const workers = opts.maxThreads ?? getDefaultThreadsCount(config);
2975
- return 1 / workers;
2976
- }
2977
- }
2978
- /**
2979
- * Converts a string representing an amount of memory to bytes.
2980
- *
2981
- * @param input The value to convert to bytes.
2982
- * @param percentageReference The reference value to use when a '%' value is supplied.
2983
- */
2984
- function stringToBytes(input, percentageReference) {
2985
- if (input === null || input === void 0) return input;
2986
- if (typeof input === "string") if (Number.isNaN(Number.parseFloat(input.slice(-1)))) {
2987
- let [, numericString, trailingChars] = input.match(/(.*?)([^0-9.-]+)$/) || [];
2988
- if (trailingChars && numericString) {
2989
- const numericValue = Number.parseFloat(numericString);
2990
- switch (trailingChars = trailingChars.toLowerCase(), trailingChars) {
2991
- case "%":
2992
- input = numericValue / 100;
2993
- break;
2994
- case "kb":
2995
- case "k": return numericValue * 1e3;
2996
- case "kib": return numericValue * 1024;
2997
- case "mb":
2998
- case "m": return numericValue * 1e3 * 1e3;
2999
- case "mib": return numericValue * 1024 * 1024;
3000
- case "gb":
3001
- case "g": return numericValue * 1e3 * 1e3 * 1e3;
3002
- case "gib": return numericValue * 1024 * 1024 * 1024;
3003
- }
3004
- }
3005
- } else input = Number.parseFloat(input);
3006
- if (typeof input === "number") if (input <= 1 && input > 0) {
3007
- if (percentageReference) return Math.floor(input * percentageReference);
3008
- throw new Error("For a percentage based memory limit a percentageReference must be supplied");
3009
- } else if (input > 1) return Math.floor(input);
3010
- else throw new Error("Unexpected numerical input for \"memoryLimit\"");
3011
- return null;
3012
- }
3013
-
3014
- const suppressWarningsPath$1 = resolve(rootDir, "./suppress-warnings.cjs");
3015
- function createChildProcessChannel(project, collect) {
3016
- const emitter = new EventEmitter(), events = {
3017
- message: "message",
3018
- response: "response"
3019
- }, rpc = createBirpc(createMethodsRPC(project, {
3020
- cacheFs: true,
3021
- collect
3022
- }), {
3023
- eventNames: ["onCancel"],
3024
- serialize: v8.serialize,
3025
- deserialize: (v) => {
3026
- try {
3027
- return v8.deserialize(Buffer.from(v));
3028
- } catch (error) {
3029
- let stringified = "";
3030
- try {
3031
- stringified = `\nReceived value: ${JSON.stringify(v)}`;
3032
- } catch {}
3033
- throw new Error(`[vitest-pool]: Unexpected call to process.send(). Make sure your test cases are not interfering with process's channel.${stringified}`, { cause: error });
3034
- }
3035
- },
3036
- post(v) {
3037
- emitter.emit(events.message, v);
3038
- },
3039
- on(fn) {
3040
- emitter.on(events.response, fn);
3041
- },
3042
- timeout: -1
3043
- });
3044
- project.vitest.onCancel((reason) => rpc.onCancel(reason));
3045
- const channel = {
3046
- onMessage: (callback) => emitter.on(events.message, callback),
3047
- postMessage: (message) => emitter.emit(events.response, message),
3048
- onClose: () => {
3049
- emitter.removeAllListeners(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
3050
- }
3051
- };
3052
- return { channel };
3053
- }
3054
- function createVmForksPool(vitest, { execArgv, env }, specifications) {
3055
- const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length, threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1), recommendedCount = vitest.config.watch ? threadsCount : Math.min(threadsCount, specifications.length), poolOptions = vitest.config.poolOptions?.vmForks ?? {}, maxThreads = poolOptions.maxForks ?? vitest.config.maxWorkers ?? recommendedCount, minThreads = vitest.config.watch ? Math.min(recommendedCount, maxThreads) : 0, worker = resolve(vitest.distPath, "workers/vmForks.js"), options = {
3056
- runtime: "child_process",
3057
- filename: resolve(vitest.distPath, "worker.js"),
3058
- maxThreads,
3059
- minThreads,
3060
- env,
3061
- execArgv: [
3062
- "--experimental-import-meta-resolve",
3063
- "--experimental-vm-modules",
3064
- "--require",
3065
- suppressWarningsPath$1,
3066
- ...poolOptions.execArgv ?? [],
3067
- ...execArgv
3068
- ],
3069
- terminateTimeout: vitest.config.teardownTimeout,
3070
- concurrentTasksPerWorker: 1,
3071
- maxMemoryLimitBeforeRecycle: getMemoryLimit$1(vitest.config) || void 0
3072
- };
3073
- if (poolOptions.singleFork || !vitest.config.fileParallelism) options.maxThreads = 1, options.minThreads = 1;
3074
- const pool = new Tinypool$1(options), runWithFiles = (name) => {
3075
- let id = 0;
3076
- async function runFiles(project, config, files, environment, invalidates = []) {
3077
- const paths = files.map((f) => f.filepath);
3078
- vitest.state.clearFiles(project, paths);
3079
- const { channel } = createChildProcessChannel(project, name === "collect"), workerId = ++id, data = {
3080
- pool: "forks",
3081
- worker,
3082
- config,
3083
- files,
3084
- invalidates,
3085
- environment,
3086
- workerId,
3087
- projectName: project.name,
3088
- providedContext: project.getProvidedContext()
3089
- };
3090
- try {
3091
- await pool.run(data, {
3092
- name,
3093
- channel
3094
- });
3095
- } catch (error) {
3096
- // Worker got stuck and won't terminate - this may cause process to hang
3097
- if (error instanceof Error && /Failed to terminate worker/.test(error.message)) vitest.state.addProcessTimeoutCause(`Failed to terminate worker while running ${paths.join(", ")}.`);
3098
- else if (vitest.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) vitest.state.cancelFiles(paths, project);
3099
- else throw error;
3100
- } finally {
3101
- channel.onClose();
3102
- }
3103
- }
3104
- return async (specs, invalidates) => {
3105
- // Cancel pending tasks from pool when possible
3106
- vitest.onCancel(() => pool.cancelPendingTasks());
3107
- const configs = /* @__PURE__ */ new Map(), getConfig = (project) => {
3108
- if (configs.has(project)) return configs.get(project);
3109
- const _config = project.serializedConfig, config = wrapSerializableConfig(_config);
3110
- return configs.set(project, config), config;
3111
- }, filesByEnv = await groupFilesByEnv(specs), promises = Object.values(filesByEnv).flat(), results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))), errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
3112
- if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
3113
- };
3114
- };
3115
- return {
3116
- name: "vmForks",
3117
- runTests: runWithFiles("run"),
3118
- collectTests: runWithFiles("collect"),
3119
- close: () => pool.destroy()
3120
- };
3121
- }
3122
- function getMemoryLimit$1(config) {
3123
- const memory = nodeos.totalmem(), limit = getWorkerMemoryLimit(config, "vmForks");
3124
- // just ignore "memoryLimit" value because we cannot detect memory limit
3125
- return typeof memory === "number" ? stringToBytes(limit, config.watch ? memory / 2 : memory) : typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%" ? stringToBytes(limit) : null;
3126
- }
3127
-
3128
- const suppressWarningsPath = resolve(rootDir, "./suppress-warnings.cjs");
3129
- function createWorkerChannel(project, collect) {
3130
- const channel = new MessageChannel(), port = channel.port2, workerPort = channel.port1, rpc = createBirpc(createMethodsRPC(project, { collect }), {
3131
- eventNames: ["onCancel"],
3132
- post(v) {
3133
- port.postMessage(v);
3134
- },
3135
- on(fn) {
3136
- port.on("message", fn);
3137
- },
3138
- timeout: -1
3139
- });
3140
- project.vitest.onCancel((reason) => rpc.onCancel(reason));
3141
- function onClose() {
3142
- workerPort.close(), port.close(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
3143
- }
3144
- return {
3145
- workerPort,
3146
- onClose
3147
- };
3148
- }
3149
- function createVmThreadsPool(vitest, { execArgv, env }, specifications) {
3150
- const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length, threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1), recommendedCount = vitest.config.watch ? threadsCount : Math.min(threadsCount, specifications.length), poolOptions = vitest.config.poolOptions?.vmThreads ?? {}, maxThreads = poolOptions.maxThreads ?? vitest.config.maxWorkers ?? recommendedCount, minThreads = vitest.config.watch ? Math.min(recommendedCount, maxThreads) : 0, worker = resolve(vitest.distPath, "workers/vmThreads.js"), options = {
3151
- filename: resolve(vitest.distPath, "worker.js"),
3152
- useAtomics: poolOptions.useAtomics ?? false,
3153
- maxThreads,
3154
- minThreads,
3155
- env,
3156
- execArgv: [
3157
- "--experimental-import-meta-resolve",
3158
- "--experimental-vm-modules",
3159
- "--require",
3160
- suppressWarningsPath,
3161
- ...poolOptions.execArgv ?? [],
3162
- ...execArgv
3163
- ],
3164
- terminateTimeout: vitest.config.teardownTimeout,
3165
- concurrentTasksPerWorker: 1,
3166
- maxMemoryLimitBeforeRecycle: getMemoryLimit(vitest.config) || void 0
3167
- };
3168
- if (poolOptions.singleThread || !vitest.config.fileParallelism) options.maxThreads = 1, options.minThreads = 1;
3169
- const pool = new Tinypool$1(options), runWithFiles = (name) => {
3170
- let id = 0;
3171
- async function runFiles(project, config, files, environment, invalidates = []) {
3172
- const paths = files.map((f) => f.filepath);
3173
- vitest.state.clearFiles(project, paths);
3174
- const { workerPort, onClose } = createWorkerChannel(project, name === "collect"), workerId = ++id, data = {
3175
- pool: "vmThreads",
3176
- worker,
3177
- port: workerPort,
3178
- config,
3179
- files: paths,
3180
- invalidates,
3181
- environment,
3182
- workerId,
3183
- projectName: project.name,
3184
- providedContext: project.getProvidedContext()
3185
- };
3186
- try {
3187
- await pool.run(data, {
3188
- transferList: [workerPort],
3189
- name
3190
- });
3191
- } catch (error) {
3192
- // Worker got stuck and won't terminate - this may cause process to hang
3193
- if (error instanceof Error && /Failed to terminate worker/.test(error.message)) vitest.state.addProcessTimeoutCause(`Failed to terminate worker while running ${paths.join(", ")}. \nSee https://vitest.dev/guide/common-errors.html#failed-to-terminate-worker for troubleshooting.`);
3194
- else if (vitest.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) vitest.state.cancelFiles(paths, project);
3195
- else throw error;
3196
- } finally {
3197
- onClose();
3198
- }
3199
- }
3200
- return async (specs, invalidates) => {
3201
- // Cancel pending tasks from pool when possible
3202
- vitest.onCancel(() => pool.cancelPendingTasks());
3203
- const configs = /* @__PURE__ */ new Map(), getConfig = (project) => {
3204
- if (configs.has(project)) return configs.get(project);
3205
- const config = project.serializedConfig;
3206
- return configs.set(project, config), config;
3207
- }, filesByEnv = await groupFilesByEnv(specs), promises = Object.values(filesByEnv).flat(), results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))), errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
3208
- if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
3209
- };
3210
- };
3211
- return {
3212
- name: "vmThreads",
3213
- runTests: runWithFiles("run"),
3214
- collectTests: runWithFiles("collect"),
3215
- close: () => pool.destroy()
3216
- };
3217
- }
3218
- function getMemoryLimit(config) {
3219
- const memory = nodeos.totalmem(), limit = getWorkerMemoryLimit(config, "vmThreads");
3220
- // just ignore "memoryLimit" value because we cannot detect memory limit
3221
- return typeof memory === "number" ? stringToBytes(limit, config.watch ? memory / 2 : memory) : typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%" ? stringToBytes(limit) : null;
3222
- }
3223
-
3224
- const builtinPools = [
3225
- "forks",
3226
- "threads",
3227
- "browser",
3228
- "vmThreads",
3229
- "vmForks",
3230
- "typescript"
3231
- ];
3232
- function getDefaultPoolName(project) {
3233
- return project.config.browser.enabled ? "browser" : project.config.pool;
3234
- }
3235
- function getFilePoolName(project) {
3236
- return getDefaultPoolName(project);
3237
- }
3238
- function createPool(ctx) {
3239
- const pools = {
3240
- forks: null,
3241
- threads: null,
3242
- browser: null,
3243
- vmThreads: null,
3244
- vmForks: null,
3245
- typescript: null
3246
- }, viteMajor = Number(version.split(".")[0]), potentialConditions = new Set(viteMajor >= 6 ? ctx.vite.config.ssr.resolve?.conditions ?? [] : [
3247
- "production",
3248
- "development",
3249
- ...ctx.vite.config.resolve.conditions
3250
- ]), conditions = [...potentialConditions].filter((condition) => {
3251
- return condition === "production" ? ctx.vite.config.isProduction : condition === "development" ? !ctx.vite.config.isProduction : true;
3252
- }).map((condition) => {
3253
- return viteMajor >= 6 && condition === "development|production" ? ctx.vite.config.isProduction ? "production" : "development" : condition;
3254
- }).flatMap((c) => ["--conditions", c]), execArgv = process.execArgv.filter((execArg) => execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"));
3255
- async function executeTests(method, files, invalidate) {
3256
- const options = {
3257
- execArgv: [...execArgv, ...conditions],
3258
- env: {
3259
- TEST: "true",
3260
- VITEST: "true",
3261
- NODE_ENV: process.env.NODE_ENV || "test",
3262
- VITEST_MODE: ctx.config.watch ? "WATCH" : "RUN",
3263
- FORCE_TTY: isatty(1) ? "true" : "",
3264
- ...process.env,
3265
- ...ctx.config.env
3266
- }
3267
- };
3268
- // env are case-insensitive on Windows, but spawned processes don't support it
3269
- if (isWindows) for (const name in options.env) options.env[name.toUpperCase()] = options.env[name];
3270
- const poolConcurrentPromises = /* @__PURE__ */ new Map(), customPools = /* @__PURE__ */ new Map();
3271
- async function resolveCustomPool(filepath) {
3272
- if (customPools.has(filepath)) return customPools.get(filepath);
3273
- const pool = await ctx.runner.import(filepath);
3274
- if (typeof pool.default !== "function") throw new TypeError(`Custom pool "${filepath}" must export a function as default export`);
3275
- const poolInstance = await pool.default(ctx, options);
3276
- if (typeof poolInstance?.name !== "string") throw new TypeError(`Custom pool "${filepath}" should return an object with "name" property`);
3277
- if (typeof poolInstance?.[method] !== "function") throw new TypeError(`Custom pool "${filepath}" should return an object with "${method}" method`);
3278
- return customPools.set(filepath, poolInstance), poolInstance;
3279
- }
3280
- function getConcurrentPool(pool, fn) {
3281
- if (poolConcurrentPromises.has(pool)) return poolConcurrentPromises.get(pool);
3282
- const promise = fn().finally(() => {
3283
- poolConcurrentPromises.delete(pool);
3284
- });
3285
- return poolConcurrentPromises.set(pool, promise), promise;
3286
- }
3287
- function getCustomPool(pool) {
3288
- return getConcurrentPool(pool, () => resolveCustomPool(pool));
3289
- }
3290
- function getBrowserPool() {
3291
- return getConcurrentPool("browser", async () => {
3292
- const { createBrowserPool } = await import('@vitest/browser');
3293
- return createBrowserPool(ctx);
3294
- });
3295
- }
3296
- const groupedSpecifications = {}, groups = /* @__PURE__ */ new Set(), factories = {
3297
- vmThreads: (specs) => createVmThreadsPool(ctx, options, specs),
3298
- vmForks: (specs) => createVmForksPool(ctx, options, specs),
3299
- threads: (specs) => createThreadsPool(ctx, options, specs),
3300
- forks: (specs) => createForksPool(ctx, options, specs),
3301
- typescript: () => createTypecheckPool(ctx)
3302
- };
3303
- for (const spec of files) {
3304
- const group = spec.project.config.sequence.groupOrder ?? 0;
3305
- groups.add(group), groupedSpecifications[group] ??= [], groupedSpecifications[group].push(spec);
3306
- }
3307
- const Sequencer = ctx.config.sequence.sequencer, sequencer = new Sequencer(ctx);
3308
- async function sortSpecs(specs) {
3309
- if (ctx.config.shard) {
3310
- if (!ctx.config.passWithNoTests && ctx.config.shard.count > specs.length) throw new Error(`--shard <count> must be a smaller than count of test files. Resolved ${specs.length} test files for --shard=${ctx.config.shard.index}/${ctx.config.shard.count}.`);
3311
- specs = await sequencer.shard(specs);
3312
- }
3313
- return sequencer.sort(specs);
3314
- }
3315
- const sortedGroups = Array.from(groups).sort();
3316
- for (const group of sortedGroups) {
3317
- const specifications = groupedSpecifications[group];
3318
- if (!specifications?.length) continue;
3319
- const filesByPool = {
3320
- forks: [],
3321
- threads: [],
3322
- vmThreads: [],
3323
- vmForks: [],
3324
- typescript: []
3325
- };
3326
- specifications.forEach((specification) => {
3327
- const pool = specification.pool;
3328
- filesByPool[pool] ??= [], filesByPool[pool].push(specification);
3329
- }), await Promise.all(Object.entries(filesByPool).map(async (entry) => {
3330
- const [pool, files] = entry;
3331
- if (!files.length) return null;
3332
- const specs = await sortSpecs(files);
3333
- if (pool in factories) {
3334
- const factory = factories[pool];
3335
- return pools[pool] ??= factory(specs), pools[pool][method](specs, invalidate);
3336
- }
3337
- if (pool === "browser") return pools.browser ??= await getBrowserPool(), pools.browser[method](specs, invalidate);
3338
- const poolHandler = await getCustomPool(pool);
3339
- return pools[poolHandler.name] ??= poolHandler, poolHandler[method](specs, invalidate);
3340
- }));
3341
- }
3342
- }
3343
- return {
3344
- name: "default",
3345
- runTests: (files, invalidates) => executeTests("runTests", files, invalidates),
3346
- collectTests: (files, invalidates) => executeTests("collectTests", files, invalidates),
3347
- async close() {
3348
- await Promise.all(Object.values(pools).map((p) => p?.close?.()));
3349
- }
3350
- };
3351
- }
3352
-
3353
2357
  class BaseSequencer {
3354
2358
  ctx;
3355
2359
  constructor(ctx) {
@@ -3359,7 +2363,7 @@ class BaseSequencer {
3359
2363
  async shard(files) {
3360
2364
  const { config } = this.ctx, { index, count } = config.shard, [shardStart, shardEnd] = this.calculateShardRange(files.length, index, count);
3361
2365
  return [...files].map((spec) => {
3362
- const fullPath = resolve$1(slash(config.root), slash(spec.moduleId)), specPath = fullPath?.slice(config.root.length);
2366
+ const specPath = resolve(slash(config.root), slash(spec.moduleId))?.slice(config.root.length);
3363
2367
  return {
3364
2368
  spec,
3365
2369
  hash: hash("sha1", specPath, "hex")
@@ -3400,7 +2404,7 @@ class RandomSequencer extends BaseSequencer {
3400
2404
  }
3401
2405
 
3402
2406
  function resolvePath(path, root) {
3403
- return normalize(/* @__PURE__ */ resolveModule(path, { paths: [root] }) ?? resolve$1(root, path));
2407
+ return normalize(/* @__PURE__ */ resolveModule(path, { paths: [root] }) ?? resolve(root, path));
3404
2408
  }
3405
2409
  function parseInspector(inspect) {
3406
2410
  if (typeof inspect === "boolean" || inspect === void 0) return {};
@@ -3442,7 +2446,8 @@ function resolveConfig$1(vitest, options, viteConfig) {
3442
2446
  root: viteConfig.root,
3443
2447
  mode
3444
2448
  };
3445
- if (resolved.project = toArray(resolved.project), resolved.provide ??= {}, resolved.name = typeof options.name === "string" ? options.name : options.name?.label || "", resolved.color = typeof options.name !== "string" ? options.name?.color : void 0, resolved.environment === "browser") throw new Error(`Looks like you set "test.environment" to "browser". To enabled Browser Mode, use "test.browser.enabled" instead.`);
2449
+ if (options.pool && typeof options.pool !== "string") resolved.pool = options.pool.name, resolved.poolRunner = options.pool;
2450
+ if (resolved.pool ??= "forks", resolved.project = toArray(resolved.project), resolved.provide ??= {}, resolved.name = typeof options.name === "string" ? options.name : options.name?.label || "", resolved.color = typeof options.name !== "string" ? options.name?.color : void 0, resolved.environment === "browser") throw new Error(`Looks like you set "test.environment" to "browser". To enabled Browser Mode, use "test.browser.enabled" instead.`);
3446
2451
  const inspector = resolved.inspect || resolved.inspectBrk;
3447
2452
  if (resolved.inspector = {
3448
2453
  ...resolved.inspector,
@@ -3468,10 +2473,9 @@ function resolveConfig$1(vitest, options, viteConfig) {
3468
2473
  resolved.maxWorkers = 1;
3469
2474
  if (resolved.maxConcurrency === 0) logger.console.warn(c.yellow(`The option "maxConcurrency" cannot be set to 0. Using default value ${configDefaults.maxConcurrency} instead.`)), resolved.maxConcurrency = configDefaults.maxConcurrency;
3470
2475
  if (resolved.inspect || resolved.inspectBrk) {
3471
- const isSingleThread = resolved.pool === "threads" && resolved.poolOptions?.threads?.singleThread, isSingleFork = resolved.pool === "forks" && resolved.poolOptions?.forks?.singleFork;
3472
- if (resolved.fileParallelism && !isSingleThread && !isSingleFork) {
2476
+ if (resolved.fileParallelism) {
3473
2477
  const inspectOption = `--inspect${resolved.inspectBrk ? "-brk" : ""}`;
3474
- throw new Error(`You cannot use ${inspectOption} without "--no-file-parallelism", "poolOptions.threads.singleThread" or "poolOptions.forks.singleFork"`);
2478
+ throw new Error(`You cannot use ${inspectOption} without "--no-file-parallelism"`);
3475
2479
  }
3476
2480
  }
3477
2481
  // apply browser CLI options only if the config already has the browser config and not disabled manually
@@ -3479,35 +2483,59 @@ function resolveConfig$1(vitest, options, viteConfig) {
3479
2483
  resolved.browser ??= {};
3480
2484
  const browser = resolved.browser;
3481
2485
  if (browser.enabled) {
3482
- if (!browser.name && !browser.instances) throw new Error(`Vitest Browser Mode requires "browser.name" (deprecated) or "browser.instances" options, none were set.`);
3483
2486
  const instances = browser.instances;
3484
- if (browser.name && browser.instances)
3485
- // --browser=chromium filters configs to a single one
3486
- browser.instances = browser.instances.filter((instance) => instance.browser === browser.name);
3487
- if (browser.instances && !browser.instances.length) throw new Error([`"browser.instances" was set in the config, but the array is empty. Define at least one browser config.`, browser.name && instances?.length ? ` The "browser.name" was set to "${browser.name}" which filtered all configs (${instances.map((c) => c.browser).join(", ")}). Did you mean to use another name?` : ""].join(""));
2487
+ if (!browser.instances) browser.instances = [];
2488
+ // use `chromium` by default when the preview provider is specified
2489
+ // for a smoother experience. if chromium is not available, it will
2490
+ // open the default browser anyway
2491
+ if (!browser.instances.length && browser.provider?.name === "preview") browser.instances = [{ browser: "chromium" }];
2492
+ if (browser.name && instances?.length) {
2493
+ // if `instances` were defined, but now they are empty,
2494
+ // let's throw an error because the filter is invalid
2495
+ if (browser.instances = browser.instances.filter((instance) => instance.browser === browser.name), !browser.instances.length) throw new Error([`"browser.instances" was set in the config, but the array is empty. Define at least one browser config.`, ` The "browser.name" was set to "${browser.name}" which filtered all configs (${instances.map((c) => c.browser).join(", ")}). Did you mean to use another name?`].join(""));
2496
+ }
3488
2497
  }
3489
- const playwrightChromiumOnly = isPlaywrightChromiumOnly(vitest, resolved);
3490
- // Browser-mode "Playwright + Chromium" only features:
3491
- if (browser.enabled && !playwrightChromiumOnly) {
3492
- const browserConfig = { browser: {
3493
- provider: browser.provider,
3494
- name: browser.name,
3495
- instances: browser.instances?.map((i) => ({ browser: i.browser }))
3496
- } };
3497
- if (resolved.coverage.enabled && resolved.coverage.provider === "v8") throw new Error(`@vitest/coverage-v8 does not work with\n${JSON.stringify(browserConfig, null, 2)}\n\nUse either:\n${JSON.stringify({ browser: {
3498
- provider: "playwright",
3499
- instances: [{ browser: "chromium" }]
3500
- } }, null, 2)}\n\n...or change your coverage provider to:\n${JSON.stringify({ coverage: { provider: "istanbul" } }, null, 2)}\n`);
3501
- if (resolved.inspect || resolved.inspectBrk) {
2498
+ const containsChromium = hasBrowserChromium(vitest, resolved), hasOnlyChromium = hasOnlyBrowserChromium(vitest, resolved);
2499
+ // Browser-mode "Chromium" only features:
2500
+ if (browser.enabled && (!containsChromium || !hasOnlyChromium)) {
2501
+ const browserConfig = `
2502
+ {
2503
+ browser: {
2504
+ provider: ${browser.provider?.name || "preview"}(),
2505
+ instances: [
2506
+ ${(browser.instances || []).map((i) => `{ browser: '${i.browser}' }`).join(",\n ")}
2507
+ ],
2508
+ },
2509
+ }
2510
+ `.trim(), preferredProvider = !browser.provider?.name || browser.provider.name === "preview" ? "playwright" : browser.provider.name, correctExample = `
2511
+ {
2512
+ browser: {
2513
+ provider: ${preferredProvider}(),
2514
+ instances: [
2515
+ { browser: '${preferredProvider === "playwright" ? "chromium" : "chrome"}' }
2516
+ ],
2517
+ },
2518
+ }
2519
+ `.trim();
2520
+ // requires all projects to be chromium
2521
+ if (!hasOnlyChromium && resolved.coverage.enabled && resolved.coverage.provider === "v8") {
2522
+ const coverageExample = `
2523
+ {
2524
+ coverage: {
2525
+ provider: 'istanbul',
2526
+ },
2527
+ }
2528
+ `.trim();
2529
+ throw new Error(`@vitest/coverage-v8 does not work with\n${browserConfig}\n\nUse either:\n${correctExample}\n\n...or change your coverage provider to:\n${coverageExample}\n`);
2530
+ }
2531
+ // ignores non-chromium browsers when there is at least one chromium project
2532
+ if (!containsChromium && (resolved.inspect || resolved.inspectBrk)) {
3502
2533
  const inspectOption = `--inspect${resolved.inspectBrk ? "-brk" : ""}`;
3503
- throw new Error(`${inspectOption} does not work with\n${JSON.stringify(browserConfig, null, 2)}\n\nUse either:\n${JSON.stringify({ browser: {
3504
- provider: "playwright",
3505
- instances: [{ browser: "chromium" }]
3506
- } }, null, 2)}\n\n...or disable ${inspectOption}\n`);
2534
+ throw new Error(`${inspectOption} does not work with\n${browserConfig}\n\nUse either:\n${correctExample}\n\n...or disable ${inspectOption}\n`);
3507
2535
  }
3508
2536
  }
3509
2537
  if (resolved.coverage.reporter = resolveCoverageReporters(resolved.coverage.reporter), resolved.coverage.enabled && resolved.coverage.reportsDirectory) {
3510
- const reportsDirectory = resolve$1(resolved.root, resolved.coverage.reportsDirectory);
2538
+ const reportsDirectory = resolve(resolved.root, resolved.coverage.reportsDirectory);
3511
2539
  if (reportsDirectory === resolved.root || reportsDirectory === process.cwd()) throw new Error(`You cannot set "coverage.reportsDirectory" as ${reportsDirectory}. Vitest needs to be able to remove this directory before test run`);
3512
2540
  }
3513
2541
  if (resolved.coverage.enabled && resolved.coverage.provider === "custom" && resolved.coverage.customProviderModule) resolved.coverage.customProviderModule = resolvePath(resolved.coverage.customProviderModule, resolved.root);
@@ -3515,7 +2543,7 @@ function resolveConfig$1(vitest, options, viteConfig) {
3515
2543
  const envModuleDirectories = process.env.VITEST_MODULE_DIRECTORIES || process.env.npm_config_VITEST_MODULE_DIRECTORIES;
3516
2544
  if (envModuleDirectories) resolved.deps.moduleDirectories.push(...envModuleDirectories.split(","));
3517
2545
  if (resolved.deps.moduleDirectories = resolved.deps.moduleDirectories.map((dir) => {
3518
- if (!dir.startsWith("/")) dir = `/${dir}`;
2546
+ if (dir[0] !== "/") dir = `/${dir}`;
3519
2547
  if (!dir.endsWith("/")) dir += "/";
3520
2548
  return normalize(dir);
3521
2549
  }), !resolved.deps.moduleDirectories.includes("/node_modules/")) resolved.deps.moduleDirectories.push("/node_modules/");
@@ -3528,9 +2556,9 @@ function resolveConfig$1(vitest, options, viteConfig) {
3528
2556
  "**/virtual:*",
3529
2557
  "**/__x00__*",
3530
2558
  "**/node_modules/**"
3531
- ].filter((pattern) => pattern != null), resolved.forceRerunTriggers = [...resolved.forceRerunTriggers, ...resolved.setupFiles], resolved.cliExclude) resolved.exclude.push(...resolved.cliExclude);
2559
+ ].filter((pattern) => typeof pattern === "string"), resolved.forceRerunTriggers = [...resolved.forceRerunTriggers, ...resolved.setupFiles], resolved.cliExclude) resolved.exclude.push(...resolved.cliExclude);
3532
2560
  if (resolved.runner) resolved.runner = resolvePath(resolved.runner, resolved.root);
3533
- if (resolved.attachmentsDir = resolve$1(resolved.root, resolved.attachmentsDir ?? ".vitest-attachments"), resolved.snapshotEnvironment) resolved.snapshotEnvironment = resolvePath(resolved.snapshotEnvironment, resolved.root);
2561
+ if (resolved.attachmentsDir = resolve(resolved.root, resolved.attachmentsDir ?? ".vitest-attachments"), resolved.snapshotEnvironment) resolved.snapshotEnvironment = resolvePath(resolved.snapshotEnvironment, resolved.root);
3534
2562
  if (resolved.testNamePattern = resolved.testNamePattern ? resolved.testNamePattern instanceof RegExp ? resolved.testNamePattern : new RegExp(resolved.testNamePattern) : void 0, resolved.snapshotFormat && "plugins" in resolved.snapshotFormat) {
3535
2563
  // TODO: support it via separate config (like DiffOptions) or via `Function.toString()`
3536
2564
  if (resolved.snapshotFormat.plugins = [], typeof resolved.snapshotFormat.compareKeys === "function") throw new TypeError(`"snapshotFormat.compareKeys" function is not supported.`);
@@ -3543,33 +2571,8 @@ function resolveConfig$1(vitest, options, viteConfig) {
3543
2571
  resolveSnapshotPath: options.resolveSnapshotPath,
3544
2572
  snapshotEnvironment: null
3545
2573
  }, resolved.snapshotSerializers ??= [], resolved.snapshotSerializers = resolved.snapshotSerializers.map((file) => resolvePath(file, resolved.root)), resolved.forceRerunTriggers.push(...resolved.snapshotSerializers), options.resolveSnapshotPath) delete resolved.resolveSnapshotPath;
3546
- if (resolved.pool ??= "threads", process.env.VITEST_MAX_THREADS) resolved.poolOptions = {
3547
- ...resolved.poolOptions,
3548
- threads: {
3549
- ...resolved.poolOptions?.threads,
3550
- maxThreads: Number.parseInt(process.env.VITEST_MAX_THREADS)
3551
- },
3552
- vmThreads: {
3553
- ...resolved.poolOptions?.vmThreads,
3554
- maxThreads: Number.parseInt(process.env.VITEST_MAX_THREADS)
3555
- }
3556
- };
3557
- if (process.env.VITEST_MAX_FORKS) resolved.poolOptions = {
3558
- ...resolved.poolOptions,
3559
- forks: {
3560
- ...resolved.poolOptions?.forks,
3561
- maxForks: Number.parseInt(process.env.VITEST_MAX_FORKS)
3562
- },
3563
- vmForks: {
3564
- ...resolved.poolOptions?.vmForks,
3565
- maxForks: Number.parseInt(process.env.VITEST_MAX_FORKS)
3566
- }
3567
- };
3568
- const poolThreadsOptions = [["threads", "maxThreads"], ["vmThreads", "maxThreads"]];
3569
- for (const [poolOptionKey, workerOptionKey] of poolThreadsOptions) if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) resolved.poolOptions[poolOptionKey][workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey][workerOptionKey]);
3570
- const poolForksOptions = [["forks", "maxForks"], ["vmForks", "maxForks"]];
3571
- for (const [poolOptionKey, workerOptionKey] of poolForksOptions) if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) resolved.poolOptions[poolOptionKey][workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey][workerOptionKey]);
3572
- if (!builtinPools.includes(resolved.pool)) resolved.pool = resolvePath(resolved.pool, resolved.root);
2574
+ if (resolved.execArgv ??= [], resolved.pool ??= "threads", resolved.pool === "vmForks" || resolved.pool === "vmThreads" || resolved.pool === "typescript") resolved.isolate = false;
2575
+ if (process.env.VITEST_MAX_WORKERS) resolved.maxWorkers = Number.parseInt(process.env.VITEST_MAX_WORKERS);
3573
2576
  if (mode === "benchmark") {
3574
2577
  resolved.benchmark = {
3575
2578
  ...benchmarkConfigDefaults,
@@ -3584,12 +2587,10 @@ function resolveConfig$1(vitest, options, viteConfig) {
3584
2587
  if (options.outputJson) resolved.benchmark.outputJson = options.outputJson;
3585
2588
  }
3586
2589
  if (typeof resolved.diff === "string") resolved.diff = resolvePath(resolved.diff, resolved.root), resolved.forceRerunTriggers.push(resolved.diff);
3587
- // the server has been created, we don't need to override vite.server options
3588
- const api = resolveApiServerConfig(options, defaultPort);
3589
2590
  if (resolved.api = {
3590
- ...api,
2591
+ ...resolveApiServerConfig(options, defaultPort),
3591
2592
  token: crypto.randomUUID()
3592
- }, options.related) resolved.related = toArray(options.related).map((file) => resolve$1(resolved.root, file));
2593
+ }, options.related) resolved.related = toArray(options.related).map((file) => resolve(resolved.root, file));
3593
2594
  /*
3594
2595
  * Reporters can be defined in many different ways:
3595
2596
  * { reporter: 'json' }
@@ -3619,7 +2620,7 @@ function resolveConfig$1(vitest, options, viteConfig) {
3619
2620
  // @ts-expect-error "reporter" is from CLI, should be absolute to the running directory
3620
2621
  // it is passed down as "vitest --reporter ../reporter.js"
3621
2622
  const reportersFromCLI = resolved.reporter, cliReporters = toArray(reportersFromCLI || []).map((reporter) => {
3622
- return /^\.\.?\//.test(reporter) ? resolve$1(process.cwd(), reporter) : reporter;
2623
+ return /^\.\.?\//.test(reporter) ? resolve(process.cwd(), reporter) : reporter;
3623
2624
  });
3624
2625
  if (cliReporters.length) resolved.reporters = Array.from(new Set(toArray(cliReporters))).filter(Boolean).map((reporter) => [reporter, {}]);
3625
2626
  }
@@ -3645,24 +2646,35 @@ function resolveConfig$1(vitest, options, viteConfig) {
3645
2646
  ...configDefaults.typecheck,
3646
2647
  ...resolved.typecheck
3647
2648
  }, resolved.typecheck ??= {}, resolved.typecheck.enabled ??= false, resolved.typecheck.enabled) logger.console.warn(c.yellow("Testing types with tsc and vue-tsc is an experimental feature.\nBreaking changes might not follow SemVer, please pin Vitest's version when using it."));
3648
- if (resolved.browser.enabled ??= false, resolved.browser.headless ??= isCI, resolved.browser.isolate ??= true, resolved.browser.fileParallelism ??= options.fileParallelism ?? mode !== "benchmark", resolved.browser.ui ??= resolved.browser.headless === true ? false : !isCI, resolved.browser.screenshotDirectory) resolved.browser.screenshotDirectory = resolve$1(resolved.root, resolved.browser.screenshotDirectory);
3649
- const isPreview = resolved.browser.provider === "preview";
2649
+ if (resolved.browser.enabled ??= false, resolved.browser.headless ??= isCI, resolved.browser.isolate ??= true, resolved.browser.fileParallelism ??= options.fileParallelism ?? mode !== "benchmark", resolved.browser.ui ??= resolved.browser.headless === true ? false : !isCI, resolved.browser.commands ??= {}, resolved.browser.screenshotDirectory) resolved.browser.screenshotDirectory = resolve(resolved.root, resolved.browser.screenshotDirectory);
2650
+ if (resolved.inspector.enabled) resolved.browser.trackUnhandledErrors ??= false;
2651
+ if (resolved.browser.viewport ??= {}, resolved.browser.viewport.width ??= 414, resolved.browser.viewport.height ??= 896, resolved.browser.locators ??= {}, resolved.browser.locators.testIdAttribute ??= "data-testid", typeof resolved.browser.provider === "string") {
2652
+ const source = `@vitest/browser-${resolved.browser.provider}`;
2653
+ throw new TypeError(`The \`browser.provider\` configuration was changed to accept a factory instead of a string. Add an import of "${resolved.browser.provider}" from "${source}" instead. See: https://vitest.dev/guide/browser/config#provider`);
2654
+ }
2655
+ const isPreview = resolved.browser.provider?.name === "preview";
2656
+ if (!isPreview && resolved.browser.enabled && provider === "stackblitz") throw new Error(`stackblitz environment does not support the ${resolved.browser.provider?.name} provider. Please, use "@vitest/browser-preview" instead.`);
3650
2657
  if (isPreview && resolved.browser.screenshotFailures === true) console.warn(c.yellow([
3651
2658
  `Browser provider "preview" doesn't support screenshots, `,
3652
2659
  `so "browser.screenshotFailures" option is forcefully disabled. `,
3653
2660
  `Set "browser.screenshotFailures" to false or remove it from the config to suppress this warning.`
3654
2661
  ].join(""))), resolved.browser.screenshotFailures = false;
3655
2662
  else resolved.browser.screenshotFailures ??= !isPreview && !resolved.browser.ui;
3656
- if (resolved.browser.viewport ??= {}, resolved.browser.viewport.width ??= 414, resolved.browser.viewport.height ??= 896, resolved.browser.locators ??= {}, resolved.browser.locators.testIdAttribute ??= "data-testid", resolved.browser.enabled && provider === "stackblitz") resolved.browser.provider = "preview";
2663
+ if (resolved.browser.provider && resolved.browser.provider.options == null) resolved.browser.provider.options = {};
3657
2664
  // enable includeTaskLocation by default in UI mode
3658
2665
  if (resolved.browser.api = resolveApiServerConfig(resolved.browser, defaultBrowserPort) || { port: defaultBrowserPort }, resolved.browser.enabled) {
3659
2666
  if (resolved.browser.ui) resolved.includeTaskLocation ??= true;
3660
2667
  } else if (resolved.ui) resolved.includeTaskLocation ??= true;
3661
- const htmlReporter = toArray(resolved.reporters).some((reporter) => {
2668
+ if (typeof resolved.browser.trace === "string" || !resolved.browser.trace) resolved.browser.trace = { mode: resolved.browser.trace || "off" };
2669
+ if (resolved.browser.trace.tracesDir != null) resolved.browser.trace.tracesDir = resolvePath(resolved.browser.trace.tracesDir, resolved.root);
2670
+ if (toArray(resolved.reporters).some((reporter) => {
3662
2671
  return Array.isArray(reporter) ? reporter[0] === "html" : false;
3663
- });
3664
- if (htmlReporter) resolved.includeTaskLocation ??= true;
3665
- return resolved.server ??= {}, resolved.server.deps ??= {}, resolved.testTimeout ??= resolved.browser.enabled ? 15e3 : 5e3, resolved.hookTimeout ??= resolved.browser.enabled ? 3e4 : 1e4, resolved;
2672
+ })) resolved.includeTaskLocation ??= true;
2673
+ if (resolved.server ??= {}, resolved.server.deps ??= {}, resolved.server.debug?.dump || process.env.VITEST_DEBUG_DUMP) {
2674
+ const userFolder = resolved.server.debug?.dump || process.env.VITEST_DEBUG_DUMP;
2675
+ resolved.dumpDir = resolve(resolved.root, typeof userFolder === "string" && userFolder !== "true" ? userFolder : ".vitest-dump", resolved.name || "root");
2676
+ }
2677
+ return resolved.testTimeout ??= resolved.browser.enabled ? 3e4 : 5e3, resolved.hookTimeout ??= resolved.browser.enabled ? 3e4 : 1e4, resolved;
3666
2678
  }
3667
2679
  function isBrowserEnabled(config) {
3668
2680
  return Boolean(config.browser?.enabled);
@@ -3679,18 +2691,22 @@ function resolveCoverageReporters(configReporters) {
3679
2691
  resolvedReporters.push([reporter, {}]);
3680
2692
  return resolvedReporters;
3681
2693
  }
3682
- function isPlaywrightChromiumOnly(vitest, config) {
2694
+ function isChromiumName(provider, name) {
2695
+ return provider === "playwright" ? name === "chromium" : name === "chrome" || name === "edge";
2696
+ }
2697
+ function hasBrowserChromium(vitest, config) {
3683
2698
  const browser = config.browser;
3684
- if (!browser || browser.provider !== "playwright" || !browser.enabled) return false;
3685
- if (browser.name) return browser.name === "chromium";
3686
- if (!browser.instances) return false;
3687
- for (const instance of browser.instances) {
2699
+ return !browser || !browser.provider || browser.provider.name === "preview" || !browser.enabled ? false : browser.name ? isChromiumName(browser.provider.name, browser.name) : browser.instances ? browser.instances.some((instance) => {
3688
2700
  const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser);
3689
- // browser config is filtered out
3690
- if (!vitest.matchesProjectFilter(name)) continue;
3691
- if (instance.browser !== "chromium") return false;
3692
- }
3693
- return true;
2701
+ return vitest.matchesProjectFilter(name) ? isChromiumName(browser.provider.name, instance.browser) : false;
2702
+ }) : false;
2703
+ }
2704
+ function hasOnlyBrowserChromium(vitest, config) {
2705
+ const browser = config.browser;
2706
+ return !browser || !browser.provider || browser.provider.name === "preview" || !browser.enabled ? false : browser.name ? isChromiumName(browser.provider.name, browser.name) : browser.instances ? browser.instances.every((instance) => {
2707
+ const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser);
2708
+ return vitest.matchesProjectFilter(name) ? isChromiumName(browser.provider.name, instance.browser) : true;
2709
+ }) : false;
3694
2710
  }
3695
2711
 
3696
2712
  const THRESHOLD_KEYS = [
@@ -3723,7 +2739,7 @@ Update your dependencies and make sure the versions match.`));
3723
2739
  ...coverageConfigDefaults,
3724
2740
  ...config,
3725
2741
  provider: this.name,
3726
- reportsDirectory: resolve$1(ctx.config.root, config.reportsDirectory || coverageConfigDefaults.reportsDirectory),
2742
+ reportsDirectory: resolve(ctx.config.root, config.reportsDirectory || coverageConfigDefaults.reportsDirectory),
3727
2743
  reporter: resolveCoverageReporters(config.reporter || coverageConfigDefaults.reporter),
3728
2744
  thresholds: config.thresholds && {
3729
2745
  ...config.thresholds,
@@ -3735,7 +2751,7 @@ Update your dependencies and make sure the versions match.`));
3735
2751
  };
3736
2752
  const shard = this.ctx.config.shard, tempDirectory = `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`;
3737
2753
  // If --project filter is set pick only roots of resolved projects
3738
- this.coverageFilesDirectory = resolve$1(this.options.reportsDirectory, tempDirectory), this.roots = ctx.config.project?.length ? [...new Set(ctx.projects.map((project) => project.config.root))] : [ctx.config.root];
2754
+ this.coverageFilesDirectory = resolve(this.options.reportsDirectory, tempDirectory), this.roots = ctx.config.project?.length ? [...new Set(ctx.projects.map((project) => project.config.root))] : [ctx.config.root];
3739
2755
  }
3740
2756
  /**
3741
2757
  * Check if file matches `coverage.include` but not `coverage.exclude`
@@ -3771,8 +2787,8 @@ Update your dependencies and make sure the versions match.`));
3771
2787
  }
3772
2788
  async getUntestedFiles(testedFiles) {
3773
2789
  if (this.options.include == null) return [];
3774
- const rootMapper = this.getUntestedFilesByRoot.bind(this, testedFiles, this.options.include), matrix = await Promise.all(this.roots.map(rootMapper));
3775
- return matrix.flatMap((files) => files);
2790
+ const rootMapper = this.getUntestedFilesByRoot.bind(this, testedFiles, this.options.include);
2791
+ return (await Promise.all(this.roots.map(rootMapper))).flatMap((files) => files);
3776
2792
  }
3777
2793
  createCoverageMap() {
3778
2794
  throw new Error("BaseReporter's createCoverageMap was not overwritten");
@@ -3787,26 +2803,26 @@ Update your dependencies and make sure the versions match.`));
3787
2803
  return this.options;
3788
2804
  }
3789
2805
  async clean(clean = true) {
3790
- if (clean && existsSync(this.options.reportsDirectory)) await promises$1.rm(this.options.reportsDirectory, {
2806
+ if (clean && existsSync(this.options.reportsDirectory)) await promises.rm(this.options.reportsDirectory, {
3791
2807
  recursive: true,
3792
2808
  force: true,
3793
2809
  maxRetries: 10
3794
2810
  });
3795
- if (existsSync(this.coverageFilesDirectory)) await promises$1.rm(this.coverageFilesDirectory, {
2811
+ if (existsSync(this.coverageFilesDirectory)) await promises.rm(this.coverageFilesDirectory, {
3796
2812
  recursive: true,
3797
2813
  force: true,
3798
2814
  maxRetries: 10
3799
2815
  });
3800
- await promises$1.mkdir(this.coverageFilesDirectory, { recursive: true }), this.coverageFiles = /* @__PURE__ */ new Map(), this.pendingPromises = [];
2816
+ await promises.mkdir(this.coverageFilesDirectory, { recursive: true }), this.coverageFiles = /* @__PURE__ */ new Map(), this.pendingPromises = [];
3801
2817
  }
3802
2818
  onAfterSuiteRun({ coverage, environment, projectName, testFiles }) {
3803
2819
  if (!coverage) return;
3804
2820
  let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT);
3805
2821
  if (!entry) entry = {}, this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
3806
- const testFilenames = testFiles.join(), filename = resolve$1(this.coverageFilesDirectory, `coverage-${uniqueId++}.json`);
2822
+ const testFilenames = testFiles.join(), filename = resolve(this.coverageFilesDirectory, `coverage-${uniqueId++}.json`);
3807
2823
  // If there's a result from previous run, overwrite it
3808
2824
  entry[environment] ??= {}, entry[environment][testFilenames] = filename;
3809
- const promise = promises$1.writeFile(filename, JSON.stringify(coverage), "utf-8");
2825
+ const promise = promises.writeFile(filename, JSON.stringify(coverage), "utf-8");
3810
2826
  this.pendingPromises.push(promise);
3811
2827
  }
3812
2828
  async readCoverageFiles({ onFileRead, onFinished, onDebug }) {
@@ -3818,7 +2834,7 @@ Update your dependencies and make sure the versions match.`));
3818
2834
  for (const chunk of this.toSlices(filenames, this.options.processingConcurrency)) {
3819
2835
  if (onDebug.enabled) index += chunk.length, onDebug(`Reading coverage results ${index}/${total}`);
3820
2836
  await Promise.all(chunk.map(async (filename) => {
3821
- const contents = await promises$1.readFile(filename, "utf-8"), coverage = JSON.parse(contents);
2837
+ const contents = await promises.readFile(filename, "utf-8"), coverage = JSON.parse(contents);
3822
2838
  onFileRead(coverage);
3823
2839
  }));
3824
2840
  }
@@ -3827,16 +2843,13 @@ Update your dependencies and make sure the versions match.`));
3827
2843
  }
3828
2844
  async cleanAfterRun() {
3829
2845
  // Remove empty reports directory, e.g. when only text-reporter is used
3830
- if (this.coverageFiles = /* @__PURE__ */ new Map(), await promises$1.rm(this.coverageFilesDirectory, { recursive: true }), readdirSync(this.options.reportsDirectory).length === 0) await promises$1.rm(this.options.reportsDirectory, { recursive: true });
2846
+ if (this.coverageFiles = /* @__PURE__ */ new Map(), await promises.rm(this.coverageFilesDirectory, { recursive: true }), readdirSync(this.options.reportsDirectory).length === 0) await promises.rm(this.options.reportsDirectory, { recursive: true });
3831
2847
  }
3832
2848
  async onTestFailure() {
3833
2849
  if (!this.options.reportOnFailure) await this.cleanAfterRun();
3834
2850
  }
3835
2851
  async reportCoverage(coverageMap, { allTestsRun }) {
3836
- await this.generateReports(coverageMap || this.createCoverageMap(), allTestsRun);
3837
- // In watch mode we need to preserve the previous results if cleanOnRerun is disabled
3838
- const keepResults = !this.options.cleanOnRerun && this.ctx.config.watch;
3839
- if (!keepResults) await this.cleanAfterRun();
2852
+ if (await this.generateReports(coverageMap || this.createCoverageMap(), allTestsRun), !(!this.options.cleanOnRerun && this.ctx.config.watch)) await this.cleanAfterRun();
3840
2853
  }
3841
2854
  async reportThresholds(coverageMap, allTestsRun) {
3842
2855
  const resolvedThresholds = this.resolveThresholds(coverageMap);
@@ -3967,10 +2980,14 @@ Update your dependencies and make sure the versions match.`));
3967
2980
  }
3968
2981
  if (thresholdsToUpdate.length === 0) continue;
3969
2982
  updatedThresholds = true;
3970
- for (const [threshold, newValue] of thresholdsToUpdate) if (name === GLOBAL_THRESHOLDS_KEY) config.test.coverage.thresholds[threshold] = newValue;
3971
- else {
3972
- const glob = config.test.coverage.thresholds[name];
3973
- glob[threshold] = newValue;
2983
+ const thresholdFormatter = typeof this.options.thresholds?.autoUpdate === "function" ? this.options.thresholds?.autoUpdate : (value) => value;
2984
+ for (const [threshold, newValue] of thresholdsToUpdate) {
2985
+ const formattedValue = thresholdFormatter(newValue);
2986
+ if (name === GLOBAL_THRESHOLDS_KEY) config.test.coverage.thresholds[threshold] = formattedValue;
2987
+ else {
2988
+ const glob = config.test.coverage.thresholds[name];
2989
+ glob[threshold] = formattedValue;
2990
+ }
3974
2991
  }
3975
2992
  }
3976
2993
  if (updatedThresholds) this.ctx.logger.log("Updating thresholds to configuration file. You may want to push with updated coverage thresholds."), onUpdate();
@@ -4087,4 +3104,4 @@ function resolveMergeConfig(mod) {
4087
3104
  }
4088
3105
  }
4089
3106
 
4090
- export { BaseCoverageProvider as B, RandomSequencer as R, resolveApiServerConfig as a, BaseSequencer as b, createMethodsRPC as c, createFetchModuleFunction as d, isBrowserEnabled as e, groupBy as f, getFilePoolName as g, hash as h, isPackageExists as i, getCoverageProvider as j, createPool as k, normalizeResolvedIdToUrl as n, resolveConfig$1 as r, stdout as s, wildcardPatternToRegExp as w };
3107
+ export { BaseCoverageProvider as B, RandomSequencer as R, resolveApiServerConfig as a, BaseSequencer as b, isBrowserEnabled as c, getCoverageProvider as g, hash as h, isPackageExists as i, resolveConfig$1 as r };