vitest 4.0.0-beta.5 → 4.0.0-beta.7

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 (64) hide show
  1. package/LICENSE.md +1 -1
  2. package/dist/browser.d.ts +3 -3
  3. package/dist/browser.js +2 -2
  4. package/dist/chunks/{base.DMfOuRWD.js → base.BXI97p6t.js} +7 -16
  5. package/dist/chunks/{benchmark.CtuRzf-i.js → benchmark.UW6Ezvxy.js} +4 -9
  6. package/dist/chunks/{browser.d.Cawq_X_N.d.ts → browser.d.DOMmqJQx.d.ts} +1 -1
  7. package/dist/chunks/{cac.CKnbxhn2.js → cac.Dsn7ixFt.js} +38 -113
  8. package/dist/chunks/{cli-api.COn58yrl.js → cli-api.DfGJyldU.js} +829 -1232
  9. package/dist/chunks/{config.d.CKNVOKm0.d.ts → config.d._GBBbReY.d.ts} +1 -0
  10. package/dist/chunks/{console.Duv2dVIC.js → console.B0quX7yH.js} +32 -68
  11. package/dist/chunks/{coverage.B6cReEn1.js → coverage.Dvxug1RM.js} +210 -579
  12. package/dist/chunks/{creator.DUVZ6rfm.js → creator.KEg6n5IC.js} +28 -74
  13. package/dist/chunks/{date.Bq6ZW5rf.js → date.-jtEtIeV.js} +6 -17
  14. package/dist/chunks/{git.BVQ8w_Sw.js → git.BFNcloKD.js} +1 -2
  15. package/dist/chunks/{globals.CJQ63oO0.js → globals.lgsmH00r.js} +5 -5
  16. package/dist/chunks/{index.QZr3S3vQ.js → index.AR8aAkCC.js} +2 -2
  17. package/dist/chunks/{index.DQhAfQQU.js → index.C3EbxYwt.js} +276 -607
  18. package/dist/chunks/{index.oWRWx-nj.js → index.CsFXYRkW.js} +17 -36
  19. package/dist/chunks/{index.DgN0Zk9a.js → index.D2B6d2vv.js} +14 -24
  20. package/dist/chunks/{index.BRtIe7r8.js → index.DfviD7lX.js} +55 -110
  21. package/dist/chunks/{inspector.C914Efll.js → inspector.CvQD-Nie.js} +10 -25
  22. package/dist/chunks/{moduleRunner.d.mmOmOGrW.d.ts → moduleRunner.d.CX4DuqOx.d.ts} +2 -2
  23. package/dist/chunks/{node.4JV5OXkt.js → node.BOqcT2jW.js} +1 -1
  24. package/dist/chunks/{plugin.d.CvOlgjxK.d.ts → plugin.d.vcD4xbMS.d.ts} +1 -1
  25. package/dist/chunks/{reporters.d.CYE9sT5z.d.ts → reporters.d.BC86JJdB.d.ts} +799 -758
  26. package/dist/chunks/{resolver.D5bG4zy5.js → resolver.Bx6lE0iq.js} +21 -64
  27. package/dist/chunks/{rpc.DGoW_Vl-.js → rpc.RpPylpp0.js} +7 -21
  28. package/dist/chunks/{runBaseTests.B3KcKqlF.js → runBaseTests.D6sfuWBM.js} +25 -54
  29. package/dist/chunks/{setup-common.lgPs-bYv.js → setup-common.hLGRxhC8.js} +9 -22
  30. package/dist/chunks/{startModuleRunner.C8FtT_BY.js → startModuleRunner.C8TW8zTN.js} +83 -205
  31. package/dist/chunks/{typechecker.BgoW4nTA.js → typechecker.DSo_maXz.js} +97 -209
  32. package/dist/chunks/{utils.CcGm2cd1.js → utils.C2YI6McM.js} +4 -13
  33. package/dist/chunks/{utils.B9FY3b73.js → utils.C7__0Iv5.js} +5 -14
  34. package/dist/chunks/{vi.DGAfBY4R.js → vi.BfdOiD4j.js} +110 -267
  35. package/dist/chunks/{vm.BKfKvaKl.js → vm.BHBje7cC.js} +73 -177
  36. package/dist/chunks/{worker.d.Db-UVmXc.d.ts → worker.d.BKu8cnnX.d.ts} +1 -1
  37. package/dist/chunks/{worker.d.D9QWnzAe.d.ts → worker.d.DYlqbejz.d.ts} +1 -1
  38. package/dist/cli.js +3 -3
  39. package/dist/config.d.ts +7 -7
  40. package/dist/coverage.d.ts +4 -4
  41. package/dist/coverage.js +2 -2
  42. package/dist/environments.js +1 -1
  43. package/dist/index.d.ts +6 -6
  44. package/dist/index.js +5 -5
  45. package/dist/module-evaluator.d.ts +3 -3
  46. package/dist/module-evaluator.js +33 -84
  47. package/dist/module-runner.js +2 -2
  48. package/dist/node.d.ts +11 -9
  49. package/dist/node.js +16 -27
  50. package/dist/reporters.d.ts +5 -5
  51. package/dist/reporters.js +3 -3
  52. package/dist/runners.d.ts +1 -1
  53. package/dist/runners.js +23 -51
  54. package/dist/snapshot.js +2 -2
  55. package/dist/suite.js +2 -2
  56. package/dist/worker.js +18 -34
  57. package/dist/workers/forks.js +4 -4
  58. package/dist/workers/runVmTests.js +19 -37
  59. package/dist/workers/threads.js +4 -4
  60. package/dist/workers/vmForks.js +7 -7
  61. package/dist/workers/vmThreads.js +7 -7
  62. package/dist/workers.d.ts +3 -3
  63. package/dist/workers.js +11 -11
  64. package/package.json +11 -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.CKnbxhn2.js';
13
+ import { v as version$1 } from './cac.Dsn7ixFt.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.DQhAfQQU.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.C3EbxYwt.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.B6cReEn1.js';
30
- import { c as convertTasksToEvents } from './typechecker.BgoW4nTA.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.Dvxug1RM.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,17 +38,16 @@ 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';
43
44
  import { hoistMocksPlugin, automockPlugin } from '@vitest/mocker/node';
44
45
  import { c as configDefaults } from './defaults.CXFFjsi8.js';
45
- import { f as findNearestPackageData } from './resolver.D5bG4zy5.js';
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.DgN0Zk9a.js';
48
+ import { a as BenchmarkReportsMap } from './index.D2B6d2vv.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
 
@@ -5017,26 +5018,18 @@ var websocketServerExports = requireWebsocketServer();
5017
5018
  var WebSocketServer = /*@__PURE__*/getDefaultExportFromCjs(websocketServerExports);
5018
5019
 
5019
5020
  async function getModuleGraph(ctx, projectName, id, browser = false) {
5020
- const graph = {};
5021
- const externalized = /* @__PURE__ */ new Set();
5022
- const inlined = /* @__PURE__ */ new Set();
5023
- const project = ctx.getProjectByName(projectName);
5021
+ const graph = {}, externalized = /* @__PURE__ */ new Set(), inlined = /* @__PURE__ */ new Set(), project = ctx.getProjectByName(projectName);
5024
5022
  async function get(mod, seen = /* @__PURE__ */ new Map()) {
5025
- if (!mod || !mod.id) return;
5026
- if (mod.id === "\0@vitest/browser/context") return;
5023
+ if (!mod || !mod.id || mod.id === "\0@vitest/browser/context") return;
5027
5024
  if (seen.has(mod)) return seen.get(mod);
5028
5025
  let id = clearId(mod.id);
5029
5026
  seen.set(mod, id);
5030
5027
  // TODO: how to know if it was rewritten(?) - what is rewritten?
5031
5028
  const rewrote = browser ? mod.file?.includes(project.browser.vite.config.cacheDir) ? mod.id : false : false;
5032
- if (rewrote) {
5033
- id = rewrote;
5034
- externalized.add(id);
5035
- seen.set(mod, id);
5036
- } else inlined.add(id);
5029
+ if (rewrote) id = rewrote, externalized.add(id), seen.set(mod, id);
5030
+ else inlined.add(id);
5037
5031
  const mods = Array.from(mod.importedModules).filter((i) => i.id && !i.id.includes("/vitest/dist/"));
5038
- graph[id] = (await Promise.all(mods.map((m) => get(m, seen)))).filter(Boolean);
5039
- return id;
5032
+ return graph[id] = (await Promise.all(mods.map((m) => get(m, seen)))).filter(Boolean), id;
5040
5033
  }
5041
5034
  if (browser && project.browser) await get(project.browser.vite.moduleGraph.getModuleById(id));
5042
5035
  else await get(project.vite.moduleGraph.getModuleById(id));
@@ -5088,21 +5081,19 @@ catch {}
5088
5081
  }
5089
5082
 
5090
5083
  function setup(ctx, _server) {
5091
- const wss = new WebSocketServer({ noServer: true });
5092
- const clients = /* @__PURE__ */ new Map();
5093
- const server = _server || ctx.server;
5084
+ const wss = new WebSocketServer({ noServer: true }), clients = /* @__PURE__ */ new Map(), server = _server || ctx.server;
5094
5085
  server.httpServer?.on("upgrade", (request, socket, head) => {
5095
5086
  if (!request.url) return;
5096
5087
  const { pathname } = new URL(request.url, "http://localhost");
5097
- if (pathname !== API_PATH) return;
5098
- if (!isValidApiRequest(ctx.config, request)) {
5099
- socket.destroy();
5100
- return;
5088
+ if (pathname === API_PATH) {
5089
+ if (!isValidApiRequest(ctx.config, request)) {
5090
+ socket.destroy();
5091
+ return;
5092
+ }
5093
+ wss.handleUpgrade(request, socket, head, (ws) => {
5094
+ wss.emit("connection", ws, request), setupClient(ws);
5095
+ });
5101
5096
  }
5102
- wss.handleUpgrade(request, socket, head, (ws) => {
5103
- wss.emit("connection", ws, request);
5104
- setupClient(ws);
5105
- });
5106
5097
  });
5107
5098
  function setupClient(ws) {
5108
5099
  const rpc = createBirpc({
@@ -5116,8 +5107,7 @@ function setup(ctx, _server) {
5116
5107
  return ctx.state.getPaths();
5117
5108
  },
5118
5109
  async readTestFile(id) {
5119
- if (!ctx.state.filesMap.has(id) || !existsSync(id)) return null;
5120
- return promises.readFile(id, "utf-8");
5110
+ return !ctx.state.filesMap.has(id) || !existsSync(id) ? null : promises.readFile(id, "utf-8");
5121
5111
  },
5122
5112
  async saveTestFile(id, content) {
5123
5113
  if (!ctx.state.filesMap.has(id) || !existsSync(id)) throw new Error(`Test file "${id}" was not registered, so it cannot be updated using the API.`);
@@ -5139,8 +5129,7 @@ function setup(ctx, _server) {
5139
5129
  }));
5140
5130
  },
5141
5131
  async getTransformResult(projectName, id, browser = false) {
5142
- const project = ctx.getProjectByName(projectName);
5143
- const result = browser ? await project.browser.vite.transformRequest(id) : await project.vite.transformRequest(id);
5132
+ const project = ctx.getProjectByName(projectName), result = browser ? await project.browser.vite.transformRequest(id) : await project.vite.transformRequest(id);
5144
5133
  if (result) {
5145
5134
  try {
5146
5135
  result.source = result.source || await promises.readFile(id, "utf-8");
@@ -5183,56 +5172,41 @@ function setup(ctx, _server) {
5183
5172
  deserialize: parse,
5184
5173
  timeout: -1
5185
5174
  });
5186
- clients.set(ws, rpc);
5187
- ws.on("close", () => {
5188
- clients.delete(ws);
5189
- rpc.$close(/* @__PURE__ */ new Error("[vitest-api]: Pending methods while closing rpc"));
5175
+ clients.set(ws, rpc), ws.on("close", () => {
5176
+ clients.delete(ws), rpc.$close(/* @__PURE__ */ new Error("[vitest-api]: Pending methods while closing rpc"));
5190
5177
  });
5191
5178
  }
5192
5179
  ctx.reporters.push(new WebSocketReporter(ctx, wss, clients));
5193
5180
  }
5194
5181
  class WebSocketReporter {
5195
5182
  constructor(ctx, wss, clients) {
5196
- this.ctx = ctx;
5197
- this.wss = wss;
5198
- this.clients = clients;
5183
+ this.ctx = ctx, this.wss = wss, this.clients = clients;
5199
5184
  }
5200
- onCollected(files) {
5201
- if (this.clients.size === 0) return;
5202
- this.clients.forEach((client) => {
5203
- client.onCollected?.(files)?.catch?.(noop);
5185
+ onTestModuleCollected(testModule) {
5186
+ this.clients.size !== 0 && this.clients.forEach((client) => {
5187
+ client.onCollected?.([testModule.task])?.catch?.(noop);
5204
5188
  });
5205
5189
  }
5206
- onSpecsCollected(specs) {
5190
+ onTestRunStart(specifications) {
5207
5191
  if (this.clients.size === 0) return;
5192
+ const serializedSpecs = specifications.map((spec) => spec.toJSON());
5208
5193
  this.clients.forEach((client) => {
5209
- client.onSpecsCollected?.(specs)?.catch?.(noop);
5194
+ client.onSpecsCollected?.(serializedSpecs)?.catch?.(noop);
5210
5195
  });
5211
5196
  }
5212
5197
  async onTestCaseAnnotate(testCase, annotation) {
5213
- if (this.clients.size === 0) return;
5214
- this.clients.forEach((client) => {
5198
+ this.clients.size !== 0 && this.clients.forEach((client) => {
5215
5199
  client.onTestAnnotate?.(testCase.id, annotation)?.catch?.(noop);
5216
5200
  });
5217
5201
  }
5218
5202
  async onTaskUpdate(packs, events) {
5219
- if (this.clients.size === 0) return;
5220
- packs.forEach(([taskId, result]) => {
5221
- const task = this.ctx.state.idMap.get(taskId);
5222
- const isBrowser = task && task.file.pool === "browser";
5223
- result?.errors?.forEach((error) => {
5224
- if (isPrimitive(error)) return;
5225
- if (isBrowser) {
5226
- const project = this.ctx.getProjectByName(task.file.projectName || "");
5227
- error.stacks = project.browser?.parseErrorStacktrace(error);
5228
- } else error.stacks = parseErrorStacktrace(error);
5229
- });
5230
- });
5231
- this.clients.forEach((client) => {
5203
+ this.clients.size !== 0 && this.clients.forEach((client) => {
5232
5204
  client.onTaskUpdate?.(packs, events)?.catch?.(noop);
5233
5205
  });
5234
5206
  }
5235
- onFinished(files, errors) {
5207
+ onTestRunEnd(testModules, unhandledErrors) {
5208
+ if (!this.clients.size) return;
5209
+ const files = testModules.map((testModule) => testModule.task), errors = [...unhandledErrors];
5236
5210
  this.clients.forEach((client) => {
5237
5211
  client.onFinished?.(files, errors)?.catch?.(noop);
5238
5212
  });
@@ -5255,6 +5229,265 @@ var setup$1 = /*#__PURE__*/Object.freeze({
5255
5229
  setup: setup
5256
5230
  });
5257
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.getName(),
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
+
5258
5491
  class BrowserSessions {
5259
5492
  sessions = /* @__PURE__ */ new Map();
5260
5493
  sessionIds = /* @__PURE__ */ new Set();
@@ -5266,23 +5499,18 @@ class BrowserSessions {
5266
5499
  }
5267
5500
  createSession(sessionId, project, pool) {
5268
5501
  // this promise only waits for the WS connection with the orhcestrator to be established
5269
- const defer = createDefer();
5270
- const timeout = setTimeout(() => {
5502
+ const defer = createDefer(), timeout = setTimeout(() => {
5271
5503
  defer.reject(/* @__PURE__ */ new Error(`Failed to connect to the browser session "${sessionId}" [${project.name}] within the timeout.`));
5272
5504
  }, project.vitest.config.browser.connectTimeout ?? 6e4).unref();
5273
- this.sessions.set(sessionId, {
5505
+ return this.sessions.set(sessionId, {
5274
5506
  project,
5275
5507
  connected: () => {
5276
- defer.resolve();
5277
- clearTimeout(timeout);
5508
+ defer.resolve(), clearTimeout(timeout);
5278
5509
  },
5279
5510
  fail: (error) => {
5280
- defer.resolve();
5281
- clearTimeout(timeout);
5282
- pool.reject(error);
5511
+ defer.resolve(), clearTimeout(timeout), pool.reject(error);
5283
5512
  }
5284
- });
5285
- return defer;
5513
+ }), defer;
5286
5514
  }
5287
5515
  }
5288
5516
 
@@ -5323,37 +5551,25 @@ class ResultsCache {
5323
5551
  return this.cachePath;
5324
5552
  }
5325
5553
  setConfig(root, config) {
5326
- this.root = root;
5327
- if (config) this.cachePath = resolve(config.dir, "results.json");
5554
+ if (this.root = root, config) this.cachePath = resolve(config.dir, "results.json");
5328
5555
  }
5329
5556
  getResults(key) {
5330
5557
  return this.cache.get(key);
5331
5558
  }
5332
5559
  async readFromCache() {
5333
- if (!this.cachePath) return;
5334
- if (!fs.existsSync(this.cachePath)) return;
5335
- const resultsCache = await fs.promises.readFile(this.cachePath, "utf8");
5336
- const { results, version } = JSON.parse(resultsCache || "[]");
5337
- const [major, minor] = version.split(".");
5560
+ if (!this.cachePath || !fs.existsSync(this.cachePath)) return;
5561
+ const resultsCache = await fs.promises.readFile(this.cachePath, "utf8"), { results, version } = JSON.parse(resultsCache || "[]"), [major, minor] = version.split(".");
5338
5562
  // handling changed in 0.30.0
5339
- if (major > 0 || Number(minor) >= 30) {
5340
- this.cache = new Map(results);
5341
- this.version = version;
5342
- results.forEach(([spec]) => {
5343
- const [projectName, relativePath] = spec.split(":");
5344
- const keyMap = this.workspacesKeyMap.get(relativePath) || [];
5345
- keyMap.push(projectName);
5346
- this.workspacesKeyMap.set(relativePath, keyMap);
5347
- });
5348
- }
5563
+ if (major > 0 || Number(minor) >= 30) this.cache = new Map(results), this.version = version, results.forEach(([spec]) => {
5564
+ const [projectName, relativePath] = spec.split(":"), keyMap = this.workspacesKeyMap.get(relativePath) || [];
5565
+ keyMap.push(projectName), this.workspacesKeyMap.set(relativePath, keyMap);
5566
+ });
5349
5567
  }
5350
5568
  updateResults(files) {
5351
5569
  files.forEach((file) => {
5352
5570
  const result = file.result;
5353
5571
  if (!result) return;
5354
- const duration = result.duration || 0;
5355
- // store as relative, so cache would be the same in CI and locally
5356
- const relativePath = relative(this.root, file.filepath);
5572
+ const duration = result.duration || 0, relativePath = relative(this.root, file.filepath);
5357
5573
  this.cache.set(`${file.projectName || ""}:${relativePath}`, {
5358
5574
  duration: duration >= 0 ? duration : 0,
5359
5575
  failed: result.state === "fail"
@@ -5367,8 +5583,7 @@ class ResultsCache {
5367
5583
  }
5368
5584
  async writeToCache() {
5369
5585
  if (!this.cachePath) return;
5370
- const results = Array.from(this.cache.entries());
5371
- const cacheDirname = dirname(this.cachePath);
5586
+ const results = Array.from(this.cache.entries()), cacheDirname = dirname(this.cachePath);
5372
5587
  if (!fs.existsSync(cacheDirname)) await fs.promises.mkdir(cacheDirname, { recursive: true });
5373
5588
  const cache = JSON.stringify({
5374
5589
  version: this.version,
@@ -5412,9 +5627,7 @@ class ServerModuleRunner extends ModuleRunner {
5412
5627
  return { error };
5413
5628
  }
5414
5629
  } }
5415
- }, new VitestModuleEvaluator());
5416
- this.environment = environment;
5417
- this.config = config;
5630
+ }, new VitestModuleEvaluator()), this.environment = environment, this.config = config;
5418
5631
  }
5419
5632
  async import(rawId) {
5420
5633
  const resolved = await this.environment.pluginContainer.resolveId(rawId, this.config.root);
@@ -5481,43 +5694,26 @@ function highlightCode(id, source, colors) {
5481
5694
  });
5482
5695
  }
5483
5696
 
5484
- const PAD = " ";
5485
- const ESC$1 = "\x1B[";
5486
- const ERASE_DOWN = `${ESC$1}J`;
5487
- const ERASE_SCROLLBACK = `${ESC$1}3J`;
5488
- const CURSOR_TO_START = `${ESC$1}1;1H`;
5489
- const HIDE_CURSOR = `${ESC$1}?25l`;
5490
- const SHOW_CURSOR = `${ESC$1}?25h`;
5491
- const CLEAR_SCREEN = "\x1Bc";
5697
+ const PAD = " ", ESC$1 = "\x1B[", ERASE_DOWN = `${ESC$1}J`, ERASE_SCROLLBACK = `${ESC$1}3J`, CURSOR_TO_START = `${ESC$1}1;1H`, HIDE_CURSOR = `${ESC$1}?25l`, SHOW_CURSOR = `${ESC$1}?25h`, CLEAR_SCREEN = "\x1Bc";
5492
5698
  class Logger {
5493
5699
  _clearScreenPending;
5494
5700
  _highlights = /* @__PURE__ */ new Map();
5495
5701
  cleanupListeners = [];
5496
5702
  console;
5497
5703
  constructor(ctx, outputStream = process.stdout, errorStream = process.stderr) {
5498
- this.ctx = ctx;
5499
- this.outputStream = outputStream;
5500
- this.errorStream = errorStream;
5501
- this.console = new Console({
5704
+ if (this.ctx = ctx, this.outputStream = outputStream, this.errorStream = errorStream, this.console = new Console({
5502
5705
  stdout: outputStream,
5503
5706
  stderr: errorStream
5504
- });
5505
- this._highlights.clear();
5506
- this.addCleanupListeners();
5507
- this.registerUnhandledRejection();
5508
- if (this.outputStream.isTTY) this.outputStream.write(HIDE_CURSOR);
5707
+ }), this._highlights.clear(), this.addCleanupListeners(), this.registerUnhandledRejection(), this.outputStream.isTTY) this.outputStream.write(HIDE_CURSOR);
5509
5708
  }
5510
5709
  log(...args) {
5511
- this._clearScreen();
5512
- this.console.log(...args);
5710
+ this._clearScreen(), this.console.log(...args);
5513
5711
  }
5514
5712
  error(...args) {
5515
- this._clearScreen();
5516
- this.console.error(...args);
5713
+ this._clearScreen(), this.console.error(...args);
5517
5714
  }
5518
5715
  warn(...args) {
5519
- this._clearScreen();
5520
- this.console.warn(...args);
5716
+ this._clearScreen(), this.console.warn(...args);
5521
5717
  }
5522
5718
  clearFullScreen(message = "") {
5523
5719
  if (!this.ctx.config.clearScreen) {
@@ -5532,14 +5728,12 @@ class Logger {
5532
5728
  this.console.log(message);
5533
5729
  return;
5534
5730
  }
5535
- this._clearScreenPending = message;
5536
- if (force) this._clearScreen();
5731
+ if (this._clearScreenPending = message, force) this._clearScreen();
5537
5732
  }
5538
5733
  _clearScreen() {
5539
5734
  if (this._clearScreenPending == null) return;
5540
5735
  const log = this._clearScreenPending;
5541
- this._clearScreenPending = void 0;
5542
- this.console.log(`${CURSOR_TO_START}${ERASE_DOWN}${log}`);
5736
+ this._clearScreenPending = void 0, this.console.log(`${CURSOR_TO_START}${ERASE_DOWN}${log}`);
5543
5737
  }
5544
5738
  printError(err, options = {}) {
5545
5739
  printError(err, this.ctx, this, options);
@@ -5554,8 +5748,7 @@ class Logger {
5554
5748
  highlight(filename, source) {
5555
5749
  if (this._highlights.has(filename)) return this._highlights.get(filename);
5556
5750
  const code = highlightCode(filename, source);
5557
- this._highlights.set(filename, code);
5558
- return code;
5751
+ return this._highlights.set(filename, code), code;
5559
5752
  }
5560
5753
  printNoTestFound(filters) {
5561
5754
  const config = this.ctx.config;
@@ -5568,34 +5761,22 @@ class Logger {
5568
5761
  const projectsFilter = toArray(config.project);
5569
5762
  if (projectsFilter.length) this.console.error(c.dim("projects: ") + c.yellow(projectsFilter.join(comma)));
5570
5763
  this.ctx.projects.forEach((project) => {
5571
- const config = project.config;
5572
- const printConfig = !project.isRootProject() && project.name;
5764
+ const config = project.config, printConfig = !project.isRootProject() && project.name;
5573
5765
  if (printConfig) this.console.error(`\n${formatProjectName(project)}\n`);
5574
5766
  if (config.include) this.console.error(c.dim("include: ") + c.yellow(config.include.join(comma)));
5575
5767
  if (config.exclude) this.console.error(c.dim("exclude: ") + c.yellow(config.exclude.join(comma)));
5576
- if (config.typecheck.enabled) {
5577
- this.console.error(c.dim("typecheck include: ") + c.yellow(config.typecheck.include.join(comma)));
5578
- this.console.error(c.dim("typecheck exclude: ") + c.yellow(config.typecheck.exclude.join(comma)));
5579
- }
5580
- });
5581
- this.console.error();
5768
+ if (config.typecheck.enabled) this.console.error(c.dim("typecheck include: ") + c.yellow(config.typecheck.include.join(comma))), this.console.error(c.dim("typecheck exclude: ") + c.yellow(config.typecheck.exclude.join(comma)));
5769
+ }), this.console.error();
5582
5770
  }
5583
5771
  printBanner() {
5584
5772
  this.log();
5585
- const color = this.ctx.config.watch ? "blue" : "cyan";
5586
- const mode = this.ctx.config.watch ? "DEV" : "RUN";
5587
- this.log(withLabel(color, mode, `v${this.ctx.version} `) + c.gray(this.ctx.config.root));
5588
- if (this.ctx.config.sequence.sequencer === RandomSequencer) this.log(PAD + c.gray(`Running tests with seed "${this.ctx.config.sequence.seed}"`));
5773
+ const color = this.ctx.config.watch ? "blue" : "cyan", mode = this.ctx.config.watch ? "DEV" : "RUN";
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}"`));
5589
5775
  if (this.ctx.config.ui) {
5590
- const host = this.ctx.config.api?.host || "localhost";
5591
- const port = this.ctx.server.config.server.port;
5592
- const base = this.ctx.config.uiBase;
5776
+ const host = this.ctx.config.api?.host || "localhost", port = this.ctx.server.config.server.port, base = this.ctx.config.uiBase;
5593
5777
  this.log(PAD + c.dim(c.green(`UI started at http://${host}:${c.bold(port)}${base}`)));
5594
5778
  } else if (this.ctx.config.api?.port) {
5595
- const resolvedUrls = this.ctx.server.resolvedUrls;
5596
- // workaround for https://github.com/vitejs/vite/issues/15438, it was fixed in vite 5.1
5597
- const fallbackUrl = `http://${this.ctx.config.api.host || "localhost"}:${this.ctx.config.api.port}`;
5598
- const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0] ?? fallbackUrl;
5779
+ 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;
5599
5780
  this.log(PAD + c.dim(c.green(`API started at ${new URL("/", origin)}`)));
5600
5781
  }
5601
5782
  if (this.ctx.coverageProvider) this.log(PAD + c.dim("Coverage enabled with ") + c.yellow(this.ctx.coverageProvider.name));
@@ -5604,35 +5785,26 @@ class Logger {
5604
5785
  }
5605
5786
  printBrowserBanner(project) {
5606
5787
  if (!project.browser) return;
5607
- const resolvedUrls = project.browser.vite.resolvedUrls;
5608
- const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
5788
+ const resolvedUrls = project.browser.vite.resolvedUrls, origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
5609
5789
  if (!origin) return;
5610
- const output = project.isRootProject() ? "" : formatProjectName(project);
5611
- const provider = project.browser.provider.name;
5612
- const providerString = provider === "preview" ? "" : ` by ${c.reset(c.bold(provider))}`;
5790
+ const output = project.isRootProject() ? "" : formatProjectName(project), provider = project.browser.provider.name, providerString = provider === "preview" ? "" : ` by ${c.reset(c.bold(provider))}`;
5613
5791
  this.log(c.dim(`${output}Browser runner started${providerString} ${c.dim("at")} ${c.blue(new URL("/__vitest_test__/", origin))}\n`));
5614
5792
  }
5615
5793
  printUnhandledErrors(errors) {
5616
5794
  const errorMessage = c.red(c.bold(`\nVitest caught ${errors.length} unhandled error${errors.length > 1 ? "s" : ""} during the test run.
5617
5795
  This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.`));
5618
- this.error(errorBanner("Unhandled Errors"));
5619
- this.error(errorMessage);
5620
- errors.forEach((err) => {
5796
+ this.error(errorBanner("Unhandled Errors")), this.error(errorMessage), errors.forEach((err) => {
5621
5797
  this.printError(err, {
5622
5798
  fullStack: true,
5623
5799
  type: err.type || "Unhandled Error"
5624
5800
  });
5625
- });
5626
- this.error(c.red(divider()));
5801
+ }), this.error(c.red(divider()));
5627
5802
  }
5628
5803
  printSourceTypeErrors(errors) {
5629
5804
  const errorMessage = c.red(c.bold(`\nVitest found ${errors.length} error${errors.length > 1 ? "s" : ""} not related to your test files.`));
5630
- this.log(errorBanner("Source Errors"));
5631
- this.log(errorMessage);
5632
- errors.forEach((err) => {
5805
+ this.log(errorBanner("Source Errors")), this.log(errorMessage), errors.forEach((err) => {
5633
5806
  this.printError(err, { fullStack: true });
5634
- });
5635
- this.log(c.red(divider()));
5807
+ }), this.log(c.red(divider()));
5636
5808
  }
5637
5809
  getColumns() {
5638
5810
  return "columns" in this.outputStream ? this.outputStream.columns : 80;
@@ -5642,38 +5814,25 @@ This might cause false positive tests. Resolve unhandled errors to make sure you
5642
5814
  }
5643
5815
  addCleanupListeners() {
5644
5816
  const cleanup = () => {
5645
- this.cleanupListeners.forEach((fn) => fn());
5646
- if (this.outputStream.isTTY) this.outputStream.write(SHOW_CURSOR);
5647
- };
5648
- const onExit = (signal, exitCode) => {
5649
- cleanup();
5817
+ if (this.cleanupListeners.forEach((fn) => fn()), this.outputStream.isTTY) this.outputStream.write(SHOW_CURSOR);
5818
+ }, onExit = (signal, exitCode) => {
5650
5819
  // Interrupted signals don't set exit code automatically.
5651
5820
  // Use same exit code as node: https://nodejs.org/api/process.html#signal-events
5652
- if (process.exitCode === void 0) process.exitCode = exitCode !== void 0 ? 128 + exitCode : Number(signal);
5821
+ if (cleanup(), process.exitCode === void 0) process.exitCode = exitCode !== void 0 ? 128 + exitCode : Number(signal);
5653
5822
  process.exit();
5654
5823
  };
5655
- process.once("SIGINT", onExit);
5656
- process.once("SIGTERM", onExit);
5657
- process.once("exit", onExit);
5658
- this.ctx.onClose(() => {
5659
- process.off("SIGINT", onExit);
5660
- process.off("SIGTERM", onExit);
5661
- process.off("exit", onExit);
5662
- cleanup();
5824
+ process.once("SIGINT", onExit), process.once("SIGTERM", onExit), process.once("exit", onExit), this.ctx.onClose(() => {
5825
+ process.off("SIGINT", onExit), process.off("SIGTERM", onExit), process.off("exit", onExit), cleanup();
5663
5826
  });
5664
5827
  }
5665
5828
  registerUnhandledRejection() {
5666
5829
  const onUnhandledRejection = (err) => {
5667
- process.exitCode = 1;
5668
- this.printError(err, {
5830
+ process.exitCode = 1, this.printError(err, {
5669
5831
  fullStack: true,
5670
5832
  type: "Unhandled Rejection"
5671
- });
5672
- this.error("\n\n");
5673
- process.exit();
5833
+ }), this.error("\n\n"), process.exit();
5674
5834
  };
5675
- process.on("unhandledRejection", onUnhandledRejection);
5676
- this.ctx.onClose(() => {
5835
+ process.on("unhandledRejection", onUnhandledRejection), this.ctx.onClose(() => {
5677
5836
  process.off("unhandledRejection", onUnhandledRejection);
5678
5837
  });
5679
5838
  }
@@ -5689,36 +5848,26 @@ class VitestPackageInstaller {
5689
5848
  if (process.versions.pnp) {
5690
5849
  const targetRequire = createRequire(__dirname);
5691
5850
  try {
5692
- targetRequire.resolve(dependency, { paths: [root, __dirname] });
5693
- return true;
5851
+ return targetRequire.resolve(dependency, { paths: [root, __dirname] }), true;
5694
5852
  } catch {}
5695
5853
  }
5696
5854
  if (/* @__PURE__ */ isPackageExists(dependency, { paths: [root, __dirname] })) return true;
5697
- process.stderr.write(c.red(`${c.inverse(c.red(" MISSING DEPENDENCY "))} Cannot find dependency '${dependency}'\n\n`));
5698
- if (!isTTY) return false;
5699
- const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; });
5700
- const { install } = await prompts.default({
5855
+ if (process.stderr.write(c.red(`${c.inverse(c.red(" MISSING DEPENDENCY "))} Cannot find dependency '${dependency}'\n\n`)), !isTTY) return false;
5856
+ const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; }), { install } = await prompts.default({
5701
5857
  type: "confirm",
5702
5858
  name: "install",
5703
5859
  message: c.reset(`Do you want to install ${c.green(dependency)}?`)
5704
5860
  });
5705
5861
  if (install) {
5706
5862
  const packageName = version ? `${dependency}@${version}` : dependency;
5707
- await (await import('./index.D3XRDfWc.js')).installPackage(packageName, { dev: true });
5708
- // TODO: somehow it fails to load the package after installation, remove this when it's fixed
5709
- process.stderr.write(c.yellow(`\nPackage ${packageName} installed, re-run the command to start.\n`));
5710
- process.exit();
5711
- return true;
5863
+ return await (await import('./index.D3XRDfWc.js')).installPackage(packageName, { dev: true }), process.stderr.write(c.yellow(`\nPackage ${packageName} installed, re-run the command to start.\n`)), process.exit(), true;
5712
5864
  }
5713
5865
  return false;
5714
5866
  }
5715
5867
  }
5716
5868
 
5717
5869
  function serializeConfig(config, coreConfig, viteConfig) {
5718
- const optimizer = config.deps?.optimizer || {};
5719
- const poolOptions = config.poolOptions;
5720
- // Resolve from server.config to avoid comparing against default value
5721
- const isolate = viteConfig?.test?.isolate;
5870
+ const optimizer = config.deps?.optimizer || {}, poolOptions = config.poolOptions, isolate = viteConfig?.test?.isolate;
5722
5871
  return {
5723
5872
  environmentOptions: config.environmentOptions,
5724
5873
  mode: config.mode,
@@ -5752,8 +5901,7 @@ function serializeConfig(config, coreConfig, viteConfig) {
5752
5901
  snapshotEnvironment: config.snapshotEnvironment,
5753
5902
  passWithNoTests: config.passWithNoTests,
5754
5903
  coverage: ((coverage) => {
5755
- const htmlReporter = coverage.reporter.find(([reporterName]) => reporterName === "html");
5756
- const subdir = htmlReporter && htmlReporter[1]?.subdir;
5904
+ const htmlReporter = coverage.reporter.find(([reporterName]) => reporterName === "html"), subdir = htmlReporter && htmlReporter[1]?.subdir;
5757
5905
  return {
5758
5906
  reportsDirectory: coverage.reportsDirectory,
5759
5907
  provider: coverage.provider,
@@ -5778,8 +5926,7 @@ function serializeConfig(config, coreConfig, viteConfig) {
5778
5926
  deps: {
5779
5927
  web: config.deps.web || {},
5780
5928
  optimizer: Object.entries(optimizer).reduce((acc, [name, option]) => {
5781
- acc[name] = { enabled: option?.enabled ?? false };
5782
- return acc;
5929
+ return acc[name] = { enabled: option?.enabled ?? false }, acc;
5783
5930
  }, {}),
5784
5931
  interopDefault: config.deps.interopDefault,
5785
5932
  moduleDirectories: config.deps.moduleDirectories
@@ -5816,7 +5963,8 @@ function serializeConfig(config, coreConfig, viteConfig) {
5816
5963
  viewport: browser.viewport,
5817
5964
  screenshotFailures: browser.screenshotFailures,
5818
5965
  locators: { testIdAttribute: browser.locators.testIdAttribute },
5819
- providerOptions: browser.provider === "playwright" ? { actionTimeout: browser.providerOptions?.context?.actionTimeout } : {}
5966
+ providerOptions: browser.provider === "playwright" ? { actionTimeout: browser.providerOptions?.context?.actionTimeout } : {},
5967
+ trackUnhandledErrors: browser.trackUnhandledErrors ?? true
5820
5968
  };
5821
5969
  })(config.browser),
5822
5970
  standalone: config.standalone,
@@ -5840,12 +5988,12 @@ async function loadGlobalSetupFile(file, runner) {
5840
5988
  file,
5841
5989
  setup: m.default
5842
5990
  };
5843
- else if (m.setup || m.teardown) return {
5991
+ if (m.setup || m.teardown) return {
5844
5992
  file,
5845
5993
  setup: m.setup,
5846
5994
  teardown: m.teardown
5847
5995
  };
5848
- else throw new Error(`invalid globalSetup file ${file}. Must export setup, teardown or have a default export`);
5996
+ throw new Error(`invalid globalSetup file ${file}. Must export setup, teardown or have a default export`);
5849
5997
  }
5850
5998
 
5851
5999
  function CoverageTransform(ctx) {
@@ -6350,12 +6498,10 @@ function MetaEnvReplacerPlugin() {
6350
6498
  transform(code, id) {
6351
6499
  if (!/\bimport\.meta\.env\b/.test(code)) return null;
6352
6500
  let s = null;
6353
- const cleanCode = stripLiteral(code);
6354
- const envs = cleanCode.matchAll(/\bimport\.meta\.env\b/g);
6501
+ const cleanCode = stripLiteral(code), envs = cleanCode.matchAll(/\bimport\.meta\.env\b/g);
6355
6502
  for (const env of envs) {
6356
6503
  s ||= new MagicString(code);
6357
- const startIndex = env.index;
6358
- const endIndex = startIndex + env[0].length;
6504
+ const startIndex = env.index, endIndex = startIndex + env[0].length;
6359
6505
  s.overwrite(startIndex, endIndex, `Object.assign(/* istanbul ignore next */ globalThis.__vitest_worker__?.metaEnv ?? import.meta.env)`);
6360
6506
  }
6361
6507
  if (s) return {
@@ -6373,9 +6519,7 @@ function MocksPlugins(options = {}) {
6373
6519
  const normalizedDistDir = normalize(distDir);
6374
6520
  return [hoistMocksPlugin({
6375
6521
  filter(id) {
6376
- if (id.includes(normalizedDistDir)) return false;
6377
- if (options.filter) return options.filter(id);
6378
- return true;
6522
+ return id.includes(normalizedDistDir) ? false : options.filter ? options.filter(id) : true;
6379
6523
  },
6380
6524
  codeFrameGenerator(node, id, code) {
6381
6525
  return generateCodeFrame(code, 4, node.start + 1);
@@ -6401,34 +6545,23 @@ const LogLevels = {
6401
6545
  info: 3
6402
6546
  };
6403
6547
  function clearScreen(logger) {
6404
- const repeatCount = process.stdout.rows - 2;
6405
- const blank = repeatCount > 0 ? "\n".repeat(repeatCount) : "";
6548
+ const repeatCount = process.stdout.rows - 2, blank = repeatCount > 0 ? "\n".repeat(repeatCount) : "";
6406
6549
  logger.clearScreen(blank);
6407
6550
  }
6408
- let lastType;
6409
- let lastMsg;
6410
- let sameCount = 0;
6411
- // Only initialize the timeFormatter when the timestamp option is used, and
6412
- // reuse it across all loggers
6413
- let timeFormatter;
6551
+ let lastType, lastMsg, sameCount = 0, timeFormatter;
6414
6552
  function getTimeFormatter() {
6415
- timeFormatter ??= new Intl.DateTimeFormat(void 0, {
6553
+ return timeFormatter ??= new Intl.DateTimeFormat(void 0, {
6416
6554
  hour: "numeric",
6417
6555
  minute: "numeric",
6418
6556
  second: "numeric"
6419
- });
6420
- return timeFormatter;
6557
+ }), timeFormatter;
6421
6558
  }
6422
6559
  // This is copy-pasted and needs to be synced from time to time. Ideally, Vite's `createLogger` should accept a custom `console`
6423
6560
  // https://github.com/vitejs/vite/blob/main/packages/vite/src/node/logger.ts?rgh-link-date=2024-10-16T23%3A29%3A19Z
6424
6561
  // When Vitest supports only Vite 6 and above, we can use Vite's `createLogger({ console })`
6425
6562
  // https://github.com/vitejs/vite/pull/18379
6426
6563
  function createViteLogger(console, level = "info", options = {}) {
6427
- const loggedErrors = /* @__PURE__ */ new WeakSet();
6428
- const { prefix = "[vite]", allowClearScreen = true } = options;
6429
- const thresh = LogLevels[level];
6430
- const canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI;
6431
- const clear = canClearScreen ? clearScreen : () => {};
6564
+ const loggedErrors = /* @__PURE__ */ new WeakSet(), { prefix = "[vite]", allowClearScreen = true } = options, thresh = LogLevels[level], canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI, clear = canClearScreen ? clearScreen : () => {};
6432
6565
  function format(type, msg, options = {}) {
6433
6566
  if (options.timestamp) {
6434
6567
  let tag = "";
@@ -6443,39 +6576,27 @@ function createViteLogger(console, level = "info", options = {}) {
6443
6576
  if (thresh >= LogLevels[type]) {
6444
6577
  const method = type === "info" ? "log" : type;
6445
6578
  if (options.error) loggedErrors.add(options.error);
6446
- if (canClearScreen) if (type === lastType && msg === lastMsg) {
6447
- sameCount++;
6448
- clear(console);
6449
- console[method](format(type, msg, options), c.yellow(`(x${sameCount + 1})`));
6450
- } else {
6451
- sameCount = 0;
6452
- lastMsg = msg;
6453
- lastType = type;
6454
- if (options.clear) clear(console);
6579
+ if (canClearScreen) if (type === lastType && msg === lastMsg) sameCount++, clear(console), console[method](format(type, msg, options), c.yellow(`(x${sameCount + 1})`));
6580
+ else {
6581
+ if (sameCount = 0, lastMsg = msg, lastType = type, options.clear) clear(console);
6455
6582
  console[method](format(type, msg, options));
6456
6583
  }
6457
6584
  else console[method](format(type, msg, options));
6458
6585
  }
6459
6586
  }
6460
- const warnedMessages = /* @__PURE__ */ new Set();
6461
- const logger = {
6587
+ const warnedMessages = /* @__PURE__ */ new Set(), logger = {
6462
6588
  hasWarned: false,
6463
6589
  info(msg, opts) {
6464
6590
  output("info", msg, opts);
6465
6591
  },
6466
6592
  warn(msg, opts) {
6467
- logger.hasWarned = true;
6468
- output("warn", msg, opts);
6593
+ logger.hasWarned = true, output("warn", msg, opts);
6469
6594
  },
6470
6595
  warnOnce(msg, opts) {
6471
- if (warnedMessages.has(msg)) return;
6472
- logger.hasWarned = true;
6473
- output("warn", msg, opts);
6474
- warnedMessages.add(msg);
6596
+ warnedMessages.has(msg) || (logger.hasWarned = true, output("warn", msg, opts), warnedMessages.add(msg));
6475
6597
  },
6476
6598
  error(msg, opts) {
6477
- logger.hasWarned = true;
6478
- output("error", msg, opts);
6599
+ logger.hasWarned = true, output("error", msg, opts);
6479
6600
  },
6480
6601
  clearScreen(type) {
6481
6602
  if (thresh >= LogLevels[type]) clear(console);
@@ -6491,16 +6612,12 @@ function silenceImportViteIgnoreWarning(logger) {
6491
6612
  return {
6492
6613
  ...logger,
6493
6614
  warn(msg, options) {
6494
- if (msg.includes("The above dynamic import cannot be analyzed by Vite")) return;
6495
- logger.warn(msg, options);
6615
+ msg.includes("The above dynamic import cannot be analyzed by Vite") || logger.warn(msg, options);
6496
6616
  }
6497
6617
  };
6498
6618
  }
6499
6619
 
6500
- const cssLangs = "\\.(?:css|less|sass|scss|styl|stylus|pcss|postcss)(?:$|\\?)";
6501
- const cssLangRE = new RegExp(cssLangs);
6502
- const cssModuleRE = /* @__PURE__ */ new RegExp(`\\.module${cssLangs}`);
6503
- const cssInlineRE = /[?&]inline(?:&|$)/;
6620
+ const cssLangs = "\\.(?:css|less|sass|scss|styl|stylus|pcss|postcss)(?:$|\\?)", cssLangRE = new RegExp(cssLangs), cssModuleRE = /* @__PURE__ */ new RegExp(`\\.module${cssLangs}`), cssInlineRE = /[?&]inline(?:&|$)/;
6504
6621
  function isCSS(id) {
6505
6622
  return cssLangRE.test(id);
6506
6623
  }
@@ -6520,45 +6637,37 @@ function getCSSModuleProxyReturn(strategy, filename) {
6520
6637
  function CSSEnablerPlugin(ctx) {
6521
6638
  const shouldProcessCSS = (id) => {
6522
6639
  const { css } = ctx.config;
6523
- if (typeof css === "boolean") return css;
6524
- if (toArray(css.exclude).some((re) => re.test(id))) return false;
6525
- if (toArray(css.include).some((re) => re.test(id))) return true;
6526
- return false;
6640
+ return typeof css === "boolean" ? css : toArray(css.exclude).some((re) => re.test(id)) ? false : !!toArray(css.include).some((re) => re.test(id));
6527
6641
  };
6528
6642
  return [{
6529
6643
  name: "vitest:css-disable",
6530
6644
  enforce: "pre",
6531
6645
  transform(code, id) {
6532
- if (!isCSS(id)) return;
6533
- // css plugin inside Vite won't do anything if the code is empty
6534
- // but it will put __vite__updateStyle anyway
6535
- if (!shouldProcessCSS(id)) return { code: "" };
6646
+ if (isCSS(id) && !shouldProcessCSS(id)) return { code: "" };
6536
6647
  }
6537
6648
  }, {
6538
6649
  name: "vitest:css-empty-post",
6539
6650
  enforce: "post",
6540
6651
  transform(_, id) {
6541
- if (!isCSS(id) || shouldProcessCSS(id)) return;
6542
- if (isCSSModule(id) && !isInline(id)) {
6543
- // return proxy for css modules, so that imported module has names:
6544
- // styles.foo returns a "foo" instead of "undefined"
6545
- // we don't use code content to generate hash for "scoped", because it's empty
6546
- const scopeStrategy = typeof ctx.config.css !== "boolean" && ctx.config.css.modules?.classNameStrategy || "stable";
6547
- const proxyReturn = getCSSModuleProxyReturn(scopeStrategy, relative(ctx.config.root, id));
6548
- const code = `export default new Proxy(Object.create(null), {
6652
+ if (!(!isCSS(id) || shouldProcessCSS(id))) {
6653
+ if (isCSSModule(id) && !isInline(id)) {
6654
+ // return proxy for css modules, so that imported module has names:
6655
+ // styles.foo returns a "foo" instead of "undefined"
6656
+ // we don't use code content to generate hash for "scoped", because it's empty
6657
+ const scopeStrategy = typeof ctx.config.css !== "boolean" && ctx.config.css.modules?.classNameStrategy || "stable", proxyReturn = getCSSModuleProxyReturn(scopeStrategy, relative(ctx.config.root, id)), code = `export default new Proxy(Object.create(null), {
6549
6658
  get(_, style) {
6550
6659
  return ${proxyReturn};
6551
6660
  },
6552
6661
  })`;
6553
- return { code };
6662
+ return { code };
6663
+ }
6664
+ return { code: "export default \"\"" };
6554
6665
  }
6555
- return { code: "export default \"\"" };
6556
6666
  }
6557
6667
  }];
6558
6668
  }
6559
6669
 
6560
- const metaUrlLength = 15;
6561
- const locationString = "self.location".padEnd(metaUrlLength, " ");
6670
+ const metaUrlLength = 15, locationString = "self.location".padEnd(metaUrlLength, " ");
6562
6671
  // Vite transforms new URL('./path', import.meta.url) to new URL('/path.js', import.meta.url)
6563
6672
  // This makes "href" equal to "http://localhost:3000/path.js" in the browser, but if we keep it like this,
6564
6673
  // then in tests the URL will become "file:///path.js".
@@ -6569,14 +6678,11 @@ function NormalizeURLPlugin() {
6569
6678
  enforce: "post",
6570
6679
  transform(code) {
6571
6680
  if (this.environment.name !== "client" || !code.includes("new URL") || !code.includes("import.meta.url")) return;
6572
- const cleanString = stripLiteral(code);
6573
- const assetImportMetaUrlRE = /\bnew\s+URL\s*\(\s*(?:'[^']+'|"[^"]+"|`[^`]+`)\s*,\s*(?:'' \+ )?import\.meta\.url\s*(?:,\s*)?\)/g;
6574
- let updatedCode = code;
6575
- let match;
6681
+ const cleanString = stripLiteral(code), assetImportMetaUrlRE = /\bnew\s+URL\s*\(\s*(?:'[^']+'|"[^"]+"|`[^`]+`)\s*,\s*(?:'' \+ )?import\.meta\.url\s*(?:,\s*)?\)/g;
6682
+ let updatedCode = code, match;
6576
6683
  // eslint-disable-next-line no-cond-assign
6577
6684
  while (match = assetImportMetaUrlRE.exec(cleanString)) {
6578
- const { 0: exp, index } = match;
6579
- const metaUrlIndex = index + exp.indexOf("import.meta.url");
6685
+ const { 0: exp, index } = match, metaUrlIndex = index + exp.indexOf("import.meta.url");
6580
6686
  updatedCode = updatedCode.slice(0, metaUrlIndex) + locationString + updatedCode.slice(metaUrlIndex + metaUrlLength);
6581
6687
  }
6582
6688
  return {
@@ -6593,10 +6699,7 @@ function VitestOptimizer() {
6593
6699
  config: {
6594
6700
  order: "post",
6595
6701
  handler(viteConfig) {
6596
- const testConfig = viteConfig.test || {};
6597
- const root = resolve(viteConfig.root || process.cwd());
6598
- const name = viteConfig.test?.name;
6599
- const label = typeof name === "string" ? name : name?.label || "";
6702
+ const testConfig = viteConfig.test || {}, root = resolve(viteConfig.root || process.cwd()), name = viteConfig.test?.name, label = typeof name === "string" ? name : name?.label || "";
6600
6703
  viteConfig.cacheDir = VitestCache.resolveCacheDir(resolve(root || process.cwd()), testConfig.cache != null && testConfig.cache !== false ? testConfig.cache.dir : viteConfig.cacheDir, label);
6601
6704
  }
6602
6705
  }
@@ -6606,21 +6709,17 @@ function VitestOptimizer() {
6606
6709
  function resolveOptimizerConfig(_testOptions, viteOptions) {
6607
6710
  const testOptions = _testOptions || {};
6608
6711
  let optimizeDeps;
6609
- if (testOptions.enabled !== true) {
6610
- testOptions.enabled ??= false;
6611
- optimizeDeps = {
6612
- disabled: true,
6613
- entries: []
6614
- };
6615
- } else {
6616
- const currentInclude = testOptions.include || viteOptions?.include || [];
6617
- const exclude = [
6712
+ if (testOptions.enabled !== true) testOptions.enabled ??= false, optimizeDeps = {
6713
+ disabled: true,
6714
+ entries: []
6715
+ };
6716
+ else {
6717
+ const currentInclude = testOptions.include || viteOptions?.include || [], exclude = [
6618
6718
  "vitest",
6619
6719
  "react",
6620
6720
  "vue",
6621
6721
  ...testOptions.exclude || viteOptions?.exclude || []
6622
- ];
6623
- const runtime = currentInclude.filter((n) => n.endsWith("jsx-dev-runtime") || n.endsWith("jsx-runtime"));
6722
+ ], runtime = currentInclude.filter((n) => n.endsWith("jsx-dev-runtime") || n.endsWith("jsx-runtime"));
6624
6723
  exclude.push(...runtime);
6625
6724
  const include = (testOptions.include || viteOptions?.include || []).filter((n) => !exclude.includes(n));
6626
6725
  optimizeDeps = {
@@ -6635,21 +6734,12 @@ function resolveOptimizerConfig(_testOptions, viteOptions) {
6635
6734
  }
6636
6735
  // `optimizeDeps.disabled` is deprecated since v5.1.0-beta.1
6637
6736
  // https://github.com/vitejs/vite/pull/15184
6638
- if (optimizeDeps.disabled) {
6639
- optimizeDeps.noDiscovery = true;
6640
- optimizeDeps.include = [];
6641
- }
6642
- delete optimizeDeps.disabled;
6643
- return optimizeDeps;
6737
+ if (optimizeDeps.disabled) optimizeDeps.noDiscovery = true, optimizeDeps.include = [];
6738
+ return delete optimizeDeps.disabled, optimizeDeps;
6644
6739
  }
6645
6740
  function deleteDefineConfig(viteConfig) {
6646
6741
  const defines = {};
6647
- if (viteConfig.define) {
6648
- delete viteConfig.define["import.meta.vitest"];
6649
- delete viteConfig.define["process.env"];
6650
- delete viteConfig.define.process;
6651
- delete viteConfig.define.global;
6652
- }
6742
+ if (viteConfig.define) delete viteConfig.define["import.meta.vitest"], delete viteConfig.define["process.env"], delete viteConfig.define.process, delete viteConfig.define.global;
6653
6743
  for (const key in viteConfig.define) {
6654
6744
  const val = viteConfig.define[key];
6655
6745
  let replacement;
@@ -6662,26 +6752,20 @@ function deleteDefineConfig(viteConfig) {
6662
6752
  }
6663
6753
  if (key.startsWith("import.meta.env.")) {
6664
6754
  const envKey = key.slice(16);
6665
- process.env[envKey] = replacement;
6666
- delete viteConfig.define[key];
6755
+ process.env[envKey] = replacement, delete viteConfig.define[key];
6667
6756
  } else if (key.startsWith("process.env.")) {
6668
6757
  const envKey = key.slice(12);
6669
- process.env[envKey] = replacement;
6670
- delete viteConfig.define[key];
6671
- } else if (!key.includes(".")) {
6672
- defines[key] = replacement;
6673
- delete viteConfig.define[key];
6674
- }
6758
+ process.env[envKey] = replacement, delete viteConfig.define[key];
6759
+ } else if (!key.includes(".")) defines[key] = replacement, delete viteConfig.define[key];
6675
6760
  }
6676
6761
  return defines;
6677
6762
  }
6678
6763
  function resolveFsAllow(projectRoot, rootConfigFile) {
6679
- if (!rootConfigFile) return [searchForWorkspaceRoot(projectRoot), rootDir];
6680
- return [
6764
+ return rootConfigFile ? [
6681
6765
  dirname(rootConfigFile),
6682
6766
  searchForWorkspaceRoot(projectRoot),
6683
6767
  rootDir
6684
- ];
6768
+ ] : [searchForWorkspaceRoot(projectRoot), rootDir];
6685
6769
  }
6686
6770
  function getDefaultResolveOptions() {
6687
6771
  return {
@@ -6708,78 +6792,44 @@ function ModuleRunnerTransform() {
6708
6792
  const testConfig = config.test || {};
6709
6793
  config.environments ??= {};
6710
6794
  const names = new Set(Object.keys(config.environments));
6711
- names.add("client");
6712
- names.add("ssr");
6795
+ names.add("client"), names.add("ssr");
6713
6796
  const pool = config.test?.pool;
6714
6797
  if (pool === "vmForks" || pool === "vmThreads") names.add("__vitest_vm__");
6715
- const external = [];
6716
- const noExternal = [];
6798
+ const external = [], noExternal = [];
6717
6799
  let noExternalAll;
6718
6800
  for (const name of names) {
6719
6801
  config.environments[name] ??= {};
6720
6802
  const environment = config.environments[name];
6721
- environment.dev ??= {};
6722
6803
  // vm tests run using the native import mechanism
6723
- if (name === "__vitest_vm__") {
6724
- environment.dev.moduleRunnerTransform = false;
6725
- environment.consumer = "client";
6726
- } else environment.dev.moduleRunnerTransform = true;
6727
- environment.dev.preTransformRequests = false;
6728
- environment.keepProcessEnv = true;
6729
- const resolveExternal = name === "client" ? config.resolve?.external : [];
6730
- const resolveNoExternal = name === "client" ? config.resolve?.noExternal : [];
6731
- const topLevelResolveOptions = {};
6804
+ if (environment.dev ??= {}, name === "__vitest_vm__") environment.dev.moduleRunnerTransform = false, environment.consumer = "client";
6805
+ else environment.dev.moduleRunnerTransform = true;
6806
+ environment.dev.preTransformRequests = false, environment.keepProcessEnv = true;
6807
+ const resolveExternal = name === "client" ? config.resolve?.external : [], resolveNoExternal = name === "client" ? config.resolve?.noExternal : [], topLevelResolveOptions = {};
6732
6808
  if (resolveExternal != null) topLevelResolveOptions.external = resolveExternal;
6733
6809
  if (resolveNoExternal != null) topLevelResolveOptions.noExternal = resolveNoExternal;
6734
- const currentResolveOptions = mergeConfig(topLevelResolveOptions, environment.resolve || {});
6735
- const envNoExternal = resolveViteResolveOptions("noExternal", currentResolveOptions);
6810
+ const currentResolveOptions = mergeConfig(topLevelResolveOptions, environment.resolve || {}), envNoExternal = resolveViteResolveOptions("noExternal", currentResolveOptions);
6736
6811
  if (envNoExternal === true) noExternalAll = true;
6737
6812
  else noExternal.push(...envNoExternal);
6738
6813
  const envExternal = resolveViteResolveOptions("external", currentResolveOptions);
6739
6814
  if (envExternal !== true) external.push(...envExternal);
6740
- // remove Vite's externalization logic because we have our own (unfortunetly)
6741
- environment.resolve ??= {};
6742
- environment.resolve.external = [...builtinModules, ...builtinModules.map((m) => `node:${m}`)];
6743
- // by setting `noExternal` to `true`, we make sure that
6744
- // Vite will never use its own externalization mechanism
6745
- // to externalize modules and always resolve static imports
6746
- // in both SSR and Client environments
6747
- environment.resolve.noExternal = true;
6748
- if (name === "__vitest_vm__" || name === "__vitest__") continue;
6749
- const currentOptimizeDeps = environment.optimizeDeps || (name === "client" ? config.optimizeDeps : name === "ssr" ? config.ssr?.optimizeDeps : void 0);
6750
- const optimizeDeps = resolveOptimizerConfig(testConfig.deps?.optimizer?.[name], currentOptimizeDeps);
6815
+ if (environment.resolve ??= {}, environment.resolve.external = [...builtinModules, ...builtinModules.map((m) => `node:${m}`)], environment.resolve.noExternal = true, name === "__vitest_vm__" || name === "__vitest__") continue;
6816
+ const currentOptimizeDeps = environment.optimizeDeps || (name === "client" ? config.optimizeDeps : name === "ssr" ? config.ssr?.optimizeDeps : void 0), optimizeDeps = resolveOptimizerConfig(testConfig.deps?.optimizer?.[name], currentOptimizeDeps);
6751
6817
  // Vite respects the root level optimize deps, so we override it instead
6752
- if (name === "client") {
6753
- config.optimizeDeps = optimizeDeps;
6754
- environment.optimizeDeps = void 0;
6755
- } else if (name === "ssr") {
6756
- config.ssr ??= {};
6757
- config.ssr.optimizeDeps = optimizeDeps;
6758
- environment.optimizeDeps = void 0;
6759
- } else environment.optimizeDeps = optimizeDeps;
6818
+ if (name === "client") config.optimizeDeps = optimizeDeps, environment.optimizeDeps = void 0;
6819
+ else if (name === "ssr") config.ssr ??= {}, config.ssr.optimizeDeps = optimizeDeps, environment.optimizeDeps = void 0;
6820
+ else environment.optimizeDeps = optimizeDeps;
6760
6821
  }
6761
- testConfig.server ??= {};
6762
- testConfig.server.deps ??= {};
6763
- if (testConfig.server.deps.inline !== true) {
6822
+ if (testConfig.server ??= {}, testConfig.server.deps ??= {}, testConfig.server.deps.inline !== true) {
6764
6823
  if (noExternalAll) testConfig.server.deps.inline = true;
6765
- else if (noExternal.length) {
6766
- testConfig.server.deps.inline ??= [];
6767
- testConfig.server.deps.inline.push(...noExternal);
6768
- }
6769
- }
6770
- if (external.length) {
6771
- testConfig.server.deps.external ??= [];
6772
- testConfig.server.deps.external.push(...external);
6824
+ else if (noExternal.length) testConfig.server.deps.inline ??= [], testConfig.server.deps.inline.push(...noExternal);
6773
6825
  }
6826
+ if (external.length) testConfig.server.deps.external ??= [], testConfig.server.deps.external.push(...external);
6774
6827
  }
6775
6828
  }
6776
6829
  };
6777
6830
  }
6778
6831
  function resolveViteResolveOptions(key, options) {
6779
- if (Array.isArray(options[key])) return options[key];
6780
- else if (typeof options[key] === "string" || options[key] instanceof RegExp) return [options[key]];
6781
- else if (typeof options[key] === "boolean") return true;
6782
- return [];
6832
+ return Array.isArray(options[key]) ? options[key] : typeof options[key] === "string" || options[key] instanceof RegExp ? [options[key]] : typeof options[key] === "boolean" ? true : [];
6783
6833
  }
6784
6834
 
6785
6835
  function VitestProjectResolver(ctx) {
@@ -6826,23 +6876,16 @@ function WorkspaceVitestPlugin(project, options) {
6826
6876
  };
6827
6877
  if (!name) if (typeof options.workspacePath === "string") {
6828
6878
  // if there is a package.json, read the name from it
6829
- const dir = options.workspacePath.endsWith("/") ? options.workspacePath.slice(0, -1) : dirname(options.workspacePath);
6830
- const pkgJsonPath = resolve(dir, "package.json");
6879
+ const dir = options.workspacePath.endsWith("/") ? options.workspacePath.slice(0, -1) : dirname(options.workspacePath), pkgJsonPath = resolve(dir, "package.json");
6831
6880
  if (existsSync(pkgJsonPath)) name = JSON.parse(readFileSync(pkgJsonPath, "utf-8")).name;
6832
6881
  if (typeof name !== "string" || !name) name = basename(dir);
6833
6882
  } else name = options.workspacePath.toString();
6834
- const isUserBrowserEnabled = viteConfig.test?.browser?.enabled;
6835
- const isBrowserEnabled = isUserBrowserEnabled ?? (viteConfig.test?.browser && project.vitest._cliOptions.browser?.enabled);
6836
- // keep project names to potentially filter it out
6837
- const workspaceNames = [name];
6838
- const browser = viteConfig.test.browser || {};
6883
+ const isUserBrowserEnabled = viteConfig.test?.browser?.enabled, isBrowserEnabled = isUserBrowserEnabled ?? (viteConfig.test?.browser && project.vitest._cliOptions.browser?.enabled), workspaceNames = [name], browser = viteConfig.test.browser || {};
6839
6884
  if (isBrowserEnabled && browser.name && !browser.instances?.length)
6840
6885
  // vitest injects `instances` in this case later on
6841
6886
  workspaceNames.push(name ? `${name} (${browser.name})` : browser.name);
6842
6887
  viteConfig.test?.browser?.instances?.forEach((instance) => {
6843
- // every instance is a potential project
6844
- instance.name ??= name ? `${name} (${instance.browser})` : instance.browser;
6845
- if (isBrowserEnabled) workspaceNames.push(instance.name);
6888
+ if (instance.name ??= name ? `${name} (${instance.browser})` : instance.browser, isBrowserEnabled) workspaceNames.push(instance.name);
6846
6889
  });
6847
6890
  const filters = project.vitest.config.project;
6848
6891
  // if there is `--project=...` filter, check if any of the potential projects match
@@ -6870,22 +6913,14 @@ function WorkspaceVitestPlugin(project, options) {
6870
6913
  this.meta.watchMode = false;
6871
6914
  },
6872
6915
  config(viteConfig) {
6873
- const defines = deleteDefineConfig(viteConfig);
6874
- const testConfig = viteConfig.test || {};
6875
- const root = testConfig.root || viteConfig.root || options.root;
6876
- const resolveOptions = getDefaultResolveOptions();
6877
- const config = {
6916
+ const defines = deleteDefineConfig(viteConfig), testConfig = viteConfig.test || {}, root = testConfig.root || viteConfig.root || options.root, resolveOptions = getDefaultResolveOptions();
6917
+ let config = {
6878
6918
  root,
6879
6919
  define: { "process.env.NODE_ENV": "process.env.NODE_ENV" },
6880
6920
  resolve: {
6881
6921
  ...resolveOptions,
6882
6922
  alias: testConfig.alias
6883
6923
  },
6884
- esbuild: viteConfig.esbuild === false ? false : {
6885
- target: viteConfig.esbuild?.target || "node18",
6886
- sourcemap: "external",
6887
- legalComments: "inline"
6888
- },
6889
6924
  server: {
6890
6925
  watch: null,
6891
6926
  open: false,
@@ -6898,19 +6933,27 @@ function WorkspaceVitestPlugin(project, options) {
6898
6933
  environments: { ssr: { resolve: resolveOptions } },
6899
6934
  test: {}
6900
6935
  };
6936
+ if ("rolldownVersion" in vite) config = {
6937
+ ...config,
6938
+ oxc: viteConfig.oxc === false ? false : { target: viteConfig.oxc?.target || "node18" }
6939
+ };
6940
+ else config = {
6941
+ ...config,
6942
+ esbuild: viteConfig.esbuild === false ? false : {
6943
+ target: viteConfig.esbuild?.target || "node18",
6944
+ sourcemap: "external",
6945
+ legalComments: "inline"
6946
+ }
6947
+ };
6901
6948
  config.test.defines = defines;
6902
6949
  const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
6903
6950
  if (classNameStrategy !== "scoped") {
6904
- config.css ??= {};
6905
- config.css.modules ??= {};
6906
- if (config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
6951
+ if (config.css ??= {}, config.css.modules ??= {}, config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
6907
6952
  const root = project.config.root;
6908
6953
  return generateScopedClassName(classNameStrategy, name, relative(root, filename));
6909
6954
  };
6910
6955
  }
6911
- config.customLogger = createViteLogger(project.vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false });
6912
- config.customLogger = silenceImportViteIgnoreWarning(config.customLogger);
6913
- return config;
6956
+ return config.customLogger = createViteLogger(project.vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false }), config.customLogger = silenceImportViteIgnoreWarning(config.customLogger), config;
6914
6957
  }
6915
6958
  },
6916
6959
  {
@@ -6918,8 +6961,7 @@ function WorkspaceVitestPlugin(project, options) {
6918
6961
  enforce: "post",
6919
6962
  async configureServer(server) {
6920
6963
  const options = deepMerge({}, configDefaults, server.config.test || {});
6921
- await project._configureServer(options, server);
6922
- await server.watcher.close();
6964
+ await project._configureServer(options, server), await server.watcher.close();
6923
6965
  }
6924
6966
  },
6925
6967
  MetaEnvReplacerPlugin(),
@@ -6962,10 +7004,7 @@ const BUILTIN_EXTENSIONS = new Set([
6962
7004
  ".cjs",
6963
7005
  ".node",
6964
7006
  ".wasm"
6965
- ]);
6966
- const ESM_EXT_RE = /\.(es|esm|esm-browser|esm-bundler|es6|module)\.js$/;
6967
- const ESM_FOLDER_RE = /\/(es|esm)\/(.*\.js)$/;
6968
- const defaultInline = [
7007
+ ]), ESM_EXT_RE = /\.(es|esm|esm-browser|esm-bundler|es6|module)\.js$/, ESM_FOLDER_RE = /\/(es|esm)\/(.*\.js)$/, defaultInline = [
6969
7008
  /virtual:/,
6970
7009
  /\.[mc]?ts$/,
6971
7010
  /[?&](init|raw|url|inline)\b/,
@@ -6973,8 +7012,7 @@ const defaultInline = [
6973
7012
  /^(?!.*node_modules).*\.mjs$/,
6974
7013
  /^(?!.*node_modules).*\.cjs\.js$/,
6975
7014
  /vite\w*\/dist\/client\/env.mjs/
6976
- ];
6977
- const depsExternal = [/\/node_modules\/.*\.cjs\.js$/, /\/node_modules\/.*\.mjs$/];
7015
+ ], depsExternal = [/\/node_modules\/.*\.cjs\.js$/, /\/node_modules\/.*\.mjs$/];
6978
7016
  function guessCJSversion(id) {
6979
7017
  if (id.match(ESM_EXT_RE)) {
6980
7018
  for (const i of [
@@ -7004,8 +7042,7 @@ async function isValidNodeImport(id) {
7004
7042
  if (/\.(?:\w+-)?esm?(?:-\w+)?\.js$|\/esm?\//.test(id)) return false;
7005
7043
  try {
7006
7044
  await esModuleLexer.init;
7007
- const code = await promises.readFile(id, "utf8");
7008
- const [, , , hasModuleSyntax] = esModuleLexer.parse(code);
7045
+ const code = await promises.readFile(id, "utf8"), [, , , hasModuleSyntax] = esModuleLexer.parse(code);
7009
7046
  return !hasModuleSyntax;
7010
7047
  } catch {
7011
7048
  return false;
@@ -7016,25 +7053,17 @@ async function shouldExternalize(id, options, cache) {
7016
7053
  return cache.get(id);
7017
7054
  }
7018
7055
  async function _shouldExternalize(id, options) {
7019
- if (isBuiltin(id)) return id;
7020
7056
  // data: should be processed by native import,
7021
7057
  // since it is a feature of ESM.
7022
7058
  // also externalize network imports since nodejs allows it when --experimental-network-imports
7023
- if (id.startsWith("data:") || /^(?:https?:)?\/\//.test(id)) return id;
7059
+ if (isBuiltin(id) || id.startsWith("data:") || /^(?:https?:)?\/\//.test(id)) return id;
7024
7060
  const moduleDirectories = options?.moduleDirectories || ["/node_modules/"];
7025
- if (matchExternalizePattern(id, moduleDirectories, options?.inline)) return false;
7026
- if (options?.inlineFiles && options?.inlineFiles.includes(id)) return false;
7027
- if (matchExternalizePattern(id, moduleDirectories, options?.external)) return id;
7061
+ if (matchExternalizePattern(id, moduleDirectories, options?.inline) || options?.inlineFiles && options?.inlineFiles.includes(id)) return false;
7028
7062
  // Unless the user explicitly opted to inline them, externalize Vite deps.
7029
7063
  // They are too big to inline by default.
7030
- if (options?.cacheDir && id.includes(options.cacheDir)) return id;
7031
- const isLibraryModule = moduleDirectories.some((dir) => id.includes(dir));
7032
- const guessCJS = isLibraryModule && options?.fallbackCJS;
7033
- id = guessCJS ? guessCJSversion(id) || id : id;
7034
- if (matchExternalizePattern(id, moduleDirectories, defaultInline)) return false;
7035
- if (matchExternalizePattern(id, moduleDirectories, depsExternal)) return id;
7036
- if (isLibraryModule && await isValidNodeImport(id)) return id;
7037
- return false;
7064
+ if (matchExternalizePattern(id, moduleDirectories, options?.external) || options?.cacheDir && id.includes(options.cacheDir)) return id;
7065
+ const isLibraryModule = moduleDirectories.some((dir) => id.includes(dir)), guessCJS = isLibraryModule && options?.fallbackCJS;
7066
+ return id = guessCJS ? guessCJSversion(id) || id : id, matchExternalizePattern(id, moduleDirectories, defaultInline) ? false : matchExternalizePattern(id, moduleDirectories, depsExternal) || isLibraryModule && await isValidNodeImport(id) ? id : false;
7038
7067
  }
7039
7068
  function matchExternalizePattern(id, moduleDirectories, patterns) {
7040
7069
  if (patterns == null) return false;
@@ -7080,24 +7109,16 @@ class TestSpecification {
7080
7109
  */
7081
7110
  testLines;
7082
7111
  constructor(project, moduleId, pool, testLines) {
7083
- this[0] = project;
7084
- this[1] = moduleId;
7085
- this[2] = { pool };
7086
- const name = project.config.name;
7087
- const hashName = pool !== "typescript" ? name : name ? `${name}:__typecheck__` : "__typecheck__";
7088
- this.taskId = generateFileHash(relative(project.config.root, moduleId), hashName);
7089
- this.project = project;
7090
- this.moduleId = moduleId;
7091
- this.pool = pool;
7092
- this.testLines = testLines;
7112
+ this[0] = project, this[1] = moduleId, this[2] = { pool };
7113
+ const name = project.config.name, hashName = pool !== "typescript" ? name : name ? `${name}:__typecheck__` : "__typecheck__";
7114
+ this.taskId = generateFileHash(relative(project.config.root, moduleId), hashName), this.project = project, this.moduleId = moduleId, this.pool = pool, this.testLines = testLines;
7093
7115
  }
7094
7116
  /**
7095
7117
  * Test module associated with the specification.
7096
7118
  */
7097
7119
  get testModule() {
7098
7120
  const task = this.project.vitest.state.idMap.get(this.taskId);
7099
- if (!task) return void 0;
7100
- return this.project.vitest.state.getReportedEntity(task);
7121
+ return task ? this.project.vitest.state.getReportedEntity(task) : void 0;
7101
7122
  }
7102
7123
  toJSON() {
7103
7124
  return [
@@ -7117,9 +7138,7 @@ class TestSpecification {
7117
7138
  * @deprecated
7118
7139
  */
7119
7140
  *[Symbol.iterator]() {
7120
- yield this.project;
7121
- yield this.moduleId;
7122
- yield this.pool;
7141
+ yield this.project, yield this.moduleId, yield this.pool;
7123
7142
  }
7124
7143
  }
7125
7144
 
@@ -7128,12 +7147,10 @@ async function createViteServer(inlineConfig) {
7128
7147
  // But Vitest works correctly either way
7129
7148
  const error = console.error;
7130
7149
  console.error = (...args) => {
7131
- if (typeof args[0] === "string" && args[0].includes("WebSocket server error:")) return;
7132
- error(...args);
7150
+ typeof args[0] === "string" && args[0].includes("WebSocket server error:") || error(...args);
7133
7151
  };
7134
7152
  const server = await createServer(inlineConfig);
7135
- console.error = error;
7136
- return server;
7153
+ return console.error = error, server;
7137
7154
  }
7138
7155
 
7139
7156
  class TestProject {
@@ -7161,18 +7178,14 @@ class TestProject {
7161
7178
  /** @internal */ _vite;
7162
7179
  /** @internal */ _hash;
7163
7180
  /** @internal */ _resolver;
7181
+ /** @inetrnal */ testFilesList = null;
7164
7182
  runner;
7165
7183
  closingPromise;
7166
- testFilesList = null;
7167
7184
  typecheckFilesList = null;
7168
7185
  _globalSetups;
7169
7186
  _provided = {};
7170
7187
  constructor(path, vitest, options) {
7171
- this.path = path;
7172
- this.options = options;
7173
- this.vitest = vitest;
7174
- this.ctx = vitest;
7175
- this.globalConfig = vitest.config;
7188
+ this.path = path, this.options = options, this.vitest = vitest, this.ctx = vitest, this.globalConfig = vitest.config;
7176
7189
  }
7177
7190
  /**
7178
7191
  * The unique hash of this project. This value is consistent between the reruns.
@@ -7201,10 +7214,9 @@ class TestProject {
7201
7214
  * Get the provided context. The project context is merged with the global context.
7202
7215
  */
7203
7216
  getProvidedContext() {
7204
- if (this.isRootProject()) return this._provided;
7205
7217
  // globalSetup can run even if core workspace is not part of the test run
7206
7218
  // so we need to inherit its provided context
7207
- return {
7219
+ return this.isRootProject() ? this._provided : {
7208
7220
  ...this.vitest.getRootProject().getProvidedContext(),
7209
7221
  ...this._provided
7210
7222
  };
@@ -7228,13 +7240,11 @@ class TestProject {
7228
7240
  */
7229
7241
  get vite() {
7230
7242
  if (!this._vite) throw new Error("The server was not set. It means that `project.vite` was called before the Vite server was established.");
7231
- // checking it once should be enough
7232
- Object.defineProperty(this, "vite", {
7243
+ return Object.defineProperty(this, "vite", {
7233
7244
  configurable: true,
7234
7245
  writable: true,
7235
7246
  value: this._vite
7236
- });
7237
- return this._vite;
7247
+ }), this._vite;
7238
7248
  }
7239
7249
  /**
7240
7250
  * Resolved project configuration.
@@ -7291,13 +7301,14 @@ class TestProject {
7291
7301
  }
7292
7302
  /** @internal */
7293
7303
  async _initializeGlobalSetup() {
7294
- if (this._globalSetups) return;
7295
- this._globalSetups = await loadGlobalSetupFiles(this.runner, this.config.globalSetup);
7296
- for (const globalSetupFile of this._globalSetups) {
7297
- const teardown = await globalSetupFile.setup?.(this);
7298
- if (teardown == null || !!globalSetupFile.teardown) continue;
7299
- if (typeof teardown !== "function") throw new TypeError(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`);
7300
- globalSetupFile.teardown = teardown;
7304
+ if (!this._globalSetups) {
7305
+ this._globalSetups = await loadGlobalSetupFiles(this.runner, this.config.globalSetup);
7306
+ for (const globalSetupFile of this._globalSetups) {
7307
+ const teardown = await globalSetupFile.setup?.(this);
7308
+ if (teardown == null || !!globalSetupFile.teardown) continue;
7309
+ if (typeof teardown !== "function") throw new TypeError(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`);
7310
+ globalSetupFile.teardown = teardown;
7311
+ }
7301
7312
  }
7302
7313
  }
7303
7314
  onTestsRerun(cb) {
@@ -7309,8 +7320,7 @@ class TestProject {
7309
7320
  }
7310
7321
  /** @internal */
7311
7322
  async _teardownGlobalSetup() {
7312
- if (!this._globalSetups) return;
7313
- for (const globalSetupFile of [...this._globalSetups].reverse()) await globalSetupFile.teardown?.();
7323
+ if (this._globalSetups) for (const globalSetupFile of [...this._globalSetups].reverse()) await globalSetupFile.teardown?.();
7314
7324
  }
7315
7325
  /** @deprecated use `vitest.logger` instead */
7316
7326
  get logger() {
@@ -7340,12 +7350,8 @@ class TestProject {
7340
7350
  * @param filters String filters to match the test files.
7341
7351
  */
7342
7352
  async globTestFiles(filters = []) {
7343
- const dir = this.config.dir || this.config.root;
7344
- const { include, exclude, includeSource } = this.config;
7345
- const typecheck = this.config.typecheck;
7346
- const [testFiles, typecheckTestFiles] = await Promise.all([typecheck.enabled && typecheck.only ? [] : this.globAllTestFiles(include, exclude, includeSource, dir), typecheck.enabled ? this.typecheckFilesList || this.globFiles(typecheck.include, typecheck.exclude, dir) : []]);
7347
- this.typecheckFilesList = typecheckTestFiles;
7348
- return {
7353
+ const dir = this.config.dir || this.config.root, { include, exclude, includeSource } = this.config, typecheck = this.config.typecheck, [testFiles, typecheckTestFiles] = await Promise.all([typecheck.enabled && typecheck.only ? [] : this.globAllTestFiles(include, exclude, includeSource, dir), typecheck.enabled ? this.typecheckFilesList || this.globFiles(typecheck.include, typecheck.exclude, dir) : []]);
7354
+ return this.typecheckFilesList = typecheckTestFiles, {
7349
7355
  testFiles: this.filterFiles(testFiles, filters, dir),
7350
7356
  typecheckTestFiles: this.filterFiles(typecheckTestFiles, filters, dir)
7351
7357
  };
@@ -7364,8 +7370,7 @@ class TestProject {
7364
7370
  }
7365
7371
  }));
7366
7372
  }
7367
- this.testFilesList = testFiles;
7368
- return testFiles;
7373
+ return this.testFilesList = testFiles, testFiles;
7369
7374
  }
7370
7375
  isBrowserEnabled() {
7371
7376
  return isBrowserEnabled(this.config);
@@ -7402,8 +7407,7 @@ class TestProject {
7402
7407
  cwd,
7403
7408
  ignore: exclude,
7404
7409
  expandDirectories: false
7405
- };
7406
- const files = await glob(include, globOptions);
7410
+ }, files = await glob(include, globOptions);
7407
7411
  // keep the slashes consistent with Vite
7408
7412
  // we are not using the pathe here because it normalizes the drive letter on Windows
7409
7413
  // and we want to keep it the same as working dir
@@ -7416,16 +7420,10 @@ class TestProject {
7416
7420
  if (this._isCachedTestFile(moduleId)) return true;
7417
7421
  const relativeId = relative(this.config.dir || this.config.root, moduleId);
7418
7422
  if (pm.isMatch(relativeId, this.config.exclude)) return false;
7419
- if (pm.isMatch(relativeId, this.config.include)) {
7420
- this.markTestFile(moduleId);
7421
- return true;
7422
- }
7423
+ if (pm.isMatch(relativeId, this.config.include)) return this.markTestFile(moduleId), true;
7423
7424
  if (this.config.includeSource?.length && pm.isMatch(relativeId, this.config.includeSource)) {
7424
7425
  const code = source?.() || readFileSync(moduleId, "utf-8");
7425
- if (this.isInSourceTestCode(code)) {
7426
- this.markTestFile(moduleId);
7427
- return true;
7428
- }
7426
+ if (this.isInSourceTestCode(code)) return this.markTestFile(moduleId), true;
7429
7427
  }
7430
7428
  return false;
7431
7429
  }
@@ -7438,7 +7436,7 @@ class TestProject {
7438
7436
  }
7439
7437
  filterFiles(testFiles, filters, dir) {
7440
7438
  if (filters.length && process.platform === "win32") filters = filters.map((f) => slash(f));
7441
- if (filters.length) return testFiles.filter((t) => {
7439
+ return filters.length ? testFiles.filter((t) => {
7442
7440
  const testFile = relative(dir, t).toLocaleLowerCase();
7443
7441
  return filters.some((f) => {
7444
7442
  // if filter is a full file path, we should include it if it's in the same folder
@@ -7446,8 +7444,7 @@ class TestProject {
7446
7444
  const relativePath = f.endsWith("/") ? join(relative(dir, f), "/") : relative(dir, f);
7447
7445
  return testFile.includes(f.toLocaleLowerCase()) || testFile.includes(relativePath.toLocaleLowerCase());
7448
7446
  });
7449
- });
7450
- return testFiles;
7447
+ }) : testFiles;
7451
7448
  }
7452
7449
  _parentBrowser;
7453
7450
  /** @internal */
@@ -7466,21 +7463,15 @@ class TestProject {
7466
7463
  }
7467
7464
  },
7468
7465
  ...MocksPlugins({ filter(id) {
7469
- if (id.includes(distRoot) || id.includes(cacheDir)) return false;
7470
- return true;
7466
+ return !(id.includes(distRoot) || id.includes(cacheDir));
7471
7467
  } }),
7472
7468
  MetaEnvReplacerPlugin()
7473
7469
  ], [CoverageTransform(this.vitest)]);
7474
- this._parentBrowser = browser;
7475
- if (this.config.browser.ui) setup(this.vitest, browser.vite);
7470
+ if (this._parentBrowser = browser, this.config.browser.ui) setup(this.vitest, browser.vite);
7476
7471
  });
7477
7472
  /** @internal */
7478
7473
  _initBrowserServer = deduped(async () => {
7479
- await this._parent?._initParentBrowser();
7480
- if (!this.browser && this._parent?._parentBrowser) {
7481
- this.browser = this._parent._parentBrowser.spawn(this);
7482
- await this.vitest.report("onBrowserInit", this);
7483
- }
7474
+ if (await this._parent?._initParentBrowser(), !this.browser && this._parent?._parentBrowser) this.browser = this._parent._parentBrowser.spawn(this), await this.vitest.report("onBrowserInit", this);
7484
7475
  });
7485
7476
  /**
7486
7477
  * Closes the project and all associated resources. This can only be called once; the closing promise is cached until the server restarts.
@@ -7493,8 +7484,7 @@ class TestProject {
7493
7484
  this.browser?.close(),
7494
7485
  this.clearTmpDir()
7495
7486
  ].filter(Boolean)).then(() => {
7496
- this._provided = {};
7497
- this._vite = void 0;
7487
+ this._provided = {}, this._vite = void 0;
7498
7488
  });
7499
7489
  return this.closingPromise;
7500
7490
  }
@@ -7518,27 +7508,22 @@ class TestProject {
7518
7508
  }
7519
7509
  /** @internal */
7520
7510
  async _configureServer(options, server) {
7521
- this._config = resolveConfig(this.vitest, {
7511
+ for (const _providedKey in this._config = resolveConfig(this.vitest, {
7522
7512
  ...options,
7523
7513
  coverage: this.vitest.config.coverage
7524
- }, server.config);
7525
- this._setHash();
7526
- for (const _providedKey in this.config.provide) {
7514
+ }, server.config), this._setHash(), this.config.provide) {
7527
7515
  const providedKey = _providedKey;
7528
7516
  // type is very strict here, so we cast it to any
7529
7517
  this.provide(providedKey, this.config.provide[providedKey]);
7530
7518
  }
7531
- this.closingPromise = void 0;
7532
- this._resolver = new VitestResolver(server.config.cacheDir, this._config);
7533
- this._vite = server;
7519
+ this.closingPromise = void 0, this._resolver = new VitestResolver(server.config.cacheDir, this._config), this._vite = server;
7534
7520
  const environment = server.environments.__vitest__;
7535
7521
  this.runner = new ServerModuleRunner(environment, this._resolver, this._config);
7536
7522
  }
7537
7523
  _serializeOverriddenConfig() {
7538
7524
  // TODO: serialize the config _once_ or when needed
7539
7525
  const config = serializeConfig(this.config, this.vitest.config, this.vite.config);
7540
- if (!this.vitest.configOverride) return config;
7541
- return deepMerge(config, this.vitest.configOverride);
7526
+ return this.vitest.configOverride ? deepMerge(config, this.vitest.configOverride) : config;
7542
7527
  }
7543
7528
  async clearTmpDir() {
7544
7529
  try {
@@ -7551,9 +7536,10 @@ class TestProject {
7551
7536
  }
7552
7537
  /** @internal */
7553
7538
  _initBrowserProvider = deduped(async () => {
7554
- if (!this.isBrowserEnabled() || this.browser?.provider) return;
7555
- if (!this.browser) await this._initBrowserServer();
7556
- await this.browser?.initBrowserProvider(this);
7539
+ if (!(!this.isBrowserEnabled() || this.browser?.provider)) {
7540
+ if (!this.browser) await this._initBrowserServer();
7541
+ await this.browser?.initBrowserProvider(this);
7542
+ }
7557
7543
  });
7558
7544
  /** @internal */
7559
7545
  _provideObject(context) {
@@ -7566,40 +7552,25 @@ class TestProject {
7566
7552
  /** @internal */
7567
7553
  static _createBasicProject(vitest) {
7568
7554
  const project = new TestProject(vitest.config.name || vitest.config.root, vitest);
7569
- project.runner = vitest.runner;
7570
- project._vite = vitest.server;
7571
- project._config = vitest.config;
7572
- project._resolver = vitest._resolver;
7573
- project._setHash();
7574
- project._provideObject(vitest.config.provide);
7575
- return project;
7555
+ 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;
7576
7556
  }
7577
7557
  /** @internal */
7578
7558
  static _cloneBrowserProject(parent, config) {
7579
7559
  const clone = new TestProject(parent.path, parent.vitest);
7580
- clone.runner = parent.runner;
7581
- clone._vite = parent._vite;
7582
- clone._resolver = parent._resolver;
7583
- clone._config = config;
7584
- clone._setHash();
7585
- clone._parent = parent;
7586
- clone._provideObject(config.provide);
7587
- return clone;
7560
+ 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;
7588
7561
  }
7589
7562
  }
7590
7563
  function deduped(cb) {
7591
7564
  let _promise;
7592
- return (...args) => {
7565
+ return ((...args) => {
7593
7566
  if (!_promise) _promise = cb(...args).finally(() => {
7594
7567
  _promise = void 0;
7595
7568
  });
7596
7569
  return _promise;
7597
- };
7570
+ });
7598
7571
  }
7599
7572
  async function initializeProject(workspacePath, ctx, options) {
7600
- const project = new TestProject(workspacePath, ctx, options);
7601
- const { configFile,...restOptions } = options;
7602
- const config = {
7573
+ const project = new TestProject(workspacePath, ctx, options), { configFile,...restOptions } = options, config = {
7603
7574
  ...restOptions,
7604
7575
  configFile,
7605
7576
  configLoader: ctx.vite.config.inlineConfig.configLoader,
@@ -7609,25 +7580,20 @@ async function initializeProject(workspacePath, ctx, options) {
7609
7580
  workspacePath
7610
7581
  })]
7611
7582
  };
7612
- await createViteServer(config);
7613
- return project;
7583
+ return await createViteServer(config), project;
7614
7584
  }
7615
7585
  function generateHash(str) {
7616
7586
  let hash = 0;
7617
7587
  if (str.length === 0) return `${hash}`;
7618
7588
  for (let i = 0; i < str.length; i++) {
7619
7589
  const char = str.charCodeAt(i);
7620
- hash = (hash << 5) - hash + char;
7621
- hash = hash & hash;
7590
+ hash = (hash << 5) - hash + char, hash = hash & hash;
7622
7591
  }
7623
7592
  return `${hash}`;
7624
7593
  }
7625
7594
 
7626
7595
  async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projectsDefinition, names) {
7627
- const { configFiles, projectConfigs, nonConfigDirectories } = await resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition);
7628
- // cli options that affect the project config,
7629
- // not all options are allowed to be overridden
7630
- const overridesOptions = [
7596
+ const { configFiles, projectConfigs, nonConfigDirectories } = await resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition), overridesOptions = [
7631
7597
  "logHeapUsage",
7632
7598
  "allowOnly",
7633
7599
  "sequence",
@@ -7646,21 +7612,12 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
7646
7612
  "inspect",
7647
7613
  "inspectBrk",
7648
7614
  "fileParallelism"
7649
- ];
7650
- const cliOverrides = overridesOptions.reduce((acc, name) => {
7615
+ ], cliOverrides = overridesOptions.reduce((acc, name) => {
7651
7616
  if (name in cliOptions) acc[name] = cliOptions[name];
7652
7617
  return acc;
7653
- }, {});
7654
- const projectPromises = [];
7655
- const fileProjects = [...configFiles, ...nonConfigDirectories];
7656
- const concurrent = limitConcurrency(nodeos__default.availableParallelism?.() || nodeos__default.cpus().length || 5);
7618
+ }, {}), projectPromises = [], fileProjects = [...configFiles, ...nonConfigDirectories], concurrent = limitConcurrency(nodeos__default.availableParallelism?.() || nodeos__default.cpus().length || 5);
7657
7619
  projectConfigs.forEach((options, index) => {
7658
- const configRoot = vitest.config.root;
7659
- // if extends a config file, resolve the file path
7660
- const configFile = typeof options.extends === "string" ? resolve(configRoot, options.extends) : options.extends === true ? vitest.vite.config.configFile || false : false;
7661
- // if `root` is configured, resolve it relative to the workspace file or vite root (like other options)
7662
- // if `root` is not specified, inline configs use the same root as the root project
7663
- const root = options.root ? resolve(configRoot, options.root) : vitest.config.root;
7620
+ const configRoot = vitest.config.root, configFile = typeof options.extends === "string" ? resolve(configRoot, options.extends) : options.extends === true ? vitest.vite.config.configFile || false : false, root = options.root ? resolve(configRoot, options.root) : vitest.config.root;
7664
7621
  projectPromises.push(concurrent(() => initializeProject(index, vitest, {
7665
7622
  ...options,
7666
7623
  root,
@@ -7678,8 +7635,7 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
7678
7635
  if (project) projectPromises.push(Promise.resolve(project));
7679
7636
  continue;
7680
7637
  }
7681
- const configFile = path.endsWith("/") ? false : path;
7682
- const root = path.endsWith("/") ? path : dirname(path);
7638
+ const configFile = path.endsWith("/") ? false : path, root = path.endsWith("/") ? path : dirname(path);
7683
7639
  projectPromises.push(concurrent(() => initializeProject(path, vitest, {
7684
7640
  root,
7685
7641
  configFile,
@@ -7692,9 +7648,7 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
7692
7648
  vitest.config.project.length ? `The filter matched no projects: ${vitest.config.project.join(", ")}. ` : "",
7693
7649
  `The projects definition: ${JSON.stringify(projectsDefinition, null, 4)}.`
7694
7650
  ].join(""));
7695
- const resolvedProjectsPromises = await Promise.allSettled(projectPromises);
7696
- const errors = [];
7697
- const resolvedProjects = [];
7651
+ const resolvedProjectsPromises = await Promise.allSettled(projectPromises), errors = [], resolvedProjects = [];
7698
7652
  for (const result of resolvedProjectsPromises) if (result.status === "rejected") {
7699
7653
  if (result.reason instanceof VitestFilteredOutProjectError)
7700
7654
  // filter out filtered out projects
@@ -7706,8 +7660,7 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
7706
7660
  for (const project of resolvedProjects) {
7707
7661
  const name = project.name;
7708
7662
  if (names.has(name)) {
7709
- const duplicate = resolvedProjects.find((p) => p.name === name && p !== project);
7710
- const filesError = fileProjects.length ? [
7663
+ const duplicate = resolvedProjects.find((p) => p.name === name && p !== project), filesError = fileProjects.length ? [
7711
7664
  "\n\nYour config matched these files:\n",
7712
7665
  fileProjects.map((p) => ` - ${relative(vitest.config.root, p)}`).join("\n"),
7713
7666
  "\n\n"
@@ -7729,24 +7682,18 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
7729
7682
  const removeProjects = /* @__PURE__ */ new Set();
7730
7683
  resolvedProjects.forEach((project) => {
7731
7684
  if (!project.config.browser.enabled) return;
7732
- const instances = project.config.browser.instances || [];
7733
- const browser = project.config.browser.name;
7734
- if (instances.length === 0 && browser) {
7735
- instances.push({
7736
- browser,
7737
- name: project.name ? `${project.name} (${browser})` : browser
7738
- });
7739
- vitest.logger.warn(withLabel("yellow", "Vitest", [
7740
- `No browser "instances" were defined`,
7741
- project.name ? ` for the "${project.name}" project. ` : ". ",
7742
- `Running tests in "${project.config.browser.name}" browser. `,
7743
- "The \"browser.name\" field is deprecated since Vitest 3. ",
7744
- "Read more: https://vitest.dev/guide/browser/config#browser-instances"
7745
- ].filter(Boolean).join("")));
7746
- }
7747
- const originalName = project.config.name;
7748
- // if original name is in the --project=name filter, keep all instances
7749
- const filteredInstances = vitest.matchesProjectFilter(originalName) ? instances : instances.filter((instance) => {
7685
+ const instances = project.config.browser.instances || [], browser = project.config.browser.name;
7686
+ if (instances.length === 0 && browser) instances.push({
7687
+ browser,
7688
+ name: project.name ? `${project.name} (${browser})` : browser
7689
+ }), vitest.logger.warn(withLabel("yellow", "Vitest", [
7690
+ `No browser "instances" were defined`,
7691
+ project.name ? ` for the "${project.name}" project. ` : ". ",
7692
+ `Running tests in "${project.config.browser.name}" browser. `,
7693
+ "The \"browser.name\" field is deprecated since Vitest 3. ",
7694
+ "Read more: https://vitest.dev/guide/browser/config#browser-instances"
7695
+ ].filter(Boolean).join("")));
7696
+ const originalName = project.config.name, filteredInstances = vitest.matchesProjectFilter(originalName) ? instances : instances.filter((instance) => {
7750
7697
  const newName = instance.name;
7751
7698
  return vitest.matchesProjectFilter(newName);
7752
7699
  });
@@ -7759,8 +7706,7 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
7759
7706
  filteredInstances.forEach((config, index) => {
7760
7707
  const browser = config.browser;
7761
7708
  if (!browser) {
7762
- const nth = index + 1;
7763
- const ending = nth === 2 ? "nd" : nth === 3 ? "rd" : "th";
7709
+ const nth = index + 1, ending = nth === 2 ? "nd" : nth === 3 ? "rd" : "th";
7764
7710
  throw new Error(`The browser configuration must have a "browser" property. The ${nth}${ending} item in "browser.instances" doesn't have it. Make sure your${originalName ? ` "${originalName}"` : ""} configuration is correct.`);
7765
7711
  }
7766
7712
  const name = config.name;
@@ -7775,18 +7721,15 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
7775
7721
  clonedConfig.name = name;
7776
7722
  const clone = TestProject._cloneBrowserProject(project, clonedConfig);
7777
7723
  resolvedProjects.push(clone);
7778
- });
7779
- removeProjects.add(project);
7780
- });
7781
- resolvedProjects = resolvedProjects.filter((project) => !removeProjects.has(project));
7724
+ }), removeProjects.add(project);
7725
+ }), resolvedProjects = resolvedProjects.filter((project) => !removeProjects.has(project));
7782
7726
  const headedBrowserProjects = resolvedProjects.filter((project) => {
7783
7727
  return project.config.browser.enabled && !project.config.browser.headless;
7784
7728
  });
7785
7729
  if (headedBrowserProjects.length > 1) {
7786
7730
  const message = [`Found multiple projects that run browser tests in headed mode: "${headedBrowserProjects.map((p) => p.name).join("\", \"")}".`, ` Vitest cannot run multiple headed browsers at the same time.`].join("");
7787
7731
  if (!isTTY) throw new Error(`${message} Please, filter projects with --browser=name or --project=name flag or run tests with "headless: true" option.`);
7788
- const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; });
7789
- const { projectName } = await prompts.default({
7732
+ const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; }), { projectName } = await prompts.default({
7790
7733
  type: "select",
7791
7734
  name: "projectName",
7792
7735
  choices: headedBrowserProjects.map((project) => ({
@@ -7801,10 +7744,9 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
7801
7744
  return resolvedProjects;
7802
7745
  }
7803
7746
  function cloneConfig(project, { browser,...config }) {
7804
- const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, browser: _browser, name,...overrideConfig } = config;
7805
- const currentConfig = project.config.browser;
7747
+ const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, browser: _browser, name,...overrideConfig } = config, currentConfig = project.config.browser, clonedConfig = deepClone(project.config);
7806
7748
  return mergeConfig({
7807
- ...deepClone(project.config),
7749
+ ...clonedConfig,
7808
7750
  browser: {
7809
7751
  ...project.config.browser,
7810
7752
  locators: locators ? { testIdAttribute: locators.testIdAttribute ?? currentConfig.locators.testIdAttribute } : project.config.browser.locators,
@@ -7816,18 +7758,15 @@ function cloneConfig(project, { browser,...config }) {
7816
7758
  name: browser,
7817
7759
  providerOptions: config,
7818
7760
  instances: void 0
7819
- }
7761
+ },
7762
+ include: overrideConfig.include && overrideConfig.include.length > 0 ? [] : clonedConfig.include,
7763
+ exclude: overrideConfig.exclude && overrideConfig.exclude.length > 0 ? [] : clonedConfig.exclude,
7764
+ includeSource: overrideConfig.includeSource && overrideConfig.includeSource.length > 0 ? [] : clonedConfig.includeSource
7820
7765
  }, overrideConfig);
7821
7766
  }
7822
7767
  async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition) {
7823
7768
  // project configurations that were specified directly
7824
- const projectsOptions = [];
7825
- // custom config files that were specified directly or resolved from a directory
7826
- const projectsConfigFiles = [];
7827
- // custom glob matches that should be resolved as directories or config files
7828
- const projectsGlobMatches = [];
7829
- // directories that don't have a config file inside, but should be treated as projects
7830
- const nonConfigProjectDirectories = [];
7769
+ const projectsOptions = [], projectsConfigFiles = [], projectsGlobMatches = [], nonConfigProjectDirectories = [];
7831
7770
  for (const definition of projectsDefinition) if (typeof definition === "string") {
7832
7771
  const stringOption = definition.replace("<rootDir>", vitest.config.root);
7833
7772
  // if the string doesn't contain a glob, we can resolve it directly
@@ -7871,8 +7810,7 @@ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDe
7871
7810
  "**/*.timestamp-*",
7872
7811
  "**/.DS_Store"
7873
7812
  ]
7874
- };
7875
- const projectsFs = await glob(projectsGlobMatches, globOptions);
7813
+ }, projectsFs = await glob(projectsGlobMatches, globOptions);
7876
7814
  await Promise.all(projectsFs.map(async (path) => {
7877
7815
  // directories are allowed with a glob like `packages/*`
7878
7816
  // in this case every directory is treated as a project
@@ -7891,21 +7829,15 @@ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDe
7891
7829
  };
7892
7830
  }
7893
7831
  async function resolveDirectoryConfig(directory) {
7894
- const files = new Set(await promises.readdir(directory));
7895
- // default resolution looks for vitest.config.* or vite.config.* files
7896
- // this simulates how `findUp` works in packages/vitest/src/node/create.ts:29
7897
- const configFile = configFiles.find((file) => files.has(file));
7898
- if (configFile) return resolve(directory, configFile);
7899
- return null;
7832
+ const files = new Set(await promises.readdir(directory)), configFile = configFiles.find((file) => files.has(file));
7833
+ return configFile ? resolve(directory, configFile) : null;
7900
7834
  }
7901
7835
  function getDefaultTestProject(vitest) {
7902
- const filter = vitest.config.project;
7903
- const project = vitest._ensureRootProject();
7836
+ const filter = vitest.config.project, project = vitest._ensureRootProject();
7904
7837
  if (!filter.length) return project;
7905
7838
  // check for the project name and browser names
7906
7839
  const hasProjects = getPotentialProjectNames(project).some((p) => vitest.matchesProjectFilter(p));
7907
- if (hasProjects) return project;
7908
- return null;
7840
+ return hasProjects ? project : null;
7909
7841
  }
7910
7842
  function getPotentialProjectNames(project) {
7911
7843
  const names = [project.name];
@@ -7925,8 +7857,7 @@ async function loadCustomReporterModule(path, runner) {
7925
7857
  return customReporterModule.default;
7926
7858
  }
7927
7859
  function createReporters(reporterReferences, ctx) {
7928
- const runner = ctx.runner;
7929
- const promisedReporters = reporterReferences.map(async (referenceOrInstance) => {
7860
+ const runner = ctx.runner, promisedReporters = reporterReferences.map(async (referenceOrInstance) => {
7930
7861
  if (Array.isArray(referenceOrInstance)) {
7931
7862
  const [reporterName, reporterOptions] = referenceOrInstance;
7932
7863
  if (reporterName === "html") {
@@ -7967,14 +7898,12 @@ function parseFilter(filter) {
7967
7898
  filename: parsedFilename,
7968
7899
  lineNumber: Number.parseInt(lineNumber)
7969
7900
  };
7970
- else if (lineNumber.match(/^\d+-\d+$/)) throw new RangeLocationFilterProvidedError(filter);
7971
- else return { filename: filter };
7901
+ if (lineNumber.match(/^\d+-\d+$/)) throw new RangeLocationFilterProvidedError(filter);
7902
+ return { filename: filter };
7972
7903
  }
7973
7904
  function groupFilters(filters) {
7974
- const groupedFilters_ = groupBy(filters, (f) => f.filename);
7975
- const groupedFilters = Object.fromEntries(Object.entries(groupedFilters_).map((entry) => {
7976
- const [filename, filters] = entry;
7977
- const testLocations = filters.map((f) => f.lineNumber);
7905
+ const groupedFilters_ = groupBy(filters, (f) => f.filename), groupedFilters = Object.fromEntries(Object.entries(groupedFilters_).map((entry) => {
7906
+ const [filename, filters] = entry, testLocations = filters.map((f) => f.lineNumber);
7978
7907
  return [filename, testLocations.filter((l) => l !== void 0)];
7979
7908
  }));
7980
7909
  return groupedFilters;
@@ -7993,45 +7922,35 @@ class VitestSpecifications {
7993
7922
  if (project._isCachedTestFile(moduleId)) specs.push(project.createSpecification(moduleId));
7994
7923
  if (project._isCachedTypecheckFile(moduleId)) specs.push(project.createSpecification(moduleId, [], "typescript"));
7995
7924
  }
7996
- specs.forEach((spec) => this.ensureSpecificationCached(spec));
7997
- return specs;
7925
+ return specs.forEach((spec) => this.ensureSpecificationCached(spec)), specs;
7998
7926
  }
7999
7927
  async getRelevantTestSpecifications(filters = []) {
8000
7928
  return this.filterTestsBySource(await this.globTestSpecifications(filters));
8001
7929
  }
8002
7930
  async globTestSpecifications(filters = []) {
8003
- const files = [];
8004
- const dir = process.cwd();
8005
- const parsedFilters = filters.map((f) => parseFilter(f));
7931
+ const files = [], dir = process.cwd(), parsedFilters = filters.map((f) => parseFilter(f));
8006
7932
  // Require includeTaskLocation when a location filter is passed
8007
7933
  if (!this.vitest.config.includeTaskLocation && parsedFilters.some((f) => f.lineNumber !== void 0)) throw new IncludeTaskLocationDisabledError();
8008
7934
  const testLines = groupFilters(parsedFilters.map((f) => ({
8009
7935
  ...f,
8010
7936
  filename: resolve(dir, f.filename)
8011
- })));
8012
- // Key is file and val specifies whether we have matched this file with testLocation
8013
- const testLocHasMatch = {};
8014
- await Promise.all(this.vitest.projects.map(async (project) => {
7937
+ }))), testLocHasMatch = {};
7938
+ return await Promise.all(this.vitest.projects.map(async (project) => {
8015
7939
  const { testFiles, typecheckTestFiles } = await project.globTestFiles(parsedFilters.map((f) => f.filename));
8016
7940
  testFiles.forEach((file) => {
8017
7941
  const lines = testLines[file];
8018
7942
  testLocHasMatch[file] = true;
8019
7943
  const spec = project.createSpecification(file, lines);
8020
- this.ensureSpecificationCached(spec);
8021
- files.push(spec);
8022
- });
8023
- typecheckTestFiles.forEach((file) => {
7944
+ this.ensureSpecificationCached(spec), files.push(spec);
7945
+ }), typecheckTestFiles.forEach((file) => {
8024
7946
  const lines = testLines[file];
8025
7947
  testLocHasMatch[file] = true;
8026
7948
  const spec = project.createSpecification(file, lines, "typescript");
8027
- this.ensureSpecificationCached(spec);
8028
- files.push(spec);
7949
+ this.ensureSpecificationCached(spec), files.push(spec);
8029
7950
  });
8030
- }));
8031
- Object.entries(testLines).forEach(([filepath, loc]) => {
7951
+ })), Object.entries(testLines).forEach(([filepath, loc]) => {
8032
7952
  if (loc.length !== 0 && !testLocHasMatch[filepath]) throw new LocationFilterFileNotFoundError(relative(dir, filepath));
8033
- });
8034
- return files;
7953
+ }), files;
8035
7954
  }
8036
7955
  clearCache(moduleId) {
8037
7956
  if (moduleId) this._cachedSpecs.delete(moduleId);
@@ -8041,30 +7960,20 @@ class VitestSpecifications {
8041
7960
  return this._cachedSpecs.get(moduleId);
8042
7961
  }
8043
7962
  ensureSpecificationCached(spec) {
8044
- const file = spec.moduleId;
8045
- const specs = this._cachedSpecs.get(file) || [];
8046
- const index = specs.findIndex((_s) => _s.project === spec.project && _s.pool === spec.pool);
8047
- if (index === -1) {
8048
- specs.push(spec);
8049
- this._cachedSpecs.set(file, specs);
8050
- } else specs.splice(index, 1, spec);
7963
+ const file = spec.moduleId, specs = this._cachedSpecs.get(file) || [], index = specs.findIndex((_s) => _s.project === spec.project && _s.pool === spec.pool);
7964
+ if (index === -1) specs.push(spec), this._cachedSpecs.set(file, specs);
7965
+ else specs.splice(index, 1, spec);
8051
7966
  return specs;
8052
7967
  }
8053
7968
  async filterTestsBySource(specs) {
8054
7969
  if (this.vitest.config.changed && !this.vitest.config.related) {
8055
- const { VitestGit } = await import('./git.BVQ8w_Sw.js');
8056
- const vitestGit = new VitestGit(this.vitest.config.root);
8057
- const related = await vitestGit.findChangedFiles({ changedSince: this.vitest.config.changed });
8058
- if (!related) {
8059
- process.exitCode = 1;
8060
- throw new GitNotFoundError();
8061
- }
7970
+ const { VitestGit } = await import('./git.BFNcloKD.js'), vitestGit = new VitestGit(this.vitest.config.root), related = await vitestGit.findChangedFiles({ changedSince: this.vitest.config.changed });
7971
+ if (!related) throw process.exitCode = 1, new GitNotFoundError();
8062
7972
  this.vitest.config.related = Array.from(new Set(related));
8063
7973
  }
8064
7974
  const related = this.vitest.config.related;
8065
7975
  if (!related) return specs;
8066
- const forceRerunTriggers = this.vitest.config.forceRerunTriggers;
8067
- const matcher = forceRerunTriggers.length ? pm(forceRerunTriggers) : void 0;
7976
+ const forceRerunTriggers = this.vitest.config.forceRerunTriggers, matcher = forceRerunTriggers.length ? pm(forceRerunTriggers) : void 0;
8068
7977
  if (matcher && related.some((file) => matcher(file))) return specs;
8069
7978
  // don't run anything if no related sources are found
8070
7979
  // if we are in watch mode, we want to process all tests
@@ -8072,8 +7981,7 @@ class VitestSpecifications {
8072
7981
  const testGraphs = await Promise.all(specs.map(async (spec) => {
8073
7982
  const deps = await this.getTestDependencies(spec);
8074
7983
  return [spec, deps];
8075
- }));
8076
- const runningTests = [];
7984
+ })), runningTests = [];
8077
7985
  for (const [specification, deps] of testGraphs)
8078
7986
  // if deps or the test itself were changed
8079
7987
  if (related.some((path) => path === specification.moduleId || deps.has(path))) runningTests.push(specification);
@@ -8083,8 +7991,7 @@ class VitestSpecifications {
8083
7991
  const addImports = async (project, filepath) => {
8084
7992
  if (deps.has(filepath)) return;
8085
7993
  deps.add(filepath);
8086
- const mod = project.vite.environments.ssr.moduleGraph.getModuleById(filepath);
8087
- const transformed = mod?.transformResult || await project.vite.environments.ssr.transformRequest(filepath);
7994
+ const mod = project.vite.environments.ssr.moduleGraph.getModuleById(filepath), transformed = mod?.transformResult || await project.vite.environments.ssr.transformRequest(filepath);
8088
7995
  if (!transformed) return;
8089
7996
  const dependencies = [...transformed.deps || [], ...transformed.dynamicDeps || []];
8090
7997
  await Promise.all(dependencies.map(async (dep) => {
@@ -8092,9 +7999,7 @@ class VitestSpecifications {
8092
7999
  if (!fsPath.includes("node_modules") && !deps.has(fsPath) && existsSync(fsPath)) await addImports(project, fsPath);
8093
8000
  }));
8094
8001
  };
8095
- await addImports(spec.project, spec.moduleId);
8096
- deps.delete(spec.moduleId);
8097
- return deps;
8002
+ return await addImports(spec.project, spec.moduleId), deps.delete(spec.moduleId), deps;
8098
8003
  }
8099
8004
  }
8100
8005
 
@@ -8120,10 +8025,7 @@ class ReportedTaskImplementation {
8120
8025
  location;
8121
8026
  /** @internal */
8122
8027
  constructor(task, project) {
8123
- this.task = task;
8124
- this.project = project;
8125
- this.id = task.id;
8126
- this.location = task.location;
8028
+ this.task = task, this.project = project, this.id = task.id, this.location = task.location;
8127
8029
  }
8128
8030
  /**
8129
8031
  * Checks if the test did not fail the suite.
@@ -8145,8 +8047,7 @@ class ReportedTaskImplementation {
8145
8047
  */
8146
8048
  static register(task, project) {
8147
8049
  const state = new this(task, project);
8148
- storeTask(project, task, state);
8149
- return state;
8050
+ return storeTask(project, task, state), state;
8150
8051
  }
8151
8052
  }
8152
8053
  class TestCase extends ReportedTaskImplementation {
@@ -8170,9 +8071,7 @@ class TestCase extends ReportedTaskImplementation {
8170
8071
  parent;
8171
8072
  /** @internal */
8172
8073
  constructor(task, project) {
8173
- super(task, project);
8174
- this.name = task.name;
8175
- this.module = getReportedTask(project, task.file);
8074
+ super(task, project), this.name = task.name, this.module = getReportedTask(project, task.file);
8176
8075
  const suite = this.task.suite;
8177
8076
  if (suite) this.parent = getReportedTask(project, suite);
8178
8077
  else this.parent = this.module;
@@ -8194,8 +8093,7 @@ class TestCase extends ReportedTaskImplementation {
8194
8093
  * - **skipped**: Test was skipped during collection or dynamically with `ctx.skip()`.
8195
8094
  */
8196
8095
  result() {
8197
- const result = this.task.result;
8198
- const mode = result?.state || this.task.mode;
8096
+ const result = this.task.result, mode = result?.state || this.task.mode;
8199
8097
  if (!result && (mode === "skip" || mode === "todo")) return {
8200
8098
  state: "skipped",
8201
8099
  note: void 0,
@@ -8206,16 +8104,14 @@ class TestCase extends ReportedTaskImplementation {
8206
8104
  errors: void 0
8207
8105
  };
8208
8106
  const state = result.state === "fail" ? "failed" : result.state === "pass" ? "passed" : "skipped";
8209
- if (state === "skipped") return {
8107
+ return state === "skipped" ? {
8210
8108
  state,
8211
8109
  note: result.note,
8212
8110
  errors: void 0
8213
- };
8214
- if (state === "passed") return {
8111
+ } : state === "passed" ? {
8215
8112
  state,
8216
8113
  errors: result.errors
8217
- };
8218
- return {
8114
+ } : {
8219
8115
  state,
8220
8116
  errors: result.errors || []
8221
8117
  };
@@ -8234,8 +8130,7 @@ class TestCase extends ReportedTaskImplementation {
8234
8130
  const result = this.task.result;
8235
8131
  // startTime should always be available if the test has properly finished
8236
8132
  if (!result || !result.startTime) return void 0;
8237
- const duration = result.duration || 0;
8238
- const slow = duration > this.project.globalConfig.slowTestThreshold;
8133
+ const duration = result.duration || 0, slow = duration > this.project.globalConfig.slowTestThreshold;
8239
8134
  return {
8240
8135
  slow,
8241
8136
  heap: result.heap,
@@ -8251,8 +8146,7 @@ class TestCollection {
8251
8146
  #task;
8252
8147
  #project;
8253
8148
  constructor(task, project) {
8254
- this.#task = task;
8255
- this.#project = project;
8149
+ this.#task = task, this.#project = project;
8256
8150
  }
8257
8151
  /**
8258
8152
  * Returns the test or suite at a specific index.
@@ -8305,10 +8199,7 @@ class TestCollection {
8305
8199
  * Filters all suites that are part of this collection and its children.
8306
8200
  */
8307
8201
  *allSuites() {
8308
- for (const child of this) if (child.type === "suite") {
8309
- yield child;
8310
- yield* child.children.allSuites();
8311
- }
8202
+ for (const child of this) if (child.type === "suite") yield child, yield* child.children.allSuites();
8312
8203
  }
8313
8204
  *[Symbol.iterator]() {
8314
8205
  for (const task of this.#task.tasks) yield getReportedTask(this.#project, task);
@@ -8321,8 +8212,7 @@ class SuiteImplementation extends ReportedTaskImplementation {
8321
8212
  children;
8322
8213
  /** @internal */
8323
8214
  constructor(task, project) {
8324
- super(task, project);
8325
- this.children = new TestCollection(task, project);
8215
+ super(task, project), this.children = new TestCollection(task, project);
8326
8216
  }
8327
8217
  /**
8328
8218
  * Errors that happened outside of the test run during collection, like syntax errors.
@@ -8352,9 +8242,7 @@ class TestSuite extends SuiteImplementation {
8352
8242
  options;
8353
8243
  /** @internal */
8354
8244
  constructor(task, project) {
8355
- super(task, project);
8356
- this.name = task.name;
8357
- this.module = getReportedTask(project, task.file);
8245
+ super(task, project), this.name = task.name, this.module = getReportedTask(project, task.file);
8358
8246
  const suite = this.task.suite;
8359
8247
  if (suite) this.parent = getReportedTask(project, suite);
8360
8248
  else this.parent = this.module;
@@ -8385,29 +8273,21 @@ class TestModule extends SuiteImplementation {
8385
8273
  moduleId;
8386
8274
  /** @internal */
8387
8275
  constructor(task, project) {
8388
- super(task, project);
8389
- this.moduleId = task.filepath;
8276
+ super(task, project), this.moduleId = task.filepath;
8390
8277
  }
8391
8278
  /**
8392
8279
  * Checks the running state of the test file.
8393
8280
  */
8394
8281
  state() {
8395
8282
  const state = this.task.result?.state;
8396
- if (state === "queued") return "queued";
8397
- return getSuiteState(this.task);
8283
+ return state === "queued" ? "queued" : getSuiteState(this.task);
8398
8284
  }
8399
8285
  /**
8400
8286
  * Useful information about the module like duration, memory usage, etc.
8401
8287
  * If the module was not executed yet, all diagnostic values will return `0`.
8402
8288
  */
8403
8289
  diagnostic() {
8404
- const setupDuration = this.task.setupDuration || 0;
8405
- const collectDuration = this.task.collectDuration || 0;
8406
- const prepareDuration = this.task.prepareDuration || 0;
8407
- const environmentSetupDuration = this.task.environmentLoad || 0;
8408
- const duration = this.task.result?.duration || 0;
8409
- const heap = this.task.result?.heap;
8410
- const importDurations = this.task.importDurations ?? {};
8290
+ const setupDuration = this.task.setupDuration || 0, collectDuration = this.task.collectDuration || 0, prepareDuration = this.task.prepareDuration || 0, environmentSetupDuration = this.task.environmentLoad || 0, duration = this.task.result?.duration || 0, heap = this.task.result?.heap, importDurations = this.task.importDurations ?? {};
8411
8291
  return {
8412
8292
  environmentSetupDuration,
8413
8293
  prepareDuration,
@@ -8439,18 +8319,19 @@ function getReportedTask(project, runnerTask) {
8439
8319
  return reportedTask;
8440
8320
  }
8441
8321
  function getSuiteState(task) {
8442
- const mode = task.mode;
8443
- const state = task.result?.state;
8322
+ const mode = task.mode, state = task.result?.state;
8444
8323
  if (mode === "skip" || mode === "todo" || state === "skip" || state === "todo") return "skipped";
8445
8324
  if (state == null || state === "run" || state === "only") return "pending";
8446
8325
  if (state === "fail") return "failed";
8447
8326
  if (state === "pass") return "passed";
8448
8327
  throw new Error(`Unknown suite state: ${state}`);
8449
8328
  }
8329
+ function experimental_getRunnerTask(entity) {
8330
+ return entity.task;
8331
+ }
8450
8332
 
8451
8333
  function isAggregateError(err) {
8452
- if (typeof AggregateError !== "undefined" && err instanceof AggregateError) return true;
8453
- return err instanceof Error && "errors" in err;
8334
+ return typeof AggregateError !== "undefined" && err instanceof AggregateError ? true : err instanceof Error && "errors" in err;
8454
8335
  }
8455
8336
  class StateManager {
8456
8337
  filesMap = /* @__PURE__ */ new Map();
@@ -8481,12 +8362,7 @@ class StateManager {
8481
8362
  const _error = error;
8482
8363
  if (_error && typeof _error === "object" && _error.code === "VITEST_PENDING") {
8483
8364
  const task = this.idMap.get(_error.taskId);
8484
- if (task) {
8485
- task.mode = "skip";
8486
- task.result ??= { state: "skip" };
8487
- task.result.state = "skip";
8488
- task.result.note = _error.note;
8489
- }
8365
+ if (task) task.mode = "skip", task.result ??= { state: "skip" }, task.result.state = "skip", task.result.note = _error.note;
8490
8366
  return;
8491
8367
  }
8492
8368
  if (!this.onUnhandledError || this.onUnhandledError(error) !== false) this.errorsSet.add(error);
@@ -8510,12 +8386,8 @@ class StateManager {
8510
8386
  * Return files that were running or collected.
8511
8387
  */
8512
8388
  getFiles(keys) {
8513
- if (keys) return keys.map((key) => this.filesMap.get(key)).flat().filter((file) => file && !file.local);
8514
- return Array.from(this.filesMap.values()).flat().filter((file) => !file.local).sort((f1, f2) => {
8515
- // print typecheck files first
8516
- if (f1.meta?.typecheck && f2.meta?.typecheck) return 0;
8517
- if (f1.meta?.typecheck) return -1;
8518
- return 1;
8389
+ return keys ? keys.map((key) => this.filesMap.get(key)).flat().filter((file) => file && !file.local) : Array.from(this.filesMap.values()).flat().filter((file) => !file.local).sort((f1, f2) => {
8390
+ return f1.meta?.typecheck && f2.meta?.typecheck ? 0 : f1.meta?.typecheck ? -1 : 1;
8519
8391
  });
8520
8392
  }
8521
8393
  getTestModules(keys) {
@@ -8534,25 +8406,17 @@ class StateManager {
8534
8406
  }
8535
8407
  collectFiles(project, files = []) {
8536
8408
  files.forEach((file) => {
8537
- const existing = this.filesMap.get(file.filepath) || [];
8538
- const otherFiles = existing.filter((i) => i.projectName !== file.projectName || i.meta.typecheck !== file.meta.typecheck);
8539
- const currentFile = existing.find((i) => i.projectName === file.projectName);
8409
+ const existing = this.filesMap.get(file.filepath) || [], otherFiles = existing.filter((i) => i.projectName !== file.projectName || i.meta.typecheck !== file.meta.typecheck), currentFile = existing.find((i) => i.projectName === file.projectName);
8540
8410
  // keep logs for the previous file because it should always be initiated before the collections phase
8541
8411
  // which means that all logs are collected during the collection and not inside tests
8542
8412
  if (currentFile) file.logs = currentFile.logs;
8543
- otherFiles.push(file);
8544
- this.filesMap.set(file.filepath, otherFiles);
8545
- this.updateId(file, project);
8413
+ otherFiles.push(file), this.filesMap.set(file.filepath, otherFiles), this.updateId(file, project);
8546
8414
  });
8547
8415
  }
8548
8416
  clearFiles(project, paths = []) {
8549
8417
  paths.forEach((path) => {
8550
- const files = this.filesMap.get(path);
8551
- const fileTask = createFileTask(path, project.config.root, project.config.name);
8552
- fileTask.local = true;
8553
- TestModule.register(fileTask, project);
8554
- this.idMap.set(fileTask.id, fileTask);
8555
- if (!files) {
8418
+ const files = this.filesMap.get(path), fileTask = createFileTask$1(path, project.config.root, project.config.name);
8419
+ if (fileTask.local = true, TestModule.register(fileTask, project), this.idMap.set(fileTask.id, fileTask), !files) {
8556
8420
  this.filesMap.set(path, [fileTask]);
8557
8421
  return;
8558
8422
  }
@@ -8563,14 +8427,14 @@ class StateManager {
8563
8427
  });
8564
8428
  }
8565
8429
  updateId(task, project) {
8566
- if (this.idMap.get(task.id) === task) return;
8567
- if (task.type === "suite" && "filepath" in task) TestModule.register(task, project);
8568
- else if (task.type === "suite") TestSuite.register(task, project);
8569
- else TestCase.register(task, project);
8570
- this.idMap.set(task.id, task);
8571
- if (task.type === "suite") task.tasks.forEach((task) => {
8572
- this.updateId(task, project);
8573
- });
8430
+ if (this.idMap.get(task.id) !== task) {
8431
+ if (task.type === "suite" && "filepath" in task) TestModule.register(task, project);
8432
+ else if (task.type === "suite") TestSuite.register(task, project);
8433
+ else TestCase.register(task, project);
8434
+ if (this.idMap.set(task.id, task), task.type === "suite") task.tasks.forEach((task) => {
8435
+ this.updateId(task, project);
8436
+ });
8437
+ }
8574
8438
  }
8575
8439
  getReportedEntity(task) {
8576
8440
  return this.reportedTasksMap.get(task);
@@ -8579,10 +8443,8 @@ class StateManager {
8579
8443
  for (const [id, result, meta] of packs) {
8580
8444
  const task = this.idMap.get(id);
8581
8445
  if (task) {
8582
- task.result = result;
8583
- task.meta = meta;
8584
8446
  // skipped with new PendingError
8585
- if (result?.state === "skip") task.mode = "skip";
8447
+ if (task.result = result, task.meta = meta, result?.state === "skip") task.mode = "skip";
8586
8448
  }
8587
8449
  }
8588
8450
  }
@@ -8597,7 +8459,7 @@ class StateManager {
8597
8459
  return Array.from(this.idMap.values()).filter((t) => t.result?.state === "fail").length;
8598
8460
  }
8599
8461
  cancelFiles(files, project) {
8600
- this.collectFiles(project, files.map((filepath) => createFileTask(filepath, project.config.root, project.config.name)));
8462
+ this.collectFiles(project, files.map((filepath) => createFileTask$1(filepath, project.config.root, project.config.name)));
8601
8463
  }
8602
8464
  }
8603
8465
 
@@ -9059,10 +8921,7 @@ class TestRun {
9059
8921
  }
9060
8922
  async start(specifications) {
9061
8923
  const filepaths = specifications.map((spec) => spec.moduleId);
9062
- this.vitest.state.collectPaths(filepaths);
9063
- await this.vitest.report("onPathsCollected", Array.from(new Set(filepaths)));
9064
- await this.vitest.report("onSpecsCollected", specifications.map((spec) => spec.toJSON()));
9065
- await this.vitest.report("onTestRunStart", [...specifications]);
8924
+ this.vitest.state.collectPaths(filepaths), await this.vitest.report("onTestRunStart", [...specifications]);
9066
8925
  }
9067
8926
  async enqueued(project, file) {
9068
8927
  this.vitest.state.collectFiles(project, [file]);
@@ -9070,30 +8929,22 @@ class TestRun {
9070
8929
  await this.vitest.report("onTestModuleQueued", testModule);
9071
8930
  }
9072
8931
  async collected(project, files) {
9073
- this.vitest.state.collectFiles(project, files);
9074
- await Promise.all([this.vitest.report("onCollected", files), ...files.map((file) => {
8932
+ this.vitest.state.collectFiles(project, files), await Promise.all(files.map((file) => {
9075
8933
  const testModule = this.vitest.state.getReportedEntity(file);
9076
8934
  return this.vitest.report("onTestModuleCollected", testModule);
9077
- })]);
8935
+ }));
9078
8936
  }
9079
8937
  async log(log) {
9080
- this.vitest.state.updateUserLog(log);
9081
- await this.vitest.report("onUserConsoleLog", log);
8938
+ this.vitest.state.updateUserLog(log), await this.vitest.report("onUserConsoleLog", log);
9082
8939
  }
9083
8940
  async annotate(testId, annotation) {
9084
- const task = this.vitest.state.idMap.get(testId);
9085
- const entity = task && this.vitest.state.getReportedEntity(task);
9086
- assert$1(task && entity, `Entity must be found for task ${task?.name || testId}`);
9087
- assert$1(entity.type === "test", `Annotation can only be added to a test, instead got ${entity.type}`);
9088
- await this.resolveTestAttachment(entity, annotation);
9089
- entity.task.annotations.push(annotation);
9090
- await this.vitest.report("onTestCaseAnnotate", entity, annotation);
9091
- return annotation;
8941
+ const task = this.vitest.state.idMap.get(testId), entity = task && this.vitest.state.getReportedEntity(task);
8942
+ 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;
9092
8943
  }
9093
8944
  async updated(update, events) {
9094
- this.vitest.state.updateTasks(update);
8945
+ this.syncUpdateStacks(update), this.vitest.state.updateTasks(update);
9095
8946
  for (const [id, event, data] of events) await this.reportEvent(id, event, data).catch((error) => {
9096
- this.vitest.state.catchError(serializeError(error), "Unhandled Reporter Error");
8947
+ this.vitest.state.catchError(serializeError$1(error), "Unhandled Reporter Error");
9097
8948
  });
9098
8949
  // TODO: what is the order or reports here?
9099
8950
  // "onTaskUpdate" in parallel with others or before all or after all?
@@ -9101,30 +8952,32 @@ class TestRun {
9101
8952
  await this.vitest.report("onTaskUpdate", update, events);
9102
8953
  }
9103
8954
  async end(specifications, errors, coverage) {
8955
+ if (coverage) await this.vitest.report("onCoverage", coverage);
9104
8956
  // specification won't have the File task if they were filtered by the --shard command
9105
- const modules = specifications.map((spec) => spec.testModule).filter((s) => s != null);
9106
- const files = modules.map((m) => m.task);
9107
- const state = this.vitest.isCancelling ? "interrupted" : this.hasFailed(modules) ? "failed" : "passed";
8957
+ const modules = specifications.map((spec) => spec.testModule).filter((s) => s != null), state = this.vitest.isCancelling ? "interrupted" : this.hasFailed(modules) ? "failed" : "passed";
9108
8958
  if (state !== "passed") process.exitCode = 1;
9109
- try {
9110
- await Promise.all([this.vitest.report("onTestRunEnd", modules, [...errors], state), this.vitest.report("onFinished", files, errors, coverage)]);
9111
- } finally {
9112
- if (coverage) await this.vitest.report("onCoverage", coverage);
9113
- }
8959
+ this.vitest.report("onTestRunEnd", modules, [...errors], state);
9114
8960
  }
9115
8961
  hasFailed(modules) {
9116
- if (!modules.length) return !this.vitest.config.passWithNoTests;
9117
- return modules.some((m) => !m.ok());
8962
+ return modules.length ? modules.some((m) => !m.ok()) : !this.vitest.config.passWithNoTests;
8963
+ }
8964
+ syncUpdateStacks(update) {
8965
+ update.forEach(([taskId, result]) => {
8966
+ const task = this.vitest.state.idMap.get(taskId), isBrowser = task && task.file.pool === "browser";
8967
+ result?.errors?.forEach((error) => {
8968
+ if (isPrimitive(error)) return;
8969
+ const project = this.vitest.getProjectByName(task.file.projectName || "");
8970
+ if (isBrowser) error.stacks = project.browser?.parseErrorStacktrace(error, { frameFilter: project.config.onStackTrace }) || [];
8971
+ else error.stacks = parseErrorStacktrace(error, { frameFilter: project.config.onStackTrace });
8972
+ });
8973
+ });
9118
8974
  }
9119
8975
  async reportEvent(id, event, data) {
9120
- const task = this.vitest.state.idMap.get(id);
9121
- const entity = task && this.vitest.state.getReportedEntity(task);
9122
- assert$1(task && entity, `Entity must be found for task ${task?.name || id}`);
9123
- if (event === "suite-prepare" && entity.type === "suite") return await this.vitest.report("onTestSuiteReady", entity);
8976
+ const task = this.vitest.state.idMap.get(id), entity = task && this.vitest.state.getReportedEntity(task);
8977
+ 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);
9124
8978
  if (event === "suite-prepare" && entity.type === "module") return await this.vitest.report("onTestModuleStart", entity);
9125
8979
  if (event === "suite-finished") {
9126
- assert$1(entity.type === "suite" || entity.type === "module", "Entity type must be suite or module");
9127
- if (entity.state() === "skipped")
8980
+ if (assert$1(entity.type === "suite" || entity.type === "module", "Entity type must be suite or module"), entity.state() === "skipped")
9128
8981
  // everything inside suite or a module is skipped,
9129
8982
  // so we won't get any children events
9130
8983
  // we need to report everything manually
@@ -9136,8 +8989,7 @@ class TestRun {
9136
8989
  if (event === "test-prepare" && entity.type === "test") return await this.vitest.report("onTestCaseReady", entity);
9137
8990
  if (event === "test-finished" && entity.type === "test") return await this.vitest.report("onTestCaseResult", entity);
9138
8991
  if (event.startsWith("before-hook") || event.startsWith("after-hook")) {
9139
- const isBefore = event.startsWith("before-hook");
9140
- const hook = entity.type === "test" ? {
8992
+ const isBefore = event.startsWith("before-hook"), hook = entity.type === "test" ? {
9141
8993
  name: isBefore ? "beforeEach" : "afterEach",
9142
8994
  entity
9143
8995
  } : {
@@ -9149,37 +9001,25 @@ class TestRun {
9149
9001
  // this can only happen in --merge-reports, and annotation is already resolved
9150
9002
  if (event === "test-annotation") {
9151
9003
  const annotation = data?.annotation;
9152
- assert$1(annotation && entity.type === "test");
9153
- await this.vitest.report("onTestCaseAnnotate", entity, annotation);
9004
+ assert$1(annotation && entity.type === "test"), await this.vitest.report("onTestCaseAnnotate", entity, annotation);
9154
9005
  }
9155
9006
  }
9156
9007
  }
9157
9008
  async resolveTestAttachment(test, annotation) {
9158
- const project = test.project;
9159
- const attachment = annotation.attachment;
9009
+ const project = test.project, attachment = annotation.attachment;
9160
9010
  if (!attachment) return attachment;
9161
9011
  const path = attachment.path;
9162
9012
  if (path && !path.startsWith("http://") && !path.startsWith("https://")) {
9163
- const currentPath = resolve(project.config.root, path);
9164
- const hash = createHash("sha1").update(currentPath).digest("hex");
9165
- const newPath = resolve(project.config.attachmentsDir, `${sanitizeFilePath(annotation.message)}-${hash}${extname(currentPath)}`);
9166
- await mkdir(dirname(newPath), { recursive: true });
9167
- await copyFile(currentPath, newPath);
9168
- attachment.path = newPath;
9013
+ const currentPath = resolve(project.config.root, path), hash = createHash("sha1").update(currentPath).digest("hex"), newPath = resolve(project.config.attachmentsDir, `${sanitizeFilePath(annotation.message)}-${hash}${extname(currentPath)}`);
9014
+ await mkdir(dirname(newPath), { recursive: true }), await copyFile(currentPath, newPath), attachment.path = newPath;
9169
9015
  const contentType = attachment.contentType ?? mime.getType(basename(currentPath));
9170
9016
  attachment.contentType = contentType || void 0;
9171
9017
  }
9172
9018
  return attachment;
9173
9019
  }
9174
9020
  async reportChildren(children) {
9175
- for (const child of children) if (child.type === "test") {
9176
- await this.vitest.report("onTestCaseReady", child);
9177
- await this.vitest.report("onTestCaseResult", child);
9178
- } else {
9179
- await this.vitest.report("onTestSuiteReady", child);
9180
- await this.reportChildren(child.children);
9181
- await this.vitest.report("onTestSuiteResult", child);
9182
- }
9021
+ for (const child of children) if (child.type === "test") await this.vitest.report("onTestCaseReady", child), await this.vitest.report("onTestCaseResult", child);
9022
+ else await this.vitest.report("onTestSuiteReady", child), await this.reportChildren(child.children), await this.vitest.report("onTestSuiteResult", child);
9183
9023
  }
9184
9024
  }
9185
9025
  function sanitizeFilePath(s) {
@@ -9207,23 +9047,15 @@ class VitestWatcher {
9207
9047
  * @internal
9208
9048
  */
9209
9049
  onWatcherRerun(cb) {
9210
- this._onRerun.push(cb);
9211
- return this;
9050
+ return this._onRerun.push(cb), this;
9212
9051
  }
9213
9052
  unregisterWatcher = noop;
9214
9053
  registerWatcher() {
9215
9054
  const watcher = this.vitest.vite.watcher;
9216
9055
  if (this.vitest.config.forceRerunTriggers.length) watcher.add(this.vitest.config.forceRerunTriggers);
9217
- watcher.on("change", this.onChange);
9218
- watcher.on("unlink", this.onUnlink);
9219
- watcher.on("add", this.onAdd);
9220
- this.unregisterWatcher = () => {
9221
- watcher.off("change", this.onChange);
9222
- watcher.off("unlink", this.onUnlink);
9223
- watcher.off("add", this.onAdd);
9224
- this.unregisterWatcher = noop;
9225
- };
9226
- return this;
9056
+ return watcher.on("change", this.onFileChange), watcher.on("unlink", this.onFileDelete), watcher.on("add", this.onFileCreate), this.unregisterWatcher = () => {
9057
+ watcher.off("change", this.onFileChange), watcher.off("unlink", this.onFileDelete), watcher.off("add", this.onFileCreate), this.unregisterWatcher = noop;
9058
+ }, this;
9227
9059
  }
9228
9060
  scheduleRerun(file) {
9229
9061
  this._onRerun.forEach((cb) => cb(file));
@@ -9231,25 +9063,17 @@ class VitestWatcher {
9231
9063
  getTestFilesFromWatcherTrigger(id) {
9232
9064
  if (!this.vitest.config.watchTriggerPatterns) return false;
9233
9065
  let triggered = false;
9234
- this.vitest.config.watchTriggerPatterns.forEach((definition) => {
9066
+ return this.vitest.config.watchTriggerPatterns.forEach((definition) => {
9235
9067
  const exec = definition.pattern.exec(id);
9236
9068
  if (exec) {
9237
9069
  const files = definition.testsToRun(id, exec);
9238
- if (Array.isArray(files)) {
9239
- triggered = true;
9240
- files.forEach((file) => this.changedTests.add(resolve(this.vitest.config.root, file)));
9241
- } else if (typeof files === "string") {
9242
- triggered = true;
9243
- this.changedTests.add(resolve(this.vitest.config.root, files));
9244
- }
9070
+ if (Array.isArray(files)) triggered = true, files.forEach((file) => this.changedTests.add(resolve(this.vitest.config.root, file)));
9071
+ else if (typeof files === "string") triggered = true, this.changedTests.add(resolve(this.vitest.config.root, files));
9245
9072
  }
9246
- });
9247
- return triggered;
9073
+ }), triggered;
9248
9074
  }
9249
- onChange = (id) => {
9250
- id = slash(id);
9251
- this.vitest.logger.clearHighlightCache(id);
9252
- this.vitest.invalidateFile(id);
9075
+ onFileChange = (id) => {
9076
+ id = slash(id), this.vitest.logger.clearHighlightCache(id), this.vitest.invalidateFile(id);
9253
9077
  const testFiles = this.getTestFilesFromWatcherTrigger(id);
9254
9078
  if (testFiles) this.scheduleRerun(id);
9255
9079
  else {
@@ -9257,22 +9081,11 @@ class VitestWatcher {
9257
9081
  if (needsRerun) this.scheduleRerun(id);
9258
9082
  }
9259
9083
  };
9260
- onUnlink = (id) => {
9261
- id = slash(id);
9262
- this.vitest.logger.clearHighlightCache(id);
9263
- this.invalidates.add(id);
9264
- if (this.vitest.state.filesMap.has(id)) {
9265
- this.vitest.projects.forEach((project) => project._removeCachedTestFile(id));
9266
- this.vitest.state.filesMap.delete(id);
9267
- this.vitest.cache.results.removeFromCache(id);
9268
- this.vitest.cache.stats.removeStats(id);
9269
- this.changedTests.delete(id);
9270
- this.vitest.report("onTestRemoved", id);
9271
- }
9084
+ onFileDelete = (id) => {
9085
+ 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);
9272
9086
  };
9273
- onAdd = (id) => {
9274
- id = slash(id);
9275
- this.vitest.invalidateFile(id);
9087
+ onFileCreate = (id) => {
9088
+ id = slash(id), this.vitest.invalidateFile(id);
9276
9089
  const testFiles = this.getTestFilesFromWatcherTrigger(id);
9277
9090
  if (testFiles) {
9278
9091
  this.scheduleRerun(id);
@@ -9280,13 +9093,10 @@ class VitestWatcher {
9280
9093
  }
9281
9094
  let fileContent;
9282
9095
  const matchingProjects = [];
9283
- this.vitest.projects.forEach((project) => {
9096
+ if (this.vitest.projects.forEach((project) => {
9284
9097
  if (project.matchesTestGlob(id, () => fileContent ??= readFileSync(id, "utf-8"))) matchingProjects.push(project);
9285
- });
9286
- if (matchingProjects.length > 0) {
9287
- this.changedTests.add(id);
9288
- this.scheduleRerun(id);
9289
- } else {
9098
+ }), matchingProjects.length > 0) this.changedTests.add(id), this.scheduleRerun(id);
9099
+ else {
9290
9100
  // it's possible that file was already there but watcher triggered "add" event instead
9291
9101
  const needsRerun = this.handleFileChanged(id);
9292
9102
  if (needsRerun) this.scheduleRerun(id);
@@ -9294,51 +9104,33 @@ class VitestWatcher {
9294
9104
  };
9295
9105
  handleSetupFile(filepath) {
9296
9106
  let isSetupFile = false;
9297
- this.vitest.projects.forEach((project) => {
9298
- if (!project.config.setupFiles.includes(filepath)) return;
9299
- this.vitest.state.filesMap.forEach((files) => {
9107
+ return this.vitest.projects.forEach((project) => {
9108
+ project.config.setupFiles.includes(filepath) && this.vitest.state.filesMap.forEach((files) => {
9300
9109
  files.forEach((file) => {
9301
- if (file.projectName === project.name) {
9302
- isSetupFile = true;
9303
- this.changedTests.add(file.filepath);
9304
- }
9110
+ if (file.projectName === project.name) isSetupFile = true, this.changedTests.add(file.filepath);
9305
9111
  });
9306
9112
  });
9307
- });
9308
- return isSetupFile;
9113
+ }), isSetupFile;
9309
9114
  }
9310
9115
  /**
9311
9116
  * @returns A value indicating whether rerun is needed (changedTests was mutated)
9312
9117
  */
9313
9118
  handleFileChanged(filepath) {
9314
9119
  if (this.changedTests.has(filepath) || this.invalidates.has(filepath)) return false;
9315
- if (pm.isMatch(filepath, this.vitest.config.forceRerunTriggers)) {
9316
- this.vitest.state.getFilepaths().forEach((file) => this.changedTests.add(file));
9317
- return true;
9318
- }
9120
+ if (pm.isMatch(filepath, this.vitest.config.forceRerunTriggers)) return this.vitest.state.getFilepaths().forEach((file) => this.changedTests.add(file)), true;
9319
9121
  if (this.handleSetupFile(filepath)) return true;
9320
9122
  const projects = this.vitest.projects.filter((project) => {
9321
9123
  const moduleGraph = project.browser?.vite.moduleGraph || project.vite.moduleGraph;
9322
9124
  return moduleGraph.getModulesByFile(filepath)?.size;
9323
9125
  });
9324
- if (!projects.length) {
9325
- // if there are no modules it's possible that server was restarted
9326
- // we don't have information about importers anymore, so let's check if the file is a test file at least
9327
- if (this.vitest.state.filesMap.has(filepath) || this.vitest.projects.some((project) => project._isCachedTestFile(filepath))) {
9328
- this.changedTests.add(filepath);
9329
- return true;
9330
- }
9331
- return false;
9332
- }
9126
+ if (!projects.length) return this.vitest.state.filesMap.has(filepath) || this.vitest.projects.some((project) => project._isCachedTestFile(filepath)) ? (this.changedTests.add(filepath), true) : false;
9333
9127
  const files = [];
9334
9128
  for (const project of projects) {
9335
9129
  const mods = project.browser?.vite.moduleGraph.getModulesByFile(filepath) || project.vite.moduleGraph.getModulesByFile(filepath);
9336
9130
  if (!mods || !mods.size) continue;
9337
- this.invalidates.add(filepath);
9338
9131
  // one of test files that we already run, or one of test files that we can run
9339
- if (this.vitest.state.filesMap.has(filepath) || project._isCachedTestFile(filepath)) {
9340
- this.changedTests.add(filepath);
9341
- files.push(filepath);
9132
+ if (this.invalidates.add(filepath), this.vitest.state.filesMap.has(filepath) || project._isCachedTestFile(filepath)) {
9133
+ this.changedTests.add(filepath), files.push(filepath);
9342
9134
  continue;
9343
9135
  }
9344
9136
  let rerun = false;
@@ -9385,6 +9177,14 @@ class Vitest {
9385
9177
  * If projects were filtered with `--project` flag, they won't appear here.
9386
9178
  */
9387
9179
  projects = [];
9180
+ /**
9181
+ * A watcher handler. This is not the file system watcher. The handler only
9182
+ * exposes methods to handle changed files.
9183
+ *
9184
+ * If you have your own watcher, you can use these methods to replicate
9185
+ * Vitest behaviour.
9186
+ */
9187
+ watcher;
9388
9188
  /** @internal */ configOverride = {};
9389
9189
  /** @internal */ coverageProvider;
9390
9190
  /** @internal */ filenamePattern;
@@ -9401,7 +9201,6 @@ class Vitest {
9401
9201
  isFirstRun = true;
9402
9202
  restartsCount = 0;
9403
9203
  specifications;
9404
- watcher;
9405
9204
  pool;
9406
9205
  _config;
9407
9206
  _vite;
@@ -9409,12 +9208,7 @@ class Vitest {
9409
9208
  _cache;
9410
9209
  _snapshot;
9411
9210
  constructor(mode, cliOptions, options = {}) {
9412
- this.mode = mode;
9413
- this._cliOptions = cliOptions;
9414
- this.logger = new Logger(this, options.stdout, options.stderr);
9415
- this.packageInstaller = options.packageInstaller || new VitestPackageInstaller();
9416
- this.specifications = new VitestSpecifications(this);
9417
- this.watcher = new VitestWatcher(this).onWatcherRerun((file) => this.scheduleRerun([file]));
9211
+ 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));
9418
9212
  }
9419
9213
  _onRestartListeners = [];
9420
9214
  _onClose = [];
@@ -9434,8 +9228,7 @@ class Vitest {
9434
9228
  * The global config.
9435
9229
  */
9436
9230
  get config() {
9437
- assert(this._config, "config");
9438
- return this._config;
9231
+ return assert(this._config, "config"), this._config;
9439
9232
  }
9440
9233
  /** @deprecated use `vitest.vite` instead */
9441
9234
  get server() {
@@ -9445,30 +9238,26 @@ class Vitest {
9445
9238
  * Global Vite's dev server instance.
9446
9239
  */
9447
9240
  get vite() {
9448
- assert(this._vite, "vite", "server");
9449
- return this._vite;
9241
+ return assert(this._vite, "vite", "server"), this._vite;
9450
9242
  }
9451
9243
  /**
9452
9244
  * The global test state manager.
9453
9245
  * @experimental The State API is experimental and not subject to semver.
9454
9246
  */
9455
9247
  get state() {
9456
- assert(this._state, "state");
9457
- return this._state;
9248
+ return assert(this._state, "state"), this._state;
9458
9249
  }
9459
9250
  /**
9460
9251
  * The global snapshot manager. You can access the current state on `snapshot.summary`.
9461
9252
  */
9462
9253
  get snapshot() {
9463
- assert(this._snapshot, "snapshot", "snapshot manager");
9464
- return this._snapshot;
9254
+ return assert(this._snapshot, "snapshot", "snapshot manager"), this._snapshot;
9465
9255
  }
9466
9256
  /**
9467
9257
  * Test results and test file stats cache. Primarily used by the sequencer to sort tests.
9468
9258
  */
9469
9259
  get cache() {
9470
- assert(this._cache, "cache");
9471
- return this._cache;
9260
+ return assert(this._cache, "cache"), this._cache;
9472
9261
  }
9473
9262
  /** @deprecated internal */
9474
9263
  setServer(options, server) {
@@ -9476,48 +9265,21 @@ class Vitest {
9476
9265
  }
9477
9266
  /** @internal */
9478
9267
  async _setServer(options, server) {
9479
- this.watcher.unregisterWatcher();
9480
- clearTimeout(this._rerunTimer);
9481
- this.restartsCount += 1;
9482
- this.pool?.close?.();
9483
- this.pool = void 0;
9484
- this.closingPromise = void 0;
9485
- this.projects = [];
9486
- this.coverageProvider = void 0;
9487
- this.runningPromise = void 0;
9488
- this.coreWorkspaceProject = void 0;
9489
- this.specifications.clearCache();
9490
- this._onUserTestsRerun = [];
9491
- this._vite = server;
9268
+ 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;
9492
9269
  const resolved = resolveConfig(this, options, server.config);
9493
- this._config = resolved;
9494
- this._state = new StateManager({ onUnhandledError: resolved.onUnhandledError });
9495
- this._cache = new VitestCache(this.version);
9496
- this._snapshot = new SnapshotManager({ ...resolved.snapshotOptions });
9497
- this._testRun = new TestRun(this);
9498
- if (this.config.watch) this.watcher.registerWatcher();
9270
+ 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();
9499
9271
  this._resolver = new VitestResolver(server.config.cacheDir, resolved);
9500
9272
  const environment = server.environments.__vitest__;
9501
- this.runner = new ServerModuleRunner(environment, this._resolver, resolved);
9502
- if (this.config.watch) {
9273
+ if (this.runner = new ServerModuleRunner(environment, this._resolver, resolved), this.config.watch) {
9503
9274
  // hijack server restart
9504
9275
  const serverRestart = server.restart;
9505
- server.restart = async (...args) => {
9506
- await Promise.all(this._onRestartListeners.map((fn) => fn()));
9507
- this.report("onServerRestart");
9508
- await this.close();
9509
- await serverRestart(...args);
9510
- };
9511
9276
  // since we set `server.hmr: false`, Vite does not auto restart itself
9512
- server.watcher.on("change", async (file) => {
9277
+ server.restart = async (...args) => {
9278
+ await Promise.all(this._onRestartListeners.map((fn) => fn())), this.report("onServerRestart"), await this.close(), await serverRestart(...args);
9279
+ }, server.watcher.on("change", async (file) => {
9513
9280
  file = normalize(file);
9514
9281
  const isConfig = file === server.config.configFile || this.projects.some((p) => p.vite.config.configFile === file);
9515
- if (isConfig) {
9516
- await Promise.all(this._onRestartListeners.map((fn) => fn("config")));
9517
- this.report("onServerRestart", "config");
9518
- await this.close();
9519
- await serverRestart();
9520
- }
9282
+ if (isConfig) await Promise.all(this._onRestartListeners.map((fn) => fn("config"))), this.report("onServerRestart", "config"), await this.close(), await serverRestart();
9521
9283
  });
9522
9284
  }
9523
9285
  this.cache.results.setConfig(resolved.root, resolved.cache);
@@ -9525,28 +9287,24 @@ class Vitest {
9525
9287
  await this.cache.results.readFromCache();
9526
9288
  } catch {}
9527
9289
  const projects = await this.resolveProjects(this._cliOptions);
9528
- this.projects = projects;
9529
- await Promise.all(projects.flatMap((project) => {
9290
+ if (this.projects = projects, await Promise.all(projects.flatMap((project) => {
9530
9291
  const hooks = project.vite.config.getSortedPluginHooks("configureVitest");
9531
9292
  return hooks.map((hook) => hook({
9532
9293
  project,
9533
9294
  vitest: this,
9534
9295
  injectTestProjects: this.injectTestProject
9535
9296
  }));
9536
- }));
9537
- if (this._cliOptions.browser?.enabled) {
9297
+ })), this._cliOptions.browser?.enabled) {
9538
9298
  const browserProjects = this.projects.filter((p) => p.config.browser.enabled);
9539
9299
  if (!browserProjects.length) throw new Error(`Vitest received --browser flag, but no project had a browser configuration.`);
9540
9300
  }
9541
9301
  if (!this.projects.length) {
9542
9302
  const filter = toArray(resolved.project).join("\", \"");
9543
- if (filter) throw new Error(`No projects matched the filter "${filter}".`);
9544
- else throw new Error(`Vitest wasn't able to resolve any project.`);
9303
+ throw filter ? new Error(`No projects matched the filter "${filter}".`) : new Error(`Vitest wasn't able to resolve any project.`);
9545
9304
  }
9546
9305
  if (!this.coreWorkspaceProject) this.coreWorkspaceProject = TestProject._createBasicProject(this);
9547
9306
  if (this.config.testNamePattern) this.configOverride.testNamePattern = this.config.testNamePattern;
9548
- this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray(resolved.benchmark?.reporters), this.runner) : await createReporters(resolved.reporters, this);
9549
- await Promise.all(this._onSetServer.map((fn) => fn()));
9307
+ 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()));
9550
9308
  }
9551
9309
  /**
9552
9310
  * Inject new test projects into the workspace.
@@ -9554,10 +9312,8 @@ class Vitest {
9554
9312
  * @returns An array of new test projects. Can be empty if the name was filtered out.
9555
9313
  */
9556
9314
  injectTestProject = async (config) => {
9557
- const currentNames = new Set(this.projects.map((p) => p.name));
9558
- const projects = await resolveProjects(this, this._cliOptions, void 0, Array.isArray(config) ? config : [config], currentNames);
9559
- this.projects.push(...projects);
9560
- return projects;
9315
+ const currentNames = new Set(this.projects.map((p) => p.name)), projects = await resolveProjects(this, this._cliOptions, void 0, Array.isArray(config) ? config : [config], currentNames);
9316
+ return this.projects.push(...projects), projects;
9561
9317
  };
9562
9318
  /**
9563
9319
  * Provide a value to the test context. This value will be available to all tests with `inject`.
@@ -9573,9 +9329,7 @@ class Vitest {
9573
9329
  }
9574
9330
  /** @internal */
9575
9331
  _ensureRootProject() {
9576
- if (this.coreWorkspaceProject) return this.coreWorkspaceProject;
9577
- this.coreWorkspaceProject = TestProject._createBasicProject(this);
9578
- return this.coreWorkspaceProject;
9332
+ return this.coreWorkspaceProject ||= TestProject._createBasicProject(this), this.coreWorkspaceProject;
9579
9333
  }
9580
9334
  /** @deprecated use `getRootProject` instead */
9581
9335
  getCoreWorkspaceProject() {
@@ -9592,8 +9346,7 @@ class Vitest {
9592
9346
  * @deprecated use Reported Task API instead
9593
9347
  */
9594
9348
  getProjectByTaskId(taskId) {
9595
- const task = this.state.idMap.get(taskId);
9596
- const projectName = task.projectName || task?.file?.projectName || "";
9349
+ const task = this.state.idMap.get(taskId), projectName = task.projectName || task?.file?.projectName || "";
9597
9350
  return this.getProjectByName(projectName);
9598
9351
  }
9599
9352
  getProjectByName(name) {
@@ -9608,6 +9361,15 @@ class Vitest {
9608
9361
  import(moduleId) {
9609
9362
  return this.runner.import(moduleId);
9610
9363
  }
9364
+ /**
9365
+ * Creates a coverage provider if `coverage` is enabled in the config.
9366
+ */
9367
+ async createCoverageProvider() {
9368
+ if (this.coverageProvider) return this.coverageProvider;
9369
+ const coverageProvider = await this.initCoverageProvider();
9370
+ if (coverageProvider) await coverageProvider.clean(this.config.coverage.clean);
9371
+ return coverageProvider || null;
9372
+ }
9611
9373
  async resolveProjects(cliOptions) {
9612
9374
  const names = /* @__PURE__ */ new Set();
9613
9375
  if (this.config.projects) return resolveProjects(this, cliOptions, void 0, this.config.projects, names);
@@ -9615,8 +9377,7 @@ class Vitest {
9615
9377
  // user can filter projects with --project flag, `getDefaultTestProject`
9616
9378
  // returns the project only if it matches the filter
9617
9379
  const project = getDefaultTestProject(this);
9618
- if (!project) return [];
9619
- return resolveBrowserProjects(this, new Set([project.name]), [project]);
9380
+ return project ? resolveBrowserProjects(this, new Set([project.name]), [project]) : [];
9620
9381
  }
9621
9382
  /**
9622
9383
  * Glob test files in every project and create a TestSpecification for each file and pool.
@@ -9626,13 +9387,10 @@ class Vitest {
9626
9387
  return this.specifications.globTestSpecifications(filters);
9627
9388
  }
9628
9389
  async initCoverageProvider() {
9629
- if (this.coverageProvider !== void 0) return;
9630
- this.coverageProvider = await getCoverageProvider(this.config.coverage, this.runner);
9631
- if (this.coverageProvider) {
9632
- await this.coverageProvider.initialize(this);
9633
- this.config.coverage = this.coverageProvider.resolveOptions();
9390
+ if (this.coverageProvider === void 0) {
9391
+ if (this.coverageProvider = await getCoverageProvider(this.config.coverage, this.runner), this.coverageProvider) await this.coverageProvider.initialize(this), this.config.coverage = this.coverageProvider.resolveOptions();
9392
+ return this.coverageProvider;
9634
9393
  }
9635
- return this.coverageProvider;
9636
9394
  }
9637
9395
  /**
9638
9396
  * Merge reports from multiple runs located in the specified directory (value from `--merge-reports` if not specified).
@@ -9645,23 +9403,15 @@ class Vitest {
9645
9403
  errors,
9646
9404
  coverages,
9647
9405
  executionTimes
9648
- };
9649
- await this.report("onInit", this);
9650
- await this.report("onPathsCollected", files.flatMap((f) => f.filepath));
9406
+ }, await this.report("onInit", this);
9651
9407
  const specifications = [];
9652
9408
  for (const file of files) {
9653
- const project = this.getProjectByName(file.projectName || "");
9654
- const specification = project.createSpecification(file.filepath, void 0, file.pool);
9409
+ const project = this.getProjectByName(file.projectName || ""), specification = project.createSpecification(file.filepath, void 0, file.pool);
9655
9410
  specifications.push(specification);
9656
9411
  }
9657
- await this.report("onSpecsCollected", specifications.map((spec) => spec.toJSON()));
9658
9412
  await this._testRun.start(specifications).catch(noop);
9659
9413
  for (const file of files) await this._reportFileTask(file);
9660
- this._checkUnhandledErrors(errors);
9661
- await this._testRun.end(specifications, errors).catch(noop);
9662
- await this.initCoverageProvider();
9663
- await this.coverageProvider?.mergeReports?.(coverages);
9664
- return {
9414
+ return this._checkUnhandledErrors(errors), await this._testRun.end(specifications, errors).catch(noop), await this.initCoverageProvider(), await this.coverageProvider?.mergeReports?.(coverages), {
9665
9415
  testModules: this.state.getTestModules(),
9666
9416
  unhandledErrors: this.state.getUnhandledErrors()
9667
9417
  };
@@ -9669,10 +9419,8 @@ class Vitest {
9669
9419
  /** @internal */
9670
9420
  async _reportFileTask(file) {
9671
9421
  const project = this.getProjectByName(file.projectName || "");
9672
- await this._testRun.enqueued(project, file).catch(noop);
9673
- await this._testRun.collected(project, [file]).catch(noop);
9674
- const logs = [];
9675
- const { packs, events } = convertTasksToEvents(file, (task) => {
9422
+ await this._testRun.enqueued(project, file).catch(noop), await this._testRun.collected(project, [file]).catch(noop);
9423
+ const logs = [], { packs, events } = convertTasksToEvents(file, (task) => {
9676
9424
  if (task.logs) logs.push(...task.logs);
9677
9425
  });
9678
9426
  logs.sort((log1, log2) => log1.time - log2.time);
@@ -9681,12 +9429,10 @@ class Vitest {
9681
9429
  }
9682
9430
  async collect(filters) {
9683
9431
  const files = await this.specifications.getRelevantTestSpecifications(filters);
9684
- // if run with --changed, don't exit if no tests are found
9685
- if (!files.length) return {
9432
+ return files.length ? this.collectTests(files) : {
9686
9433
  testModules: [],
9687
9434
  unhandledErrors: []
9688
9435
  };
9689
- return this.collectTests(files);
9690
9436
  }
9691
9437
  /** @deprecated use `getRelevantTestSpecifications` instead */
9692
9438
  listFiles(filters) {
@@ -9709,8 +9455,7 @@ class Vitest {
9709
9455
  */
9710
9456
  async start(filters) {
9711
9457
  try {
9712
- await this.initCoverageProvider();
9713
- await this.coverageProvider?.clean(this.config.coverage.clean);
9458
+ await this.initCoverageProvider(), await this.coverageProvider?.clean(this.config.coverage.clean);
9714
9459
  } finally {
9715
9460
  await this.report("onInit", this);
9716
9461
  }
@@ -9720,20 +9465,13 @@ class Vitest {
9720
9465
  if (!files.length) {
9721
9466
  await this._testRun.start([]);
9722
9467
  const coverage = await this.coverageProvider?.generateCoverage?.({ allTestsRun: true });
9723
- await this._testRun.end([], [], coverage);
9724
- // Report coverage for uncovered files
9725
- await this.reportCoverage(coverage, true);
9726
- if (!this.config.watch || !(this.config.changed || this.config.related?.length)) throw new FilesNotFoundError(this.mode);
9468
+ if (await this._testRun.end([], [], coverage), await this.reportCoverage(coverage, true), !this.config.watch || !(this.config.changed || this.config.related?.length)) throw new FilesNotFoundError(this.mode);
9727
9469
  }
9728
9470
  let testModules = {
9729
9471
  testModules: [],
9730
9472
  unhandledErrors: []
9731
9473
  };
9732
- if (files.length) {
9733
- // populate once, update cache on watch
9734
- await this.cache.stats.populateStats(this.config.root, files);
9735
- testModules = await this.runFiles(files, true);
9736
- }
9474
+ if (files.length) await this.cache.stats.populateStats(this.config.root, files), testModules = await this.runFiles(files, true);
9737
9475
  if (this.config.watch) await this.report("onWatcherStart");
9738
9476
  return testModules;
9739
9477
  }
@@ -9743,14 +9481,11 @@ class Vitest {
9743
9481
  */
9744
9482
  async init() {
9745
9483
  try {
9746
- await this.initCoverageProvider();
9747
- await this.coverageProvider?.clean(this.config.coverage.clean);
9484
+ await this.initCoverageProvider(), await this.coverageProvider?.clean(this.config.coverage.clean);
9748
9485
  } finally {
9749
9486
  await this.report("onInit", this);
9750
9487
  }
9751
- // populate test files cache so watch mode can trigger a file rerun
9752
- await this.globTestSpecifications();
9753
- if (this.config.watch) await this.report("onWatcherStart");
9488
+ if (await this.globTestSpecifications(), this.config.watch) await this.report("onWatcherStart");
9754
9489
  }
9755
9490
  /**
9756
9491
  * @deprecated remove when vscode extension supports "getModuleSpecifications"
@@ -9763,6 +9498,13 @@ class Vitest {
9763
9498
  return this.getModuleSpecifications(file);
9764
9499
  }
9765
9500
  /**
9501
+ * If there is a test run happening, returns a promise that will
9502
+ * resolve when the test run is finished.
9503
+ */
9504
+ async waitForTestRunEnd() {
9505
+ this.runningPromise && await this.runningPromise;
9506
+ }
9507
+ /**
9766
9508
  * Get test specifications associated with the given module. If module is not a test file, an empty array is returned.
9767
9509
  *
9768
9510
  * **Note:** this method relies on a cache generated by `globTestSpecifications`. If the file was not processed yet, use `project.matchesGlobPattern` instead.
@@ -9775,7 +9517,9 @@ class Vitest {
9775
9517
  * Vitest automatically caches test specifications for each file. This method clears the cache for the given file or the whole cache altogether.
9776
9518
  */
9777
9519
  clearSpecificationsCache(moduleId) {
9778
- this.specifications.clearCache(moduleId);
9520
+ if (this.specifications.clearCache(moduleId), !moduleId) this.projects.forEach((project) => {
9521
+ project.testFilesList = null;
9522
+ });
9779
9523
  }
9780
9524
  /**
9781
9525
  * Run tests for the given test specifications. This does not trigger `onWatcher*` events.
@@ -9783,8 +9527,7 @@ class Vitest {
9783
9527
  * @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
9784
9528
  */
9785
9529
  runTestSpecifications(specifications, allTestsRun = false) {
9786
- specifications.forEach((spec) => this.specifications.ensureSpecificationCached(spec));
9787
- return this.runFiles(specifications, allTestsRun);
9530
+ return specifications.forEach((spec) => this.specifications.ensureSpecificationCached(spec)), this.runFiles(specifications, allTestsRun);
9788
9531
  }
9789
9532
  /**
9790
9533
  * Rerun files and trigger `onWatcherRerun`, `onWatcherStart` and `onTestsRerun` events.
@@ -9796,24 +9539,14 @@ class Vitest {
9796
9539
  const files = specifications.map((spec) => spec.moduleId);
9797
9540
  await Promise.all([this.report("onWatcherRerun", files, "rerun test"), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
9798
9541
  const result = await this.runTestSpecifications(specifications, allTestsRun);
9799
- await this.report("onWatcherStart", this.state.getFiles(files));
9800
- return result;
9542
+ return await this.report("onWatcherStart", this.state.getFiles(files)), result;
9801
9543
  }
9802
9544
  async runFiles(specs, allTestsRun) {
9803
- await this._testRun.start(specs);
9804
- // previous run
9805
- await this.runningPromise;
9806
- this._onCancelListeners = [];
9807
- this.isCancelling = false;
9808
- // schedule the new run
9809
- this.runningPromise = (async () => {
9545
+ return await this._testRun.start(specs), await this.runningPromise, this._onCancelListeners = [], this.isCancelling = false, this.runningPromise = (async () => {
9810
9546
  try {
9811
9547
  if (!this.pool) this.pool = createPool(this);
9812
9548
  const invalidates = Array.from(this.watcher.invalidates);
9813
- this.watcher.invalidates.clear();
9814
- this.snapshot.clear();
9815
- this.state.clearErrors();
9816
- if (!this.isFirstRun && this.config.coverage.cleanOnRerun) await this.coverageProvider?.clean();
9549
+ if (this.watcher.invalidates.clear(), this.snapshot.clear(), this.state.clearErrors(), !this.isFirstRun && this.config.coverage.cleanOnRerun) await this.coverageProvider?.clean();
9817
9550
  await this.initializeGlobalSetup(specs);
9818
9551
  try {
9819
9552
  await this.pool.runTests(specs, invalidates);
@@ -9830,21 +9563,24 @@ class Vitest {
9830
9563
  unhandledErrors: this.state.getUnhandledErrors()
9831
9564
  };
9832
9565
  } finally {
9833
- // TODO: wait for coverage only if `onFinished` is defined
9834
- const coverage = await this.coverageProvider?.generateCoverage({ allTestsRun });
9835
- const errors = this.state.getUnhandledErrors();
9836
- this._checkUnhandledErrors(errors);
9837
- await this._testRun.end(specs, errors, coverage);
9838
- await this.reportCoverage(coverage, allTestsRun);
9566
+ const coverage = await this.coverageProvider?.generateCoverage({ allTestsRun }), errors = this.state.getUnhandledErrors();
9567
+ this._checkUnhandledErrors(errors), await this._testRun.end(specs, errors, coverage), await this.reportCoverage(coverage, allTestsRun);
9839
9568
  }
9840
9569
  })().finally(() => {
9841
- this.runningPromise = void 0;
9842
- this.isFirstRun = false;
9843
- // all subsequent runs will treat this as a fresh run
9844
- this.config.changed = false;
9845
- this.config.related = void 0;
9570
+ this.runningPromise = void 0, this.isFirstRun = false, this.config.changed = false, this.config.related = void 0;
9571
+ }), await this.runningPromise;
9572
+ }
9573
+ async experimental_parseSpecifications(specifications, options) {
9574
+ if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecifications\` does not support "${this.mode}" mode.`);
9575
+ 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)));
9576
+ return Promise.all(promises);
9577
+ }
9578
+ async experimental_parseSpecification(specification) {
9579
+ if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecification\` does not support "${this.mode}" mode.`);
9580
+ const file = await astCollectTests(specification.project, specification.moduleId).catch((error) => {
9581
+ return createFailedFileTask(specification.project, specification.moduleId, error);
9846
9582
  });
9847
- return await this.runningPromise;
9583
+ return this.state.collectFiles(specification.project, [file]), this.state.getReportedEntity(file);
9848
9584
  }
9849
9585
  /**
9850
9586
  * Collect tests in specified modules. Vitest will run the files to collect tests.
@@ -9852,19 +9588,10 @@ class Vitest {
9852
9588
  */
9853
9589
  async collectTests(specifications) {
9854
9590
  const filepaths = specifications.map((spec) => spec.moduleId);
9855
- this.state.collectPaths(filepaths);
9856
- // previous run
9857
- await this.runningPromise;
9858
- this._onCancelListeners = [];
9859
- this.isCancelling = false;
9860
- // schedule the new run
9861
- this.runningPromise = (async () => {
9591
+ return this.state.collectPaths(filepaths), await this.runningPromise, this._onCancelListeners = [], this.isCancelling = false, this.runningPromise = (async () => {
9862
9592
  if (!this.pool) this.pool = createPool(this);
9863
9593
  const invalidates = Array.from(this.watcher.invalidates);
9864
- this.watcher.invalidates.clear();
9865
- this.snapshot.clear();
9866
- this.state.clearErrors();
9867
- await this.initializeGlobalSetup(specifications);
9594
+ this.watcher.invalidates.clear(), this.snapshot.clear(), this.state.clearErrors(), await this.initializeGlobalSetup(specifications);
9868
9595
  try {
9869
9596
  await this.pool.collectTests(specifications, invalidates);
9870
9597
  } catch (err) {
@@ -9879,28 +9606,21 @@ class Vitest {
9879
9606
  unhandledErrors: this.state.getUnhandledErrors()
9880
9607
  };
9881
9608
  })().finally(() => {
9882
- this.runningPromise = void 0;
9883
- // all subsequent runs will treat this as a fresh run
9884
- this.config.changed = false;
9885
- this.config.related = void 0;
9886
- });
9887
- return await this.runningPromise;
9609
+ this.runningPromise = void 0, this.config.changed = false, this.config.related = void 0;
9610
+ }), await this.runningPromise;
9888
9611
  }
9889
9612
  /**
9890
9613
  * Gracefully cancel the current test run. Vitest will wait until all running tests are finished before cancelling.
9891
9614
  */
9892
9615
  async cancelCurrentRun(reason) {
9893
- this.isCancelling = true;
9894
- await Promise.all(this._onCancelListeners.splice(0).map((listener) => listener(reason)));
9895
- await this.runningPromise;
9616
+ this.isCancelling = true, await Promise.all(this._onCancelListeners.splice(0).map((listener) => listener(reason))), await this.runningPromise;
9896
9617
  }
9897
9618
  /** @internal */
9898
9619
  async _initBrowserServers() {
9899
9620
  await Promise.all(this.projects.map((p) => p._initBrowserServer()));
9900
9621
  }
9901
9622
  async initializeGlobalSetup(paths) {
9902
- const projects = new Set(paths.map((spec) => spec.project));
9903
- const coreProject = this.getRootProject();
9623
+ const projects = new Set(paths.map((spec) => spec.project)), coreProject = this.getRootProject();
9904
9624
  if (!projects.has(coreProject)) projects.add(coreProject);
9905
9625
  for (const project of projects) await project._initializeGlobalSetup();
9906
9626
  }
@@ -9914,8 +9634,7 @@ class Vitest {
9914
9634
  const specifications = files.flatMap((file) => this.getModuleSpecifications(file));
9915
9635
  await Promise.all([this.report("onWatcherRerun", files, trigger), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
9916
9636
  const testResult = await this.runFiles(specifications, allTestsRun);
9917
- await this.report("onWatcherStart", this.state.getFiles(files));
9918
- return testResult;
9637
+ return await this.report("onWatcherStart", this.state.getFiles(files)), testResult;
9919
9638
  }
9920
9639
  /** @internal */
9921
9640
  async rerunTask(id) {
@@ -9935,9 +9654,8 @@ class Vitest {
9935
9654
  // Empty test name pattern should reset filename pattern as well
9936
9655
  if (pattern === "") this.filenamePattern = void 0;
9937
9656
  const testNamePattern = pattern ? new RegExp(pattern) : void 0;
9938
- this.configOverride.testNamePattern = testNamePattern;
9939
9657
  // filter only test files that have tests matching the pattern
9940
- if (testNamePattern) files = files.filter((filepath) => {
9658
+ if (this.configOverride.testNamePattern = testNamePattern, testNamePattern) files = files.filter((filepath) => {
9941
9659
  const files = this.state.getFiles([filepath]);
9942
9660
  return !files.length || files.some((file) => {
9943
9661
  const tasks = getTasks(file);
@@ -9961,9 +9679,7 @@ class Vitest {
9961
9679
  * @param files The list of files on the file system
9962
9680
  */
9963
9681
  async updateSnapshot(files) {
9964
- // default to failed files
9965
- files = files || [...this.state.getFailedFilepaths(), ...this.snapshot.summary.uncheckedKeysByFile.map((s) => s.filePath)];
9966
- this.enableSnapshotUpdate();
9682
+ files = files || [...this.state.getFailedFilepaths(), ...this.snapshot.summary.uncheckedKeysByFile.map((s) => s.filePath)], this.enableSnapshotUpdate();
9967
9683
  try {
9968
9684
  return await this.rerunFiles(files, "update snapshot", false);
9969
9685
  } finally {
@@ -9981,15 +9697,13 @@ class Vitest {
9981
9697
  this.configOverride.snapshotOptions = {
9982
9698
  updateSnapshot: "all",
9983
9699
  snapshotEnvironment: null
9984
- };
9985
- this.snapshot.options.updateSnapshot = "all";
9700
+ }, this.snapshot.options.updateSnapshot = "all";
9986
9701
  }
9987
9702
  /**
9988
9703
  * Disable the mode that allows updating snapshots when running tests.
9989
9704
  */
9990
9705
  resetSnapshotUpdate() {
9991
- delete this.configOverride.snapshotOptions;
9992
- this.snapshot.options.updateSnapshot = this.config.snapshotOptions.updateSnapshot;
9706
+ delete this.configOverride.snapshotOptions, this.snapshot.options.updateSnapshot = this.config.snapshotOptions.updateSnapshot;
9993
9707
  }
9994
9708
  /**
9995
9709
  * Set the global test name pattern to a regexp.
@@ -10006,42 +9720,28 @@ class Vitest {
10006
9720
  this.configOverride.testNamePattern = void 0;
10007
9721
  }
10008
9722
  _rerunTimer;
10009
- // we can't use a single `triggerId` yet because vscode extension relies on this
10010
9723
  async scheduleRerun(triggerId) {
10011
9724
  const currentCount = this.restartsCount;
10012
- clearTimeout(this._rerunTimer);
10013
- await this.runningPromise;
10014
- clearTimeout(this._rerunTimer);
10015
- // server restarted
10016
- if (this.restartsCount !== currentCount) return;
10017
- this._rerunTimer = setTimeout(async () => {
9725
+ clearTimeout(this._rerunTimer), await this.runningPromise, clearTimeout(this._rerunTimer), this.restartsCount === currentCount && (this._rerunTimer = setTimeout(async () => {
10018
9726
  if (this.watcher.changedTests.size === 0) {
10019
9727
  this.watcher.invalidates.clear();
10020
9728
  return;
10021
9729
  }
10022
9730
  // server restarted
10023
9731
  if (this.restartsCount !== currentCount) return;
10024
- this.isFirstRun = false;
10025
- this.snapshot.clear();
9732
+ this.isFirstRun = false, this.snapshot.clear();
10026
9733
  let files = Array.from(this.watcher.changedTests);
10027
9734
  if (this.filenamePattern) {
10028
9735
  const filteredFiles = await this.globTestSpecifications(this.filenamePattern);
10029
- files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file));
10030
9736
  // A file that does not match the current filename pattern was changed
10031
- if (files.length === 0) return;
9737
+ if (files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file)), files.length === 0) return;
10032
9738
  }
10033
9739
  this.watcher.changedTests.clear();
10034
- const triggerIds = new Set(triggerId.map((id) => relative(this.config.root, id)));
10035
- const triggerLabel = Array.from(triggerIds).join(", ");
10036
- // get file specifications and filter them if needed
10037
- const specifications = files.flatMap((file) => this.getModuleSpecifications(file)).filter((specification) => {
10038
- if (this._onFilterWatchedSpecification.length === 0) return true;
10039
- return this._onFilterWatchedSpecification.every((fn) => fn(specification));
9740
+ const triggerLabel = relative(this.config.root, triggerId), specifications = files.flatMap((file) => this.getModuleSpecifications(file)).filter((specification) => {
9741
+ return this._onFilterWatchedSpecification.length === 0 ? true : this._onFilterWatchedSpecification.every((fn) => fn(specification));
10040
9742
  });
10041
- await Promise.all([this.report("onWatcherRerun", files, triggerLabel), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
10042
- await this.runFiles(specifications, false);
10043
- await this.report("onWatcherStart", this.state.getFiles(files));
10044
- }, WATCHER_DEBOUNCE);
9743
+ 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));
9744
+ }, WATCHER_DEBOUNCE));
10045
9745
  }
10046
9746
  /**
10047
9747
  * Invalidate a file in all projects.
@@ -10065,8 +9765,7 @@ class Vitest {
10065
9765
  }
10066
9766
  async reportCoverage(coverage, allTestsRun) {
10067
9767
  if (this.state.getCountOfFailedTests() > 0) {
10068
- await this.coverageProvider?.onTestFailure?.();
10069
- if (!this.config.coverage.reportOnFailure) return;
9768
+ if (await this.coverageProvider?.onTestFailure?.(), !this.config.coverage.reportOnFailure) return;
10070
9769
  }
10071
9770
  if (this.coverageProvider) {
10072
9771
  await this.coverageProvider.reportCoverage(coverage, { allTestsRun });
@@ -10089,11 +9788,9 @@ class Vitest {
10089
9788
  // it's possible that it's not initialized at all because it's not running any tests
10090
9789
  if (this.coreWorkspaceProject && !this.projects.includes(this.coreWorkspaceProject)) closePromises.push(this.coreWorkspaceProject.close().then(() => this._vite = void 0));
10091
9790
  if (this.pool) closePromises.push((async () => {
10092
- await this.pool?.close?.();
10093
- this.pool = void 0;
9791
+ await this.pool?.close?.(), this.pool = void 0;
10094
9792
  })());
10095
- closePromises.push(...this._onClose.map((fn) => fn()));
10096
- return Promise.allSettled(closePromises).then((results) => {
9793
+ return closePromises.push(...this._onClose.map((fn) => fn())), Promise.allSettled(closePromises).then((results) => {
10097
9794
  results.forEach((r) => {
10098
9795
  if (r.status === "rejected") this.logger.error("error during close", r.reason);
10099
9796
  });
@@ -10106,11 +9803,9 @@ class Vitest {
10106
9803
  * @param force If true, the process will exit immediately after closing the projects.
10107
9804
  */
10108
9805
  async exit(force = false) {
10109
- setTimeout(() => {
9806
+ if (setTimeout(() => {
10110
9807
  this.report("onProcessTimeout").then(() => {
10111
- console.warn(`close timed out after ${this.config.teardownTimeout}ms`);
10112
- this.state.getProcessTimeoutCauses().forEach((cause) => console.warn(cause));
10113
- if (!this.pool) {
9808
+ if (console.warn(`close timed out after ${this.config.teardownTimeout}ms`), this.state.getProcessTimeoutCauses().forEach((cause) => console.warn(cause)), !this.pool) {
10114
9809
  const runningServers = [this._vite, ...this.projects.map((p) => p._vite)].filter(Boolean).length;
10115
9810
  if (runningServers === 1) console.warn("Tests closed successfully but something prevents Vite server from exiting");
10116
9811
  else if (runningServers > 1) console.warn(`Tests closed successfully but something prevents ${runningServers} Vite servers from exiting`);
@@ -10119,9 +9814,7 @@ class Vitest {
10119
9814
  }
10120
9815
  process.exit();
10121
9816
  });
10122
- }, this.config.teardownTimeout).unref();
10123
- await this.close();
10124
- if (force) process.exit();
9817
+ }, this.config.teardownTimeout).unref(), await this.close(), force) process.exit();
10125
9818
  }
10126
9819
  /** @internal */
10127
9820
  async report(name, ...args) {
@@ -10203,9 +9896,7 @@ class Vitest {
10203
9896
  */
10204
9897
  matchesProjectFilter(name) {
10205
9898
  const projects = this._config?.project || this._cliOptions?.project;
10206
- // no filters applied, any project can be included
10207
- if (!projects || !projects.length) return true;
10208
- return toArray(projects).some((project) => {
9899
+ return !projects || !projects.length ? true : toArray(projects).some((project) => {
10209
9900
  const regexp = wildcardPatternToRegExp(project);
10210
9901
  return regexp.test(name);
10211
9902
  });
@@ -10218,8 +9909,7 @@ function assert(condition, property, name = property) {
10218
9909
  async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(options))) {
10219
9910
  const userConfig = deepMerge({}, options);
10220
9911
  async function UIPlugin() {
10221
- await vitest.packageInstaller.ensureInstalled("@vitest/ui", options.root || process.cwd(), vitest.version);
10222
- return (await import('@vitest/ui')).default(vitest);
9912
+ return await vitest.packageInstaller.ensureInstalled("@vitest/ui", options.root || process.cwd(), vitest.version), (await import('@vitest/ui')).default(vitest);
10223
9913
  }
10224
9914
  return [
10225
9915
  {
@@ -10245,14 +9935,9 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
10245
9935
  let open = false;
10246
9936
  if (testConfig.ui && testConfig.open) open = testConfig.uiBase ?? "/__vitest__/";
10247
9937
  const resolveOptions = getDefaultResolveOptions();
10248
- const config = {
9938
+ let config = {
10249
9939
  root: viteConfig.test?.root || options.root,
10250
9940
  define: { "process.env.NODE_ENV": "process.env.NODE_ENV" },
10251
- esbuild: viteConfig.esbuild === false ? false : {
10252
- target: viteConfig.esbuild?.target || "node18",
10253
- sourcemap: "external",
10254
- legalComments: "inline"
10255
- },
10256
9941
  resolve: {
10257
9942
  ...resolveOptions,
10258
9943
  alias: testConfig.alias
@@ -10282,21 +9967,29 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
10282
9967
  deps: testConfig.deps ?? viteConfig.test?.deps
10283
9968
  }
10284
9969
  };
9970
+ if ("rolldownVersion" in vite) config = {
9971
+ ...config,
9972
+ oxc: viteConfig.oxc === false ? false : { target: viteConfig.oxc?.target || "node18" }
9973
+ };
9974
+ else config = {
9975
+ ...config,
9976
+ esbuild: viteConfig.esbuild === false ? false : {
9977
+ target: viteConfig.esbuild?.target || "node18",
9978
+ sourcemap: "external",
9979
+ legalComments: "inline"
9980
+ }
9981
+ };
10285
9982
  // inherit so it's available in VitestOptimizer
10286
9983
  // I cannot wait to rewrite all of this in Vitest 4
10287
9984
  if (options.cache != null) config.test.cache = options.cache;
10288
9985
  if (vitest.configOverride.project)
10289
9986
  // project filter was set by the user, so we need to filter the project
10290
9987
  options.project = vitest.configOverride.project;
10291
- config.customLogger = createViteLogger(vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false });
10292
- config.customLogger = silenceImportViteIgnoreWarning(config.customLogger);
10293
9988
  // chokidar fsevents is unstable on macos when emitting "ready" event
10294
- if (process.platform === "darwin" && false);
9989
+ if (config.customLogger = createViteLogger(vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false }), config.customLogger = silenceImportViteIgnoreWarning(config.customLogger), process.platform === "darwin" && false);
10295
9990
  const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
10296
9991
  if (classNameStrategy !== "scoped") {
10297
- config.css ??= {};
10298
- config.css.modules ??= {};
10299
- if (config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
9992
+ if (config.css ??= {}, config.css.modules ??= {}, config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
10300
9993
  const root = vitest.config.root || options.root || process.cwd();
10301
9994
  return generateScopedClassName(classNameStrategy, name, relative(root, filename));
10302
9995
  };
@@ -10307,17 +10000,11 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
10307
10000
  const viteConfigTest = viteConfig.test || {};
10308
10001
  if (viteConfigTest.watch === false) viteConfigTest.run = true;
10309
10002
  if ("alias" in viteConfigTest) delete viteConfigTest.alias;
10310
- // viteConfig.test is final now, merge it for real
10311
- options = deepMerge({}, configDefaults, viteConfigTest, options);
10312
- options.api = resolveApiServerConfig(options, defaultPort);
10003
+ options = deepMerge({}, configDefaults, viteConfigTest, options), options.api = resolveApiServerConfig(options, defaultPort);
10313
10004
  // we replace every "import.meta.env" with "process.env"
10314
10005
  // to allow reassigning, so we need to put all envs on process.env
10315
10006
  const { PROD, DEV,...envs } = viteConfig.env;
10316
- // process.env can have only string values and will cast string on it if we pass other type,
10317
- // so we are making them truthy
10318
- process.env.PROD ??= PROD ? "1" : "";
10319
- process.env.DEV ??= DEV ? "1" : "";
10320
- for (const name in envs) process.env[name] ??= envs[name];
10007
+ for (const name in process.env.PROD ??= PROD ? "1" : "", process.env.DEV ??= DEV ? "1" : "", envs) process.env[name] ??= envs[name];
10321
10008
  // don't watch files in run mode
10322
10009
  if (!options.watch) viteConfig.server.watch = null;
10323
10010
  if (options.ui)
@@ -10337,8 +10024,7 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
10337
10024
  order: "post",
10338
10025
  async handler(server) {
10339
10026
  if (options.watch && false);
10340
- await vitest._setServer(options, server);
10341
- if (options.api && options.watch) (await Promise.resolve().then(function () { return setup$1; })).setup(vitest);
10027
+ if (await vitest._setServer(options, server), options.api && options.watch) (await Promise.resolve().then(function () { return setup$1; })).setup(vitest);
10342
10028
  // #415, in run mode we don't need the watcher, close it would improve the performance
10343
10029
  if (!options.watch) await server.watcher.close();
10344
10030
  }
@@ -10360,25 +10046,19 @@ function removeUndefinedValues(obj) {
10360
10046
  }
10361
10047
 
10362
10048
  async function createVitest(mode, options, viteOverrides = {}, vitestOptions = {}) {
10363
- const ctx = new Vitest(mode, deepClone(options), vitestOptions);
10364
- const root = slash(resolve$1(options.root || process.cwd()));
10365
- const configPath = options.config === false ? false : options.config ? resolve$1(root, options.config) : await findUp(configFiles, { cwd: root });
10049
+ const ctx = new Vitest(mode, deepClone(options), vitestOptions), root = slash(resolve$1(options.root || process.cwd())), configPath = options.config === false ? false : options.config ? resolve$1(root, options.config) : await findUp(configFiles, { cwd: root });
10366
10050
  options.config = configPath;
10367
- const { browser: _removeBrowser,...restOptions } = options;
10368
- const config = {
10051
+ const { browser: _removeBrowser,...restOptions } = options, config = {
10369
10052
  configFile: configPath,
10370
10053
  configLoader: options.configLoader,
10371
10054
  mode: options.mode || mode,
10372
10055
  plugins: await VitestPlugin(restOptions, ctx)
10373
- };
10374
- const server = await createViteServer(mergeConfig(config, mergeConfig(viteOverrides, { root: options.root })));
10056
+ }, server = await createViteServer(mergeConfig(config, mergeConfig(viteOverrides, { root: options.root })));
10375
10057
  if (ctx.config.api?.port) await server.listen();
10376
10058
  return ctx;
10377
10059
  }
10378
10060
 
10379
- const MAX_RESULT_COUNT = 10;
10380
- const SELECTION_MAX_INDEX = 7;
10381
- const ESC = "\x1B[";
10061
+ const MAX_RESULT_COUNT = 10, SELECTION_MAX_INDEX = 7, ESC = "\x1B[";
10382
10062
  class WatchFilter {
10383
10063
  filterRL;
10384
10064
  currentKeyword = void 0;
@@ -10389,23 +10069,17 @@ class WatchFilter {
10389
10069
  stdin;
10390
10070
  stdout;
10391
10071
  constructor(message, stdin = process.stdin, stdout$1 = stdout()) {
10392
- this.message = message;
10393
- this.stdin = stdin;
10394
- this.stdout = stdout$1;
10395
- this.filterRL = readline.createInterface({
10072
+ if (this.message = message, this.stdin = stdin, this.stdout = stdout$1, this.filterRL = readline.createInterface({
10396
10073
  input: this.stdin,
10397
10074
  escapeCodeTimeout: 50
10398
- });
10399
- readline.emitKeypressEvents(this.stdin, this.filterRL);
10400
- if (this.stdin.isTTY) this.stdin.setRawMode(true);
10075
+ }), readline.emitKeypressEvents(this.stdin, this.filterRL), this.stdin.isTTY) this.stdin.setRawMode(true);
10401
10076
  }
10402
10077
  async filter(filterFunc) {
10403
10078
  this.write(this.promptLine());
10404
10079
  const resultPromise = createDefer();
10405
10080
  this.onKeyPress = this.filterHandler(filterFunc, (result) => {
10406
10081
  resultPromise.resolve(result);
10407
- });
10408
- this.stdin.on("keypress", this.onKeyPress);
10082
+ }), this.stdin.on("keypress", this.onKeyPress);
10409
10083
  try {
10410
10084
  return await resultPromise;
10411
10085
  } finally {
@@ -10421,13 +10095,11 @@ class WatchFilter {
10421
10095
  break;
10422
10096
  case key?.ctrl && key?.name === "c":
10423
10097
  case key?.name === "escape":
10424
- this.write(`${ESC}1G${ESC}0J`);
10425
- onSubmit(void 0);
10098
+ this.write(`${ESC}1G${ESC}0J`), onSubmit(void 0);
10426
10099
  return;
10427
10100
  case key?.name === "enter":
10428
10101
  case key?.name === "return":
10429
- onSubmit(this.results[this.selectionIndex] || this.currentKeyword || "");
10430
- this.currentKeyword = void 0;
10102
+ onSubmit(this.results[this.selectionIndex] || this.currentKeyword || ""), this.currentKeyword = void 0;
10431
10103
  break;
10432
10104
  case key?.name === "up":
10433
10105
  if (this.selectionIndex && this.selectionIndex > 0) this.selectionIndex--;
@@ -10454,17 +10126,13 @@ class WatchFilter {
10454
10126
  const resultCountLine = this.results.length === 1 ? `Pattern matches ${this.results.length} result` : `Pattern matches ${this.results.length} results`;
10455
10127
  let resultBody = "";
10456
10128
  if (this.results.length > MAX_RESULT_COUNT) {
10457
- const offset = this.selectionIndex > SELECTION_MAX_INDEX ? this.selectionIndex - SELECTION_MAX_INDEX : 0;
10458
- const displayResults = this.results.slice(offset, MAX_RESULT_COUNT + offset);
10459
- const remainingResultCount = this.results.length - offset - displayResults.length;
10460
- resultBody = `${displayResults.map((result, index) => index + offset === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n")}`;
10461
- if (remainingResultCount > 0) resultBody += `
10129
+ const offset = this.selectionIndex > SELECTION_MAX_INDEX ? this.selectionIndex - SELECTION_MAX_INDEX : 0, displayResults = this.results.slice(offset, MAX_RESULT_COUNT + offset), remainingResultCount = this.results.length - offset - displayResults.length;
10130
+ if (resultBody = `${displayResults.map((result, index) => index + offset === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n")}`, remainingResultCount > 0) resultBody += `
10462
10131
  ${c.dim(` ...and ${remainingResultCount} more ${remainingResultCount === 1 ? "result" : "results"}`)}`;
10463
10132
  } else resultBody = this.results.map((result, index) => index === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n");
10464
10133
  printStr += `\n${resultCountLine}\n${resultBody}`;
10465
10134
  }
10466
- this.eraseAndPrint(printStr);
10467
- this.restoreCursor();
10135
+ this.eraseAndPrint(printStr), this.restoreCursor();
10468
10136
  }
10469
10137
  keywordOffset() {
10470
10138
  return `? ${this.message} › `.length + 1;
@@ -10480,14 +10148,10 @@ ${c.dim(` ...and ${remainingResultCount} more ${remainingResultCount === 1 ? "
10480
10148
  // We have to take care of screen width in case of long lines
10481
10149
  rows += 1 + Math.floor(Math.max(stripVTControlCharacters(line).length - 1, 0) / columns);
10482
10150
  }
10483
- this.write(`${ESC}1G`);
10484
- this.write(`${ESC}J`);
10485
- this.write(str);
10486
- this.write(`${ESC}${rows - 1}A`);
10151
+ this.write(`${ESC}1G`), this.write(`${ESC}J`), this.write(str), this.write(`${ESC}${rows - 1}A`);
10487
10152
  }
10488
10153
  close() {
10489
- this.filterRL.close();
10490
- if (this.onKeyPress) this.stdin.removeListener("keypress", this.onKeyPress);
10154
+ if (this.filterRL.close(), this.onKeyPress) this.stdin.removeListener("keypress", this.onKeyPress);
10491
10155
  if (this.stdin.isTTY) this.stdin.setRawMode(false);
10492
10156
  }
10493
10157
  restoreCursor() {
@@ -10512,8 +10176,7 @@ const keys = [
10512
10176
  ["w", "filter by a project name"],
10513
10177
  ["b", "start the browser server if not started yet"],
10514
10178
  ["q", "quit"]
10515
- ];
10516
- const cancelKeys = [
10179
+ ], cancelKeys = [
10517
10180
  "space",
10518
10181
  "c",
10519
10182
  "h",
@@ -10531,17 +10194,12 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
10531
10194
  // Cancel run and exit when ctrl-c or esc is pressed.
10532
10195
  // If cancelling takes long and key is pressed multiple times, exit forcefully.
10533
10196
  if (str === "" || str === "\x1B" || key && key.ctrl && key.name === "c") {
10534
- if (!ctx.isCancelling) {
10535
- ctx.logger.log(c.red("Cancelling test run. Press CTRL+c again to exit forcefully.\n"));
10536
- process.exitCode = 130;
10537
- await ctx.cancelCurrentRun("keyboard-input");
10538
- }
10197
+ if (!ctx.isCancelling) ctx.logger.log(c.red("Cancelling test run. Press CTRL+c again to exit forcefully.\n")), process.exitCode = 130, await ctx.cancelCurrentRun("keyboard-input");
10539
10198
  return ctx.exit(true);
10540
10199
  }
10541
10200
  // window not support suspend
10542
10201
  if (!isWindows && key && key.ctrl && key.name === "z") {
10543
- process.kill(process.ppid, "SIGTSTP");
10544
- process.kill(process.pid, "SIGTSTP");
10202
+ process.kill(process.ppid, "SIGTSTP"), process.kill(process.pid, "SIGTSTP");
10545
10203
  return;
10546
10204
  }
10547
10205
  const name = key?.name;
@@ -10570,24 +10228,17 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
10570
10228
  if (name === "t") return inputNamePattern();
10571
10229
  // change fileNamePattern
10572
10230
  if (name === "p") return inputFilePattern();
10573
- if (name === "b") {
10574
- await ctx._initBrowserServers();
10575
- ctx.projects.forEach((project) => {
10576
- ctx.logger.log();
10577
- ctx.logger.printBrowserBanner(project);
10578
- });
10579
- return null;
10580
- }
10231
+ if (name === "b") return await ctx._initBrowserServers(), ctx.projects.forEach((project) => {
10232
+ ctx.logger.log(), ctx.logger.printBrowserBanner(project);
10233
+ }), null;
10581
10234
  }
10582
10235
  async function keypressHandler(str, key) {
10583
10236
  await _keypressHandler(str, key);
10584
10237
  }
10585
10238
  async function inputNamePattern() {
10586
10239
  off();
10587
- const watchFilter = new WatchFilter("Input test name pattern (RegExp)", stdin, stdout);
10588
- const filter = await watchFilter.filter((str) => {
10589
- const files = ctx.state.getFiles();
10590
- const tests = getTests(files);
10240
+ const watchFilter = new WatchFilter("Input test name pattern (RegExp)", stdin, stdout), filter = await watchFilter.filter((str) => {
10241
+ const files = ctx.state.getFiles(), tests = getTests(files);
10591
10242
  try {
10592
10243
  const reg = new RegExp(str);
10593
10244
  return tests.map((test) => test.name).filter((testName) => testName.match(reg));
@@ -10596,11 +10247,8 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
10596
10247
  return [];
10597
10248
  }
10598
10249
  });
10599
- on();
10600
- if (typeof filter === "undefined") return;
10601
- const files = ctx.state.getFilepaths();
10602
- // if running in standalone mode, Vitest instance doesn't know about any test file
10603
- const cliFiles = ctx.config.standalone && !files.length ? await ctx._globTestFilepaths() : void 0;
10250
+ if (on(), typeof filter === "undefined") return;
10251
+ const files = ctx.state.getFilepaths(), cliFiles = ctx.config.standalone && !files.length ? await ctx._globTestFilepaths() : void 0;
10604
10252
  await ctx.changeNamePattern(filter?.trim() || "", cliFiles, "change pattern");
10605
10253
  }
10606
10254
  async function inputProjectName() {
@@ -10611,41 +10259,31 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
10611
10259
  message: "Input a single project name",
10612
10260
  initial: ctx.config.project[0] || ""
10613
10261
  }]);
10614
- on();
10615
- await ctx.changeProjectName(filter.trim());
10262
+ on(), await ctx.changeProjectName(filter.trim());
10616
10263
  }
10617
10264
  async function inputFilePattern() {
10618
10265
  off();
10619
- const watchFilter = new WatchFilter("Input filename pattern", stdin, stdout);
10620
- const filter = await watchFilter.filter(async (str) => {
10266
+ const watchFilter = new WatchFilter("Input filename pattern", stdin, stdout), filter = await watchFilter.filter(async (str) => {
10621
10267
  const files = await ctx.globTestFiles([str]);
10622
10268
  return files.map((file) => relative(ctx.config.root, file[1])).filter((file, index, all) => all.indexOf(file) === index);
10623
10269
  });
10624
- on();
10625
- if (typeof filter === "undefined") return;
10270
+ if (on(), typeof filter === "undefined") return;
10626
10271
  latestFilename = filter?.trim() || "";
10627
10272
  const lastResults = watchFilter.getLastResults();
10628
10273
  await ctx.changeFilenamePattern(latestFilename, filter && lastResults.length ? lastResults.map((i) => resolve(ctx.config.root, i)) : void 0);
10629
10274
  }
10630
10275
  let rl;
10631
10276
  function on() {
10632
- off();
10633
- rl = readline.createInterface({
10277
+ if (off(), rl = readline.createInterface({
10634
10278
  input: stdin,
10635
10279
  escapeCodeTimeout: 50
10636
- });
10637
- readline.emitKeypressEvents(stdin, rl);
10638
- if (stdin.isTTY) stdin.setRawMode(true);
10280
+ }), readline.emitKeypressEvents(stdin, rl), stdin.isTTY) stdin.setRawMode(true);
10639
10281
  stdin.on("keypress", keypressHandler);
10640
10282
  }
10641
10283
  function off() {
10642
- rl?.close();
10643
- rl = void 0;
10644
- stdin.removeListener("keypress", keypressHandler);
10645
- if (stdin.isTTY) stdin.setRawMode(false);
10284
+ if (rl?.close(), rl = void 0, stdin.removeListener("keypress", keypressHandler), stdin.isTTY) stdin.setRawMode(false);
10646
10285
  }
10647
- on();
10648
- return function cleanup() {
10286
+ return on(), function cleanup() {
10649
10287
  off();
10650
10288
  };
10651
10289
  }
@@ -10656,20 +10294,14 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
10656
10294
  * Returns a Vitest instance if initialized successfully.
10657
10295
  */
10658
10296
  async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, vitestOptions) {
10659
- const root = resolve(options.root || process.cwd());
10660
- const ctx = await prepareVitest(mode, options, viteOverrides, vitestOptions, cliFilters);
10297
+ const root = resolve(options.root || process.cwd()), ctx = await prepareVitest(mode, options, viteOverrides, vitestOptions, cliFilters);
10661
10298
  if (mode === "test" && ctx.config.coverage.enabled) {
10662
- const provider = ctx.config.coverage.provider || "v8";
10663
- const requiredPackages = CoverageProviderMap[provider];
10299
+ const provider = ctx.config.coverage.provider || "v8", requiredPackages = CoverageProviderMap[provider];
10664
10300
  if (requiredPackages) {
10665
- if (!await ctx.packageInstaller.ensureInstalled(requiredPackages, root, ctx.version)) {
10666
- process.exitCode = 1;
10667
- return ctx;
10668
- }
10301
+ if (!await ctx.packageInstaller.ensureInstalled(requiredPackages, root, ctx.version)) return process.exitCode = 1, ctx;
10669
10302
  }
10670
10303
  }
10671
- const stdin = vitestOptions?.stdin || process.stdin;
10672
- const stdout = vitestOptions?.stdout || process.stdout;
10304
+ const stdin = vitestOptions?.stdin || process.stdin, stdout = vitestOptions?.stdout || process.stdout;
10673
10305
  let stdinCleanup;
10674
10306
  if (stdin.isTTY && ctx.config.watch) stdinCleanup = registerConsoleShortcuts(ctx, stdin, stdout);
10675
10307
  ctx.onAfterSetServer(() => {
@@ -10681,55 +10313,27 @@ async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, v
10681
10313
  else if (ctx.config.standalone) await ctx.init();
10682
10314
  else await ctx.start(cliFilters);
10683
10315
  } catch (e) {
10684
- if (e instanceof FilesNotFoundError) return ctx;
10685
- if (e instanceof GitNotFoundError) {
10686
- ctx.logger.error(e.message);
10687
- return ctx;
10688
- }
10689
- if (e instanceof IncludeTaskLocationDisabledError || e instanceof RangeLocationFilterProvidedError || e instanceof LocationFilterFileNotFoundError) {
10690
- ctx.logger.printError(e, { verbose: false });
10691
- return ctx;
10692
- }
10693
- process.exitCode = 1;
10694
- ctx.logger.printError(e, {
10316
+ return e instanceof FilesNotFoundError ? ctx : e instanceof GitNotFoundError ? (ctx.logger.error(e.message), ctx) : e instanceof IncludeTaskLocationDisabledError || e instanceof RangeLocationFilterProvidedError || e instanceof LocationFilterFileNotFoundError ? (ctx.logger.printError(e, { verbose: false }), ctx) : (process.exitCode = 1, ctx.logger.printError(e, {
10695
10317
  fullStack: true,
10696
10318
  type: "Unhandled Error"
10697
- });
10698
- ctx.logger.error("\n\n");
10699
- return ctx;
10319
+ }), ctx.logger.error("\n\n"), ctx);
10700
10320
  }
10701
- if (ctx.shouldKeepServer()) return ctx;
10702
- stdinCleanup?.();
10703
- await ctx.close();
10704
- return ctx;
10321
+ return ctx.shouldKeepServer() ? ctx : (stdinCleanup?.(), await ctx.close(), ctx);
10705
10322
  }
10706
10323
  async function prepareVitest(mode, options = {}, viteOverrides, vitestOptions, cliFilters) {
10707
- process.env.TEST = "true";
10708
- process.env.VITEST = "true";
10709
- process.env.NODE_ENV ??= "test";
10710
- if (options.run) options.watch = false;
10324
+ if (process.env.TEST = "true", process.env.VITEST = "true", process.env.NODE_ENV ??= "test", options.run) options.watch = false;
10711
10325
  if (options.standalone && (cliFilters?.length || 0) > 0) options.standalone = false;
10712
10326
  // this shouldn't affect _application root_ that can be changed inside config
10713
- const root = resolve(options.root || process.cwd());
10714
- const ctx = await createVitest(mode, options, viteOverrides, vitestOptions);
10715
- const environmentPackage = getEnvPackageName(ctx.config.environment);
10716
- if (environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root)) {
10717
- process.exitCode = 1;
10718
- return ctx;
10719
- }
10720
- return ctx;
10327
+ const root = resolve(options.root || process.cwd()), ctx = await createVitest(mode, options, viteOverrides, vitestOptions), environmentPackage = getEnvPackageName(ctx.config.environment);
10328
+ return environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root) && (process.exitCode = 1), ctx;
10721
10329
  }
10722
10330
  function processCollected(ctx, files, options) {
10723
10331
  let errorsPrinted = false;
10724
- forEachSuite(files, (suite) => {
10332
+ if (forEachSuite(files, (suite) => {
10725
10333
  suite.errors().forEach((error) => {
10726
- errorsPrinted = true;
10727
- ctx.logger.printError(error, { project: suite.project });
10334
+ errorsPrinted = true, ctx.logger.printError(error, { project: suite.project });
10728
10335
  });
10729
- });
10730
- if (errorsPrinted) return;
10731
- if (typeof options.json !== "undefined") return processJsonOutput(files, options);
10732
- return formatCollectedAsString(files).forEach((test) => console.log(test));
10336
+ }), !errorsPrinted) return typeof options.json === "undefined" ? formatCollectedAsString(files).forEach((test) => console.log(test)) : processJsonOutput(files, options);
10733
10337
  }
10734
10338
  function outputFileList(files, options) {
10735
10339
  if (typeof options.json !== "undefined") return outputJsonFileList(files, options);
@@ -10739,8 +10343,7 @@ function outputJsonFileList(files, options) {
10739
10343
  if (typeof options.json === "boolean") return console.log(JSON.stringify(formatFilesAsJSON(files), null, 2));
10740
10344
  if (typeof options.json === "string") {
10741
10345
  const jsonPath = resolve(options.root || process.cwd(), options.json);
10742
- mkdirSync(dirname(jsonPath), { recursive: true });
10743
- writeFileSync(jsonPath, JSON.stringify(formatFilesAsJSON(files), null, 2));
10346
+ mkdirSync(dirname(jsonPath), { recursive: true }), writeFileSync(jsonPath, JSON.stringify(formatFilesAsJSON(files), null, 2));
10744
10347
  }
10745
10348
  }
10746
10349
  function formatFilesAsJSON(files) {
@@ -10761,8 +10364,7 @@ function processJsonOutput(files, options) {
10761
10364
  if (typeof options.json === "boolean") return console.log(JSON.stringify(formatCollectedAsJSON(files), null, 2));
10762
10365
  if (typeof options.json === "string") {
10763
10366
  const jsonPath = resolve(options.root || process.cwd(), options.json);
10764
- mkdirSync(dirname(jsonPath), { recursive: true });
10765
- writeFileSync(jsonPath, JSON.stringify(formatCollectedAsJSON(files), null, 2));
10367
+ mkdirSync(dirname(jsonPath), { recursive: true }), writeFileSync(jsonPath, JSON.stringify(formatCollectedAsJSON(files), null, 2));
10766
10368
  }
10767
10369
  }
10768
10370
  function forEachSuite(modules, callback) {
@@ -10773,7 +10375,7 @@ function forEachSuite(modules, callback) {
10773
10375
  }
10774
10376
  function formatCollectedAsJSON(files) {
10775
10377
  const results = [];
10776
- files.forEach((file) => {
10378
+ return files.forEach((file) => {
10777
10379
  for (const test of file.children.allTests()) {
10778
10380
  if (test.result().state === "skipped") continue;
10779
10381
  const result = {
@@ -10784,19 +10386,17 @@ function formatCollectedAsJSON(files) {
10784
10386
  if (test.location) result.location = test.location;
10785
10387
  results.push(result);
10786
10388
  }
10787
- });
10788
- return results;
10389
+ }), results;
10789
10390
  }
10790
10391
  function formatCollectedAsString(testModules) {
10791
10392
  const results = [];
10792
- testModules.forEach((testModule) => {
10393
+ return testModules.forEach((testModule) => {
10793
10394
  for (const test of testModule.children.allTests()) {
10794
10395
  if (test.result().state === "skipped") continue;
10795
10396
  const fullName = `${test.module.task.name} > ${test.fullName}`;
10796
10397
  results.push((test.project.name ? `[${test.project.name}] ` : "") + fullName);
10797
10398
  }
10798
- });
10799
- return results;
10399
+ }), results;
10800
10400
  }
10801
10401
  const envPackageNames = {
10802
10402
  "jsdom": "jsdom",
@@ -10804,10 +10404,7 @@ const envPackageNames = {
10804
10404
  "edge-runtime": "@edge-runtime/vm"
10805
10405
  };
10806
10406
  function getEnvPackageName(env) {
10807
- if (env === "node") return null;
10808
- if (env in envPackageNames) return envPackageNames[env];
10809
- if (env[0] === "." || isAbsolute(env)) return null;
10810
- return `vitest-environment-${env}`;
10407
+ return env === "node" ? null : env in envPackageNames ? envPackageNames[env] : env[0] === "." || isAbsolute(env) ? null : `vitest-environment-${env}`;
10811
10408
  }
10812
10409
 
10813
10410
  var cliApi = /*#__PURE__*/Object.freeze({
@@ -10820,4 +10417,4 @@ var cliApi = /*#__PURE__*/Object.freeze({
10820
10417
  startVitest: startVitest
10821
10418
  });
10822
10419
 
10823
- 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 };
10420
+ 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 };