vitest 5.0.0-beta.3 → 5.0.0-beta.4

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 (43) hide show
  1. package/dist/browser.d.ts +1 -1
  2. package/dist/browser.js +1 -1
  3. package/dist/chunks/{base.Bay6B1Dz.js → base.BEGVMQrS.js} +6 -6
  4. package/dist/chunks/{browser.d.DM1g8UNp.d.ts → browser.d.BGxB4Xum.d.ts} +4 -25
  5. package/dist/chunks/{cac.DoK9yX-i.js → cac.CyXAEMkE.js} +22 -31
  6. package/dist/chunks/{cli-api.BCY9ylNq.js → cli-api.DJMXq34b.js} +502 -549
  7. package/dist/chunks/{config.d.C0UMwus7.d.ts → config.d.DXq1aBpy.d.ts} +7 -26
  8. package/dist/chunks/{creator.BqL2U_x4.js → creator.D66cVXYh.js} +2 -2
  9. package/dist/chunks/{defaults.DVfzlTkU.js → defaults.CUUnbOrq.js} +5 -3
  10. package/dist/chunks/global.d.BtKPuz2X.d.ts +194 -0
  11. package/dist/chunks/{globals.8_qjZdeE.js → globals.BuY-yD0m.js} +2 -1
  12. package/dist/chunks/{index.ukHtlBbI.js → index.CE58PZNH.js} +355 -146
  13. package/dist/chunks/{index.PuMGMNHF.js → index.CcluKS59.js} +4 -4
  14. package/dist/chunks/{index.CbgUM9E5.js → index.nQFVd50u.js} +2 -1
  15. package/dist/chunks/{init-forks.OoZmDo1g.js → init-forks.Ce3vGWgL.js} +1 -1
  16. package/dist/chunks/{init-threads.eSHAowcx.js → init-threads.8e1OLv5v.js} +1 -1
  17. package/dist/chunks/{init.YjNsCb-_.js → init.6qx-LaHs.js} +30 -2
  18. package/dist/chunks/{nativeModuleMocker.DKpFw0pk.js → nativeModuleMocker.DDZfQXLs.js} +1 -1
  19. package/dist/chunks/{plugin.d.C00LxKL6.d.ts → plugin.d.B7MTG_Fe.d.ts} +71 -82
  20. package/dist/chunks/{rpc.d.7JZuxZ8u.d.ts → rpc.d.OQ_EZi1Z.d.ts} +18 -2
  21. package/dist/chunks/{setup-common.eQsbxe88.js → setup-common.DdEF_hkE.js} +1 -1
  22. package/dist/chunks/{vm.BE_VOfSs.js → vm.Bu7mmcZq.js} +2 -2
  23. package/dist/chunks/{worker.d.Dv3hDCFf.d.ts → worker.d.yR22cs6X.d.ts} +3 -2
  24. package/dist/cli.js +1 -1
  25. package/dist/config.cjs +1 -1
  26. package/dist/config.d.ts +6 -8
  27. package/dist/config.js +1 -1
  28. package/dist/index.d.ts +23 -40
  29. package/dist/index.js +2 -1
  30. package/dist/module-evaluator.d.ts +4 -1
  31. package/dist/module-evaluator.js +14 -19
  32. package/dist/node.d.ts +20 -12
  33. package/dist/node.js +5 -5
  34. package/dist/runtime.js +2 -2
  35. package/dist/worker.d.ts +3 -3
  36. package/dist/worker.js +7 -6
  37. package/dist/workers/forks.js +8 -7
  38. package/dist/workers/runVmTests.js +4 -3
  39. package/dist/workers/threads.js +8 -7
  40. package/dist/workers/vmForks.js +4 -4
  41. package/dist/workers/vmThreads.js +4 -4
  42. package/package.json +15 -15
  43. package/dist/chunks/global.d.DZbA5YnY.d.ts +0 -101
@@ -1,6 +1,5 @@
1
1
  import * as fs from 'node:fs';
2
2
  import fs__default, { promises, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync, statSync } from 'node:fs';
3
- import * as pathe from 'pathe';
4
3
  import { join, dirname, basename, isAbsolute, resolve as resolve$1, relative, normalize, extname } from 'pathe';
5
4
  import { r as resolveCoverageProviderModule, C as CoverageProviderMap } from './coverage.CTzCuANN.js';
6
5
  import path, { resolve as resolve$2 } from 'node:path';
@@ -8,13 +7,13 @@ import { unique, createDefer, slash, shuffle, toArray, cleanUrl, withTrailingSla
8
7
  import { a as any, p as prompt } from './index.og1WyBLx.js';
9
8
  import { r as resolveModule, i as isPackageExists, N as NativeModuleRunner } from './nativeModuleRunner.BOeMnHl4.js';
10
9
  import * as vite from 'vite';
11
- import { parseAst, searchForWorkspaceRoot, mergeConfig, fetchModule, parseAstAsync, version, createServer, isFileLoadingAllowed, normalizePath as normalizePath$1, isRunnableDevEnvironment } from 'vite';
10
+ import { parseAst, searchForWorkspaceRoot, mergeConfig, fetchModule, version, createServer, isFileLoadingAllowed, normalizePath as normalizePath$1, isRunnableDevEnvironment } from 'vite';
12
11
  import { c as configFiles, d as defaultBrowserPort, b as defaultInspectPort, a as defaultPort, A as API_PATH } from './constants.-juJ8b_4.js';
13
12
  import * as nodeos from 'node:os';
14
13
  import nodeos__default, { tmpdir, hostname } from 'node:os';
15
- import { getTests, createFileTask as createFileTask$1, createTaskName, validateTags, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, hasFailed, generateFileHash, limitConcurrency, getTestName, getSuites, getTasks, getFullName, createTagsFilter, isTestCase } from '@vitest/runner/utils';
14
+ import { getTests, createFileTask as createFileTask$1, createTaskName, validateTags, calculateSuiteHash, hasFailed, generateFileHash, limitConcurrency, getTestName, getSuites, getTasks, getFullName, createTagsFilter, someTasksAreOnly, interpretTaskModes, isTestCase } from '@vitest/runner/utils';
16
15
  import { serializeValue } from '@vitest/utils/serialize';
17
- import { v as version$1 } from './cac.DoK9yX-i.js';
16
+ import { v as version$1 } from './cac.CyXAEMkE.js';
18
17
  import { distDir, rootDir } from '../path.js';
19
18
  import { Traces } from '../traces.js';
20
19
  import { createDebug } from 'obug';
@@ -23,7 +22,7 @@ import { rm, readFile, writeFile, rename, stat, unlink, mkdir, readdir, copyFile
23
22
  import c from 'tinyrainbow';
24
23
  import url, { pathToFileURL, fileURLToPath } from 'node:url';
25
24
  import { isDynamicPattern, glob } from 'tinyglobby';
26
- import { c as configDefaults, e as benchmarkConfigDefaults, a as coverageConfigDefaults } from './defaults.DVfzlTkU.js';
25
+ import { c as configDefaults, e as benchmarkConfigDefaults, a as coverageConfigDefaults } from './defaults.CUUnbOrq.js';
27
26
  import { a as isTTY, b as isWindows, i as isForceColor } from './env.BKKtU2WC.js';
28
27
  import { w as withLabel, t as truncateString, e as errorBanner, F as F_POINTER, d as divider, f as formatProjectName, a as formatTimeString, b as taskFail, s as separator, c as F_CHECK, g as F_DOWN_RIGHT, h as getStateSymbol, r as renderSnapshotSummary, p as padSummaryTitle, i as getStateString$1, j as formatTime, k as countTestErrors, l as F_TREE_NODE_END, m as F_TREE_NODE_MIDDLE, n as noun, o as F_RIGHT } from './utils.DKODp04v.js';
29
28
  import { isAgent, isCI, provider } from 'std-env';
@@ -1222,6 +1221,15 @@ function detectCodeBlock(content) {
1222
1221
 
1223
1222
  const debug$1 = createDebugger("vitest:ast-collect-info");
1224
1223
  const verbose = createDebugger("vitest:ast-collect-verbose");
1224
+ const INTERMEDIATE_CALL_PROPERTIES = new Set([
1225
+ "each",
1226
+ "for",
1227
+ "skipIf",
1228
+ "runIf",
1229
+ "extend",
1230
+ "scoped",
1231
+ "override"
1232
+ ]);
1225
1233
  function isTestFunctionName(name) {
1226
1234
  return name === "it" || name === "test" || name.startsWith("test") || name.endsWith("Test");
1227
1235
  }
@@ -1274,15 +1282,7 @@ function astParseFile(filepath, code) {
1274
1282
  const properties = getProperties(callee);
1275
1283
  const property = callee?.property?.name;
1276
1284
  // intermediate calls like .each(), .for() will be picked up in the next iteration
1277
- if (property && [
1278
- "each",
1279
- "for",
1280
- "skipIf",
1281
- "runIf",
1282
- "extend",
1283
- "scoped",
1284
- "override"
1285
- ].includes(property)) return;
1285
+ if (property && INTERMEDIATE_CALL_PROPERTIES.has(property)) return;
1286
1286
  // skip properties on return values of calls - e.g., test('name', fn).skip()
1287
1287
  if (callee.type === "MemberExpression" && callee.object?.type === "CallExpression") return;
1288
1288
  // derive mode from the full chain (handles any order like .skip.concurrent or .concurrent.skip)
@@ -1349,11 +1349,12 @@ function astParseFile(filepath, code) {
1349
1349
  definitions
1350
1350
  };
1351
1351
  }
1352
- function createFailedFileTask(project, filepath, error) {
1352
+ function createFailedFileTask(project, filepath, error, options) {
1353
1353
  const config = project.serializedConfig;
1354
+ const pool = options?.pool ?? config.pool;
1354
1355
  const file = {
1355
- ...createFileTask$1(filepath, config.root, config.name, config.pool, void 0, {
1356
- typecheck: config.pool === "typescript",
1356
+ ...createFileTask$1(filepath, config.root, config.name, pool, void 0, {
1357
+ typecheck: pool === "typescript",
1357
1358
  __vitest_label__: config.mergeReportsLabel
1358
1359
  }),
1359
1360
  mode: "run",
@@ -1381,12 +1382,13 @@ function serializeError(ctx, error) {
1381
1382
  message: error.message
1382
1383
  }];
1383
1384
  }
1384
- function createFileTask(project, testFilepath, code, requestMap, filepath, fileTags) {
1385
+ function createFileTask(project, testFilepath, code, requestMap, filepath, fileTags, options) {
1385
1386
  const { definitions, ast } = astParseFile(testFilepath, code);
1386
1387
  const config = project.serializedConfig;
1388
+ const pool = options?.pool ?? config.pool;
1387
1389
  const file = {
1388
- ...createFileTask$1(filepath, config.root, config.name, config.pool, void 0, {
1389
- typecheck: config.pool === "typescript",
1390
+ ...createFileTask$1(filepath, config.root, config.name, pool, void 0, {
1391
+ typecheck: pool === "typescript",
1390
1392
  __vitest_label__: config.mergeReportsLabel
1391
1393
  }),
1392
1394
  mode: "run",
@@ -1416,10 +1418,10 @@ function createFileTask(project, testFilepath, code, requestMap, filepath, fileT
1416
1418
  column: processedLocation.column
1417
1419
  });
1418
1420
  if (originalLocation.column != null) {
1419
- verbose?.(`Found location for`, definition.type, definition.name, `${processedLocation.line}:${processedLocation.column}`, "->", `${originalLocation.line}:${originalLocation.column}`);
1421
+ verbose?.(`Found location for`, definition.type, definition.name, `${processedLocation.line}:${processedLocation.column + 1}`, "->", `${originalLocation.line}:${originalLocation.column + 1}`);
1420
1422
  location = {
1421
1423
  line: originalLocation.line,
1422
- column: originalLocation.column
1424
+ column: originalLocation.column + 1
1423
1425
  };
1424
1426
  } else debug$1?.("Cannot find original location for", definition.type, definition.name, `${processedLocation.column}:${processedLocation.line}`);
1425
1427
  } else debug$1?.("Cannot find original location for", definition.type, definition.name, `${definition.start}`);
@@ -1471,6 +1473,7 @@ function createFileTask(project, testFilepath, code, requestMap, filepath, fileT
1471
1473
  timeout: 0,
1472
1474
  annotations: [],
1473
1475
  artifacts: [],
1476
+ benchmarks: [],
1474
1477
  tags: taskTags
1475
1478
  };
1476
1479
  definition.task = task;
@@ -1485,16 +1488,35 @@ function createFileTask(project, testFilepath, code, requestMap, filepath, fileT
1485
1488
  message: `No test suite found in file ${filepath}`
1486
1489
  }]
1487
1490
  };
1488
- return file;
1491
+ return {
1492
+ file,
1493
+ definitions
1494
+ };
1489
1495
  }
1490
1496
  async function astCollectTests(project, filepath) {
1497
+ return (await astCollectFileInformation(project, filepath)).file;
1498
+ }
1499
+ async function astCollectFileInformation(project, filepath, options) {
1491
1500
  const request = await transformSSR(project, filepath);
1492
1501
  const testFilepath = relative(project.config.root, filepath);
1493
1502
  if (!request) {
1494
1503
  debug$1?.("Cannot parse", testFilepath, "(vite didn't return anything)");
1495
- return createFailedFileTask(project, filepath, /* @__PURE__ */ new Error(`Failed to parse ${testFilepath}. Vite didn't return anything.`));
1504
+ return {
1505
+ file: createFailedFileTask(project, filepath, /* @__PURE__ */ new Error(`Failed to parse ${testFilepath}. Vite didn't return anything.`), options),
1506
+ filepath,
1507
+ parsed: "",
1508
+ map: null,
1509
+ definitions: []
1510
+ };
1496
1511
  }
1497
- return createFileTask(project, testFilepath, request.code, request.map, filepath, request.fileTags);
1512
+ const { file, definitions } = createFileTask(project, testFilepath, request.code, request.map, filepath, request.fileTags, options);
1513
+ return {
1514
+ file,
1515
+ filepath,
1516
+ parsed: request.code,
1517
+ map: request.map,
1518
+ definitions
1519
+ };
1498
1520
  }
1499
1521
  async function transformSSR(project, filepath) {
1500
1522
  const { env: pragmaEnv, tags: fileTags } = detectCodeBlock(await promises.readFile(filepath, "utf-8").catch(() => ""));
@@ -2261,8 +2283,10 @@ function resolveInlineWorkerOption(value) {
2261
2283
  if (typeof value === "string" && value.trim().endsWith("%")) return getWorkersCountByPercentage(value);
2262
2284
  else return Number(value);
2263
2285
  }
2286
+ // warn only once, check one PER PROCESS, not per instance,
2287
+ // that's why it's on a module-level
2288
+ let warnedTypeCheck = false;
2264
2289
  function resolveConfig$1(vitest, options, viteConfig) {
2265
- const mode = vitest.mode;
2266
2290
  const logger = vitest.logger;
2267
2291
  if (options.dom) {
2268
2292
  if (viteConfig.test?.environment != null && viteConfig.test.environment !== "happy-dom") logger.console.warn(withLabel("yellow", "Vitest", `Your config.test.environment ("${viteConfig.test.environment}") conflicts with --dom flag ("happy-dom"), ignoring "${viteConfig.test.environment}"`));
@@ -2271,9 +2295,9 @@ function resolveConfig$1(vitest, options, viteConfig) {
2271
2295
  const resolved = {
2272
2296
  ...configDefaults,
2273
2297
  ...options,
2274
- root: viteConfig.root,
2275
- mode
2298
+ root: viteConfig.root
2276
2299
  };
2300
+ resolved.mode ??= viteConfig.mode ?? "test";
2277
2301
  if (resolved.retry && typeof resolved.retry === "object" && typeof resolved.retry.condition === "function") {
2278
2302
  logger.console.warn(c.yellow("Warning: retry.condition function cannot be used inside a config file. Use a RegExp pattern instead, or define the function in your test file."));
2279
2303
  resolved.retry = {
@@ -2305,6 +2329,10 @@ function resolveConfig$1(vitest, options, viteConfig) {
2305
2329
  resolved.name = typeof options.name === "string" ? options.name : options.name?.label || "";
2306
2330
  resolved.color = typeof options.name !== "string" ? options.name?.color : void 0;
2307
2331
  if (resolved.environment === "browser") throw new Error(`Looks like you set "test.environment" to "browser". To enable Browser Mode, use "test.browser.enabled" instead.`);
2332
+ resolved.benchmark = {
2333
+ ...benchmarkConfigDefaults,
2334
+ ...resolved.benchmark
2335
+ };
2308
2336
  const inspector = resolved.inspect || resolved.inspectBrk;
2309
2337
  resolved.inspector = {
2310
2338
  ...resolved.inspector,
@@ -2329,7 +2357,7 @@ function resolveConfig$1(vitest, options, viteConfig) {
2329
2357
  if (resolved.standalone && !resolved.watch) throw new Error(`Vitest standalone mode requires --watch`);
2330
2358
  if (resolved.mergeReports && resolved.watch) throw new Error(`Cannot merge reports with --watch enabled`);
2331
2359
  if (resolved.maxWorkers) resolved.maxWorkers = resolveInlineWorkerOption(resolved.maxWorkers);
2332
- if (!(options.fileParallelism ?? mode !== "benchmark"))
2360
+ if (!(options.fileParallelism ?? true))
2333
2361
  // ignore user config, parallelism cannot be implemented without limiting workers
2334
2362
  resolved.maxWorkers = 1;
2335
2363
  if (resolved.maxConcurrency === 0) {
@@ -2492,25 +2520,6 @@ function resolveConfig$1(vitest, options, viteConfig) {
2492
2520
  resolved.pool ??= "threads";
2493
2521
  if (resolved.pool === "vmForks" || resolved.pool === "vmThreads" || resolved.pool === "typescript") resolved.isolate = false;
2494
2522
  if (process.env.VITEST_MAX_WORKERS) resolved.maxWorkers = Number.parseInt(process.env.VITEST_MAX_WORKERS);
2495
- if (mode === "benchmark") {
2496
- resolved.benchmark = {
2497
- ...benchmarkConfigDefaults,
2498
- ...resolved.benchmark
2499
- };
2500
- // override test config
2501
- resolved.coverage.enabled = false;
2502
- resolved.typecheck.enabled = false;
2503
- resolved.include = resolved.benchmark.include;
2504
- resolved.exclude = resolved.benchmark.exclude;
2505
- resolved.includeSource = resolved.benchmark.includeSource;
2506
- const reporters = Array.from(new Set([...toArray(resolved.benchmark.reporters), ...toArray(options.reporter)])).filter(Boolean);
2507
- if (reporters.length) resolved.benchmark.reporters = reporters;
2508
- else resolved.benchmark.reporters = ["default"];
2509
- if (options.outputFile) resolved.benchmark.outputFile = options.outputFile;
2510
- // --compare from cli
2511
- if (options.compare) resolved.benchmark.compare = options.compare;
2512
- if (options.outputJson) resolved.benchmark.outputJson = options.outputJson;
2513
- }
2514
2523
  if (typeof resolved.diff === "string") {
2515
2524
  resolved.diff = resolvePath(resolved.diff, resolved.root);
2516
2525
  resolved.forceRerunTriggers.push(resolved.diff);
@@ -2546,25 +2555,23 @@ function resolveConfig$1(vitest, options, viteConfig) {
2546
2555
  // Inline reporter, e.g. { reporter: [{ onFinish() { method() } }] }
2547
2556
  resolved.reporters.push(reporter);
2548
2557
  }
2549
- if (mode !== "benchmark") {
2550
- // @ts-expect-error "reporter" is from CLI, should be absolute to the running directory
2551
- // it is passed down as "vitest --reporter ../reporter.js"
2552
- const reportersFromCLI = resolved.reporter;
2553
- const cliReporters = toArray(reportersFromCLI || []).map((reporter) => {
2554
- // ./reporter.js || ../reporter.js, but not .reporters/reporter.js
2555
- if (/^\.\.?\//.test(reporter)) return resolve$1(process.cwd(), reporter);
2556
- return reporter;
2557
- });
2558
- if (cliReporters.length) {
2559
- // When CLI reporters are specified, preserve options from config file
2560
- const configReportersMap = /* @__PURE__ */ new Map();
2561
- // Build a map of reporter names to their options from the config
2562
- for (const reporter of resolved.reporters) if (Array.isArray(reporter)) {
2563
- const [reporterName, reporterOptions] = reporter;
2564
- if (typeof reporterName === "string") configReportersMap.set(reporterName, reporterOptions);
2565
- }
2566
- resolved.reporters = Array.from(new Set(toArray(cliReporters))).filter(Boolean).map((reporter) => [reporter, configReportersMap.get(reporter) || {}]);
2558
+ // @ts-expect-error "reporter" is from CLI, should be absolute to the running directory
2559
+ // it is passed down as "vitest --reporter ../reporter.js"
2560
+ const reportersFromCLI = resolved.reporter;
2561
+ const cliReporters = toArray(reportersFromCLI || []).map((reporter) => {
2562
+ // ./reporter.js || ../reporter.js, but not .reporters/reporter.js
2563
+ if (/^\.\.?\//.test(reporter)) return resolve$1(process.cwd(), reporter);
2564
+ return reporter;
2565
+ });
2566
+ if (cliReporters.length) {
2567
+ // When CLI reporters are specified, preserve options from config file
2568
+ const configReportersMap = /* @__PURE__ */ new Map();
2569
+ // Build a map of reporter names to their options from the config
2570
+ for (const reporter of resolved.reporters) if (Array.isArray(reporter)) {
2571
+ const [reporterName, reporterOptions] = reporter;
2572
+ if (typeof reporterName === "string") configReportersMap.set(reporterName, reporterOptions);
2567
2573
  }
2574
+ resolved.reporters = Array.from(new Set(toArray(cliReporters))).filter(Boolean).map((reporter) => [reporter, configReportersMap.get(reporter) || {}]);
2568
2575
  }
2569
2576
  resolved.mergeReportsLabel = process.env.VITEST_BLOB_LABEL;
2570
2577
  for (const reporter of resolved.reporters) if (Array.isArray(reporter) && reporter[0] === "blob") {
@@ -2600,12 +2607,15 @@ function resolveConfig$1(vitest, options, viteConfig) {
2600
2607
  };
2601
2608
  resolved.typecheck ??= {};
2602
2609
  resolved.typecheck.enabled ??= false;
2603
- if (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."));
2610
+ if (resolved.typecheck.enabled && !warnedTypeCheck) {
2611
+ warnedTypeCheck = true;
2612
+ 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."));
2613
+ }
2604
2614
  resolved.browser.enabled ??= false;
2605
2615
  resolved.browser.headless ??= isCI;
2606
2616
  if (resolved.browser.isolate) logger.console.warn(c.yellow("`browser.isolate` is deprecated. Use top-level `isolate` instead."));
2607
2617
  resolved.browser.isolate ??= resolved.isolate ?? true;
2608
- resolved.browser.fileParallelism ??= options.fileParallelism ?? mode !== "benchmark";
2618
+ resolved.browser.fileParallelism ??= options.fileParallelism ?? true;
2609
2619
  // disable in headless mode by default, and if CI is detected
2610
2620
  resolved.browser.ui ??= resolved.browser.headless === true ? false : !isCI;
2611
2621
  resolved.browser.commands ??= {};
@@ -2617,7 +2627,7 @@ function resolveConfig$1(vitest, options, viteConfig) {
2617
2627
  resolved.browser.viewport.height ??= 896;
2618
2628
  resolved.browser.locators ??= {};
2619
2629
  resolved.browser.locators.testIdAttribute ??= "data-testid";
2620
- resolved.browser.locators.exact ??= false;
2630
+ resolved.browser.locators.exact ??= true;
2621
2631
  resolved.browser.locators.errorFormat ??= "all";
2622
2632
  if (typeof resolved.browser.provider === "string") {
2623
2633
  const source = `@vitest/browser-${resolved.browser.provider}`;
@@ -3569,8 +3579,8 @@ class ServerModuleRunner extends ModuleRunner {
3569
3579
 
3570
3580
  class FilesNotFoundError extends Error {
3571
3581
  code = "VITEST_FILES_NOT_FOUND";
3572
- constructor(mode) {
3573
- super(`No ${mode} files found`);
3582
+ constructor() {
3583
+ super(`No test files found`);
3574
3584
  }
3575
3585
  }
3576
3586
  class GitNotFoundError extends Error {
@@ -4148,144 +4158,6 @@ function getDefs(c) {
4148
4158
  };
4149
4159
  }
4150
4160
 
4151
- async function collectTests(ctx, filepath) {
4152
- const request = await ctx.vite.environments.ssr.transformRequest(filepath);
4153
- if (!request) return null;
4154
- const ast = await parseAstAsync(request.code);
4155
- const projectName = ctx.name;
4156
- const file = {
4157
- ...createFileTask$1(filepath, ctx.config.root, projectName, void 0, void 0, { typecheck: true }),
4158
- start: ast.start,
4159
- end: ast.end,
4160
- mode: "run"
4161
- };
4162
- file.file = file;
4163
- const definitions = [];
4164
- const getName = (callee) => {
4165
- if (!callee) return null;
4166
- if (callee.type === "Identifier") return callee.name;
4167
- if (callee.type === "CallExpression") return getName(callee.callee);
4168
- if (callee.type === "TaggedTemplateExpression") return getName(callee.tag);
4169
- if (callee.type === "MemberExpression") {
4170
- if (callee.object?.type === "Identifier" && [
4171
- "it",
4172
- "test",
4173
- "describe",
4174
- "suite"
4175
- ].includes(callee.object.name)) return callee.object?.name;
4176
- // direct call as `__vite_ssr_exports_0__.test()`
4177
- if (callee.object?.name?.startsWith("__vite_ssr_")) return getName(callee.property);
4178
- // call as `__vite_ssr__.test.skip()`
4179
- return getName(callee.object?.property);
4180
- }
4181
- // unwrap (0, ...)
4182
- if (callee.type === "SequenceExpression" && callee.expressions.length === 2) {
4183
- const [e0, e1] = callee.expressions;
4184
- if (e0.type === "Literal" && e0.value === 0) return getName(e1);
4185
- }
4186
- return null;
4187
- };
4188
- ancestor(ast, { CallExpression(node) {
4189
- const { callee } = node;
4190
- const name = getName(callee);
4191
- if (!name) return;
4192
- if (![
4193
- "it",
4194
- "test",
4195
- "describe",
4196
- "suite"
4197
- ].includes(name)) return;
4198
- const property = callee?.property?.name;
4199
- let mode = !property || property === name ? "run" : property;
4200
- // they will be picked up in the next iteration
4201
- if ([
4202
- "each",
4203
- "for",
4204
- "skipIf",
4205
- "runIf"
4206
- ].includes(mode)) return;
4207
- let start;
4208
- const end = node.end;
4209
- // .each
4210
- if (callee.type === "CallExpression") start = callee.end;
4211
- else if (callee.type === "TaggedTemplateExpression") start = callee.end + 1;
4212
- else start = node.start;
4213
- const { arguments: [messageNode] } = node;
4214
- const message = messageNode?.type === "Literal" || messageNode?.type === "TemplateLiteral" ? request.code.slice(messageNode.start + 1, messageNode.end - 1) : request.code.slice(messageNode.start, messageNode.end);
4215
- // cannot statically analyze, so we always skip it
4216
- if (mode === "skipIf" || mode === "runIf") mode = "skip";
4217
- definitions.push({
4218
- start,
4219
- end,
4220
- name: message,
4221
- type: name === "it" || name === "test" ? "test" : "suite",
4222
- mode,
4223
- task: null
4224
- });
4225
- } });
4226
- let lastSuite = file;
4227
- const updateLatestSuite = (index) => {
4228
- while (lastSuite.suite && lastSuite.end < index) lastSuite = lastSuite.suite;
4229
- return lastSuite;
4230
- };
4231
- definitions.sort((a, b) => a.start - b.start).forEach((definition) => {
4232
- const latestSuite = updateLatestSuite(definition.start);
4233
- let mode = definition.mode;
4234
- if (latestSuite.mode !== "run")
4235
- // inherit suite mode, if it's set
4236
- mode = latestSuite.mode;
4237
- if (definition.type === "suite") {
4238
- const task = {
4239
- type: definition.type,
4240
- id: "",
4241
- suite: latestSuite,
4242
- file,
4243
- tasks: [],
4244
- mode,
4245
- name: definition.name,
4246
- fullName: createTaskName([lastSuite.fullName, definition.name]),
4247
- fullTestName: createTaskName([lastSuite.fullTestName, definition.name]),
4248
- end: definition.end,
4249
- start: definition.start,
4250
- meta: { typecheck: true }
4251
- };
4252
- definition.task = task;
4253
- latestSuite.tasks.push(task);
4254
- lastSuite = task;
4255
- return;
4256
- }
4257
- const task = {
4258
- type: definition.type,
4259
- id: "",
4260
- suite: latestSuite,
4261
- file,
4262
- mode,
4263
- timeout: 0,
4264
- context: {},
4265
- name: definition.name,
4266
- fullName: createTaskName([lastSuite.fullName, definition.name]),
4267
- fullTestName: createTaskName([lastSuite.fullTestName, definition.name]),
4268
- end: definition.end,
4269
- start: definition.start,
4270
- annotations: [],
4271
- artifacts: [],
4272
- meta: { typecheck: true }
4273
- };
4274
- definition.task = task;
4275
- latestSuite.tasks.push(task);
4276
- });
4277
- calculateSuiteHash(file);
4278
- const hasOnly = someTasksAreOnly(file);
4279
- interpretTaskModes(file, ctx.config.testNamePattern, void 0, void 0, void 0, hasOnly, false, ctx.config.allowOnly);
4280
- return {
4281
- file,
4282
- parsed: request.code,
4283
- filepath,
4284
- map: request.map,
4285
- definitions
4286
- };
4287
- }
4288
-
4289
4161
  const newLineRegExp = /\r?\n/;
4290
4162
  const errCodeRegExp = /error TS(?<errCode>\d+)/;
4291
4163
  async function makeTscErrorInfo(errInfo) {
@@ -4366,7 +4238,7 @@ class Typechecker {
4366
4238
  this._onWatcherRerun = fn;
4367
4239
  }
4368
4240
  async collectFileTests(filepath) {
4369
- return collectTests(this.project, filepath);
4241
+ return astCollectFileInformation(this.project, filepath, { pool: "typescript" });
4370
4242
  }
4371
4243
  getFiles() {
4372
4244
  return this.files;
@@ -4755,9 +4627,9 @@ function printErrorInner(error, project, options) {
4755
4627
  const testName = e.VITEST_TEST_NAME;
4756
4628
  // testName has testPath inside
4757
4629
  if (testPath) logger.error(c.red(`This error originated in "${c.bold(relative(project.config.root, testPath))}" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.`));
4758
- if (testName) logger.error(c.red(`The latest test that might've caused the error is "${c.bold(testName)}". It might mean one of the following:
4759
- - The error was thrown, while Vitest was running this test.
4760
- - If the error occurred after the test had been completed, this was the last documented test before it was thrown.`));
4630
+ if (testName) logger.error(c.red(`The last test to run before this error was "${c.bold(testName)}". This means either:
4631
+ - the error was thrown while Vitest was running this test, or
4632
+ - the error was thrown after the test completed, and this was the most recent test at that point.`));
4761
4633
  if (typeof e.cause === "object" && e.cause && "name" in e.cause) {
4762
4634
  e.cause.name = `Caused by: ${e.cause.name}`;
4763
4635
  printErrorInner(e.cause, project, {
@@ -5011,10 +4883,10 @@ class Logger {
5011
4883
  }
5012
4884
  printNoTestFound(filters) {
5013
4885
  const config = this.ctx.config;
5014
- if (config.watch && (config.changed || config.related?.length)) this.log(`No affected ${config.mode} files found\n`);
5015
- else if (config.watch) this.log(c.red(`No ${config.mode} files found. You can change the file name pattern by pressing "p"\n`));
5016
- else if (config.passWithNoTests) this.log(`No ${config.mode} files found, exiting with code 0\n`);
5017
- else this.error(c.red(`No ${config.mode} files found, exiting with code 1\n`));
4886
+ if (config.watch && (config.changed || config.related?.length)) this.log(`No affected test files found\n`);
4887
+ else if (config.watch) this.log(c.red(`No test files found. You can change the file name pattern by pressing "p"\n`));
4888
+ else if (config.passWithNoTests) this.log(`No test files found, exiting with code 0\n`);
4889
+ else this.error(c.red(`No test files found, exiting with code 1\n`));
5018
4890
  const comma = c.dim(", ");
5019
4891
  if (filters?.length) this.console.error(c.dim("filter: ") + c.yellow(filters.join(comma)));
5020
4892
  const projectsFilter = toArray(config.project);
@@ -5775,6 +5647,15 @@ function createMethodsRPC(project, methodsOptions = {}) {
5775
5647
  onAfterSuiteRun(meta) {
5776
5648
  vitest.coverageProvider?.onAfterSuiteRun(meta);
5777
5649
  },
5650
+ async onTestBenchmark(testId, benchmark) {
5651
+ return vitest._testRun.recordBenchmark(testId, benchmark);
5652
+ },
5653
+ async readBenchmarkResult(relativePath) {
5654
+ return project.benchmark.readResult(relativePath);
5655
+ },
5656
+ async writeBenchmarkResult(relativePath, data) {
5657
+ return project.benchmark.writeResult(relativePath, data);
5658
+ },
5778
5659
  async onTaskArtifactRecord(testId, artifact) {
5779
5660
  return vitest._testRun.recordArtifact(testId, artifact);
5780
5661
  },
@@ -6067,7 +5948,7 @@ class PoolRunner {
6067
5948
  }
6068
5949
  };
6069
5950
  emitUnexpectedExit = () => {
6070
- const error = /* @__PURE__ */ new Error("Worker exited unexpectedly");
5951
+ const error = /* @__PURE__ */ new Error(`Worker exited unexpectedly during ${this._state} state`);
6071
5952
  this._eventEmitter.emit("error", error);
6072
5953
  };
6073
5954
  waitForStart() {
@@ -6638,7 +6519,7 @@ function deepEqual$1(obj1, obj2) {
6638
6519
  const keys1 = Object.keys(obj1);
6639
6520
  const keys2 = Object.keys(obj2);
6640
6521
  if (keys1.length !== keys2.length) return false;
6641
- for (const key of keys1) if (!keys2.includes(key) || !deepEqual$1(obj1[key], obj2[key])) return false;
6522
+ for (const key of keys1) if (!Object.prototype.hasOwnProperty.call(obj2, key) || !deepEqual$1(obj1[key], obj2[key])) return false;
6642
6523
  return true;
6643
6524
  }
6644
6525
 
@@ -11902,11 +11783,12 @@ function getTestFileEnvironment(project, testFile, browser = false) {
11902
11783
  }
11903
11784
  }
11904
11785
 
11905
- async function getModuleGraph(ctx, projectName, testFilePath, browser = false) {
11786
+ async function getModuleGraph(ctx, projectName, testFilePath) {
11906
11787
  const graph = {};
11907
11788
  const externalized = /* @__PURE__ */ new Set();
11908
11789
  const inlined = /* @__PURE__ */ new Set();
11909
11790
  const project = ctx.getProjectByName(projectName);
11791
+ const browser = project.config.browser.enabled;
11910
11792
  const environment = project.config.experimental.viteModuleRunner === false ? project.vite.environments.__vitest__ : getTestFileEnvironment(project, testFilePath, browser);
11911
11793
  if (!environment) throw new Error(`Cannot find environment for ${testFilePath}`);
11912
11794
  const seen = /* @__PURE__ */ new Map();
@@ -12048,10 +11930,11 @@ function setup(ctx, _server) {
12048
11930
  } catch {}
12049
11931
  return result;
12050
11932
  },
12051
- async getTransformResult(projectName, moduleId, testFileTaskId, browser = false) {
11933
+ async getTransformResult(projectName, moduleId, testFileTaskId) {
12052
11934
  const project = ctx.getProjectByName(projectName);
12053
11935
  const testModule = ctx.state.getReportedEntityById(testFileTaskId);
12054
11936
  if (!testModule || !isFileServingAllowed(project.vite.config, moduleId)) return;
11937
+ const browser = !!project.config.browser.enabled;
12055
11938
  const environment = getTestFileEnvironment(project, testModule.moduleId, browser);
12056
11939
  const moduleNode = environment?.moduleGraph.getModuleById(moduleId);
12057
11940
  if (!environment || !moduleNode?.transformResult) return;
@@ -12069,8 +11952,8 @@ function setup(ctx, _server) {
12069
11952
  } catch {}
12070
11953
  return result;
12071
11954
  },
12072
- async getModuleGraph(project, id, browser) {
12073
- return getModuleGraph(ctx, project, id, browser);
11955
+ async getModuleGraph(project, id) {
11956
+ return getModuleGraph(ctx, project, id);
12074
11957
  },
12075
11958
  async updateSnapshot(file) {
12076
11959
  // silently ignore exec/write attempts if not allowed
@@ -12242,13 +12125,39 @@ function handleDefineValue(value) {
12242
12125
  return JSON.stringify(value);
12243
12126
  }
12244
12127
 
12128
+ class BenchmarkManager {
12129
+ constructor(project) {
12130
+ this.project = project;
12131
+ }
12132
+ // Resolve a user-supplied path against the project root. Reject paths that
12133
+ // escape the project root: `bench.from()` accepts arbitrary input, and we
12134
+ // never want a benchmark file to be able to read or clobber files outside
12135
+ // the workspace.
12136
+ resolve(relativePath) {
12137
+ const root = this.project.config.root;
12138
+ const absolute = isAbsolute(relativePath) ? resolve$1(relativePath) : resolve$1(root, relativePath);
12139
+ const rootWithSep = root.endsWith("/") ? root : `${root}/`;
12140
+ if (absolute !== root && !absolute.startsWith(rootWithSep)) throw new Error(`Benchmark artifact path "${relativePath}" resolves outside the project root (${root}). Paths passed to \`writeResult\` and \`bench.from()\` must point inside the project.`);
12141
+ return absolute;
12142
+ }
12143
+ async readResult(relativePath) {
12144
+ const path = this.resolve(relativePath);
12145
+ if (!existsSync(path)) return null;
12146
+ return JSON.parse(await readFile(path, "utf-8"));
12147
+ }
12148
+ async writeResult(relativePath, data) {
12149
+ const absolute = this.resolve(relativePath);
12150
+ await mkdir(dirname(absolute), { recursive: true });
12151
+ await writeFile(absolute, `${JSON.stringify(data, null, 2)}\n`, "utf-8");
12152
+ }
12153
+ }
12154
+
12245
12155
  function serializeConfig(project) {
12246
12156
  const { config, globalConfig } = project;
12247
12157
  const viteConfig = project._vite?.config;
12248
12158
  const optimizer = config.deps?.optimizer || {};
12249
12159
  return {
12250
12160
  environmentOptions: config.environmentOptions,
12251
- mode: config.mode,
12252
12161
  isolate: config.isolate,
12253
12162
  maxWorkers: config.maxWorkers,
12254
12163
  base: config.base,
@@ -12354,7 +12263,12 @@ function serializeConfig(project) {
12354
12263
  })(config.browser),
12355
12264
  standalone: config.standalone,
12356
12265
  printConsoleTrace: config.printConsoleTrace ?? globalConfig.printConsoleTrace,
12357
- benchmark: config.benchmark && { includeSamples: config.benchmark.includeSamples },
12266
+ benchmark: {
12267
+ enabled: config.benchmark.enabled,
12268
+ retainSamples: config.benchmark.retainSamples,
12269
+ suppressExportGetterWarnings: config.benchmark.suppressExportGetterWarnings,
12270
+ projectName: config.benchmark.projectName
12271
+ },
12358
12272
  serializedDefines: config.browser.enabled ? "" : project._serializedDefines || "",
12359
12273
  experimental: {
12360
12274
  fsModuleCache: config.experimental.fsModuleCache ?? false,
@@ -13365,7 +13279,8 @@ function WorkspaceVitestPlugin(project, options) {
13365
13279
  name: "vitest:project:name",
13366
13280
  enforce: "post",
13367
13281
  config(viteConfig) {
13368
- const testConfig = viteConfig.test || {};
13282
+ viteConfig.test ??= {};
13283
+ const testConfig = viteConfig.test;
13369
13284
  let { label: name, color } = typeof testConfig.name === "string" ? { label: testConfig.name } : {
13370
13285
  label: "",
13371
13286
  ...testConfig.name
@@ -13377,6 +13292,10 @@ function WorkspaceVitestPlugin(project, options) {
13377
13292
  if (existsSync(pkgJsonPath)) name = JSON.parse(readFileSync(pkgJsonPath, "utf-8")).name;
13378
13293
  if (typeof name !== "string" || !name) name = basename(dir);
13379
13294
  } else name = options.workspacePath.toString();
13295
+ if (project.vitest._cliOptions.benchmarkOnly) {
13296
+ viteConfig.test.benchmark ??= {};
13297
+ viteConfig.test.benchmark.enabled = true;
13298
+ }
13380
13299
  const isBrowserEnabled = viteConfig.test?.browser?.enabled ?? (viteConfig.test?.browser && project.vitest._cliOptions.browser?.enabled);
13381
13300
  // keep project names to potentially filter it out
13382
13301
  const workspaceNames = [name];
@@ -13389,6 +13308,7 @@ function WorkspaceVitestPlugin(project, options) {
13389
13308
  instance.name ??= name ? `${name} (${instance.browser})` : instance.browser;
13390
13309
  if (isBrowserEnabled) workspaceNames.push(instance.name);
13391
13310
  });
13311
+ if (viteConfig.test?.benchmark?.enabled) workspaceNames.push(name ? `${name} (bench)` : "bench");
13392
13312
  // if there is `--project=...` filter, check if any of the potential projects match
13393
13313
  // if projects don't match, we ignore the test project altogether
13394
13314
  // if some of them match, they will later be filtered again by `resolveWorkspace`
@@ -13721,6 +13641,7 @@ class TestProject {
13721
13641
  * Temporary directory for the project. This is unique for each project. Vitest stores transformed content here.
13722
13642
  */
13723
13643
  tmpDir;
13644
+ benchmark = new BenchmarkManager(this);
13724
13645
  /** @internal */ typechecker;
13725
13646
  /** @internal */ _config;
13726
13647
  /** @internal */ _vite;
@@ -14126,7 +14047,7 @@ class TestProject {
14126
14047
  return project;
14127
14048
  }
14128
14049
  /** @internal */
14129
- static _cloneBrowserProject(parent, config) {
14050
+ static _cloneTestProject(parent, config) {
14130
14051
  const clone = new TestProject(parent.vitest, void 0, parent.tmpDir);
14131
14052
  clone.runner = parent.runner;
14132
14053
  clone._vite = parent._vite;
@@ -14288,7 +14209,58 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
14288
14209
  }
14289
14210
  names.add(name);
14290
14211
  }
14291
- return resolveBrowserProjects(vitest, names, resolvedProjects);
14212
+ return resolveDefaultProjects(vitest, names, resolvedProjects);
14213
+ }
14214
+ async function resolveDefaultProjects(vitest, names, resolvedProjects) {
14215
+ const newProjects = await resolveBrowserProjects(vitest, names, resolvedProjects);
14216
+ let lastGroupOrder = Math.max(0, ...newProjects.map((p) => p.config.sequence.groupOrder));
14217
+ newProjects.forEach((project) => {
14218
+ const benchmark = project.config.benchmark;
14219
+ if (!benchmark.enabled) return;
14220
+ if (vitest.isExcludedByProjectFilter(project.config.name)) {
14221
+ benchmark.enabled = false;
14222
+ return;
14223
+ }
14224
+ const name = project.config.name ? `${project.config.name} (bench)` : "bench";
14225
+ if (!vitest.matchesProjectFilter(name)) {
14226
+ benchmark.enabled = false;
14227
+ return;
14228
+ }
14229
+ if (names.has(name)) throw new Error(`Cannot create a benchmark project because the name "${name}" is already in use.`);
14230
+ names.add(name);
14231
+ const benchmarkProject = TestProject._cloneTestProject(project, {
14232
+ ...project.config,
14233
+ name,
14234
+ include: benchmark.include,
14235
+ exclude: benchmark.exclude,
14236
+ includeSource: benchmark.includeSource,
14237
+ coverage: {
14238
+ ...project.config.coverage,
14239
+ enabled: false
14240
+ },
14241
+ maxWorkers: 1,
14242
+ maxConcurrency: 1,
14243
+ testTimeout: project.config.testTimeout < 6e4 ? 6e4 : project.config.testTimeout,
14244
+ hookTimeout: project.config.hookTimeout < 12e4 ? 12e4 : project.config.hookTimeout,
14245
+ benchmark: {
14246
+ ...benchmark,
14247
+ projectName: project.config.name ?? ""
14248
+ },
14249
+ sequence: {
14250
+ ...project.config.sequence,
14251
+ concurrent: false,
14252
+ groupOrder: ++lastGroupOrder
14253
+ },
14254
+ typecheck: {
14255
+ ...project.config.typecheck,
14256
+ enabled: false
14257
+ }
14258
+ });
14259
+ // disable benchmark in the original project
14260
+ benchmark.enabled = false;
14261
+ newProjects.push(benchmarkProject);
14262
+ });
14263
+ return newProjects;
14292
14264
  }
14293
14265
  async function resolveBrowserProjects(vitest, names, resolvedProjects) {
14294
14266
  const removeProjects = /* @__PURE__ */ new Set();
@@ -14329,7 +14301,7 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
14329
14301
  names.add(name);
14330
14302
  const clonedConfig = cloneConfig(project, config);
14331
14303
  clonedConfig.name = name;
14332
- const clone = TestProject._cloneBrowserProject(project, clonedConfig);
14304
+ const clone = TestProject._cloneTestProject(project, clonedConfig);
14333
14305
  resolvedProjects.push(clone);
14334
14306
  });
14335
14307
  removeProjects.add(project);
@@ -14454,8 +14426,10 @@ function getDefaultTestProject(vitest) {
14454
14426
  }
14455
14427
  function getPotentialProjectNames(project) {
14456
14428
  const names = [project.name];
14429
+ // TODO: include benchmarks in browsers
14457
14430
  if (project.config.browser.instances) names.push(...project.config.browser.instances.map((i) => i.name));
14458
14431
  else if (project.config.browser.name) names.push(project.config.browser.name);
14432
+ if (project.config.benchmark.enabled) names.push(project.name ? `${project.name} (bench)` : "bench");
14459
14433
  return names;
14460
14434
  }
14461
14435
 
@@ -14687,6 +14661,66 @@ function createReport(ctx, scope) {
14687
14661
  };
14688
14662
  }
14689
14663
 
14664
+ const BENCH_TABLE_HEAD = [
14665
+ "hz",
14666
+ "min",
14667
+ "max",
14668
+ "mean",
14669
+ "p75",
14670
+ "p99",
14671
+ "p995",
14672
+ "p999",
14673
+ "rme",
14674
+ "samples"
14675
+ ];
14676
+ function formatBenchNumber(number) {
14677
+ const res = String(number.toFixed(number < 100 ? 4 : 2)).split(".");
14678
+ return res[0].replace(/(?=(?:\d{3})+$)\B/g, ",") + (res[1] ? `.${res[1]}` : "");
14679
+ }
14680
+ // Plain-text rendering of the benchmark table (no ANSI colors, no indent).
14681
+ // Used by the junit reporter to embed benchmark data in <system-out>.
14682
+ function renderBenchmarkTableText(benchmarks, columnName = "name") {
14683
+ const lines = [];
14684
+ for (const benchmark of benchmarks) {
14685
+ const { tasks } = benchmark;
14686
+ if (tasks.length === 0) continue;
14687
+ if (lines.length > 0) lines.push("");
14688
+ const rows = tasks.map(renderBenchmarkRow);
14689
+ const head = [columnName, ...BENCH_TABLE_HEAD];
14690
+ const widths = computeBenchColumnWidths(head, rows);
14691
+ lines.push(padBenchRow(head, widths).join(" "));
14692
+ for (const task of tasks) {
14693
+ let row = padBenchRow(renderBenchmarkRow(task), widths).join(" ");
14694
+ if (task.rank === 1 && tasks.length > 1) row += " fastest";
14695
+ if (task.rank === tasks.length && tasks.length > 2) row += " slowest";
14696
+ lines.push(row);
14697
+ }
14698
+ }
14699
+ return lines.join("\n");
14700
+ }
14701
+ function renderBenchmarkRow(task) {
14702
+ return [
14703
+ task.name,
14704
+ formatBenchNumber(task.throughput.mean || 0),
14705
+ formatBenchNumber(task.latency.min || 0),
14706
+ formatBenchNumber(task.latency.max || 0),
14707
+ formatBenchNumber(task.latency.mean || 0),
14708
+ formatBenchNumber(task.latency.p75 || 0),
14709
+ formatBenchNumber(task.latency.p99 || 0),
14710
+ formatBenchNumber(task.latency.p995 || 0),
14711
+ formatBenchNumber(task.latency.p999 || 0),
14712
+ `\u00B1${(task.latency.rme || 0).toFixed(2)}%`,
14713
+ String(task.latency.samplesCount || 0)
14714
+ ];
14715
+ }
14716
+ function computeBenchColumnWidths(header, rows) {
14717
+ const allRows = [header, ...rows];
14718
+ return Array.from(header, (_, i) => Math.max(...allRows.map((row) => stripVTControlCharacters(row[i]).length)));
14719
+ }
14720
+ function padBenchRow(row, widths) {
14721
+ return row.map((v, i) => i === 0 ? v.padEnd(widths[i]) : v.padStart(widths[i]));
14722
+ }
14723
+
14690
14724
  const BADGE_PADDING = " ";
14691
14725
  class BaseReporter {
14692
14726
  start = 0;
@@ -14700,6 +14734,7 @@ class BaseReporter {
14700
14734
  silent;
14701
14735
  _filesInWatchMode = /* @__PURE__ */ new Map();
14702
14736
  _timeStart = formatTimeString(/* @__PURE__ */ new Date());
14737
+ _perProjectBenchmarks = /* @__PURE__ */ new Map();
14703
14738
  constructor(options = {}) {
14704
14739
  this.isTTY = options.isTTY ?? isTTY;
14705
14740
  this.silent = options.silent;
@@ -14721,17 +14756,34 @@ class BaseReporter {
14721
14756
  onTestRunStart(_specifications) {
14722
14757
  this.start = performance$1.now();
14723
14758
  this._timeStart = formatTimeString(/* @__PURE__ */ new Date());
14759
+ this._perProjectBenchmarks.clear();
14724
14760
  }
14725
14761
  onTestRunEnd(testModules, unhandledErrors, _reason) {
14726
14762
  const files = testModules.map((testModule) => testModule.task);
14727
14763
  const errors = [...unhandledErrors];
14728
14764
  this.end = performance$1.now();
14729
14765
  if (!files.length && !errors.length) this.ctx.logger.printNoTestFound(this.ctx.filenamePattern);
14730
- else this.reportSummary(files, errors);
14766
+ else {
14767
+ this.printPerProjectBenchmarks();
14768
+ this.reportSummary(files, errors);
14769
+ }
14731
14770
  }
14732
14771
  onTestCaseResult(testCase) {
14733
14772
  if (testCase.result().state === "failed") this.logFailedTask(testCase.task);
14734
14773
  }
14774
+ onTestCaseBenchmark(testCase, benchmark) {
14775
+ const projectName = testCase.project.name || "";
14776
+ for (const task of benchmark.tasks) {
14777
+ if (!task.perProject) continue;
14778
+ const benchKey = `${testCase.module.relativeModuleId} > ${testCase.fullName} > ${task.name}`;
14779
+ let projectMap = this._perProjectBenchmarks.get(benchKey);
14780
+ if (!projectMap) {
14781
+ projectMap = /* @__PURE__ */ new Map();
14782
+ this._perProjectBenchmarks.set(benchKey, projectMap);
14783
+ }
14784
+ projectMap.set(projectName, task);
14785
+ }
14786
+ }
14735
14787
  onTestSuiteResult(testSuite) {
14736
14788
  if (testSuite.state() === "failed") this.logFailedTask(testSuite.task);
14737
14789
  }
@@ -14790,9 +14842,13 @@ class BaseReporter {
14790
14842
  const { duration = 0 } = test.diagnostic() || {};
14791
14843
  const padding = this.getTestIndentation(test.task);
14792
14844
  const suffix = this.getTestCaseSuffix(test);
14845
+ // perProject tasks still appear in the inline table — they're additionally
14846
+ // aggregated in the cross-project section at the end of the run
14847
+ const inlineBenchmarks = test.benchmarks().filter((b) => b.tasks.length > 0);
14793
14848
  if (testResult.state === "failed") this.log(c.red(` ${padding}${taskFail} ${this.getTestName(test.task, separator)}`) + suffix);
14794
- else if (duration > this.ctx.config.slowTestThreshold) this.log(` ${padding}${c.yellow(c.dim(F_CHECK))} ${this.getTestName(test.task, separator)} ${suffix}`);
14795
- else if (this.ctx.config.hideSkippedTests && testResult.state === "skipped" && test.options.mode !== "todo") ; else if (this.renderSucceed || moduleState === "failed") this.log(` ${padding}${this.getStateSymbol(test)} ${this.getTestName(test.task, separator)}${suffix}`);
14849
+ else if (duration > this.ctx.config.slowTestThreshold) this.log(` ${padding}${c.yellow(c.dim(F_CHECK))} ${this.getTestName(test.task, separator)}${suffix}`);
14850
+ else if (this.ctx.config.hideSkippedTests && testResult.state === "skipped" && test.options.mode !== "todo") ; else if (this.renderSucceed || moduleState === "failed" || inlineBenchmarks.length) this.log(` ${padding}${this.getStateSymbol(test)} ${this.getTestName(test.task, separator)}${suffix}`);
14851
+ if (inlineBenchmarks.length > 0) this.printBenchmarkTable(inlineBenchmarks, padding);
14796
14852
  }
14797
14853
  getModuleLog(testModule, counts) {
14798
14854
  let state = c.dim(`${counts.tests} test${counts.tests > 1 ? "s" : ""}`);
@@ -14946,8 +15002,7 @@ class BaseReporter {
14946
15002
  reportSummary(files, errors) {
14947
15003
  this.printErrorsSummary(files, errors);
14948
15004
  const leakCount = this.printLeaksSummary();
14949
- if (this.ctx.config.mode === "benchmark") this.reportBenchmarkSummary(files);
14950
- else this.reportTestSummary(files, errors, leakCount);
15005
+ this.reportTestSummary(files, errors, leakCount);
14951
15006
  }
14952
15007
  reportTestSummary(files, errors, leakCount) {
14953
15008
  this.log();
@@ -15012,19 +15067,23 @@ class BaseReporter {
15012
15067
  }
15013
15068
  }
15014
15069
  if (allImports.length === 0) return;
15015
- const dangerImports = allImports.filter((imp) => imp.totalTime >= thresholds.danger);
15016
- const warnImports = allImports.filter((imp) => imp.totalTime >= thresholds.warn);
15017
- const hasDangerImports = dangerImports.length > 0;
15018
- const hasWarnImports = warnImports.length > 0;
15070
+ let dangerImportsCount = 0;
15071
+ let hasWarnImports = false;
15072
+ let totalSelfTime = 0;
15073
+ let totalTotalTime = 0;
15074
+ for (const imp of allImports) {
15075
+ if (imp.totalTime >= thresholds.danger) dangerImportsCount++;
15076
+ if (imp.totalTime >= thresholds.warn) hasWarnImports = true;
15077
+ totalSelfTime += imp.selfTime;
15078
+ totalTotalTime += imp.totalTime;
15079
+ }
15019
15080
  // Determine if we should print
15020
- const shouldFail = failOnDanger && hasDangerImports;
15081
+ const shouldFail = failOnDanger && dangerImportsCount > 0;
15021
15082
  if (!(print === true || print === "on-warn" && hasWarnImports || shouldFail)) return;
15022
15083
  const sortedImports = allImports.sort((a, b) => b.totalTime - a.totalTime);
15023
15084
  const maxTotalTime = sortedImports[0].totalTime;
15024
15085
  const limit = this.ctx.config.experimental.importDurations.limit;
15025
15086
  const topImports = sortedImports.slice(0, limit);
15026
- const totalSelfTime = allImports.reduce((sum, imp) => sum + imp.selfTime, 0);
15027
- const totalTotalTime = allImports.reduce((sum, imp) => sum + imp.totalTime, 0);
15028
15087
  const slowestImport = sortedImports[0];
15029
15088
  this.log();
15030
15089
  this.log(c.bold("Import Duration Breakdown") + c.dim(` (Top ${limit})`));
@@ -15064,7 +15123,7 @@ class BaseReporter {
15064
15123
  // Fail if danger threshold exceeded
15065
15124
  if (shouldFail) {
15066
15125
  this.log();
15067
- this.ctx.logger.error(`ERROR: ${dangerImports.length} import(s) exceeded the danger threshold of ${thresholds.danger}ms`);
15126
+ this.ctx.logger.error(`ERROR: ${dangerImportsCount} import(s) exceeded the danger threshold of ${thresholds.danger}ms`);
15068
15127
  process.exitCode = 1;
15069
15128
  }
15070
15129
  }
@@ -15131,21 +15190,63 @@ class BaseReporter {
15131
15190
  }
15132
15191
  return leakWithStacks.size;
15133
15192
  }
15134
- reportBenchmarkSummary(files) {
15135
- const topBenches = getTests(files).filter((i) => i.result?.benchmark?.rank === 1);
15136
- this.log(`\n${withLabel("cyan", "BENCH", "Summary\n")}`);
15137
- for (const bench of topBenches) {
15138
- const group = bench.suite || bench.file;
15139
- if (!group) continue;
15140
- const groupName = this.getFullName(group, separator);
15141
- const project = this.ctx.projects.find((p) => p.name === bench.file.projectName);
15142
- this.log(` ${formatProjectName(project)}${bench.name}${c.dim(` - ${groupName}`)}`);
15143
- const siblings = group.tasks.filter((i) => i.meta.benchmark && i.result?.benchmark && i !== bench).sort((a, b) => a.result.benchmark.rank - b.result.benchmark.rank);
15144
- for (const sibling of siblings) {
15145
- const number = (sibling.result.benchmark.mean / bench.result.benchmark.mean).toFixed(2);
15146
- this.log(c.green(` ${number}x `) + c.gray("faster than ") + sibling.name);
15147
- }
15193
+ printPerProjectBenchmarks() {
15194
+ if (this._perProjectBenchmarks.size === 0) return;
15195
+ let hasComparable = false;
15196
+ for (const projectMap of this._perProjectBenchmarks.values()) if (projectMap.size > 1) {
15197
+ hasComparable = true;
15198
+ break;
15199
+ }
15200
+ if (!hasComparable) return;
15201
+ this.log("");
15202
+ this.log(divider(c.bold(c.bgBlue(` Cross-Project Benchmark Comparison `)), null, null, c.blue));
15203
+ for (const [benchName, projectMap] of this._perProjectBenchmarks) {
15204
+ const tasks = [...projectMap.entries()].sort((a, b) => a[1].latency.mean - b[1].latency.mean).map(([projectName, task], index) => ({
15205
+ ...task,
15206
+ name: projectName,
15207
+ rank: index + 1
15208
+ }));
15209
+ if (tasks.length <= 1) continue;
15148
15210
  this.log("");
15211
+ this.log(` ${c.dim(benchName)}`);
15212
+ this.printBenchmarkTable([{
15213
+ name: benchName,
15214
+ tasks
15215
+ }], "", "project");
15216
+ }
15217
+ this.log("");
15218
+ }
15219
+ printBenchmarkTable(benchmarks, basePadding, columnName = "name") {
15220
+ let printedCount = 0;
15221
+ for (const benchmark of benchmarks) {
15222
+ const { tasks } = benchmark;
15223
+ if (tasks.length === 0) continue;
15224
+ if (printedCount > 0) this.log("");
15225
+ const rows = tasks.map((t) => renderBenchmarkRow(t));
15226
+ const tableHead = [columnName, ...BENCH_TABLE_HEAD];
15227
+ const widths = computeBenchColumnWidths(tableHead, rows);
15228
+ const indent = ` ${basePadding} `;
15229
+ this.log(`${indent}${padBenchRow(tableHead, widths).map(c.bold).join(" ")}`);
15230
+ printedCount++;
15231
+ for (const task of tasks) {
15232
+ const padded = padBenchRow(renderBenchmarkRow(task), widths);
15233
+ let row = [
15234
+ padded[0],
15235
+ c.blue(padded[1]),
15236
+ c.cyan(padded[2]),
15237
+ c.cyan(padded[3]),
15238
+ c.cyan(padded[4]),
15239
+ c.cyan(padded[5]),
15240
+ c.cyan(padded[6]),
15241
+ c.cyan(padded[7]),
15242
+ c.cyan(padded[8]),
15243
+ c.dim(padded[9]),
15244
+ c.dim(padded[10])
15245
+ ].join(" ");
15246
+ if (task.rank === 1 && tasks.length > 1) row += c.bold(c.green(" fastest"));
15247
+ if (task.rank === tasks.length && tasks.length > 2) row += c.bold(c.gray(" slowest"));
15248
+ this.log(`${indent}${row}`);
15249
+ }
15149
15250
  }
15150
15251
  }
15151
15252
  printTaskErrors(tasks, errorDivider) {
@@ -15203,7 +15304,7 @@ function deepEqual(a, b) {
15203
15304
  const keysA = Object.keys(a);
15204
15305
  const keysB = Object.keys(b);
15205
15306
  if (keysA.length !== keysB.length) return false;
15206
- for (const key of keysA) if (!keysB.includes(key) || !deepEqual(a[key], b[key])) return false;
15307
+ for (const key of keysA) if (!Object.prototype.hasOwnProperty.call(b, key) || !deepEqual(a[key], b[key])) return false;
15207
15308
  return true;
15208
15309
  }
15209
15310
  function sum(items, cb) {
@@ -15436,28 +15537,30 @@ class SummaryReporter {
15436
15537
  this.maxParallelTests = Math.max(this.maxParallelTests, this.runningModules.size);
15437
15538
  this.renderer.schedule();
15438
15539
  }
15439
- onHookStart(options) {
15440
- const stats = this.getHookStats(options);
15441
- if (!stats) return;
15442
- const hook = {
15443
- name: options.name,
15540
+ startStep(stats, name) {
15541
+ const step = {
15542
+ name,
15444
15543
  visible: false,
15445
15544
  startTime: performance.now(),
15446
15545
  onFinish: () => {}
15447
15546
  };
15448
- stats.hook?.onFinish?.();
15449
- stats.hook = hook;
15547
+ stats.step?.onFinish?.();
15548
+ stats.step = step;
15450
15549
  if (!Number.isFinite(this.ctx.config.slowTestThreshold)) return;
15451
15550
  const timeout = setTimeout(() => {
15452
- hook.visible = true;
15551
+ step.visible = true;
15453
15552
  }, this.ctx.config.slowTestThreshold).unref();
15454
- hook.onFinish = () => clearTimeout(timeout);
15553
+ step.onFinish = () => clearTimeout(timeout);
15554
+ }
15555
+ onHookStart(options) {
15556
+ const stats = this.getStepStats(options.entity);
15557
+ if (stats) this.startStep(stats, options.name);
15455
15558
  }
15456
15559
  onHookEnd(options) {
15457
- const stats = this.getHookStats(options);
15458
- if (stats?.hook?.name !== options.name) return;
15459
- stats.hook.onFinish();
15460
- stats.hook.visible = false;
15560
+ const stats = this.getStepStats(options.entity);
15561
+ if (stats?.step?.name !== options.name) return;
15562
+ stats.step.onFinish();
15563
+ stats.step.visible = false;
15461
15564
  }
15462
15565
  onTestCaseReady(test) {
15463
15566
  // Track slow running tests only on verbose mode
@@ -15474,7 +15577,7 @@ class SummaryReporter {
15474
15577
  slowTest.visible = true;
15475
15578
  }, this.ctx.config.slowTestThreshold).unref() : void 0;
15476
15579
  slowTest.onFinish = () => {
15477
- slowTest.hook?.onFinish();
15580
+ slowTest.step?.onFinish();
15478
15581
  clearTimeout(timeout);
15479
15582
  };
15480
15583
  stats.tests.set(test.id, slowTest);
@@ -15514,7 +15617,7 @@ class SummaryReporter {
15514
15617
  this.removeTestModule(module.id);
15515
15618
  this.renderer.schedule();
15516
15619
  }
15517
- getHookStats({ entity }) {
15620
+ getStepStats(entity) {
15518
15621
  // Track slow running hooks only on verbose mode
15519
15622
  if (!this.options.verbose) return;
15520
15623
  const module = entity.type === "module" ? entity : entity.module;
@@ -15531,12 +15634,12 @@ class SummaryReporter {
15531
15634
  name: testFile.projectName,
15532
15635
  color: testFile.projectColor
15533
15636
  }) + typecheck + label + testFile.filename + c.dim(!testFile.completed && !testFile.total ? " [queued]" : ` ${testFile.completed}/${testFile.total}`));
15534
- const slowTasks = [testFile.hook, ...testFile.tests.values()].filter((t) => t != null && t.visible);
15637
+ const slowTasks = [testFile.step, ...testFile.tests.values()].filter((t) => t != null && t.visible);
15535
15638
  for (const [index, task] of slowTasks.entries()) {
15536
15639
  const elapsed = this.currentTime - task.startTime;
15537
15640
  const icon = index === slowTasks.length - 1 ? F_TREE_NODE_END : F_TREE_NODE_MIDDLE;
15538
15641
  summary.push(c.bold(c.yellow(` ${icon} `)) + task.name + c.bold(c.yellow(` ${formatTime(Math.max(0, elapsed))}`)));
15539
- if (task.hook?.visible) summary.push(c.bold(c.yellow(` ${F_TREE_NODE_END} `)) + task.hook.name);
15642
+ if (task.step?.visible) summary.push(c.bold(c.yellow(` ${F_TREE_NODE_END} `)) + task.step.name);
15540
15643
  }
15541
15644
  }
15542
15645
  if (this.runningModules.size > 0) summary.push("");
@@ -15558,7 +15661,7 @@ class SummaryReporter {
15558
15661
  removeTestModule(id) {
15559
15662
  if (!id) return;
15560
15663
  const testFile = this.runningModules.get(id);
15561
- testFile?.hook?.onFinish();
15664
+ testFile?.step?.onFinish();
15562
15665
  testFile?.tests?.forEach((test) => test.onFinish());
15563
15666
  this.runningModules.delete(id);
15564
15667
  clearTimeout(this.finishedModules.get(id));
@@ -16099,7 +16202,8 @@ class JsonReporter {
16099
16202
  }
16100
16203
  return filtered;
16101
16204
  })() : t.meta,
16102
- tags: t.tags || []
16205
+ tags: t.tags || [],
16206
+ benchmarks: t.benchmarks
16103
16207
  };
16104
16208
  });
16105
16209
  if (tests.some((t) => t.result?.state === "run" || t.result?.state === "queued")) this.ctx.logger.warn("WARNING: Some tests are still running when generating the JSON report.This is likely an internal bug in Vitest.Please report it to https://github.com/vitest-dev/vitest/issues");
@@ -16259,6 +16363,18 @@ class JUnitReporter {
16259
16363
  for (const log of logs) await this.baseLog(escapeXML(log.content));
16260
16364
  });
16261
16365
  }
16366
+ async writeSystemOut(task) {
16367
+ const logs = this.options.includeConsoleOutput && task.logs ? task.logs.filter((log) => log.type === "stdout") : [];
16368
+ const benchmarks = task.type === "test" ? task.benchmarks : [];
16369
+ if (logs.length === 0 && benchmarks.length === 0) return;
16370
+ await this.writeElement("system-out", {}, async () => {
16371
+ for (const log of logs) await this.baseLog(escapeXML(log.content));
16372
+ if (benchmarks.length > 0) {
16373
+ if (logs.length > 0) await this.baseLog("");
16374
+ await this.baseLog(escapeXML(renderBenchmarkTableText(benchmarks)));
16375
+ }
16376
+ });
16377
+ }
16262
16378
  applyTemplate(template, vars) {
16263
16379
  if (typeof template === "function") return template(vars);
16264
16380
  return template.replace(/\{filename\}/g, () => vars.filename).replace(/\{filepath\}/g, () => vars.filepath).replace(/\{basename\}/g, () => vars.basename).replace(/\{classname\}/g, () => vars.classname).replace(/\{title\}/g, () => vars.title).replace(/\{suitename\}/g, () => vars.suitename).replace(/\{displayName\}/g, () => vars.displayName);
@@ -16284,10 +16400,8 @@ class JUnitReporter {
16284
16400
  name: testcaseName,
16285
16401
  time: getDuration(task)
16286
16402
  }, async () => {
16287
- if (this.options.includeConsoleOutput) {
16288
- await this.writeLogs(task, "out");
16289
- await this.writeLogs(task, "err");
16290
- }
16403
+ await this.writeSystemOut(task);
16404
+ if (this.options.includeConsoleOutput) await this.writeLogs(task, "err");
16291
16405
  if (task.mode === "skip" || task.mode === "todo") await this.logger.log("<skipped/>");
16292
16406
  if (task.type === "test" && task.annotations.length) {
16293
16407
  await this.logger.log("<properties>");
@@ -16405,7 +16519,8 @@ class JUnitReporter {
16405
16519
  suite: null,
16406
16520
  file: null,
16407
16521
  annotations: [],
16408
- artifacts: []
16522
+ artifacts: [],
16523
+ benchmarks: []
16409
16524
  });
16410
16525
  }
16411
16526
  return {
@@ -16607,231 +16722,11 @@ class VerboseReporter extends DefaultReporter {
16607
16722
  this.printAnnotations(test, "log", 3);
16608
16723
  this.log();
16609
16724
  }
16725
+ const inlineBenchmarks = test.benchmarks().filter((b) => b.tasks.length > 0);
16726
+ if (inlineBenchmarks.length > 0) this.printBenchmarkTable(inlineBenchmarks, "");
16610
16727
  }
16611
16728
  }
16612
16729
 
16613
- function createBenchmarkJsonReport(files) {
16614
- const report = { files: [] };
16615
- for (const file of files) {
16616
- const groups = [];
16617
- for (const task of getTasks(file)) if (task?.type === "suite") {
16618
- const benchmarks = [];
16619
- for (const t of task.tasks) {
16620
- const benchmark = t.meta.benchmark && t.result?.benchmark;
16621
- if (benchmark) benchmarks.push({
16622
- id: t.id,
16623
- ...benchmark,
16624
- samples: []
16625
- });
16626
- }
16627
- if (benchmarks.length) groups.push({
16628
- fullName: getFullName(task, " > "),
16629
- benchmarks
16630
- });
16631
- }
16632
- report.files.push({
16633
- filepath: file.filepath,
16634
- groups
16635
- });
16636
- }
16637
- return report;
16638
- }
16639
- function flattenFormattedBenchmarkReport(report) {
16640
- const flat = {};
16641
- for (const file of report.files) for (const group of file.groups) for (const t of group.benchmarks) flat[t.id] = t;
16642
- return flat;
16643
- }
16644
-
16645
- const outputMap = /* @__PURE__ */ new WeakMap();
16646
- function formatNumber(number) {
16647
- const res = String(number.toFixed(number < 100 ? 4 : 2)).split(".");
16648
- return res[0].replace(/(?=(?:\d{3})+$)\B/g, ",") + (res[1] ? `.${res[1]}` : "");
16649
- }
16650
- const tableHead = [
16651
- "name",
16652
- "hz",
16653
- "min",
16654
- "max",
16655
- "mean",
16656
- "p75",
16657
- "p99",
16658
- "p995",
16659
- "p999",
16660
- "rme",
16661
- "samples"
16662
- ];
16663
- function renderBenchmarkItems(result) {
16664
- return [
16665
- result.name,
16666
- formatNumber(result.hz || 0),
16667
- formatNumber(result.min || 0),
16668
- formatNumber(result.max || 0),
16669
- formatNumber(result.mean || 0),
16670
- formatNumber(result.p75 || 0),
16671
- formatNumber(result.p99 || 0),
16672
- formatNumber(result.p995 || 0),
16673
- formatNumber(result.p999 || 0),
16674
- `±${(result.rme || 0).toFixed(2)}%`,
16675
- (result.sampleCount || 0).toString()
16676
- ];
16677
- }
16678
- function computeColumnWidths(results) {
16679
- const rows = [tableHead, ...results.map((v) => renderBenchmarkItems(v))];
16680
- return Array.from(tableHead, (_, i) => Math.max(...rows.map((row) => stripVTControlCharacters(row[i]).length)));
16681
- }
16682
- function padRow(row, widths) {
16683
- return row.map((v, i) => i ? v.padStart(widths[i], " ") : v.padEnd(widths[i], " "));
16684
- }
16685
- function renderTableHead(widths) {
16686
- return " ".repeat(3) + padRow(tableHead, widths).map(c.bold).join(" ");
16687
- }
16688
- function renderBenchmark(result, widths) {
16689
- const padded = padRow(renderBenchmarkItems(result), widths);
16690
- return [
16691
- padded[0],
16692
- c.blue(padded[1]),
16693
- c.cyan(padded[2]),
16694
- c.cyan(padded[3]),
16695
- c.cyan(padded[4]),
16696
- c.cyan(padded[5]),
16697
- c.cyan(padded[6]),
16698
- c.cyan(padded[7]),
16699
- c.cyan(padded[8]),
16700
- c.dim(padded[9]),
16701
- c.dim(padded[10])
16702
- ].join(" ");
16703
- }
16704
- function renderTable(options) {
16705
- const output = [];
16706
- const benchMap = {};
16707
- for (const task of options.tasks) if (task.meta.benchmark && task.result?.benchmark) benchMap[task.id] = {
16708
- current: task.result.benchmark,
16709
- baseline: options.compare?.[task.id]
16710
- };
16711
- const benchCount = Object.entries(benchMap).length;
16712
- const columnWidths = computeColumnWidths(Object.values(benchMap).flatMap((v) => [v.current, v.baseline]).filter(notNullish));
16713
- let idx = 0;
16714
- const padding = " ".repeat(1 );
16715
- for (const task of options.tasks) {
16716
- const duration = task.result?.duration;
16717
- const bench = benchMap[task.id];
16718
- let prefix = "";
16719
- if (idx === 0 && task.meta?.benchmark) prefix += `${renderTableHead(columnWidths)}\n${padding}`;
16720
- prefix += ` ${getStateSymbol(task)} `;
16721
- let suffix = "";
16722
- if (task.type === "suite") suffix += c.dim(` (${getTests(task).length})`);
16723
- if (task.mode === "skip" || task.mode === "todo") suffix += c.dim(c.gray(" [skipped]"));
16724
- if (duration != null) {
16725
- const color = duration > options.slowTestThreshold ? c.yellow : c.green;
16726
- suffix += color(` ${Math.round(duration)}${c.dim("ms")}`);
16727
- }
16728
- if (options.showHeap && task.result?.heap != null) suffix += c.magenta(` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`);
16729
- if (bench) {
16730
- let body = renderBenchmark(bench.current, columnWidths);
16731
- if (options.compare && bench.baseline) {
16732
- if (bench.current.hz) {
16733
- const diff = bench.current.hz / bench.baseline.hz;
16734
- const diffFixed = diff.toFixed(2);
16735
- if (diffFixed === "1.0.0") body += c.gray(` [${diffFixed}x]`);
16736
- if (diff > 1) body += c.blue(` [${diffFixed}x] ⇑`);
16737
- else body += c.red(` [${diffFixed}x] ⇓`);
16738
- }
16739
- output.push(padding + prefix + body + suffix);
16740
- const bodyBaseline = renderBenchmark(bench.baseline, columnWidths);
16741
- output.push(`${padding} ${bodyBaseline} ${c.dim("(baseline)")}`);
16742
- } else {
16743
- if (bench.current.rank === 1 && benchCount > 1) body += c.bold(c.green(" fastest"));
16744
- if (bench.current.rank === benchCount && benchCount > 2) body += c.bold(c.gray(" slowest"));
16745
- output.push(padding + prefix + body + suffix);
16746
- }
16747
- } else output.push(padding + prefix + task.name + suffix);
16748
- if (task.result?.state !== "pass" && outputMap.get(task) != null) {
16749
- let data = outputMap.get(task);
16750
- if (typeof data === "string") {
16751
- data = stripVTControlCharacters(data.trim().split("\n").filter(Boolean).pop());
16752
- if (data === "") data = void 0;
16753
- }
16754
- if (data != null) {
16755
- const out = ` ${" ".repeat(options.level)}${F_RIGHT} ${data}`;
16756
- output.push(c.gray(truncateString(out, options.columns)));
16757
- }
16758
- }
16759
- idx++;
16760
- }
16761
- return output.filter(Boolean).join("\n");
16762
- }
16763
-
16764
- class BenchmarkReporter extends DefaultReporter {
16765
- compare;
16766
- async onInit(ctx) {
16767
- super.onInit(ctx);
16768
- if (this.ctx.config.benchmark?.compare) {
16769
- const compareFile = pathe.resolve(this.ctx.config.root, this.ctx.config.benchmark?.compare);
16770
- try {
16771
- this.compare = flattenFormattedBenchmarkReport(JSON.parse(await fs__default.promises.readFile(compareFile, "utf-8")));
16772
- } catch (e) {
16773
- this.error(`Failed to read '${compareFile}'`, e);
16774
- }
16775
- }
16776
- }
16777
- onTaskUpdate(packs) {
16778
- for (const pack of packs) {
16779
- const task = this.ctx.state.idMap.get(pack[0]);
16780
- if (task?.type === "suite" && task.result?.state !== "run") task.tasks.filter((task) => task.result?.benchmark).sort((benchA, benchB) => benchA.result.benchmark.mean - benchB.result.benchmark.mean).forEach((bench, idx) => {
16781
- bench.result.benchmark.rank = Number(idx) + 1;
16782
- });
16783
- }
16784
- }
16785
- onTestSuiteResult(testSuite) {
16786
- super.onTestSuiteResult(testSuite);
16787
- this.printSuiteTable(testSuite);
16788
- }
16789
- printTestModule(testModule) {
16790
- this.printSuiteTable(testModule);
16791
- }
16792
- printSuiteTable(testTask) {
16793
- const state = testTask.state();
16794
- if (state === "pending" || state === "queued") return;
16795
- const benches = testTask.task.tasks.filter((t) => t.meta.benchmark);
16796
- const duration = testTask.task.result?.duration || 0;
16797
- if (benches.length > 0 && benches.every((t) => t.result?.state !== "run" && t.result?.state !== "queued")) {
16798
- let title = `\n ${getStateSymbol(testTask.task)} ${formatProjectName(testTask.project)}${getFullName(testTask.task, separator)}`;
16799
- if (duration != null && duration > this.ctx.config.slowTestThreshold) title += c.yellow(` ${Math.round(duration)}${c.dim("ms")}`);
16800
- this.log(title);
16801
- this.log(renderTable({
16802
- tasks: benches,
16803
- level: 1,
16804
- columns: this.ctx.logger.getColumns(),
16805
- compare: this.compare,
16806
- showHeap: this.ctx.config.logHeapUsage,
16807
- slowTestThreshold: this.ctx.config.slowTestThreshold
16808
- }));
16809
- }
16810
- }
16811
- async onTestRunEnd(testModules, unhandledErrors, reason) {
16812
- super.onTestRunEnd(testModules, unhandledErrors, reason);
16813
- // write output for future comparison
16814
- let outputFile = this.ctx.config.benchmark?.outputJson;
16815
- if (outputFile) {
16816
- outputFile = pathe.resolve(this.ctx.config.root, outputFile);
16817
- const outputDirectory = pathe.dirname(outputFile);
16818
- if (!fs__default.existsSync(outputDirectory)) await fs__default.promises.mkdir(outputDirectory, { recursive: true });
16819
- const output = createBenchmarkJsonReport(testModules.map((t) => t.task.file));
16820
- await fs__default.promises.writeFile(outputFile, JSON.stringify(output, null, 2));
16821
- this.log(`Benchmark report written to ${outputFile}`);
16822
- }
16823
- }
16824
- }
16825
-
16826
- class VerboseBenchmarkReporter extends BenchmarkReporter {
16827
- verbose = true;
16828
- }
16829
-
16830
- const BenchmarkReportsMap = {
16831
- default: BenchmarkReporter,
16832
- verbose: VerboseBenchmarkReporter
16833
- };
16834
-
16835
16730
  const ReportersMap = {
16836
16731
  "default": DefaultReporter,
16837
16732
  "agent": MinimalReporter,
@@ -16875,16 +16770,6 @@ function createReporters(reporterReferences, ctx) {
16875
16770
  });
16876
16771
  return Promise.all(promisedReporters);
16877
16772
  }
16878
- function createBenchmarkReporters(reporterReferences, runner) {
16879
- const promisedReporters = reporterReferences.map(async (referenceOrInstance) => {
16880
- if (typeof referenceOrInstance === "string") if (referenceOrInstance in BenchmarkReportsMap) {
16881
- const BuiltinReporter = BenchmarkReportsMap[referenceOrInstance];
16882
- return new BuiltinReporter();
16883
- } else return new (await (loadCustomReporterModule(referenceOrInstance, runner)))();
16884
- return referenceOrInstance;
16885
- });
16886
- return Promise.all(promisedReporters);
16887
- }
16888
16773
 
16889
16774
  function parseFilter(filter) {
16890
16775
  const colonIndex = filter.lastIndexOf(":");
@@ -17166,6 +17051,14 @@ class TestCase extends ReportedTaskImplementation {
17166
17051
  return [...this.task.artifacts];
17167
17052
  }
17168
17053
  /**
17054
+ * @experimental
17055
+ *
17056
+ * A list of benchmarks performed during the test.
17057
+ */
17058
+ benchmarks() {
17059
+ return [...this.task.benchmarks];
17060
+ }
17061
+ /**
17169
17062
  * Useful information about the test like duration, memory usage, etc.
17170
17063
  * Diagnostic is only available after the test has finished.
17171
17064
  */
@@ -18070,21 +17963,23 @@ class TestRun {
18070
17963
  this.vitest.state.updateUserLog(log);
18071
17964
  await this.vitest.report("onUserConsoleLog", log);
18072
17965
  }
17966
+ async recordBenchmark(testId, benchmark) {
17967
+ const testCase = this.getTestCaseById(testId, "Benchmark");
17968
+ testCase.task.benchmarks.push(benchmark);
17969
+ await this.vitest.report("onTestCaseBenchmark", testCase, benchmark);
17970
+ }
18073
17971
  async recordArtifact(testId, artifact) {
18074
- const task = this.vitest.state.idMap.get(testId);
18075
- const entity = task && this.vitest.state.getReportedEntity(task);
18076
- assert$1(task && entity, `Entity must be found for task ${task?.name || testId}`);
18077
- assert$1(entity.type === "test", `Artifacts can only be recorded on a test, instead got ${entity.type}`);
17972
+ const testCase = this.getTestCaseById(testId, "Artifact");
18078
17973
  // annotations won't resolve as artifacts for backwards compatibility until next major
18079
17974
  if (artifact.type === "internal:annotation") {
18080
- await this.resolveTestAttachment(entity, artifact.annotation.attachment, artifact.annotation.message);
18081
- entity.task.annotations.push(artifact.annotation);
18082
- await this.vitest.report("onTestCaseAnnotate", entity, artifact.annotation);
17975
+ await this.resolveTestAttachment(testCase, artifact.annotation.attachment, artifact.annotation.message);
17976
+ testCase.task.annotations.push(artifact.annotation);
17977
+ await this.vitest.report("onTestCaseAnnotate", testCase, artifact.annotation);
18083
17978
  return artifact;
18084
17979
  }
18085
- if (Array.isArray(artifact.attachments)) await Promise.all(artifact.attachments.map((attachment) => this.resolveTestAttachment(entity, attachment)));
18086
- entity.task.artifacts.push(artifact);
18087
- await this.vitest.report("onTestCaseArtifactRecord", entity, artifact);
17980
+ if (Array.isArray(artifact.attachments)) await Promise.all(artifact.attachments.map((attachment) => this.resolveTestAttachment(testCase, attachment)));
17981
+ testCase.task.artifacts.push(artifact);
17982
+ await this.vitest.report("onTestCaseArtifactRecord", testCase, artifact);
18088
17983
  return artifact;
18089
17984
  }
18090
17985
  async updated(update, events) {
@@ -18098,6 +17993,13 @@ class TestRun {
18098
17993
  // TODO: error handling - what happens if custom reporter throws an error?
18099
17994
  await this.vitest.report("onTaskUpdate", update, events);
18100
17995
  }
17996
+ getTestCaseById(testId, recordType) {
17997
+ const task = this.vitest.state.idMap.get(testId);
17998
+ const entity = task && this.vitest.state.getReportedEntity(task);
17999
+ assert$1(task && entity, `Entity must be found for task ${task?.name || testId}`);
18000
+ assert$1(entity.type === "test", `${recordType} can only be recorded on a test, instead got ${entity.type}`);
18001
+ return entity;
18002
+ }
18101
18003
  async end(specifications, errors, coverage) {
18102
18004
  if (coverage) await this.vitest.report("onCoverage", coverage);
18103
18005
  // specification won't have the File task if they were filtered by the --shard command
@@ -18462,7 +18364,7 @@ class Vitest {
18462
18364
  * The logger instance used to log messages. It's recommended to use this logger instead of `console`.
18463
18365
  * It's possible to override stdout and stderr streams when initiating Vitest.
18464
18366
  * @example
18465
- * new Vitest('test', {
18367
+ * new Vitest({
18466
18368
  * stdout: new Writable(),
18467
18369
  * })
18468
18370
  */
@@ -18524,8 +18426,20 @@ class Vitest {
18524
18426
  _cache;
18525
18427
  _snapshot;
18526
18428
  _coverageProvider;
18527
- constructor(mode, cliOptions, options = {}) {
18528
- this.mode = mode;
18429
+ /**
18430
+ * @deprecated Do not rely on this property, it's always `test`. Scheduled to be removed in the next major.
18431
+ */
18432
+ mode = "test";
18433
+ constructor(modeOrCliOptions, cliOptionsOrOptions, maybeOptions) {
18434
+ let cliOptions;
18435
+ let options;
18436
+ if (typeof modeOrCliOptions === "string") {
18437
+ cliOptions = cliOptionsOrOptions;
18438
+ options = maybeOptions ?? {};
18439
+ } else {
18440
+ cliOptions = modeOrCliOptions;
18441
+ options = cliOptionsOrOptions ?? {};
18442
+ }
18529
18443
  this._cliOptions = cliOptions;
18530
18444
  this.logger = new Logger(this, options.stdout, options.stderr);
18531
18445
  this.packageInstaller = options.packageInstaller || new VitestPackageInstaller();
@@ -18643,9 +18557,9 @@ class Vitest {
18643
18557
  try {
18644
18558
  await this.cache.results.readFromCache();
18645
18559
  } catch {}
18646
- const projects = await this.resolveProjects(this._cliOptions);
18647
- this.projects = projects;
18648
- await Promise.all(projects.flatMap((project) => {
18560
+ this.projects = await this.resolveProjects(this._cliOptions);
18561
+ if (this._cliOptions.benchmarkOnly) this.projects = this.projects.filter((c) => c.config.benchmark.enabled);
18562
+ await Promise.all(this.projects.flatMap((project) => {
18649
18563
  return project.vite.config.getSortedPluginHooks("configureVitest").map((hook) => hook({
18650
18564
  project,
18651
18565
  vitest: this,
@@ -18670,7 +18584,7 @@ class Vitest {
18670
18584
  // populate will merge all configs into every project,
18671
18585
  // we don't want that when just listing tags
18672
18586
  if (!this.config.listTags) populateProjectsTags(this.coreWorkspaceProject, this.projects);
18673
- this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray(resolved.benchmark?.reporters), this.runner) : await createReporters(resolved.reporters, this);
18587
+ this.reporters = await createReporters(resolved.reporters, this);
18674
18588
  await this._fsCache.ensureCacheIntegrity();
18675
18589
  await Promise.all([...this._onSetServer.map((fn) => fn()), this._traces.waitInit()]);
18676
18590
  }
@@ -18797,7 +18711,7 @@ class Vitest {
18797
18711
  // returns the project only if it matches the filter
18798
18712
  const project = getDefaultTestProject(this);
18799
18713
  if (!project) return [];
18800
- return resolveBrowserProjects(this, new Set([project.name]), [project]);
18714
+ return resolveDefaultProjects(this, new Set([project.name]), [project]);
18801
18715
  }
18802
18716
  /**
18803
18717
  * Glob test files in every project and create a TestSpecification for each file and pool.
@@ -18963,7 +18877,7 @@ class Vitest {
18963
18877
  // Report coverage for uncovered files
18964
18878
  await this.reportCoverage(coverage, true);
18965
18879
  });
18966
- if (!this.config.watch || !(this.config.changed || this.config.related?.length)) throw new FilesNotFoundError(this.mode);
18880
+ if (!this.config.watch || !(this.config.changed || this.config.related?.length)) throw new FilesNotFoundError();
18967
18881
  }
18968
18882
  let testModules = {
18969
18883
  testModules: [],
@@ -19147,7 +19061,6 @@ class Vitest {
19147
19061
  }));
19148
19062
  }
19149
19063
  async experimental_parseSpecifications(specifications, options) {
19150
- if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecifications\` does not support "${this.mode}" mode.`);
19151
19064
  const limit = limitConcurrency(options?.concurrency ?? (typeof nodeos__default.availableParallelism === "function" ? nodeos__default.availableParallelism() : nodeos__default.cpus().length));
19152
19065
  // Phase 1: parse all files in parallel (without mode interpretation)
19153
19066
  const results = await Promise.all(specifications.map((specification) => limit(async () => {
@@ -19169,7 +19082,6 @@ class Vitest {
19169
19082
  return results.map(({ file }) => this.state.getReportedEntity(file));
19170
19083
  }
19171
19084
  async experimental_parseSpecification(specification) {
19172
- if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecification\` does not support "${this.mode}" mode.`);
19173
19085
  const file = await astCollectTests(specification.project, specification.moduleId).catch((error) => {
19174
19086
  return createFailedFileTask(specification.project, specification.moduleId, error);
19175
19087
  });
@@ -19565,7 +19477,7 @@ function assert(condition, property, name = property) {
19565
19477
  if (!condition) throw new Error(`The ${name} was not set. It means that \`vitest.${property}\` was called before the Vite server was established. Await the Vitest promise before accessing \`vitest.${property}\`.`);
19566
19478
  }
19567
19479
 
19568
- async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(options))) {
19480
+ async function VitestPlugin(options = {}, vitest = new Vitest(deepClone(options))) {
19569
19481
  const userConfig = deepMerge({}, options);
19570
19482
  async function UIPlugin() {
19571
19483
  await vitest.packageInstaller.ensureInstalled("@vitest/ui", resolve$1(options.root || process.cwd()), vitest.version);
@@ -19638,6 +19550,10 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
19638
19550
  legalComments: "inline"
19639
19551
  }
19640
19552
  };
19553
+ if (vitest._cliOptions.benchmarkOnly) {
19554
+ config.test.benchmark ??= {};
19555
+ config.test.benchmark.enabled = true;
19556
+ }
19641
19557
  // inherit so it's available in VitestOptimizer
19642
19558
  // I cannot wait to rewrite all of this in Vitest 4
19643
19559
  if (options.cache != null) config.test.cache = options.cache;
@@ -19707,8 +19623,20 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
19707
19623
  ].filter(notNullish);
19708
19624
  }
19709
19625
 
19710
- async function createVitest(mode, options, viteOverrides = {}, vitestOptions = {}) {
19711
- const ctx = new Vitest(mode, deepClone(options), vitestOptions);
19626
+ async function createVitest(modeOrOptions, optionsOrViteOverrides = {}, viteOverridesOrVitestOptions = {}, maybeVitestOptions = {}) {
19627
+ let options;
19628
+ let viteOverrides;
19629
+ let vitestOptions;
19630
+ if (typeof modeOrOptions === "string") {
19631
+ options = optionsOrViteOverrides;
19632
+ viteOverrides = viteOverridesOrVitestOptions;
19633
+ vitestOptions = maybeVitestOptions;
19634
+ } else {
19635
+ options = modeOrOptions;
19636
+ viteOverrides = optionsOrViteOverrides;
19637
+ vitestOptions = viteOverridesOrVitestOptions;
19638
+ }
19639
+ const ctx = new Vitest(deepClone(options), vitestOptions);
19712
19640
  const root = slash(resolve$2(options.root || process.cwd()));
19713
19641
  const configPath = options.config === false ? false : options.config ? resolveModule(options.config, { paths: [root] }) ?? resolve$2(root, options.config) : any(configFiles, { cwd: root });
19714
19642
  options.config = configPath;
@@ -19716,7 +19644,7 @@ async function createVitest(mode, options, viteOverrides = {}, vitestOptions = {
19716
19644
  const config = {
19717
19645
  configFile: configPath,
19718
19646
  configLoader: options.configLoader,
19719
- mode: options.mode || mode,
19647
+ mode: options.mode || "test",
19720
19648
  plugins: await VitestPlugin(restOptions, ctx)
19721
19649
  };
19722
19650
  try {
@@ -20023,15 +19951,25 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
20023
19951
  };
20024
19952
  }
20025
19953
 
20026
- /**
20027
- * Start Vitest programmatically
20028
- *
20029
- * Returns a Vitest instance if initialized successfully.
20030
- */
20031
- async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, vitestOptions) {
19954
+ async function startVitest(modeOrCliFilters, cliFiltersOrOptions, optionsOrViteOverrides, viteOverridesOrVitestOptions, maybeVitestOptions) {
19955
+ let cliFilters;
19956
+ let options;
19957
+ let viteOverrides;
19958
+ let vitestOptions;
19959
+ if (typeof modeOrCliFilters === "string") {
19960
+ cliFilters = cliFiltersOrOptions ?? [];
19961
+ options = optionsOrViteOverrides ?? {};
19962
+ viteOverrides = viteOverridesOrVitestOptions;
19963
+ vitestOptions = maybeVitestOptions;
19964
+ } else {
19965
+ cliFilters = modeOrCliFilters ?? [];
19966
+ options = cliFiltersOrOptions ?? {};
19967
+ viteOverrides = optionsOrViteOverrides;
19968
+ vitestOptions = viteOverridesOrVitestOptions;
19969
+ }
20032
19970
  const root = resolve$1(options.root || process.cwd());
20033
- const ctx = await prepareVitest(mode, options, viteOverrides, vitestOptions, cliFilters);
20034
- if (mode === "test" && ctx._coverageOptions.enabled) {
19971
+ const ctx = await prepareVitest(options, viteOverrides, vitestOptions, cliFilters);
19972
+ if (ctx._coverageOptions.enabled) {
20035
19973
  const requiredPackages = CoverageProviderMap[ctx._coverageOptions.provider || "v8"];
20036
19974
  if (requiredPackages) {
20037
19975
  if (!await ctx.packageInstaller.ensureInstalled(requiredPackages, root, ctx.version)) {
@@ -20079,7 +20017,22 @@ async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, v
20079
20017
  }
20080
20018
  }
20081
20019
  }
20082
- async function prepareVitest(mode, options = {}, viteOverrides, vitestOptions, cliFilters) {
20020
+ async function prepareVitest(modeOrOptions, optionsOrViteOverrides, viteOverridesOrVitestOptions, vitestOptionsOrCliFilters, maybeCliFilters) {
20021
+ let options;
20022
+ let viteOverrides;
20023
+ let vitestOptions;
20024
+ let cliFilters;
20025
+ if (typeof modeOrOptions === "string") {
20026
+ options = optionsOrViteOverrides ?? {};
20027
+ viteOverrides = viteOverridesOrVitestOptions;
20028
+ vitestOptions = vitestOptionsOrCliFilters;
20029
+ cliFilters = maybeCliFilters;
20030
+ } else {
20031
+ options = modeOrOptions ?? {};
20032
+ viteOverrides = optionsOrViteOverrides;
20033
+ vitestOptions = viteOverridesOrVitestOptions;
20034
+ cliFilters = vitestOptionsOrCliFilters;
20035
+ }
20083
20036
  process.env.TEST = "true";
20084
20037
  process.env.VITEST = "true";
20085
20038
  process.env.NODE_ENV ??= "test";
@@ -20087,7 +20040,7 @@ async function prepareVitest(mode, options = {}, viteOverrides, vitestOptions, c
20087
20040
  if (options.standalone && (cliFilters?.length || 0) > 0) options.standalone = false;
20088
20041
  // this shouldn't affect _application root_ that can be changed inside config
20089
20042
  const root = resolve$1(options.root || process.cwd());
20090
- const ctx = await createVitest(mode, options, viteOverrides, vitestOptions);
20043
+ const ctx = await createVitest(options, viteOverrides, vitestOptions);
20091
20044
  const environmentPackage = getEnvPackageName(ctx.config.environment);
20092
20045
  if (environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root)) {
20093
20046
  process.exitCode = 1;
@@ -20196,4 +20149,4 @@ var cliApi = /*#__PURE__*/Object.freeze({
20196
20149
  startVitest: startVitest
20197
20150
  });
20198
20151
 
20199
- export { registerConsoleShortcuts as A, BaseCoverageProvider as B, resolveApiServerConfig as C, DefaultReporter as D, resolveFsAllow as E, ForksPoolWorker as F, GitNotFoundError as G, HangingProcessReporter as H, startVitest as I, JUnitReporter as J, cliApi as K, MinimalReporter as M, ReportersMap as R, TapFlatReporter as T, Vitest as V, VitestPlugin as a, BaseSequencer as b, BenchmarkReporter as c, BenchmarkReportsMap as d, DotReporter as e, GithubActionsReporter as f, JsonReporter as g, TapReporter as h, FilesNotFoundError as i, ThreadsPoolWorker as j, TypecheckPoolWorker as k, VerboseBenchmarkReporter as l, VerboseReporter as m, VitestPackageInstaller as n, VmForksPoolWorker as o, VmThreadsPoolWorker as p, createDebugger as q, resolveConfig$1 as r, createMethodsRPC as s, createViteLogger as t, createVitest as u, escapeTestName as v, experimental_getRunnerTask as w, getFilePoolName as x, isFileServingAllowed as y, isValidApiRequest as z };
20152
+ export { startVitest as A, BaseCoverageProvider as B, cliApi as C, DefaultReporter as D, ForksPoolWorker as F, GitNotFoundError as G, HangingProcessReporter as H, JUnitReporter as J, MinimalReporter as M, ReportersMap as R, TapFlatReporter as T, Vitest as V, VitestPlugin as a, BaseSequencer as b, DotReporter as c, GithubActionsReporter as d, JsonReporter as e, TapReporter as f, FilesNotFoundError as g, ThreadsPoolWorker as h, TypecheckPoolWorker as i, VerboseReporter as j, VitestPackageInstaller as k, VmForksPoolWorker as l, VmThreadsPoolWorker as m, createDebugger as n, createMethodsRPC as o, createViteLogger as p, createVitest as q, resolveConfig$1 as r, escapeTestName as s, experimental_getRunnerTask as t, getFilePoolName as u, isFileServingAllowed as v, isValidApiRequest as w, registerConsoleShortcuts as x, resolveApiServerConfig as y, resolveFsAllow as z };