vitest 4.0.0-beta.6 → 4.0.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/browser.d.ts +3 -3
  2. package/dist/chunks/{browser.d.Cawq_X_N.d.ts → browser.d.DOMmqJQx.d.ts} +1 -1
  3. package/dist/chunks/{cac.WE-urWw5.js → cac.By1HvRIk.js} +7 -7
  4. package/dist/chunks/{cli-api.CZz3evYC.js → cli-api.C-JHgQgp.js} +383 -210
  5. package/dist/chunks/{config.d.CKNVOKm0.d.ts → config.d._GBBbReY.d.ts} +1 -0
  6. package/dist/chunks/{coverage.BPRS6xgn.js → coverage.DarITf6U.js} +7 -7
  7. package/dist/chunks/{index.VNI-1z5c.js → index.AzwzFtyi.js} +14 -5
  8. package/dist/chunks/{index.7w0eqmYM.js → index.BuwjkI-q.js} +1 -1
  9. package/dist/chunks/{index.BG0gqZH-.js → index.DfviD7lX.js} +16 -8
  10. package/dist/chunks/{moduleRunner.d.8kKUsuDg.d.ts → moduleRunner.d.CX4DuqOx.d.ts} +1 -1
  11. package/dist/chunks/{plugin.d.DuiQJfUL.d.ts → plugin.d.CHe6slQs.d.ts} +1 -1
  12. package/dist/chunks/{reporters.d.CqR9-CDJ.d.ts → reporters.d.37tJQ2uV.d.ts} +950 -995
  13. package/dist/chunks/{typechecker.Cd1wvxUM.js → typechecker.DSo_maXz.js} +1 -1
  14. package/dist/chunks/{worker.d.Db-UVmXc.d.ts → worker.d.BKu8cnnX.d.ts} +1 -1
  15. package/dist/chunks/{worker.d.D9QWnzAe.d.ts → worker.d.DYlqbejz.d.ts} +1 -1
  16. package/dist/cli.js +3 -3
  17. package/dist/config.d.ts +9 -9
  18. package/dist/coverage.d.ts +7 -7
  19. package/dist/coverage.js +2 -2
  20. package/dist/environments.js +1 -1
  21. package/dist/index.d.ts +6 -6
  22. package/dist/module-evaluator.d.ts +3 -3
  23. package/dist/node.d.ts +24 -12
  24. package/dist/node.js +11 -16
  25. package/dist/reporters.d.ts +7 -7
  26. package/dist/reporters.js +3 -3
  27. package/dist/runners.d.ts +1 -1
  28. package/dist/worker.js +1 -1
  29. package/dist/workers.d.ts +3 -3
  30. package/dist/workers.js +1 -1
  31. package/package.json +10 -11
@@ -2,16 +2,17 @@ import fs, { promises, existsSync, readFileSync, mkdirSync, writeFileSync } from
2
2
  import { relative, resolve, dirname, extname, normalize, join, basename, isAbsolute } from 'pathe';
3
3
  import { C as CoverageProviderMap } from './coverage.D_JHT54q.js';
4
4
  import path, { resolve as resolve$1 } from 'node:path';
5
- import { noop, isPrimitive, createDefer, slash, highlight, toArray, cleanUrl, deepMerge, KNOWN_ASSET_RE, nanoid, deepClone, notNullish } from '@vitest/utils';
5
+ import { noop, createDefer, slash, highlight, toArray, cleanUrl, deepMerge, KNOWN_ASSET_RE, nanoid, deepClone, isPrimitive, notNullish } from '@vitest/utils';
6
6
  import { f as findUp, p as prompt } from './index.X0nbfr6-.js';
7
7
  import * as vite from 'vite';
8
- import { searchForWorkspaceRoot, version, mergeConfig, createServer } from 'vite';
8
+ import { parseAst, searchForWorkspaceRoot, version, mergeConfig, createServer } from 'vite';
9
9
  import { A as API_PATH, c as configFiles, d as defaultBrowserPort, a as defaultPort } from './constants.D_Q9UYh-.js';
10
- import { generateFileHash, limitConcurrency, createFileTask, hasFailed, getTasks, getTests } from '@vitest/runner/utils';
10
+ import nodeos__default, { tmpdir } from 'node:os';
11
+ import { generateHash as generateHash$1, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, generateFileHash, limitConcurrency, createFileTask as createFileTask$1, hasFailed, getTasks, getTests } from '@vitest/runner/utils';
11
12
  import { SnapshotManager } from '@vitest/snapshot/manager';
12
- import { v as version$1 } from './cac.WE-urWw5.js';
13
+ import { v as version$1 } from './cac.By1HvRIk.js';
13
14
  import { c as createBirpc } from './index.Bgo3tNWt.js';
14
- import { p as parse, s as stringify, d as printError, f as formatProjectName, w as withLabel, e as errorBanner, h as divider, i as generateCodeFrame, R as ReportersMap, B as BlobReporter, r as readBlobs, H as HangingProcessReporter } from './index.VNI-1z5c.js';
15
+ import { p as parse, s as stringify, d as printError, f as formatProjectName, w as withLabel, e as errorBanner, h as divider, i as generateCodeFrame, R as ReportersMap, B as BlobReporter, r as readBlobs, H as HangingProcessReporter } from './index.AzwzFtyi.js';
15
16
  import require$$0$3 from 'events';
16
17
  import require$$1$1 from 'https';
17
18
  import require$$2 from 'http';
@@ -23,11 +24,12 @@ import require$$7 from 'url';
23
24
  import require$$0 from 'zlib';
24
25
  import require$$0$1 from 'buffer';
25
26
  import { g as getDefaultExportFromCjs } from './_commonjsHelpers.BFTU3MAI.js';
26
- import { parseErrorStacktrace } from '@vitest/utils/source-map';
27
27
  import crypto, { createHash } from 'node:crypto';
28
28
  import { distDir, rootDir } from '../path.js';
29
- import { h as hash, d as createFetchModuleFunction, n as normalizeResolvedIdToUrl, R as RandomSequencer, i as isPackageExists, g as getFilePoolName, e as isBrowserEnabled, r as resolveConfig, f as groupBy, j as getCoverageProvider, k as createPool, w as wildcardPatternToRegExp, a as resolveApiServerConfig, s as stdout } from './coverage.BPRS6xgn.js';
30
- import { c as convertTasksToEvents } from './typechecker.Cd1wvxUM.js';
29
+ import { h as hash, d as createFetchModuleFunction, n as normalizeResolvedIdToUrl, R as RandomSequencer, i as isPackageExists, g as getFilePoolName, e as isBrowserEnabled, r as resolveConfig, f as groupBy, j as getCoverageProvider, k as createPool, w as wildcardPatternToRegExp, a as resolveApiServerConfig, s as stdout } from './coverage.DarITf6U.js';
30
+ import { b as ancestor, c as convertTasksToEvents } from './typechecker.DSo_maXz.js';
31
+ import { TraceMap, originalPositionFor, parseErrorStacktrace } from '@vitest/utils/source-map';
32
+ import createDebug from 'debug';
31
33
  import { VitestModuleEvaluator } from '#module-evaluator';
32
34
  import { ModuleRunner } from 'vite/module-runner';
33
35
  import { Console } from 'node:console';
@@ -36,7 +38,6 @@ import { createRequire, builtinModules, isBuiltin } from 'node:module';
36
38
  import url, { pathToFileURL } from 'node:url';
37
39
  import { i as isTTY, a as isWindows } from './env.D4Lgay0q.js';
38
40
  import { rm, mkdir, copyFile } from 'node:fs/promises';
39
- import nodeos__default, { tmpdir } from 'node:os';
40
41
  import pm from 'picomatch';
41
42
  import { glob, isDynamicPattern } from 'tinyglobby';
42
43
  import MagicString from 'magic-string';
@@ -44,9 +45,9 @@ import { hoistMocksPlugin, automockPlugin } from '@vitest/mocker/node';
44
45
  import { c as configDefaults } from './defaults.CXFFjsi8.js';
45
46
  import { f as findNearestPackageData } from './resolver.Bx6lE0iq.js';
46
47
  import * as esModuleLexer from 'es-module-lexer';
47
- import { a as BenchmarkReportsMap } from './index.7w0eqmYM.js';
48
+ import { a as BenchmarkReportsMap } from './index.BuwjkI-q.js';
48
49
  import assert$1 from 'node:assert';
49
- import { serializeError } from '@vitest/utils/error';
50
+ import { serializeError as serializeError$1 } from '@vitest/utils/error';
50
51
  import readline from 'node:readline';
51
52
  import { stripVTControlCharacters } from 'node:util';
52
53
 
@@ -5080,7 +5081,7 @@ catch {}
5080
5081
  }
5081
5082
 
5082
5083
  function setup(ctx, _server) {
5083
- const wss = new WebSocketServer({ noServer: true }), clients = /* @__PURE__ */ new Map(), server = _server || ctx.server;
5084
+ const wss = new WebSocketServer({ noServer: true }), clients = /* @__PURE__ */ new Map(), server = _server || ctx.vite;
5084
5085
  server.httpServer?.on("upgrade", (request, socket, head) => {
5085
5086
  if (!request.url) return;
5086
5087
  const { pathname } = new URL(request.url, "http://localhost");
@@ -5199,17 +5200,9 @@ class WebSocketReporter {
5199
5200
  });
5200
5201
  }
5201
5202
  async onTaskUpdate(packs, events) {
5202
- this.clients.size !== 0 && (packs.forEach(([taskId, result]) => {
5203
- const task = this.ctx.state.idMap.get(taskId), isBrowser = task && task.file.pool === "browser";
5204
- result?.errors?.forEach((error) => {
5205
- if (!isPrimitive(error)) if (isBrowser) {
5206
- const project = this.ctx.getProjectByName(task.file.projectName || "");
5207
- error.stacks = project.browser?.parseErrorStacktrace(error);
5208
- } else error.stacks = parseErrorStacktrace(error);
5209
- });
5210
- }), this.clients.forEach((client) => {
5203
+ this.clients.size !== 0 && this.clients.forEach((client) => {
5211
5204
  client.onTaskUpdate?.(packs, events)?.catch?.(noop);
5212
- }));
5205
+ });
5213
5206
  }
5214
5207
  onTestRunEnd(testModules, unhandledErrors) {
5215
5208
  if (!this.clients.size) return;
@@ -5236,6 +5229,265 @@ var setup$1 = /*#__PURE__*/Object.freeze({
5236
5229
  setup: setup
5237
5230
  });
5238
5231
 
5232
+ function createDebugger(namespace) {
5233
+ const debug = createDebug(namespace);
5234
+ if (debug.enabled) return debug;
5235
+ }
5236
+
5237
+ const debug = createDebugger("vitest:ast-collect-info"), verbose = createDebugger("vitest:ast-collect-verbose");
5238
+ function astParseFile(filepath, code) {
5239
+ const ast = parseAst(code);
5240
+ if (verbose) verbose("Collecting", filepath, code);
5241
+ else debug?.("Collecting", filepath);
5242
+ const definitions = [], getName = (callee) => {
5243
+ if (!callee) return null;
5244
+ if (callee.type === "Identifier") return callee.name;
5245
+ if (callee.type === "CallExpression") return getName(callee.callee);
5246
+ if (callee.type === "TaggedTemplateExpression") return getName(callee.tag);
5247
+ if (callee.type === "MemberExpression")
5248
+ // call as `__vite_ssr__.test.skip()`
5249
+ return callee.object?.type === "Identifier" && [
5250
+ "it",
5251
+ "test",
5252
+ "describe",
5253
+ "suite"
5254
+ ].includes(callee.object.name) ? callee.object?.name : callee.object?.name?.startsWith("__vite_ssr_") || callee.object?.object?.name?.startsWith("__vite_ssr_") && callee.object?.property?.name === "Vitest" ? getName(callee.property) : getName(callee.object?.property);
5255
+ // unwrap (0, ...)
5256
+ if (callee.type === "SequenceExpression" && callee.expressions.length === 2) {
5257
+ const [e0, e1] = callee.expressions;
5258
+ if (e0.type === "Literal" && e0.value === 0) return getName(e1);
5259
+ }
5260
+ return null;
5261
+ };
5262
+ return ancestor(ast, { CallExpression(node) {
5263
+ const { callee } = node, name = getName(callee);
5264
+ if (!name) return;
5265
+ if (![
5266
+ "it",
5267
+ "test",
5268
+ "describe",
5269
+ "suite"
5270
+ ].includes(name)) {
5271
+ verbose?.(`Skipping ${name} (unknown call)`);
5272
+ return;
5273
+ }
5274
+ const property = callee?.property?.name;
5275
+ let mode = !property || property === name ? "run" : property;
5276
+ // they will be picked up in the next iteration
5277
+ if ([
5278
+ "each",
5279
+ "for",
5280
+ "skipIf",
5281
+ "runIf"
5282
+ ].includes(mode)) return;
5283
+ let start;
5284
+ const end = node.end;
5285
+ // .each or (0, __vite_ssr_exports_0__.test)()
5286
+ if (callee.type === "CallExpression" || callee.type === "SequenceExpression" || callee.type === "TaggedTemplateExpression") start = callee.end;
5287
+ else start = node.start;
5288
+ const messageNode = node.arguments?.[0];
5289
+ if (messageNode == null) {
5290
+ verbose?.(`Skipping node at ${node.start} because it doesn't have a name`);
5291
+ return;
5292
+ }
5293
+ let message;
5294
+ if (messageNode?.type === "Literal" || messageNode?.type === "TemplateLiteral") message = code.slice(messageNode.start + 1, messageNode.end - 1);
5295
+ else message = code.slice(messageNode.start, messageNode.end);
5296
+ if (message.startsWith("0,")) message = message.slice(2);
5297
+ // cannot statically analyze, so we always skip it
5298
+ if (message = message.replace(/__vite_ssr_import_\d+__\./g, "").replace(/__vi_import_\d+__\./g, ""), mode === "skipIf" || mode === "runIf") mode = "skip";
5299
+ const parentCalleeName = typeof callee?.callee === "object" && callee?.callee.type === "MemberExpression" && callee?.callee.property?.name;
5300
+ let isDynamicEach = parentCalleeName === "each" || parentCalleeName === "for";
5301
+ if (!isDynamicEach && callee.type === "TaggedTemplateExpression") {
5302
+ const property = callee.tag?.property?.name;
5303
+ isDynamicEach = property === "each" || property === "for";
5304
+ }
5305
+ debug?.("Found", name, message, `(${mode})`), definitions.push({
5306
+ start,
5307
+ end,
5308
+ name: message,
5309
+ type: name === "it" || name === "test" ? "test" : "suite",
5310
+ mode,
5311
+ task: null,
5312
+ dynamic: isDynamicEach
5313
+ });
5314
+ } }), {
5315
+ ast,
5316
+ definitions
5317
+ };
5318
+ }
5319
+ function createFailedFileTask(project, filepath, error) {
5320
+ const testFilepath = relative(project.config.root, filepath), file = {
5321
+ filepath,
5322
+ type: "suite",
5323
+ id: /* @__PURE__ */ generateHash$1(`${testFilepath}${project.config.name || ""}`),
5324
+ name: testFilepath,
5325
+ mode: "run",
5326
+ tasks: [],
5327
+ start: 0,
5328
+ end: 0,
5329
+ projectName: project.name,
5330
+ meta: {},
5331
+ pool: project.browser ? "browser" : project.config.pool,
5332
+ file: null,
5333
+ result: {
5334
+ state: "fail",
5335
+ errors: serializeError(project, error)
5336
+ }
5337
+ };
5338
+ return file.file = file, file;
5339
+ }
5340
+ function serializeError(ctx, error) {
5341
+ if ("errors" in error && "pluginCode" in error) {
5342
+ const errors = error.errors.map((e) => {
5343
+ return {
5344
+ name: error.name,
5345
+ message: e.text,
5346
+ stack: e.location ? `${error.name}: ${e.text}\n at ${relative(ctx.config.root, e.location.file)}:${e.location.line}:${e.location.column}` : ""
5347
+ };
5348
+ });
5349
+ return errors;
5350
+ }
5351
+ return [{
5352
+ name: error.name,
5353
+ stack: error.stack,
5354
+ message: error.message
5355
+ }];
5356
+ }
5357
+ function createFileTask(testFilepath, code, requestMap, options) {
5358
+ const { definitions, ast } = astParseFile(testFilepath, code), file = {
5359
+ filepath: options.filepath,
5360
+ type: "suite",
5361
+ id: /* @__PURE__ */ generateHash$1(`${testFilepath}${options.name || ""}`),
5362
+ name: testFilepath,
5363
+ mode: "run",
5364
+ tasks: [],
5365
+ start: ast.start,
5366
+ end: ast.end,
5367
+ projectName: options.name,
5368
+ meta: {},
5369
+ pool: "browser",
5370
+ file: null
5371
+ };
5372
+ file.file = file;
5373
+ const indexMap = createIndexMap(code), map = requestMap && new TraceMap(requestMap);
5374
+ let lastSuite = file;
5375
+ const updateLatestSuite = (index) => {
5376
+ while (lastSuite.suite && lastSuite.end < index) lastSuite = lastSuite.suite;
5377
+ return lastSuite;
5378
+ };
5379
+ definitions.sort((a, b) => a.start - b.start).forEach((definition) => {
5380
+ const latestSuite = updateLatestSuite(definition.start);
5381
+ let mode = definition.mode;
5382
+ if (latestSuite.mode !== "run")
5383
+ // inherit suite mode, if it's set
5384
+ mode = latestSuite.mode;
5385
+ const processedLocation = indexMap.get(definition.start);
5386
+ let location;
5387
+ if (map && processedLocation) {
5388
+ const originalLocation = originalPositionFor(map, {
5389
+ line: processedLocation.line,
5390
+ column: processedLocation.column
5391
+ });
5392
+ if (originalLocation.column != null) verbose?.(`Found location for`, definition.type, definition.name, `${processedLocation.line}:${processedLocation.column}`, "->", `${originalLocation.line}:${originalLocation.column}`), location = originalLocation;
5393
+ else debug?.("Cannot find original location for", definition.type, definition.name, `${processedLocation.column}:${processedLocation.line}`);
5394
+ } else debug?.("Cannot find original location for", definition.type, definition.name, `${definition.start}`);
5395
+ if (definition.type === "suite") {
5396
+ const task = {
5397
+ type: definition.type,
5398
+ id: "",
5399
+ suite: latestSuite,
5400
+ file,
5401
+ tasks: [],
5402
+ mode,
5403
+ name: definition.name,
5404
+ end: definition.end,
5405
+ start: definition.start,
5406
+ location,
5407
+ dynamic: definition.dynamic,
5408
+ meta: {}
5409
+ };
5410
+ definition.task = task, latestSuite.tasks.push(task), lastSuite = task;
5411
+ return;
5412
+ }
5413
+ const task = {
5414
+ type: definition.type,
5415
+ id: "",
5416
+ suite: latestSuite,
5417
+ file,
5418
+ mode,
5419
+ context: {},
5420
+ name: definition.name,
5421
+ end: definition.end,
5422
+ start: definition.start,
5423
+ location,
5424
+ dynamic: definition.dynamic,
5425
+ meta: {},
5426
+ timeout: 0,
5427
+ annotations: []
5428
+ };
5429
+ definition.task = task, latestSuite.tasks.push(task);
5430
+ }), calculateSuiteHash(file);
5431
+ const hasOnly = someTasksAreOnly(file);
5432
+ if (interpretTaskModes(file, options.testNamePattern, void 0, hasOnly, false, options.allowOnly), markDynamicTests(file.tasks), !file.tasks.length) file.result = {
5433
+ state: "fail",
5434
+ errors: [{
5435
+ name: "Error",
5436
+ message: `No test suite found in file ${options.filepath}`
5437
+ }]
5438
+ };
5439
+ return file;
5440
+ }
5441
+ async function astCollectTests(project, filepath) {
5442
+ const request = await transformSSR(project, filepath), testFilepath = relative(project.config.root, filepath);
5443
+ return request ? createFileTask(testFilepath, request.code, request.map, {
5444
+ name: project.config.name,
5445
+ filepath,
5446
+ allowOnly: project.config.allowOnly,
5447
+ testNamePattern: project.config.testNamePattern,
5448
+ pool: project.browser ? "browser" : project.config.pool
5449
+ }) : (debug?.("Cannot parse", testFilepath, "(vite didn't return anything)"), createFailedFileTask(project, filepath, /* @__PURE__ */ new Error(`Failed to parse ${testFilepath}. Vite didn't return anything.`)));
5450
+ }
5451
+ async function transformSSR(project, filepath) {
5452
+ const request = await project.vite.transformRequest(filepath, { ssr: false });
5453
+ return request ? await project.vite.ssrTransform(request.code, request.map, filepath) : null;
5454
+ }
5455
+ function createIndexMap(source) {
5456
+ const map = /* @__PURE__ */ new Map();
5457
+ let index = 0, line = 1, column = 1;
5458
+ for (const char of source) if (map.set(index++, {
5459
+ line,
5460
+ column
5461
+ }), char === "\n" || char === "\r\n") line++, column = 0;
5462
+ else column++;
5463
+ return map;
5464
+ }
5465
+ function markDynamicTests(tasks) {
5466
+ for (const task of tasks) {
5467
+ if (task.dynamic) task.id += "-dynamic";
5468
+ if ("tasks" in task) markDynamicTests(task.tasks);
5469
+ }
5470
+ }
5471
+ function escapeRegex(str) {
5472
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5473
+ }
5474
+ const kReplacers = new Map([
5475
+ ["%i", "\\d+?"],
5476
+ ["%#", "\\d+?"],
5477
+ ["%d", "[\\d.eE+-]+?"],
5478
+ ["%f", "[\\d.eE+-]+?"],
5479
+ ["%s", ".+?"],
5480
+ ["%j", ".+?"],
5481
+ ["%o", ".+?"],
5482
+ ["%%", "%"]
5483
+ ]);
5484
+ function escapeTestName(label, dynamic) {
5485
+ if (!dynamic) return escapeRegex(label);
5486
+ // Replace object access patterns ($value, $obj.a) with %s first
5487
+ let pattern = label.replace(/\$[a-z_.]+/gi, "%s");
5488
+ return pattern = escapeRegex(pattern), pattern = pattern.replace(/%[i#dfsjo%]/g, (m) => kReplacers.get(m) || m), pattern;
5489
+ }
5490
+
5239
5491
  class BrowserSessions {
5240
5492
  sessions = /* @__PURE__ */ new Map();
5241
5493
  sessionIds = /* @__PURE__ */ new Set();
@@ -5269,7 +5521,7 @@ class FilesStatsCache {
5269
5521
  }
5270
5522
  async populateStats(root, specs) {
5271
5523
  const promises = specs.map((spec) => {
5272
- const key = `${spec[0].name}:${relative(root, spec.moduleId)}`;
5524
+ const key = `${spec.project.name}:${relative(root, spec.moduleId)}`;
5273
5525
  return this.updateStats(spec.moduleId, key);
5274
5526
  });
5275
5527
  await Promise.all(promises);
@@ -5521,10 +5773,10 @@ class Logger {
5521
5773
  const color = this.ctx.config.watch ? "blue" : "cyan", mode = this.ctx.config.watch ? "DEV" : "RUN";
5522
5774
  if (this.log(withLabel(color, mode, `v${this.ctx.version} `) + c.gray(this.ctx.config.root)), this.ctx.config.sequence.sequencer === RandomSequencer) this.log(PAD + c.gray(`Running tests with seed "${this.ctx.config.sequence.seed}"`));
5523
5775
  if (this.ctx.config.ui) {
5524
- const host = this.ctx.config.api?.host || "localhost", port = this.ctx.server.config.server.port, base = this.ctx.config.uiBase;
5776
+ const host = this.ctx.config.api?.host || "localhost", port = this.ctx.vite.config.server.port, base = this.ctx.config.uiBase;
5525
5777
  this.log(PAD + c.dim(c.green(`UI started at http://${host}:${c.bold(port)}${base}`)));
5526
5778
  } else if (this.ctx.config.api?.port) {
5527
- const resolvedUrls = this.ctx.server.resolvedUrls, fallbackUrl = `http://${this.ctx.config.api.host || "localhost"}:${this.ctx.config.api.port}`, origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0] ?? fallbackUrl;
5779
+ const resolvedUrls = this.ctx.vite.resolvedUrls, fallbackUrl = `http://${this.ctx.config.api.host || "localhost"}:${this.ctx.config.api.port}`, origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0] ?? fallbackUrl;
5528
5780
  this.log(PAD + c.dim(c.green(`API started at ${new URL("/", origin)}`)));
5529
5781
  }
5530
5782
  if (this.ctx.coverageProvider) this.log(PAD + c.dim("Coverage enabled with ") + c.yellow(this.ctx.coverageProvider.name));
@@ -5711,7 +5963,8 @@ function serializeConfig(config, coreConfig, viteConfig) {
5711
5963
  viewport: browser.viewport,
5712
5964
  screenshotFailures: browser.screenshotFailures,
5713
5965
  locators: { testIdAttribute: browser.locators.testIdAttribute },
5714
- providerOptions: browser.provider === "playwright" ? { actionTimeout: browser.providerOptions?.context?.actionTimeout } : {}
5966
+ providerOptions: browser.provider === "playwright" ? { actionTimeout: browser.providerOptions?.context?.actionTimeout } : {},
5967
+ trackUnhandledErrors: browser.trackUnhandledErrors ?? true
5715
5968
  };
5716
5969
  })(config.browser),
5717
5970
  standalone: config.standalone,
@@ -6587,7 +6840,7 @@ function VitestProjectResolver(ctx) {
6587
6840
  if (id === "vitest" || id.startsWith("@vitest/") || id.startsWith("vitest/")) {
6588
6841
  // always redirect the request to the root vitest plugin since
6589
6842
  // it will be the one used to run Vitest
6590
- const resolved = await ctx.server.pluginContainer.resolveId(id, void 0, {
6843
+ const resolved = await ctx.vite.pluginContainer.resolveId(id, void 0, {
6591
6844
  skip: new Set([plugin]),
6592
6845
  ssr
6593
6846
  });
@@ -6822,18 +7075,6 @@ function matchExternalizePattern(id, moduleDirectories, patterns) {
6822
7075
  }
6823
7076
 
6824
7077
  class TestSpecification {
6825
- /**
6826
- * @deprecated use `project` instead
6827
- */
6828
- 0;
6829
- /**
6830
- * @deprecated use `moduleId` instead
6831
- */
6832
- 1;
6833
- /**
6834
- * @deprecated use `pool` instead
6835
- */
6836
- 2;
6837
7078
  /**
6838
7079
  * The task ID associated with the test module.
6839
7080
  */
@@ -6856,7 +7097,6 @@ class TestSpecification {
6856
7097
  */
6857
7098
  testLines;
6858
7099
  constructor(project, moduleId, pool, testLines) {
6859
- this[0] = project, this[1] = moduleId, this[2] = { pool };
6860
7100
  const name = project.config.name, hashName = pool !== "typescript" ? name : name ? `${name}:__typecheck__` : "__typecheck__";
6861
7101
  this.taskId = generateFileHash(relative(project.config.root, moduleId), hashName), this.project = project, this.moduleId = moduleId, this.pool = pool, this.testLines = testLines;
6862
7102
  }
@@ -6880,13 +7120,6 @@ class TestSpecification {
6880
7120
  }
6881
7121
  ];
6882
7122
  }
6883
- /**
6884
- * for backwards compatibility
6885
- * @deprecated
6886
- */
6887
- *[Symbol.iterator]() {
6888
- yield this.project, yield this.moduleId, yield this.pool;
6889
- }
6890
7123
  }
6891
7124
 
6892
7125
  async function createViteServer(inlineConfig) {
@@ -6914,8 +7147,6 @@ class TestProject {
6914
7147
  * Browser instance if the browser is enabled. This is initialized when the tests run for the first time.
6915
7148
  */
6916
7149
  browser;
6917
- /** @deprecated use `vitest` instead */
6918
- ctx;
6919
7150
  /**
6920
7151
  * Temporary directory for the project. This is unique for each project. Vitest stores transformed content here.
6921
7152
  */
@@ -6925,14 +7156,14 @@ class TestProject {
6925
7156
  /** @internal */ _vite;
6926
7157
  /** @internal */ _hash;
6927
7158
  /** @internal */ _resolver;
7159
+ /** @inetrnal */ testFilesList = null;
6928
7160
  runner;
6929
7161
  closingPromise;
6930
- testFilesList = null;
6931
7162
  typecheckFilesList = null;
6932
7163
  _globalSetups;
6933
7164
  _provided = {};
6934
- constructor(path, vitest, options) {
6935
- this.path = path, this.options = options, this.vitest = vitest, this.ctx = vitest, this.globalConfig = vitest.config;
7165
+ constructor(vitest, options) {
7166
+ this.options = options, this.vitest = vitest, this.globalConfig = vitest.config;
6936
7167
  }
6937
7168
  /**
6938
7169
  * The unique hash of this project. This value is consistent between the reruns.
@@ -7024,28 +7255,12 @@ class TestProject {
7024
7255
  get serializedConfig() {
7025
7256
  return this._serializeOverriddenConfig();
7026
7257
  }
7027
- /** @deprecated use `vite` instead */
7028
- get server() {
7029
- return this._vite;
7030
- }
7031
7258
  /**
7032
7259
  * Check if this is the root project. The root project is the one that has the root config.
7033
7260
  */
7034
7261
  isRootProject() {
7035
7262
  return this.vitest.getRootProject() === this;
7036
7263
  }
7037
- /** @deprecated use `isRootProject` instead */
7038
- isCore() {
7039
- return this.isRootProject();
7040
- }
7041
- /** @deprecated use `createSpecification` instead */
7042
- createSpec(moduleId, pool) {
7043
- return new TestSpecification(this, moduleId, pool);
7044
- }
7045
- /** @deprecated */
7046
- initializeGlobalSetup() {
7047
- return this._initializeGlobalSetup();
7048
- }
7049
7264
  /** @internal */
7050
7265
  async _initializeGlobalSetup() {
7051
7266
  if (!this._globalSetups) {
@@ -7061,37 +7276,10 @@ class TestProject {
7061
7276
  onTestsRerun(cb) {
7062
7277
  this.vitest.onTestsRerun(cb);
7063
7278
  }
7064
- /** @deprecated */
7065
- teardownGlobalSetup() {
7066
- return this._teardownGlobalSetup();
7067
- }
7068
7279
  /** @internal */
7069
7280
  async _teardownGlobalSetup() {
7070
7281
  if (this._globalSetups) for (const globalSetupFile of [...this._globalSetups].reverse()) await globalSetupFile.teardown?.();
7071
7282
  }
7072
- /** @deprecated use `vitest.logger` instead */
7073
- get logger() {
7074
- return this.vitest.logger;
7075
- }
7076
- // it's possible that file path was imported with different queries (?raw, ?url, etc)
7077
- /** @deprecated use `.vite` or `.browser.vite` directly */
7078
- getModulesByFilepath(file) {
7079
- const set = this.server.moduleGraph.getModulesByFile(file) || this.browser?.vite.moduleGraph.getModulesByFile(file);
7080
- return set || /* @__PURE__ */ new Set();
7081
- }
7082
- /** @deprecated use `.vite` or `.browser.vite` directly */
7083
- getModuleById(id) {
7084
- return this.server.moduleGraph.getModuleById(id) || this.browser?.vite.moduleGraph.getModuleById(id);
7085
- }
7086
- /** @deprecated use `.vite` or `.browser.vite` directly */
7087
- getSourceMapModuleById(id) {
7088
- const mod = this.server.moduleGraph.getModuleById(id);
7089
- return mod?.ssrTransformResult?.map || mod?.transformResult?.map;
7090
- }
7091
- /** @deprecated use `vitest.reporters` instead */
7092
- get reporters() {
7093
- return this.ctx.reporters;
7094
- }
7095
7283
  /**
7096
7284
  * Get all files in the project that match the globs in the config and the filters.
7097
7285
  * @param filters String filters to match the test files.
@@ -7143,10 +7331,6 @@ class TestProject {
7143
7331
  _isCachedTypecheckFile(testPath) {
7144
7332
  return !!this.typecheckFilesList && this.typecheckFilesList.includes(testPath);
7145
7333
  }
7146
- /** @deprecated use `serializedConfig` instead */
7147
- getSerializableConfig() {
7148
- return this._serializeOverriddenConfig();
7149
- }
7150
7334
  /** @internal */
7151
7335
  async globFiles(include, exclude, cwd) {
7152
7336
  const globOptions = {
@@ -7174,10 +7358,6 @@ class TestProject {
7174
7358
  }
7175
7359
  return false;
7176
7360
  }
7177
- /** @deprecated use `matchesTestGlob` instead */
7178
- async isTargetFile(id, source) {
7179
- return this.matchesTestGlob(id, source ? () => source : void 0);
7180
- }
7181
7361
  isInSourceTestCode(code) {
7182
7362
  return code.includes("import.meta.vitest");
7183
7363
  }
@@ -7242,14 +7422,6 @@ class TestProject {
7242
7422
  import(moduleId) {
7243
7423
  return this.runner.import(moduleId);
7244
7424
  }
7245
- /** @deprecated use `name` instead */
7246
- getName() {
7247
- return this.config.name || "";
7248
- }
7249
- /** @deprecated internal */
7250
- setServer(options, server) {
7251
- return this._configureServer(options, server);
7252
- }
7253
7425
  _setHash() {
7254
7426
  this._hash = generateHash(this._config.root + this._config.name);
7255
7427
  }
@@ -7277,10 +7449,6 @@ class TestProject {
7277
7449
  await rm(this.tmpDir, { recursive: true });
7278
7450
  } catch {}
7279
7451
  }
7280
- /** @deprecated */
7281
- initBrowserProvider() {
7282
- return this._initBrowserProvider();
7283
- }
7284
7452
  /** @internal */
7285
7453
  _initBrowserProvider = deduped(async () => {
7286
7454
  if (!(!this.isBrowserEnabled() || this.browser?.provider)) {
@@ -7298,12 +7466,12 @@ class TestProject {
7298
7466
  }
7299
7467
  /** @internal */
7300
7468
  static _createBasicProject(vitest) {
7301
- const project = new TestProject(vitest.config.name || vitest.config.root, vitest);
7302
- return project.runner = vitest.runner, project._vite = vitest.server, project._config = vitest.config, project._resolver = vitest._resolver, project._setHash(), project._provideObject(vitest.config.provide), project;
7469
+ const project = new TestProject(vitest);
7470
+ return project.runner = vitest.runner, project._vite = vitest.vite, project._config = vitest.config, project._resolver = vitest._resolver, project._setHash(), project._provideObject(vitest.config.provide), project;
7303
7471
  }
7304
7472
  /** @internal */
7305
7473
  static _cloneBrowserProject(parent, config) {
7306
- const clone = new TestProject(parent.path, parent.vitest);
7474
+ const clone = new TestProject(parent.vitest);
7307
7475
  return clone.runner = parent.runner, clone._vite = parent._vite, clone._resolver = parent._resolver, clone._config = config, clone._setHash(), clone._parent = parent, clone._provideObject(config.provide), clone;
7308
7476
  }
7309
7477
  }
@@ -7317,7 +7485,7 @@ function deduped(cb) {
7317
7485
  });
7318
7486
  }
7319
7487
  async function initializeProject(workspacePath, ctx, options) {
7320
- const project = new TestProject(workspacePath, ctx, options), { configFile,...restOptions } = options, config = {
7488
+ const project = new TestProject(ctx, options), { configFile,...restOptions } = options, config = {
7321
7489
  ...restOptions,
7322
7490
  configFile,
7323
7491
  configLoader: ctx.vite.config.inlineConfig.configLoader,
@@ -8073,6 +8241,9 @@ function getSuiteState(task) {
8073
8241
  if (state === "pass") return "passed";
8074
8242
  throw new Error(`Unknown suite state: ${state}`);
8075
8243
  }
8244
+ function experimental_getRunnerTask(entity) {
8245
+ return entity.task;
8246
+ }
8076
8247
 
8077
8248
  function isAggregateError(err) {
8078
8249
  return typeof AggregateError !== "undefined" && err instanceof AggregateError ? true : err instanceof Error && "errors" in err;
@@ -8159,7 +8330,7 @@ class StateManager {
8159
8330
  }
8160
8331
  clearFiles(project, paths = []) {
8161
8332
  paths.forEach((path) => {
8162
- const files = this.filesMap.get(path), fileTask = createFileTask(path, project.config.root, project.config.name);
8333
+ const files = this.filesMap.get(path), fileTask = createFileTask$1(path, project.config.root, project.config.name);
8163
8334
  if (fileTask.local = true, TestModule.register(fileTask, project), this.idMap.set(fileTask.id, fileTask), !files) {
8164
8335
  this.filesMap.set(path, [fileTask]);
8165
8336
  return;
@@ -8203,7 +8374,7 @@ class StateManager {
8203
8374
  return Array.from(this.idMap.values()).filter((t) => t.result?.state === "fail").length;
8204
8375
  }
8205
8376
  cancelFiles(files, project) {
8206
- this.collectFiles(project, files.map((filepath) => createFileTask(filepath, project.config.root, project.config.name)));
8377
+ this.collectFiles(project, files.map((filepath) => createFileTask$1(filepath, project.config.root, project.config.name)));
8207
8378
  }
8208
8379
  }
8209
8380
 
@@ -8686,9 +8857,9 @@ class TestRun {
8686
8857
  return assert$1(task && entity, `Entity must be found for task ${task?.name || testId}`), assert$1(entity.type === "test", `Annotation can only be added to a test, instead got ${entity.type}`), await this.resolveTestAttachment(entity, annotation), entity.task.annotations.push(annotation), await this.vitest.report("onTestCaseAnnotate", entity, annotation), annotation;
8687
8858
  }
8688
8859
  async updated(update, events) {
8689
- this.vitest.state.updateTasks(update);
8860
+ this.syncUpdateStacks(update), this.vitest.state.updateTasks(update);
8690
8861
  for (const [id, event, data] of events) await this.reportEvent(id, event, data).catch((error) => {
8691
- this.vitest.state.catchError(serializeError(error), "Unhandled Reporter Error");
8862
+ this.vitest.state.catchError(serializeError$1(error), "Unhandled Reporter Error");
8692
8863
  });
8693
8864
  // TODO: what is the order or reports here?
8694
8865
  // "onTaskUpdate" in parallel with others or before all or after all?
@@ -8705,6 +8876,17 @@ class TestRun {
8705
8876
  hasFailed(modules) {
8706
8877
  return modules.length ? modules.some((m) => !m.ok()) : !this.vitest.config.passWithNoTests;
8707
8878
  }
8879
+ syncUpdateStacks(update) {
8880
+ update.forEach(([taskId, result]) => {
8881
+ const task = this.vitest.state.idMap.get(taskId), isBrowser = task && task.file.pool === "browser";
8882
+ result?.errors?.forEach((error) => {
8883
+ if (isPrimitive(error)) return;
8884
+ const project = this.vitest.getProjectByName(task.file.projectName || "");
8885
+ if (isBrowser) error.stacks = project.browser?.parseErrorStacktrace(error, { frameFilter: project.config.onStackTrace }) || [];
8886
+ else error.stacks = parseErrorStacktrace(error, { frameFilter: project.config.onStackTrace });
8887
+ });
8888
+ });
8889
+ }
8708
8890
  async reportEvent(id, event, data) {
8709
8891
  const task = this.vitest.state.idMap.get(id), entity = task && this.vitest.state.getReportedEntity(task);
8710
8892
  if (assert$1(task && entity, `Entity must be found for task ${task?.name || id}`), event === "suite-prepare" && entity.type === "suite") return await this.vitest.report("onTestSuiteReady", entity);
@@ -8786,8 +8968,8 @@ class VitestWatcher {
8786
8968
  registerWatcher() {
8787
8969
  const watcher = this.vitest.vite.watcher;
8788
8970
  if (this.vitest.config.forceRerunTriggers.length) watcher.add(this.vitest.config.forceRerunTriggers);
8789
- return watcher.on("change", this.onChange), watcher.on("unlink", this.onUnlink), watcher.on("add", this.onAdd), this.unregisterWatcher = () => {
8790
- watcher.off("change", this.onChange), watcher.off("unlink", this.onUnlink), watcher.off("add", this.onAdd), this.unregisterWatcher = noop;
8971
+ return watcher.on("change", this.onFileChange), watcher.on("unlink", this.onFileDelete), watcher.on("add", this.onFileCreate), this.unregisterWatcher = () => {
8972
+ watcher.off("change", this.onFileChange), watcher.off("unlink", this.onFileDelete), watcher.off("add", this.onFileCreate), this.unregisterWatcher = noop;
8791
8973
  }, this;
8792
8974
  }
8793
8975
  scheduleRerun(file) {
@@ -8805,7 +8987,7 @@ class VitestWatcher {
8805
8987
  }
8806
8988
  }), triggered;
8807
8989
  }
8808
- onChange = (id) => {
8990
+ onFileChange = (id) => {
8809
8991
  id = slash(id), this.vitest.logger.clearHighlightCache(id), this.vitest.invalidateFile(id);
8810
8992
  const testFiles = this.getTestFilesFromWatcherTrigger(id);
8811
8993
  if (testFiles) this.scheduleRerun(id);
@@ -8814,10 +8996,10 @@ class VitestWatcher {
8814
8996
  if (needsRerun) this.scheduleRerun(id);
8815
8997
  }
8816
8998
  };
8817
- onUnlink = (id) => {
8999
+ onFileDelete = (id) => {
8818
9000
  if (id = slash(id), this.vitest.logger.clearHighlightCache(id), this.invalidates.add(id), this.vitest.state.filesMap.has(id)) this.vitest.projects.forEach((project) => project._removeCachedTestFile(id)), this.vitest.state.filesMap.delete(id), this.vitest.cache.results.removeFromCache(id), this.vitest.cache.stats.removeStats(id), this.changedTests.delete(id), this.vitest.report("onTestRemoved", id);
8819
9001
  };
8820
- onAdd = (id) => {
9002
+ onFileCreate = (id) => {
8821
9003
  id = slash(id), this.vitest.invalidateFile(id);
8822
9004
  const testFiles = this.getTestFilesFromWatcherTrigger(id);
8823
9005
  if (testFiles) {
@@ -8910,8 +9092,15 @@ class Vitest {
8910
9092
  * If projects were filtered with `--project` flag, they won't appear here.
8911
9093
  */
8912
9094
  projects = [];
9095
+ /**
9096
+ * A watcher handler. This is not the file system watcher. The handler only
9097
+ * exposes methods to handle changed files.
9098
+ *
9099
+ * If you have your own watcher, you can use these methods to replicate
9100
+ * Vitest behaviour.
9101
+ */
9102
+ watcher;
8913
9103
  /** @internal */ configOverride = {};
8914
- /** @internal */ coverageProvider;
8915
9104
  /** @internal */ filenamePattern;
8916
9105
  /** @internal */ runningPromise;
8917
9106
  /** @internal */ closingPromise;
@@ -8926,15 +9115,15 @@ class Vitest {
8926
9115
  isFirstRun = true;
8927
9116
  restartsCount = 0;
8928
9117
  specifications;
8929
- watcher;
8930
9118
  pool;
8931
9119
  _config;
8932
9120
  _vite;
8933
9121
  _state;
8934
9122
  _cache;
8935
9123
  _snapshot;
9124
+ _coverageProvider;
8936
9125
  constructor(mode, cliOptions, options = {}) {
8937
- this.mode = mode, this._cliOptions = cliOptions, this.logger = new Logger(this, options.stdout, options.stderr), this.packageInstaller = options.packageInstaller || new VitestPackageInstaller(), this.specifications = new VitestSpecifications(this), this.watcher = new VitestWatcher(this).onWatcherRerun((file) => this.scheduleRerun([file]));
9126
+ this.mode = mode, this._cliOptions = cliOptions, this.logger = new Logger(this, options.stdout, options.stderr), this.packageInstaller = options.packageInstaller || new VitestPackageInstaller(), this.specifications = new VitestSpecifications(this), this.watcher = new VitestWatcher(this).onWatcherRerun((file) => this.scheduleRerun(file));
8938
9127
  }
8939
9128
  _onRestartListeners = [];
8940
9129
  _onClose = [];
@@ -8942,24 +9131,12 @@ class Vitest {
8942
9131
  _onCancelListeners = [];
8943
9132
  _onUserTestsRerun = [];
8944
9133
  _onFilterWatchedSpecification = [];
8945
- /** @deprecated will be removed in 4.0, use `onFilterWatchedSpecification` instead */
8946
- get invalidates() {
8947
- return this.watcher.invalidates;
8948
- }
8949
- /** @deprecated will be removed in 4.0, use `onFilterWatchedSpecification` instead */
8950
- get changedTests() {
8951
- return this.watcher.changedTests;
8952
- }
8953
9134
  /**
8954
9135
  * The global config.
8955
9136
  */
8956
9137
  get config() {
8957
9138
  return assert(this._config, "config"), this._config;
8958
9139
  }
8959
- /** @deprecated use `vitest.vite` instead */
8960
- get server() {
8961
- return this._vite;
8962
- }
8963
9140
  /**
8964
9141
  * Global Vite's dev server instance.
8965
9142
  */
@@ -8985,13 +9162,9 @@ class Vitest {
8985
9162
  get cache() {
8986
9163
  return assert(this._cache, "cache"), this._cache;
8987
9164
  }
8988
- /** @deprecated internal */
8989
- setServer(options, server) {
8990
- return this._setServer(options, server);
8991
- }
8992
9165
  /** @internal */
8993
9166
  async _setServer(options, server) {
8994
- this.watcher.unregisterWatcher(), clearTimeout(this._rerunTimer), this.restartsCount += 1, this.pool?.close?.(), this.pool = void 0, this.closingPromise = void 0, this.projects = [], this.coverageProvider = void 0, this.runningPromise = void 0, this.coreWorkspaceProject = void 0, this.specifications.clearCache(), this._onUserTestsRerun = [], this._vite = server;
9167
+ this.watcher.unregisterWatcher(), clearTimeout(this._rerunTimer), this.restartsCount += 1, this.pool?.close?.(), this.pool = void 0, this.closingPromise = void 0, this.projects = [], this.runningPromise = void 0, this.coreWorkspaceProject = void 0, this.specifications.clearCache(), this._coverageProvider = void 0, this._onUserTestsRerun = [], this._vite = server;
8995
9168
  const resolved = resolveConfig(this, options, server.config);
8996
9169
  if (this._config = resolved, this._state = new StateManager({ onUnhandledError: resolved.onUnhandledError }), this._cache = new VitestCache(this.version), this._snapshot = new SnapshotManager({ ...resolved.snapshotOptions }), this._testRun = new TestRun(this), this.config.watch) this.watcher.registerWatcher();
8997
9170
  this._resolver = new VitestResolver(server.config.cacheDir, resolved);
@@ -9032,6 +9205,26 @@ class Vitest {
9032
9205
  if (this.config.testNamePattern) this.configOverride.testNamePattern = this.config.testNamePattern;
9033
9206
  this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray(resolved.benchmark?.reporters), this.runner) : await createReporters(resolved.reporters, this), await Promise.all(this._onSetServer.map((fn) => fn()));
9034
9207
  }
9208
+ /** @internal */
9209
+ get coverageProvider() {
9210
+ return this.configOverride.coverage?.enabled === false ? null : this._coverageProvider;
9211
+ }
9212
+ async enableCoverage() {
9213
+ this.configOverride.coverage = {}, this.configOverride.coverage.enabled = true, await this.createCoverageProvider(), await this.coverageProvider?.onEnabled?.();
9214
+ }
9215
+ disableCoverage() {
9216
+ this.configOverride.coverage ??= {}, this.configOverride.coverage.enabled = false;
9217
+ }
9218
+ _coverageOverrideCache = /* @__PURE__ */ new WeakMap();
9219
+ /** @internal */
9220
+ get _coverageOptions() {
9221
+ if (!this.configOverride.coverage) return this.config.coverage;
9222
+ if (!this._coverageOverrideCache.has(this.configOverride.coverage)) {
9223
+ const coverage = deepClone(this.config.coverage), options = deepMerge(coverage, this.configOverride.coverage);
9224
+ this._coverageOverrideCache.set(this.configOverride.coverage, options);
9225
+ }
9226
+ return this._coverageOverrideCache.get(this.configOverride.coverage);
9227
+ }
9035
9228
  /**
9036
9229
  * Inject new test projects into the workspace.
9037
9230
  * @param config Glob, config path or a custom config options.
@@ -9057,10 +9250,6 @@ class Vitest {
9057
9250
  _ensureRootProject() {
9058
9251
  return this.coreWorkspaceProject ||= TestProject._createBasicProject(this), this.coreWorkspaceProject;
9059
9252
  }
9060
- /** @deprecated use `getRootProject` instead */
9061
- getCoreWorkspaceProject() {
9062
- return this.getRootProject();
9063
- }
9064
9253
  /**
9065
9254
  * Return project that has the root (or "global") config.
9066
9255
  */
@@ -9068,13 +9257,6 @@ class Vitest {
9068
9257
  if (!this.coreWorkspaceProject) throw new Error(`Root project is not initialized. This means that the Vite server was not established yet and the the workspace config is not resolved.`);
9069
9258
  return this.coreWorkspaceProject;
9070
9259
  }
9071
- /**
9072
- * @deprecated use Reported Task API instead
9073
- */
9074
- getProjectByTaskId(taskId) {
9075
- const task = this.state.idMap.get(taskId), projectName = task.projectName || task?.file?.projectName || "";
9076
- return this.getProjectByName(projectName);
9077
- }
9078
9260
  getProjectByName(name) {
9079
9261
  const project = this.projects.find((p) => p.name === name) || this.coreWorkspaceProject || this.projects[0];
9080
9262
  if (!project) throw new Error(`Project "${name}" was not found.`);
@@ -9087,6 +9269,15 @@ class Vitest {
9087
9269
  import(moduleId) {
9088
9270
  return this.runner.import(moduleId);
9089
9271
  }
9272
+ /**
9273
+ * Creates a coverage provider if `coverage` is enabled in the config.
9274
+ */
9275
+ async createCoverageProvider() {
9276
+ if (this._coverageProvider) return this._coverageProvider;
9277
+ const coverageProvider = await this.initCoverageProvider();
9278
+ if (coverageProvider) await coverageProvider.clean(this._coverageOptions.clean);
9279
+ return coverageProvider || null;
9280
+ }
9090
9281
  async resolveProjects(cliOptions) {
9091
9282
  const names = /* @__PURE__ */ new Set();
9092
9283
  if (this.config.projects) return resolveProjects(this, cliOptions, void 0, this.config.projects, names);
@@ -9104,10 +9295,10 @@ class Vitest {
9104
9295
  return this.specifications.globTestSpecifications(filters);
9105
9296
  }
9106
9297
  async initCoverageProvider() {
9107
- if (this.coverageProvider === void 0) {
9108
- if (this.coverageProvider = await getCoverageProvider(this.config.coverage, this.runner), this.coverageProvider) await this.coverageProvider.initialize(this), this.config.coverage = this.coverageProvider.resolveOptions();
9109
- return this.coverageProvider;
9110
- }
9298
+ if (this._coverageProvider != null) return;
9299
+ const coverageConfig = this.configOverride.coverage ? this.getRootProject().serializedConfig.coverage : this.config.coverage;
9300
+ if (this._coverageProvider = await getCoverageProvider(coverageConfig, this.runner), this._coverageProvider) await this._coverageProvider.initialize(this), this.config.coverage = this._coverageProvider.resolveOptions();
9301
+ return this._coverageProvider;
9111
9302
  }
9112
9303
  /**
9113
9304
  * Merge reports from multiple runs located in the specified directory (value from `--merge-reports` if not specified).
@@ -9151,10 +9342,6 @@ class Vitest {
9151
9342
  unhandledErrors: []
9152
9343
  };
9153
9344
  }
9154
- /** @deprecated use `getRelevantTestSpecifications` instead */
9155
- listFiles(filters) {
9156
- return this.getRelevantTestSpecifications(filters);
9157
- }
9158
9345
  /**
9159
9346
  * Returns the list of test files that match the config and filters.
9160
9347
  * @param filters String filters to match the test files
@@ -9172,7 +9359,7 @@ class Vitest {
9172
9359
  */
9173
9360
  async start(filters) {
9174
9361
  try {
9175
- await this.initCoverageProvider(), await this.coverageProvider?.clean(this.config.coverage.clean);
9362
+ await this.initCoverageProvider(), await this.coverageProvider?.clean(this._coverageOptions.clean);
9176
9363
  } finally {
9177
9364
  await this.report("onInit", this);
9178
9365
  }
@@ -9198,21 +9385,18 @@ class Vitest {
9198
9385
  */
9199
9386
  async init() {
9200
9387
  try {
9201
- await this.initCoverageProvider(), await this.coverageProvider?.clean(this.config.coverage.clean);
9388
+ await this.initCoverageProvider(), await this.coverageProvider?.clean(this._coverageOptions.clean);
9202
9389
  } finally {
9203
9390
  await this.report("onInit", this);
9204
9391
  }
9205
9392
  if (await this.globTestSpecifications(), this.config.watch) await this.report("onWatcherStart");
9206
9393
  }
9207
9394
  /**
9208
- * @deprecated remove when vscode extension supports "getModuleSpecifications"
9395
+ * If there is a test run happening, returns a promise that will
9396
+ * resolve when the test run is finished.
9209
9397
  */
9210
- getProjectsByTestFile(file) {
9211
- return this.getModuleSpecifications(file);
9212
- }
9213
- /** @deprecated */
9214
- getFileWorkspaceSpecs(file) {
9215
- return this.getModuleSpecifications(file);
9398
+ async waitForTestRunEnd() {
9399
+ this.runningPromise && await this.runningPromise;
9216
9400
  }
9217
9401
  /**
9218
9402
  * Get test specifications associated with the given module. If module is not a test file, an empty array is returned.
@@ -9227,7 +9411,9 @@ class Vitest {
9227
9411
  * Vitest automatically caches test specifications for each file. This method clears the cache for the given file or the whole cache altogether.
9228
9412
  */
9229
9413
  clearSpecificationsCache(moduleId) {
9230
- this.specifications.clearCache(moduleId);
9414
+ if (this.specifications.clearCache(moduleId), !moduleId) this.projects.forEach((project) => {
9415
+ project.testFilesList = null;
9416
+ });
9231
9417
  }
9232
9418
  /**
9233
9419
  * Run tests for the given test specifications. This does not trigger `onWatcher*` events.
@@ -9243,7 +9429,6 @@ class Vitest {
9243
9429
  * @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
9244
9430
  */
9245
9431
  async rerunTestSpecifications(specifications, allTestsRun = false) {
9246
- this.configOverride.testNamePattern = void 0;
9247
9432
  const files = specifications.map((spec) => spec.moduleId);
9248
9433
  await Promise.all([this.report("onWatcherRerun", files, "rerun test"), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
9249
9434
  const result = await this.runTestSpecifications(specifications, allTestsRun);
@@ -9254,7 +9439,7 @@ class Vitest {
9254
9439
  try {
9255
9440
  if (!this.pool) this.pool = createPool(this);
9256
9441
  const invalidates = Array.from(this.watcher.invalidates);
9257
- if (this.watcher.invalidates.clear(), this.snapshot.clear(), this.state.clearErrors(), !this.isFirstRun && this.config.coverage.cleanOnRerun) await this.coverageProvider?.clean();
9442
+ if (this.watcher.invalidates.clear(), this.snapshot.clear(), this.state.clearErrors(), !this.isFirstRun && this._coverageOptions.cleanOnRerun) await this.coverageProvider?.clean();
9258
9443
  await this.initializeGlobalSetup(specs);
9259
9444
  try {
9260
9445
  await this.pool.runTests(specs, invalidates);
@@ -9278,6 +9463,18 @@ class Vitest {
9278
9463
  this.runningPromise = void 0, this.isFirstRun = false, this.config.changed = false, this.config.related = void 0;
9279
9464
  }), await this.runningPromise;
9280
9465
  }
9466
+ async experimental_parseSpecifications(specifications, options) {
9467
+ if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecifications\` does not support "${this.mode}" mode.`);
9468
+ const concurrency = options?.concurrency ?? (typeof nodeos__default.availableParallelism === "function" ? nodeos__default.availableParallelism() : nodeos__default.cpus().length), limit = limitConcurrency(concurrency), promises = specifications.map((specification) => limit(() => this.experimental_parseSpecification(specification)));
9469
+ return Promise.all(promises);
9470
+ }
9471
+ async experimental_parseSpecification(specification) {
9472
+ if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecification\` does not support "${this.mode}" mode.`);
9473
+ const file = await astCollectTests(specification.project, specification.moduleId).catch((error) => {
9474
+ return createFailedFileTask(specification.project, specification.moduleId, error);
9475
+ });
9476
+ return this.state.collectFiles(specification.project, [file]), this.state.getReportedEntity(file);
9477
+ }
9281
9478
  /**
9282
9479
  * Collect tests in specified modules. Vitest will run the files to collect tests.
9283
9480
  * @param specifications A list of specifications to run.
@@ -9416,7 +9613,6 @@ class Vitest {
9416
9613
  this.configOverride.testNamePattern = void 0;
9417
9614
  }
9418
9615
  _rerunTimer;
9419
- // we can't use a single `triggerId` yet because vscode extension relies on this
9420
9616
  async scheduleRerun(triggerId) {
9421
9617
  const currentCount = this.restartsCount;
9422
9618
  clearTimeout(this._rerunTimer), await this.runningPromise, clearTimeout(this._rerunTimer), this.restartsCount === currentCount && (this._rerunTimer = setTimeout(async () => {
@@ -9434,7 +9630,7 @@ class Vitest {
9434
9630
  if (files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file)), files.length === 0) return;
9435
9631
  }
9436
9632
  this.watcher.changedTests.clear();
9437
- const triggerIds = new Set(triggerId.map((id) => relative(this.config.root, id))), triggerLabel = Array.from(triggerIds).join(", "), specifications = files.flatMap((file) => this.getModuleSpecifications(file)).filter((specification) => {
9633
+ const triggerLabel = relative(this.config.root, triggerId), specifications = files.flatMap((file) => this.getModuleSpecifications(file)).filter((specification) => {
9438
9634
  return this._onFilterWatchedSpecification.length === 0 ? true : this._onFilterWatchedSpecification.every((fn) => fn(specification));
9439
9635
  });
9440
9636
  await Promise.all([this.report("onWatcherRerun", files, triggerLabel), ...this._onUserTestsRerun.map((fn) => fn(specifications))]), await this.runFiles(specifications, false), await this.report("onWatcherStart", this.state.getFiles(files));
@@ -9452,17 +9648,13 @@ class Vitest {
9452
9648
  });
9453
9649
  });
9454
9650
  }
9455
- /** @deprecated use `invalidateFile` */
9456
- updateLastChanged(filepath) {
9457
- this.invalidateFile(filepath);
9458
- }
9459
9651
  /** @internal */
9460
9652
  _checkUnhandledErrors(errors) {
9461
9653
  if (errors.length && !this.config.dangerouslyIgnoreUnhandledErrors) process.exitCode = 1;
9462
9654
  }
9463
9655
  async reportCoverage(coverage, allTestsRun) {
9464
9656
  if (this.state.getCountOfFailedTests() > 0) {
9465
- if (await this.coverageProvider?.onTestFailure?.(), !this.config.coverage.reportOnFailure) return;
9657
+ if (await this.coverageProvider?.onTestFailure?.(), !this._coverageOptions.reportOnFailure) return;
9466
9658
  }
9467
9659
  if (this.coverageProvider) {
9468
9660
  await this.coverageProvider.reportCoverage(coverage, { allTestsRun });
@@ -9526,25 +9718,6 @@ class Vitest {
9526
9718
  return Array.from(new Set(specifications.map((spec) => spec.moduleId)));
9527
9719
  }
9528
9720
  /**
9529
- * @deprecated use `globTestSpecifications` instead
9530
- */
9531
- async globTestSpecs(filters = []) {
9532
- return this.globTestSpecifications(filters);
9533
- }
9534
- /**
9535
- * @deprecated use `globTestSpecifications` instead
9536
- */
9537
- async globTestFiles(filters = []) {
9538
- return this.globTestSpecifications(filters);
9539
- }
9540
- /** @deprecated filter by `this.projects` yourself */
9541
- getModuleProjects(filepath) {
9542
- return this.projects.filter((project) => {
9543
- return project.getModulesByFilepath(filepath).size;
9544
- // TODO: reevaluate || project.browser?.moduleGraph.getModulesByFile(id)?.size
9545
- });
9546
- }
9547
- /**
9548
9721
  * Should the server be kept running after the tests are done.
9549
9722
  */
9550
9723
  shouldKeepServer() {
@@ -9961,8 +10134,8 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
9961
10134
  async function inputFilePattern() {
9962
10135
  off();
9963
10136
  const watchFilter = new WatchFilter("Input filename pattern", stdin, stdout), filter = await watchFilter.filter(async (str) => {
9964
- const files = await ctx.globTestFiles([str]);
9965
- return files.map((file) => relative(ctx.config.root, file[1])).filter((file, index, all) => all.indexOf(file) === index);
10137
+ const specifications = await ctx.globTestSpecifications([str]);
10138
+ return specifications.map((specification) => relative(ctx.config.root, specification.moduleId)).filter((file, index, all) => all.indexOf(file) === index);
9966
10139
  });
9967
10140
  if (on(), typeof filter === "undefined") return;
9968
10141
  latestFilename = filter?.trim() || "";
@@ -9992,8 +10165,8 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
9992
10165
  */
9993
10166
  async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, vitestOptions) {
9994
10167
  const root = resolve(options.root || process.cwd()), ctx = await prepareVitest(mode, options, viteOverrides, vitestOptions, cliFilters);
9995
- if (mode === "test" && ctx.config.coverage.enabled) {
9996
- const provider = ctx.config.coverage.provider || "v8", requiredPackages = CoverageProviderMap[provider];
10168
+ if (mode === "test" && ctx._coverageOptions.enabled) {
10169
+ const provider = ctx._coverageOptions.provider || "v8", requiredPackages = CoverageProviderMap[provider];
9997
10170
  if (requiredPackages) {
9998
10171
  if (!await ctx.packageInstaller.ensureInstalled(requiredPackages, root, ctx.version)) return process.exitCode = 1, ctx;
9999
10172
  }
@@ -10114,4 +10287,4 @@ var cliApi = /*#__PURE__*/Object.freeze({
10114
10287
  startVitest: startVitest
10115
10288
  });
10116
10289
 
10117
- export { FilesNotFoundError as F, GitNotFoundError as G, Vitest as V, VitestPlugin as a, VitestPackageInstaller as b, createVitest as c, registerConsoleShortcuts as d, createViteLogger as e, cliApi as f, isValidApiRequest as i, resolveFsAllow as r, startVitest as s };
10290
+ export { FilesNotFoundError as F, GitNotFoundError as G, Vitest as V, VitestPlugin as a, VitestPackageInstaller as b, createVitest as c, experimental_getRunnerTask as d, escapeTestName as e, registerConsoleShortcuts as f, createViteLogger as g, createDebugger as h, isValidApiRequest as i, cliApi as j, resolveFsAllow as r, startVitest as s };