vitest 4.0.16 → 4.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/browser.d.ts +2 -1
  2. package/dist/browser.js +2 -1
  3. package/dist/chunks/{base.Bin-9uYm.js → base.CBRNZa3k.js} +8 -7
  4. package/dist/chunks/{browser.d.Bz3lxTX-.d.ts → browser.d.8hOapKZr.d.ts} +5 -1
  5. package/dist/chunks/{cac.BGonGPac.js → cac.B1v3xxoC.js} +26 -8
  6. package/dist/chunks/{cli-api.BKg19Fvw.js → cli-api.B4CqEpI6.js} +225 -110
  7. package/dist/chunks/{config.d.CzIjkicf.d.ts → config.d.idH22YSr.d.ts} +13 -11
  8. package/dist/chunks/{console.Cf-YriPC.js → console.uGgdMhyZ.js} +2 -1
  9. package/dist/chunks/{coverage.BuJUwVtg.js → coverage.BMlOMIWl.js} +18 -4
  10. package/dist/chunks/{creator.DAmOKTvJ.js → creator.C7WwjkuR.js} +32 -1
  11. package/dist/chunks/{globals.DOayXfHP.js → globals.DjuGMoMc.js} +10 -9
  12. package/dist/chunks/{index.Z5E_ObnR.js → index.BEFi2-_3.js} +3 -1
  13. package/dist/chunks/{index.6Qv1eEA6.js → index.BiOAd_ki.js} +16 -4
  14. package/dist/chunks/{index.BspFP3mn.js → index.CyBMJtT7.js} +1 -1
  15. package/dist/chunks/{index.456_DGfR.js → index.Dm4xqZ0s.js} +28 -4
  16. package/dist/chunks/{index.Drsj_6e7.js → index.DyBZXrH3.js} +1 -1
  17. package/dist/chunks/{init-forks.v9UONQS6.js → init-forks.CHeQ9Moq.js} +1 -1
  18. package/dist/chunks/{init-threads.DqYg3Trk.js → init-threads.uZiNAuPk.js} +1 -1
  19. package/dist/chunks/{init.KmQZdqFg.js → init.DVtKdFty.js} +24 -11
  20. package/dist/chunks/{plugin.d.v1sC_bv1.d.ts → plugin.d.D8KU2PY_.d.ts} +1 -1
  21. package/dist/chunks/{reporters.d.Rsi0PyxX.d.ts → reporters.d.Db3MiIWX.d.ts} +51 -22
  22. package/dist/chunks/rpc.HLmECnw_.js +148 -0
  23. package/dist/chunks/{setup-common.Cm-kSBVi.js → setup-common.BcqLPsn5.js} +1 -1
  24. package/dist/chunks/{startModuleRunner.DpqpB8k3.js → startModuleRunner.C5CcWyXW.js} +23 -23
  25. package/dist/chunks/{vi.2VT5v0um.js → test.prxIahgM.js} +500 -119
  26. package/dist/chunks/{traces.U4xDYhzZ.js → traces.CCmnQaNT.js} +46 -1
  27. package/dist/chunks/{vm.qFl6P1nF.js → vm.CrifS09m.js} +5 -8
  28. package/dist/chunks/{worker.d.5JNaocaN.d.ts → worker.d.Bji1eq5g.d.ts} +2 -1
  29. package/dist/cli.js +2 -2
  30. package/dist/config.d.ts +9 -9
  31. package/dist/coverage.d.ts +8 -8
  32. package/dist/coverage.js +3 -1
  33. package/dist/environments.js +3 -1
  34. package/dist/index.d.ts +22 -10
  35. package/dist/index.js +8 -7
  36. package/dist/module-evaluator.js +2 -6
  37. package/dist/node.d.ts +14 -11
  38. package/dist/node.js +20 -20
  39. package/dist/reporters.d.ts +7 -7
  40. package/dist/reporters.js +4 -2
  41. package/dist/runners.d.ts +23 -4
  42. package/dist/runners.js +4 -4
  43. package/dist/runtime.d.ts +6 -0
  44. package/dist/runtime.js +36 -0
  45. package/dist/snapshot.js +2 -0
  46. package/dist/suite.js +2 -0
  47. package/dist/worker.d.ts +4 -3
  48. package/dist/worker.js +10 -12
  49. package/dist/workers/forks.js +11 -13
  50. package/dist/workers/runVmTests.js +10 -12
  51. package/dist/workers/threads.js +11 -13
  52. package/dist/workers/vmForks.js +8 -9
  53. package/dist/workers/vmThreads.js +8 -9
  54. package/package.json +23 -27
  55. package/dist/chunks/date.Bq6ZW5rf.js +0 -73
  56. package/dist/chunks/rpc.BoxB0q7B.js +0 -76
  57. package/dist/chunks/test.B8ej_ZHS.js +0 -254
  58. package/dist/mocker.d.ts +0 -1
  59. package/dist/mocker.js +0 -1
  60. package/dist/module-runner.js +0 -17
@@ -4,7 +4,7 @@ import { C as CoverageProviderMap } from './coverage.D_JHT54q.js';
4
4
  import path, { resolve as resolve$1 } from 'node:path';
5
5
  import { noop, createDefer, slash, withTrailingSlash, cleanUrl, wrapId, isExternalUrl, unwrapId, toArray, deepMerge, nanoid, deepClone, isPrimitive, notNullish } from '@vitest/utils/helpers';
6
6
  import { a as any, p as prompt } from './index.D4KonVSU.js';
7
- import { h as hash, R as RandomSequencer, i as isPackageExists, c as isBrowserEnabled, r as resolveConfig, g as getCoverageProvider, a as resolveApiServerConfig, d as resolveModule } from './coverage.BuJUwVtg.js';
7
+ import { h as hash, R as RandomSequencer, i as isPackageExists, c as isBrowserEnabled, r as resolveConfig, g as getCoverageProvider, a as resolveApiServerConfig, d as resolveModule } from './coverage.BMlOMIWl.js';
8
8
  import * as vite from 'vite';
9
9
  import { isFileServingAllowed as isFileServingAllowed$1, parseAst, searchForWorkspaceRoot, fetchModule, version, mergeConfig, createServer, isFileLoadingAllowed, normalizePath } from 'vite';
10
10
  import { A as API_PATH, c as configFiles, d as defaultBrowserPort, a as defaultPort } from './constants.D_Q9UYh-.js';
@@ -12,10 +12,10 @@ import * as nodeos from 'node:os';
12
12
  import nodeos__default, { tmpdir } from 'node:os';
13
13
  import { generateHash as generateHash$1, createTaskName, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, hasFailed, generateFileHash, limitConcurrency, createFileTask as createFileTask$1, getTasks, isTestCase } from '@vitest/runner/utils';
14
14
  import { SnapshotManager } from '@vitest/snapshot/manager';
15
- import { v as version$1 } from './cac.BGonGPac.js';
15
+ import { v as version$1 } from './cac.B1v3xxoC.js';
16
16
  import { performance as performance$1 } from 'node:perf_hooks';
17
17
  import { c as createBirpc } from './index.Chj8NDwU.js';
18
- import { p as parse, d as stringify, e as createIndexLocationsMap, h as TraceMap, o as originalPositionFor, i as ancestor, j as printError, f as formatProjectName, w as withLabel, k as errorBanner, l as divider, m as Typechecker, n as generateCodeFrame, q as escapeRegExp, r as createDefinesScript, R as ReportersMap, u as groupBy, B as BlobReporter, v as readBlobs, x as convertTasksToEvents, H as HangingProcessReporter, y as wildcardPatternToRegExp, z as stdout } from './index.456_DGfR.js';
18
+ import { p as parse, d as stringify, e as createIndexLocationsMap, h as TraceMap, o as originalPositionFor, i as ancestor, j as printError, f as formatProjectName, w as withLabel, k as errorBanner, l as divider, m as Typechecker, n as generateCodeFrame, q as escapeRegExp, r as createDefinesScript, R as ReportersMap, u as groupBy, B as BlobReporter, v as readBlobs, x as convertTasksToEvents, H as HangingProcessReporter, y as wildcardPatternToRegExp, z as stdout } from './index.Dm4xqZ0s.js';
19
19
  import require$$0$3 from 'events';
20
20
  import require$$1$1 from 'https';
21
21
  import require$$2 from 'http';
@@ -29,7 +29,7 @@ import require$$0$1 from 'buffer';
29
29
  import { g as getDefaultExportFromCjs } from './_commonjsHelpers.D26ty3Ew.js';
30
30
  import crypto, { createHash } from 'node:crypto';
31
31
  import { rootDir, distDir } from '../path.js';
32
- import { T as Traces } from './traces.U4xDYhzZ.js';
32
+ import { T as Traces } from './traces.CCmnQaNT.js';
33
33
  import { createDebug } from 'obug';
34
34
  import { rm, readFile, writeFile, rename, stat, unlink, mkdir, copyFile } from 'node:fs/promises';
35
35
  import c from 'tinyrainbow';
@@ -53,7 +53,7 @@ import { c as configDefaults } from './defaults.BOqNVLsY.js';
53
53
  import { KNOWN_ASSET_RE } from '@vitest/utils/constants';
54
54
  import { findNearestPackageData } from '@vitest/utils/resolver';
55
55
  import * as esModuleLexer from 'es-module-lexer';
56
- import { a as BenchmarkReportsMap } from './index.Drsj_6e7.js';
56
+ import { a as BenchmarkReportsMap } from './index.DyBZXrH3.js';
57
57
  import assert$1 from 'node:assert';
58
58
  import { serializeValue } from '@vitest/utils/serialize';
59
59
  import { parseErrorStacktrace } from '@vitest/utils/source-map';
@@ -76,6 +76,7 @@ function requireConstants () {
76
76
 
77
77
  constants = {
78
78
  BINARY_TYPES,
79
+ CLOSE_TIMEOUT: 30000,
79
80
  EMPTY_BUFFER: Buffer.alloc(0),
80
81
  GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
81
82
  hasBlob,
@@ -2846,6 +2847,7 @@ function requireWebsocket () {
2846
2847
 
2847
2848
  const {
2848
2849
  BINARY_TYPES,
2850
+ CLOSE_TIMEOUT,
2849
2851
  EMPTY_BUFFER,
2850
2852
  GUID,
2851
2853
  kForOnEventAttribute,
@@ -2860,7 +2862,6 @@ function requireWebsocket () {
2860
2862
  const { format, parse } = requireExtension();
2861
2863
  const { toBuffer } = requireBufferUtil();
2862
2864
 
2863
- const closeTimeout = 30 * 1000;
2864
2865
  const kAborted = Symbol('kAborted');
2865
2866
  const protocolVersions = [8, 13];
2866
2867
  const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
@@ -2916,6 +2917,7 @@ function requireWebsocket () {
2916
2917
  initAsClient(this, address, protocols, options);
2917
2918
  } else {
2918
2919
  this._autoPong = options.autoPong;
2920
+ this._closeTimeout = options.closeTimeout;
2919
2921
  this._isServer = true;
2920
2922
  }
2921
2923
  }
@@ -3457,6 +3459,8 @@ function requireWebsocket () {
3457
3459
  * times in the same tick
3458
3460
  * @param {Boolean} [options.autoPong=true] Specifies whether or not to
3459
3461
  * automatically send a pong in response to a ping
3462
+ * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait
3463
+ * for the closing handshake to finish after `websocket.close()` is called
3460
3464
  * @param {Function} [options.finishRequest] A function which can be used to
3461
3465
  * customize the headers of each http request before it is sent
3462
3466
  * @param {Boolean} [options.followRedirects=false] Whether or not to follow
@@ -3483,6 +3487,7 @@ function requireWebsocket () {
3483
3487
  const opts = {
3484
3488
  allowSynchronousEvents: true,
3485
3489
  autoPong: true,
3490
+ closeTimeout: CLOSE_TIMEOUT,
3486
3491
  protocolVersion: protocolVersions[1],
3487
3492
  maxPayload: 100 * 1024 * 1024,
3488
3493
  skipUTF8Validation: false,
@@ -3501,6 +3506,7 @@ function requireWebsocket () {
3501
3506
  };
3502
3507
 
3503
3508
  websocket._autoPong = opts.autoPong;
3509
+ websocket._closeTimeout = opts.closeTimeout;
3504
3510
 
3505
3511
  if (!protocolVersions.includes(opts.protocolVersion)) {
3506
3512
  throw new RangeError(
@@ -4118,7 +4124,7 @@ function requireWebsocket () {
4118
4124
  function setCloseTimer(websocket) {
4119
4125
  websocket._closeTimer = setTimeout(
4120
4126
  websocket._socket.destroy.bind(websocket._socket),
4121
- closeTimeout
4127
+ websocket._closeTimeout
4122
4128
  );
4123
4129
  }
4124
4130
 
@@ -4136,23 +4142,23 @@ function requireWebsocket () {
4136
4142
 
4137
4143
  websocket._readyState = WebSocket.CLOSING;
4138
4144
 
4139
- let chunk;
4140
-
4141
4145
  //
4142
4146
  // The close frame might not have been received or the `'end'` event emitted,
4143
4147
  // for example, if the socket was destroyed due to an error. Ensure that the
4144
4148
  // `receiver` stream is closed after writing any remaining buffered data to
4145
4149
  // it. If the readable side of the socket is in flowing mode then there is no
4146
- // buffered data as everything has been already written and `readable.read()`
4147
- // will return `null`. If instead, the socket is paused, any possible buffered
4148
- // data will be read as a single chunk.
4150
+ // buffered data as everything has been already written. If instead, the
4151
+ // socket is paused, any possible buffered data will be read as a single
4152
+ // chunk.
4149
4153
  //
4150
4154
  if (
4151
4155
  !this._readableState.endEmitted &&
4152
4156
  !websocket._closeFrameReceived &&
4153
4157
  !websocket._receiver._writableState.errorEmitted &&
4154
- (chunk = websocket._socket.read()) !== null
4158
+ this._readableState.length !== 0
4155
4159
  ) {
4160
+ const chunk = this.read(this._readableState.length);
4161
+
4156
4162
  websocket._receiver.write(chunk);
4157
4163
  }
4158
4164
 
@@ -4483,7 +4489,7 @@ function requireWebsocketServer () {
4483
4489
  const PerMessageDeflate = requirePermessageDeflate();
4484
4490
  const subprotocol = requireSubprotocol();
4485
4491
  const WebSocket = requireWebsocket();
4486
- const { GUID, kWebSocket } = requireConstants();
4492
+ const { CLOSE_TIMEOUT, GUID, kWebSocket } = requireConstants();
4487
4493
 
4488
4494
  const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
4489
4495
 
@@ -4510,6 +4516,9 @@ function requireWebsocketServer () {
4510
4516
  * pending connections
4511
4517
  * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
4512
4518
  * track clients
4519
+ * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to
4520
+ * wait for the closing handshake to finish after `websocket.close()` is
4521
+ * called
4513
4522
  * @param {Function} [options.handleProtocols] A hook to handle protocols
4514
4523
  * @param {String} [options.host] The hostname where to bind the server
4515
4524
  * @param {Number} [options.maxPayload=104857600] The maximum allowed message
@@ -4539,6 +4548,7 @@ function requireWebsocketServer () {
4539
4548
  perMessageDeflate: false,
4540
4549
  handleProtocols: null,
4541
4550
  clientTracking: true,
4551
+ closeTimeout: CLOSE_TIMEOUT,
4542
4552
  verifyClient: null,
4543
4553
  noServer: false,
4544
4554
  backlog: null, // use default (511 as implemented in net.js)
@@ -5327,6 +5337,12 @@ function createDebugger(namespace) {
5327
5337
 
5328
5338
  const debug$1 = createDebugger("vitest:ast-collect-info");
5329
5339
  const verbose = createDebugger("vitest:ast-collect-verbose");
5340
+ function isTestFunctionName(name) {
5341
+ return name === "it" || name === "test" || name.startsWith("test") || name.endsWith("Test");
5342
+ }
5343
+ function isVitestFunctionName(name) {
5344
+ return name === "describe" || name === "suite" || isTestFunctionName(name);
5345
+ }
5330
5346
  function astParseFile(filepath, code) {
5331
5347
  const ast = parseAst(code);
5332
5348
  if (verbose) verbose("Collecting", filepath, code);
@@ -5338,12 +5354,7 @@ function astParseFile(filepath, code) {
5338
5354
  if (callee.type === "CallExpression") return getName(callee.callee);
5339
5355
  if (callee.type === "TaggedTemplateExpression") return getName(callee.tag);
5340
5356
  if (callee.type === "MemberExpression") {
5341
- if (callee.object?.type === "Identifier" && [
5342
- "it",
5343
- "test",
5344
- "describe",
5345
- "suite"
5346
- ].includes(callee.object.name)) return callee.object?.name;
5357
+ if (callee.object?.type === "Identifier" && isVitestFunctionName(callee.object.name)) return callee.object?.name;
5347
5358
  if (callee.object?.name?.startsWith("__vite_ssr_") || callee.object?.object?.name?.startsWith("__vite_ssr_") && callee.object?.property?.name === "Vitest") return getName(callee.property);
5348
5359
  // call as `__vite_ssr__.test.skip()`
5349
5360
  return getName(callee.object?.property);
@@ -5359,12 +5370,7 @@ function astParseFile(filepath, code) {
5359
5370
  const { callee } = node;
5360
5371
  const name = getName(callee);
5361
5372
  if (!name) return;
5362
- if (![
5363
- "it",
5364
- "test",
5365
- "describe",
5366
- "suite"
5367
- ].includes(name)) {
5373
+ if (!isVitestFunctionName(name)) {
5368
5374
  verbose?.(`Skipping ${name} (unknown call)`);
5369
5375
  return;
5370
5376
  }
@@ -5375,7 +5381,9 @@ function astParseFile(filepath, code) {
5375
5381
  "each",
5376
5382
  "for",
5377
5383
  "skipIf",
5378
- "runIf"
5384
+ "runIf",
5385
+ "extend",
5386
+ "scoped"
5379
5387
  ].includes(mode)) return;
5380
5388
  let start;
5381
5389
  const end = node.end;
@@ -5405,7 +5413,7 @@ function astParseFile(filepath, code) {
5405
5413
  start,
5406
5414
  end,
5407
5415
  name: message,
5408
- type: name === "it" || name === "test" ? "test" : "suite",
5416
+ type: isTestFunctionName(name) ? "test" : "suite",
5409
5417
  mode,
5410
5418
  task: null,
5411
5419
  dynamic: isDynamicEach
@@ -5494,7 +5502,10 @@ function createFileTask(testFilepath, code, requestMap, options) {
5494
5502
  });
5495
5503
  if (originalLocation.column != null) {
5496
5504
  verbose?.(`Found location for`, definition.type, definition.name, `${processedLocation.line}:${processedLocation.column}`, "->", `${originalLocation.line}:${originalLocation.column}`);
5497
- location = originalLocation;
5505
+ location = {
5506
+ line: originalLocation.line,
5507
+ column: originalLocation.column
5508
+ };
5498
5509
  } else debug$1?.("Cannot find original location for", definition.type, definition.name, `${processedLocation.column}:${processedLocation.line}`);
5499
5510
  } else debug$1?.("Cannot find original location for", definition.type, definition.name, `${definition.start}`);
5500
5511
  if (definition.type === "suite") {
@@ -5543,7 +5554,7 @@ function createFileTask(testFilepath, code, requestMap, options) {
5543
5554
  });
5544
5555
  calculateSuiteHash(file);
5545
5556
  const hasOnly = someTasksAreOnly(file);
5546
- interpretTaskModes(file, options.testNamePattern, void 0, hasOnly, false, options.allowOnly);
5557
+ interpretTaskModes(file, options.testNamePattern, void 0, void 0, hasOnly, false, options.allowOnly);
5547
5558
  markDynamicTests(file.tasks);
5548
5559
  if (!file.tasks.length) file.result = {
5549
5560
  state: "fail",
@@ -5570,9 +5581,9 @@ async function astCollectTests(project, filepath) {
5570
5581
  });
5571
5582
  }
5572
5583
  async function transformSSR(project, filepath) {
5573
- const request = await project.vite.transformRequest(filepath, { ssr: false });
5574
- if (!request) return null;
5575
- return await project.vite.ssrTransform(request.code, request.map, filepath);
5584
+ const environment = project.config.environment;
5585
+ if (environment === "jsdom" || environment === "happy-dom") return project.vite.environments.client.transformRequest(filepath);
5586
+ return project.vite.environments.ssr.transformRequest(filepath);
5576
5587
  }
5577
5588
  function markDynamicTests(tasks) {
5578
5589
  for (const task of tasks) {
@@ -5771,7 +5782,7 @@ class FileSystemModuleCache {
5771
5782
  */
5772
5783
  rootCache;
5773
5784
  metadataFilePath;
5774
- version = "1.0.0-beta.3";
5785
+ version = "1.0.0-beta.4";
5775
5786
  fsCacheRoots = /* @__PURE__ */ new WeakMap();
5776
5787
  fsEnvironmentHashMap = /* @__PURE__ */ new WeakMap();
5777
5788
  fsCacheKeyGenerators = /* @__PURE__ */ new Set();
@@ -5828,18 +5839,16 @@ class FileSystemModuleCache {
5828
5839
  url: meta.url,
5829
5840
  file: meta.file,
5830
5841
  code,
5831
- importers: meta.importers,
5832
5842
  importedUrls: meta.importedUrls,
5833
5843
  mappings: meta.mappings
5834
5844
  };
5835
5845
  }
5836
- async saveCachedModule(cachedFilePath, fetchResult, importers = [], importedUrls = [], mappings = false) {
5846
+ async saveCachedModule(cachedFilePath, fetchResult, importedUrls = [], mappings = false) {
5837
5847
  if ("code" in fetchResult) {
5838
5848
  const result = {
5839
5849
  file: fetchResult.file,
5840
5850
  id: fetchResult.id,
5841
5851
  url: fetchResult.url,
5842
- importers,
5843
5852
  importedUrls,
5844
5853
  mappings
5845
5854
  };
@@ -6178,17 +6187,16 @@ class ModuleFetcher {
6178
6187
  this.recordResult(trace, result);
6179
6188
  return result;
6180
6189
  });
6181
- const cachedModule = await this.getCachedModule(cachePath, environment, moduleGraphModule);
6190
+ const cachedModule = await this.getCachedModule(cachePath, environment, moduleGraphModule, importer);
6182
6191
  if (cachedModule) {
6183
6192
  this.recordResult(trace, cachedModule);
6184
6193
  return cachedModule;
6185
6194
  }
6186
6195
  const result = await this.fetchAndProcess(environment, url, importer, moduleGraphModule, options);
6187
- const importers = this.getSerializedDependencies(moduleGraphModule);
6188
6196
  const importedUrls = this.getSerializedImports(moduleGraphModule);
6189
6197
  const map = moduleGraphModule.transformResult?.map;
6190
6198
  const mappings = map && !("version" in map) && map.mappings === "";
6191
- return this.cacheResult(result, cachePath, importers, importedUrls, !!mappings);
6199
+ return this.cacheResult(result, cachePath, importedUrls, !!mappings);
6192
6200
  }
6193
6201
  // we need this for UI to be able to show a module graph
6194
6202
  getSerializedImports(node) {
@@ -6198,14 +6206,6 @@ class ModuleFetcher {
6198
6206
  });
6199
6207
  return imports;
6200
6208
  }
6201
- // we need this for the watcher to be able to find the related test file
6202
- getSerializedDependencies(node) {
6203
- const dependencies = [];
6204
- node.importers.forEach((importer) => {
6205
- if (importer.id) dependencies.push(importer.id);
6206
- });
6207
- return dependencies;
6208
- }
6209
6209
  recordResult(trace, result) {
6210
6210
  if ("externalize" in result) trace.setAttributes({
6211
6211
  "vitest.fetched_module.external": result.externalize,
@@ -6242,7 +6242,7 @@ class ModuleFetcher {
6242
6242
  if (loadResult != null) return loadResult.code;
6243
6243
  return "";
6244
6244
  }
6245
- async getCachedModule(cachePath, environment, moduleGraphModule) {
6245
+ async getCachedModule(cachePath, environment, moduleGraphModule, importer) {
6246
6246
  if (moduleGraphModule.transformResult?.__vitestTmp) return {
6247
6247
  cached: true,
6248
6248
  file: moduleGraphModule.file,
@@ -6265,13 +6265,16 @@ class ModuleFetcher {
6265
6265
  __vitestTmp: cachePath
6266
6266
  };
6267
6267
  // we populate the module graph to make the watch mode work because it relies on importers
6268
- cachedModule.importers.forEach((importer) => {
6268
+ if (importer) {
6269
6269
  const environmentNode = environment.moduleGraph.getModuleById(importer);
6270
6270
  if (environmentNode) moduleGraphModule.importers.add(environmentNode);
6271
- });
6271
+ }
6272
6272
  await Promise.all(cachedModule.importedUrls.map(async (url) => {
6273
6273
  const moduleNode = await environment.moduleGraph.ensureEntryFromUrl(url).catch(() => null);
6274
- if (moduleNode) moduleGraphModule.importedModules.add(moduleNode);
6274
+ if (moduleNode) {
6275
+ moduleNode.importers.add(moduleGraphModule);
6276
+ moduleGraphModule.importedModules.add(moduleNode);
6277
+ }
6275
6278
  }));
6276
6279
  return {
6277
6280
  cached: true,
@@ -6288,13 +6291,13 @@ class ModuleFetcher {
6288
6291
  inlineSourceMap: false
6289
6292
  }).catch(handleRollupError));
6290
6293
  }
6291
- async cacheResult(result, cachePath, importers = [], importedUrls = [], mappings = false) {
6294
+ async cacheResult(result, cachePath, importedUrls = [], mappings = false) {
6292
6295
  const returnResult = "code" in result ? getCachedResult(result, cachePath) : result;
6293
6296
  if (saveCachePromises.has(cachePath)) {
6294
6297
  await saveCachePromises.get(cachePath);
6295
6298
  return returnResult;
6296
6299
  }
6297
- const savePromise = this.fsCache.saveCachedModule(cachePath, result, importers, importedUrls, mappings).then(() => result).finally(() => {
6300
+ const savePromise = this.fsCache.saveCachedModule(cachePath, result, importedUrls, mappings).then(() => result).finally(() => {
6298
6301
  saveCachePromises.delete(cachePath);
6299
6302
  });
6300
6303
  saveCachePromises.set(cachePath, savePromise);
@@ -7056,11 +7059,13 @@ function createBrowserPool(vitest) {
7056
7059
  };
7057
7060
  const runWorkspaceTests = async (method, specs) => {
7058
7061
  const groupedFiles = /* @__PURE__ */ new Map();
7059
- for (const { project, moduleId, testLines } of specs) {
7062
+ for (const { project, moduleId, testLines, testIds, testNamePattern } of specs) {
7060
7063
  const files = groupedFiles.get(project) || [];
7061
7064
  files.push({
7062
7065
  filepath: moduleId,
7063
- testLocations: testLines
7066
+ testLocations: testLines,
7067
+ testIds,
7068
+ testNamePattern
7064
7069
  });
7065
7070
  groupedFiles.set(project, files);
7066
7071
  }
@@ -7129,12 +7134,21 @@ class BrowserPool {
7129
7134
  _promise;
7130
7135
  _providedContext;
7131
7136
  readySessions = /* @__PURE__ */ new Set();
7137
+ _traces;
7138
+ _otel;
7132
7139
  constructor(project, options) {
7133
7140
  this.project = project;
7134
7141
  this.options = options;
7142
+ this._traces = project.vitest._traces;
7143
+ this._otel = this._traces.startContextSpan("vitest.browser");
7144
+ this._otel.span.setAttributes({
7145
+ "vitest.project": project.name,
7146
+ "vitest.browser.provider": this.project.browser.provider.name
7147
+ });
7135
7148
  }
7136
7149
  cancel() {
7137
7150
  this._queue = [];
7151
+ this._otel.span.end();
7138
7152
  }
7139
7153
  reject(error) {
7140
7154
  this._promise?.reject(error);
@@ -7172,7 +7186,11 @@ class BrowserPool {
7172
7186
  this.project.vitest._browserSessions.sessionIds.add(sessionId);
7173
7187
  const project = this.project.name;
7174
7188
  debug?.("[%s] creating session for %s", sessionId, project);
7175
- const page = this.openPage(sessionId).then(() => {
7189
+ let page = this._traces.$(`vitest.browser.open`, {
7190
+ context: this._otel.context,
7191
+ attributes: { "vitest.browser.session_id": sessionId }
7192
+ }, () => this.openPage(sessionId));
7193
+ page = page.then(() => {
7176
7194
  // start running tests on the page when it's ready
7177
7195
  this.runNextTest(method, sessionId);
7178
7196
  });
@@ -7187,6 +7205,8 @@ class BrowserPool {
7187
7205
  const browser = this.project.browser;
7188
7206
  const url = new URL("/__vitest_test__/", this.options.origin);
7189
7207
  url.searchParams.set("sessionId", sessionId);
7208
+ const otelCarrier = this._traces.getContextCarrier();
7209
+ if (otelCarrier) url.searchParams.set("otelCarrier", JSON.stringify(otelCarrier));
7190
7210
  const pagePromise = browser.provider.openPage(sessionId, url.toString());
7191
7211
  await Promise.all([sessionPromise, pagePromise]);
7192
7212
  }
@@ -7199,6 +7219,7 @@ class BrowserPool {
7199
7219
  this.readySessions.add(sessionId);
7200
7220
  // the last worker finished running tests
7201
7221
  if (this.readySessions.size === this.orchestrators.size) {
7222
+ this._otel.span.end();
7202
7223
  this._promise?.resolve();
7203
7224
  this._promise = void 0;
7204
7225
  debug?.("[%s] all tests finished running", sessionId);
@@ -7221,11 +7242,16 @@ class BrowserPool {
7221
7242
  const orchestrator = this.getOrchestrator(sessionId);
7222
7243
  debug?.("[%s] run test %s", sessionId, file);
7223
7244
  this.setBreakpoint(sessionId, file.filepath).then(() => {
7224
- // this starts running tests inside the orchestrator
7225
- orchestrator.createTesters({
7226
- method,
7227
- files: [file],
7228
- providedContext: this._providedContext || "[{}]"
7245
+ this._traces.$(`vitest.browser.run`, {
7246
+ context: this._otel.context,
7247
+ attributes: { "code.file.path": file.filepath }
7248
+ }, async () => {
7249
+ return orchestrator.createTesters({
7250
+ method,
7251
+ files: [file],
7252
+ providedContext: this._providedContext || "[{}]",
7253
+ otelCarrier: this._traces.getContextCarrier()
7254
+ });
7229
7255
  }).then(() => {
7230
7256
  debug?.("[%s] test %s finished running", sessionId, file);
7231
7257
  this.runNextTest(method, sessionId);
@@ -7359,6 +7385,7 @@ var RunnerState = /* @__PURE__ */ function(RunnerState) {
7359
7385
  RunnerState["IDLE"] = "idle";
7360
7386
  RunnerState["STARTING"] = "starting";
7361
7387
  RunnerState["STARTED"] = "started";
7388
+ RunnerState["START_FAILURE"] = "start_failure";
7362
7389
  RunnerState["STOPPING"] = "stopping";
7363
7390
  RunnerState["STOPPED"] = "stopped";
7364
7391
  return RunnerState;
@@ -7420,6 +7447,14 @@ class PoolRunner {
7420
7447
  });
7421
7448
  this._offCancel = vitest.onCancel((reason) => this._rpc.onCancel(reason));
7422
7449
  }
7450
+ /**
7451
+ * "reconfigure" can only be called if `environment` is different, since different project always
7452
+ * requires a new PoolRunner instance.
7453
+ */
7454
+ reconfigure(task) {
7455
+ this.environment = task.context.environment;
7456
+ this._otel?.span.setAttribute("vitest.environment", this.environment.name);
7457
+ }
7423
7458
  postMessage(message) {
7424
7459
  // Only send messages when runner is active (not fully stopped)
7425
7460
  // Allow sending during STOPPING state for the 'stop' message itself
@@ -7495,7 +7530,7 @@ class PoolRunner {
7495
7530
  await startPromise;
7496
7531
  this._state = RunnerState.STARTED;
7497
7532
  } catch (error) {
7498
- this._state = RunnerState.IDLE;
7533
+ this._state = RunnerState.START_FAILURE;
7499
7534
  startSpan?.recordException(error);
7500
7535
  throw error;
7501
7536
  } finally {
@@ -7932,6 +7967,9 @@ class VmForksPoolWorker extends ForksPoolWorker {
7932
7967
  /** Loads {@link file://./../../../runtime/workers/vmForks.ts} */
7933
7968
  this.entrypoint = resolve$1(options.distPath, "workers/vmForks.js");
7934
7969
  }
7970
+ canReuse() {
7971
+ return true;
7972
+ }
7935
7973
  }
7936
7974
 
7937
7975
  /** @experimental */
@@ -7947,6 +7985,9 @@ class VmThreadsPoolWorker extends ThreadsPoolWorker {
7947
7985
  /** Loads {@link file://./../../../runtime/workers/vmThreads.ts} */
7948
7986
  this.entrypoint = resolve$1(options.distPath, "workers/vmThreads.js");
7949
7987
  }
7988
+ canReuse() {
7989
+ return true;
7990
+ }
7950
7991
  }
7951
7992
 
7952
7993
  const WORKER_START_TIMEOUT = 9e4;
@@ -8015,17 +8056,15 @@ class Pool {
8015
8056
  resolver.reject(new Error(`[vitest-pool]: Worker ${task.worker} emitted error.`, { cause: error }));
8016
8057
  });
8017
8058
  const id = setTimeout(() => resolver.reject(/* @__PURE__ */ new Error(`[vitest-pool]: Timeout starting ${task.worker} runner.`)), WORKER_START_TIMEOUT);
8018
- await runner.start({ workerId: task.context.workerId }).finally(() => clearTimeout(id));
8059
+ await runner.start({ workerId: task.context.workerId }).catch((error) => resolver.reject(new Error(`[vitest-pool]: Failed to start ${task.worker} worker for test files ${formatFiles(task)}.`, { cause: error }))).finally(() => clearTimeout(id));
8019
8060
  }
8020
- const span = runner.startTracesSpan(`vitest.worker.${method}`);
8021
- // Start running the test in the worker
8022
- runner.request(method, task.context);
8023
- await resolver.promise.catch((error) => {
8024
- span.recordException(error);
8025
- throw error;
8026
- }).finally(() => {
8027
- span.end();
8028
- });
8061
+ let span;
8062
+ if (!resolver.isRejected) {
8063
+ span = runner.startTracesSpan(`vitest.worker.${method}`);
8064
+ // Start running the test in the worker
8065
+ runner.request(method, task.context);
8066
+ }
8067
+ await resolver.promise.catch((error) => span?.recordException(error)).finally(() => span?.end());
8029
8068
  const index = this.activeTasks.indexOf(activeTask);
8030
8069
  if (index !== -1) this.activeTasks.splice(index, 1);
8031
8070
  if (!task.isolate && !isMemoryLimitReached && this.queue[0]?.task.isolate === false && isEqualRunner(runner, this.queue[0].task)) {
@@ -8036,7 +8075,7 @@ class Pool {
8036
8075
  // Runner termination can also already start from task cancellation.
8037
8076
  if (!runner.isTerminated) {
8038
8077
  const id = setTimeout(() => this.logger.error(`[vitest-pool]: Timeout terminating ${task.worker} worker for test files ${formatFiles(task)}.`), this.options.teardownTimeout);
8039
- this.exitPromises.push(runner.stop().then(() => clearTimeout(id)).catch((error) => this.logger.error(`[vitest-pool]: Failed to terminate ${task.worker} worker for test files ${formatFiles(task)}.`, error)));
8078
+ this.exitPromises.push(runner.stop({ force: resolver.isRejected }).then(() => clearTimeout(id)).catch((error) => this.logger.error(`[vitest-pool]: Failed to terminate ${task.worker} worker for test files ${formatFiles(task)}.`, error)));
8040
8079
  }
8041
8080
  this.freeWorkerId(poolId);
8042
8081
  }
@@ -8073,13 +8112,17 @@ catch (error) {
8073
8112
  getPoolRunner(task, method) {
8074
8113
  if (task.isolate === false) {
8075
8114
  const index = this.sharedRunners.findIndex((runner) => isEqualRunner(runner, task));
8076
- if (index !== -1) return this.sharedRunners.splice(index, 1)[0];
8115
+ if (index !== -1) {
8116
+ const runner = this.sharedRunners.splice(index, 1)[0];
8117
+ runner.reconfigure(task);
8118
+ return runner;
8119
+ }
8077
8120
  }
8078
8121
  const options = {
8079
8122
  distPath: this.options.distPath,
8080
8123
  project: task.project,
8081
8124
  method,
8082
- environment: task.environment,
8125
+ environment: task.context.environment,
8083
8126
  env: task.env,
8084
8127
  execArgv: task.execArgv
8085
8128
  };
@@ -8111,22 +8154,44 @@ catch (error) {
8111
8154
  function withResolvers() {
8112
8155
  let resolve = () => {};
8113
8156
  let reject = (_error) => {};
8114
- const promise = new Promise((res, rej) => {
8115
- resolve = res;
8116
- reject = rej;
8117
- });
8118
- return {
8157
+ const resolver = {
8158
+ promise: new Promise((res, rej) => {
8159
+ resolve = res;
8160
+ reject = rej;
8161
+ }),
8119
8162
  resolve,
8120
- reject,
8121
- promise
8163
+ reject: (reason) => {
8164
+ resolver.isRejected = true;
8165
+ reject(reason);
8166
+ },
8167
+ isRejected: false
8122
8168
  };
8169
+ return resolver;
8123
8170
  }
8124
8171
  function formatFiles(task) {
8125
8172
  return task.context.files.map((file) => file.filepath).join(", ");
8126
8173
  }
8127
8174
  function isEqualRunner(runner, task) {
8128
8175
  if (task.isolate) throw new Error("Isolated tasks should not share runners");
8129
- return runner.worker.name === task.worker && runner.project === task.project && runner.environment.name === task.environment.name && (!runner.worker.canReuse || runner.worker.canReuse(task));
8176
+ if (runner.worker.name !== task.worker || runner.project !== task.project) return false;
8177
+ // by default, check that the environments are the same
8178
+ // some workers (like vmThreads/vmForks) do not need this check
8179
+ if (!runner.worker.canReuse) return isEnvironmentEqual(task.context.environment, runner.environment);
8180
+ return runner.worker.canReuse(task);
8181
+ }
8182
+ function isEnvironmentEqual(env1, env2) {
8183
+ if (env1.name !== env2.name) return false;
8184
+ return deepEqual(env1.options, env2.options);
8185
+ }
8186
+ function deepEqual(obj1, obj2) {
8187
+ if (obj1 === obj2) return true;
8188
+ if (obj1 == null || obj2 == null) return obj1 === obj2;
8189
+ if (typeof obj1 !== "object" || typeof obj2 !== "object") return false;
8190
+ const keys1 = Object.keys(obj1);
8191
+ const keys2 = Object.keys(obj2);
8192
+ if (keys1.length !== keys2.length) return false;
8193
+ for (const key of keys1) if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) return false;
8194
+ return true;
8130
8195
  }
8131
8196
 
8132
8197
  const suppressWarningsPath = resolve(rootDir, "./suppress-warnings.cjs");
@@ -8195,13 +8260,15 @@ function createPool(ctx) {
8195
8260
  context: {
8196
8261
  files: specs.map((spec) => ({
8197
8262
  filepath: spec.moduleId,
8198
- testLocations: spec.testLines
8263
+ testLocations: spec.testLines,
8264
+ testNamePattern: spec.testNamePattern,
8265
+ testIds: spec.testIds
8199
8266
  })),
8200
8267
  invalidates,
8201
8268
  providedContext: project.getProvidedContext(),
8202
- workerId: workerId++
8269
+ workerId: workerId++,
8270
+ environment
8203
8271
  },
8204
- environment,
8205
8272
  project,
8206
8273
  env,
8207
8274
  execArgv,
@@ -8468,7 +8535,8 @@ function serializeConfig(project) {
8468
8535
  serializedDefines: config.browser.enabled ? "" : project._serializedDefines || "",
8469
8536
  experimental: {
8470
8537
  fsModuleCache: config.experimental.fsModuleCache ?? false,
8471
- printImportBreakdown: config.experimental.printImportBreakdown
8538
+ printImportBreakdown: config.experimental.printImportBreakdown,
8539
+ openTelemetry: config.experimental.openTelemetry
8472
8540
  }
8473
8541
  };
8474
8542
  }
@@ -9550,6 +9618,7 @@ function WorkspaceVitestPlugin(project, options) {
9550
9618
  this.meta.watchMode = false;
9551
9619
  },
9552
9620
  config(viteConfig) {
9621
+ const originalDefine = { ...viteConfig.define };
9553
9622
  const defines = deleteDefineConfig(viteConfig);
9554
9623
  const testConfig = viteConfig.test || {};
9555
9624
  const root = testConfig.root || viteConfig.root || options.root;
@@ -9586,6 +9655,7 @@ function WorkspaceVitestPlugin(project, options) {
9586
9655
  }
9587
9656
  };
9588
9657
  config.test.defines = defines;
9658
+ config.test.viteDefine = originalDefine;
9589
9659
  const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
9590
9660
  if (classNameStrategy !== "scoped") {
9591
9661
  config.css ??= {};
@@ -9752,7 +9822,7 @@ function matchPattern(id, moduleDirectories, patterns) {
9752
9822
 
9753
9823
  class TestSpecification {
9754
9824
  /**
9755
- * The task ID associated with the test module.
9825
+ * The task id associated with the test module.
9756
9826
  */
9757
9827
  taskId;
9758
9828
  /**
@@ -9760,29 +9830,46 @@ class TestSpecification {
9760
9830
  */
9761
9831
  project;
9762
9832
  /**
9763
- * The ID of the module in the Vite module graph. It is usually an absolute file path.
9833
+ * The id of the module in the Vite module graph. It is usually an absolute file path.
9764
9834
  */
9765
9835
  moduleId;
9766
9836
  /**
9767
- * The current test pool. It's possible to have multiple pools in a single test project with `poolMatchGlob` and `typecheck.enabled`.
9768
- * @experimental In Vitest 4, the project will only support a single pool and this property will be removed.
9837
+ * The current test pool. It's possible to have multiple pools in a single test project with `typecheck.enabled`.
9838
+ * @experimental In later versions, the project will only support a single pool.
9769
9839
  */
9770
9840
  pool;
9771
9841
  /**
9772
9842
  * Line numbers of the test locations to run.
9773
9843
  */
9774
9844
  testLines;
9775
- constructor(project, moduleId, pool, testLines) {
9776
- const name = project.config.name;
9777
- const hashName = pool !== "typescript" ? name : name ? `${name}:__typecheck__` : "__typecheck__";
9845
+ /**
9846
+ * Regular expression pattern to filter test names.
9847
+ */
9848
+ testNamePattern;
9849
+ /**
9850
+ * The ids of tasks inside of this specification to run.
9851
+ */
9852
+ testIds;
9853
+ /**
9854
+ * This class represents a test suite for a test module within a single project.
9855
+ * @internal
9856
+ */
9857
+ constructor(project, moduleId, pool, testLinesOrOptions) {
9858
+ const projectName = project.config.name;
9859
+ const hashName = pool !== "typescript" ? projectName : projectName ? `${projectName}:__typecheck__` : "__typecheck__";
9778
9860
  this.taskId = generateFileHash(relative(project.config.root, moduleId), hashName);
9779
9861
  this.project = project;
9780
9862
  this.moduleId = moduleId;
9781
9863
  this.pool = pool;
9782
- this.testLines = testLines;
9864
+ if (Array.isArray(testLinesOrOptions)) this.testLines = testLinesOrOptions;
9865
+ else if (testLinesOrOptions && typeof testLinesOrOptions === "object") {
9866
+ this.testLines = testLinesOrOptions.testLines;
9867
+ this.testNamePattern = testLinesOrOptions.testNamePattern;
9868
+ this.testIds = testLinesOrOptions.testIds;
9869
+ }
9783
9870
  }
9784
9871
  /**
9785
- * Test module associated with the specification.
9872
+ * Test module associated with the specification. This will be `undefined` if tests have not been run yet.
9786
9873
  */
9787
9874
  get testModule() {
9788
9875
  const task = this.project.vitest.state.idMap.get(this.taskId);
@@ -9798,7 +9885,9 @@ class TestSpecification {
9798
9885
  this.moduleId,
9799
9886
  {
9800
9887
  pool: this.pool,
9801
- testLines: this.testLines
9888
+ testLines: this.testLines,
9889
+ testIds: this.testIds,
9890
+ testNamePattern: this.testNamePattern
9802
9891
  }
9803
9892
  ];
9804
9893
  }
@@ -9907,8 +9996,8 @@ class TestProject {
9907
9996
  * Creates a new test specification. Specifications describe how to run tests.
9908
9997
  * @param moduleId The file path
9909
9998
  */
9910
- createSpecification(moduleId, locations, pool) {
9911
- return new TestSpecification(this, moduleId, pool || getFilePoolName(this), locations);
9999
+ createSpecification(moduleId, locationsOrOptions, pool) {
10000
+ return new TestSpecification(this, moduleId, pool || getFilePoolName(this), locationsOrOptions);
9912
10001
  }
9913
10002
  toJSON() {
9914
10003
  return {
@@ -10106,7 +10195,7 @@ class TestProject {
10106
10195
  _initParentBrowser = deduped(async (childProject) => {
10107
10196
  if (!this.isBrowserEnabled() || this._parentBrowser) return;
10108
10197
  const provider = this.config.browser.provider || childProject.config.browser.provider;
10109
- if (provider == null) throw new Error(`Proider was not specified in the "browser.provider" setting. Please, pass down playwright(), webdriverio() or preview() from "@vitest/browser-playwright", "@vitest/browser-webdriverio" or "@vitest/browser-preview" package respectively.`);
10198
+ if (provider == null) throw new Error(`Provider was not specified in the "browser.provider" setting. Please, pass down playwright(), webdriverio() or preview() from "@vitest/browser-playwright", "@vitest/browser-webdriverio" or "@vitest/browser-preview" package respectively.`);
10110
10199
  if (typeof provider.serverFactory !== "function") throw new TypeError(`The browser provider options do not return a "serverFactory" function. Are you using the latest "@vitest/browser-${provider.name}" package?`);
10111
10200
  const browser = await provider.serverFactory({
10112
10201
  project: this,
@@ -10133,7 +10222,7 @@ class TestProject {
10133
10222
  if (!this.closingPromise) this.closingPromise = Promise.all([
10134
10223
  this.vite?.close(),
10135
10224
  this.typechecker?.stop(),
10136
- this.browser?.close(),
10225
+ (this.browser || this._parent?._parentBrowser?.vite)?.close(),
10137
10226
  this.clearTmpDir()
10138
10227
  ].filter(Boolean)).then(() => {
10139
10228
  if (!this.runner.isClosed()) return this.runner.close();
@@ -10159,6 +10248,7 @@ class TestProject {
10159
10248
  ...options,
10160
10249
  coverage: this.vitest.config.coverage
10161
10250
  }, server.config);
10251
+ this._config.api.token = this.vitest.config.api.token;
10162
10252
  this._setHash();
10163
10253
  for (const _providedKey in this.config.provide) {
10164
10254
  const providedKey = _providedKey;
@@ -10411,7 +10501,7 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
10411
10501
  return resolvedProjects.filter((project) => !removeProjects.has(project));
10412
10502
  }
10413
10503
  function cloneConfig(project, { browser, ...config }) {
10414
- const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, browser: _browser, name, provider, ...overrideConfig } = config;
10504
+ const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, fileParallelism, browser: _browser, name, provider, ...overrideConfig } = config;
10415
10505
  const currentConfig = project.config.browser;
10416
10506
  const clonedConfig = deepClone(project.config);
10417
10507
  return mergeConfig({
@@ -10425,6 +10515,7 @@ function cloneConfig(project, { browser, ...config }) {
10425
10515
  screenshotFailures: screenshotFailures ?? currentConfig.screenshotFailures,
10426
10516
  headless: headless ?? currentConfig.headless,
10427
10517
  provider: provider ?? currentConfig.provider,
10518
+ fileParallelism: fileParallelism ?? currentConfig.fileParallelism,
10428
10519
  name: browser,
10429
10520
  instances: []
10430
10521
  },
@@ -11767,6 +11858,12 @@ class TestRun {
11767
11858
  const task = this.vitest.state.idMap.get(id);
11768
11859
  const entity = task && this.vitest.state.getReportedEntity(task);
11769
11860
  assert$1(task && entity, `Entity must be found for task ${task?.name || id}`);
11861
+ if (event === "suite-failed-early" && entity.type === "module") {
11862
+ // the file failed during import
11863
+ await this.vitest.report("onTestModuleStart", entity);
11864
+ await this.vitest.report("onTestModuleEnd", entity);
11865
+ return;
11866
+ }
11770
11867
  if (event === "suite-prepare" && entity.type === "suite") return await this.vitest.report("onTestSuiteReady", entity);
11771
11868
  if (event === "suite-prepare" && entity.type === "module") return await this.vitest.report("onTestModuleStart", entity);
11772
11869
  if (event === "suite-finished") {
@@ -12401,7 +12498,7 @@ class Vitest {
12401
12498
  * @param filters String filters to match the test files
12402
12499
  */
12403
12500
  async start(filters) {
12404
- return this._traces.$("vitest.start", async (startSpan) => {
12501
+ return this._traces.$("vitest.start", { context: this._traces.getContextFromEnv(process.env) }, async (startSpan) => {
12405
12502
  startSpan.setAttributes({ config: this.vite.config.configFile });
12406
12503
  try {
12407
12504
  await this._traces.$("vitest.coverage.init", async () => {
@@ -12413,7 +12510,7 @@ class Vitest {
12413
12510
  }
12414
12511
  this.filenamePattern = filters && filters?.length > 0 ? filters : void 0;
12415
12512
  startSpan.setAttribute("vitest.start.filters", this.filenamePattern || []);
12416
- const files = await this._traces.$("vitest.config.resolve_include_glob", async () => {
12513
+ const specifications = await this._traces.$("vitest.config.resolve_include_glob", async () => {
12417
12514
  const specifications = await this.specifications.getRelevantTestSpecifications(filters);
12418
12515
  startSpan.setAttribute("vitest.start.specifications", specifications.map((s) => {
12419
12516
  const relativeModuleId = relative(s.project.config.root, s.moduleId);
@@ -12423,7 +12520,7 @@ class Vitest {
12423
12520
  return specifications;
12424
12521
  });
12425
12522
  // if run with --changed, don't exit if no tests are found
12426
- if (!files.length) {
12523
+ if (!specifications.length) {
12427
12524
  await this._traces.$("vitest.test_run", async () => {
12428
12525
  await this._testRun.start([]);
12429
12526
  const coverage = await this.coverageProvider?.generateCoverage?.({ allTestsRun: true });
@@ -12437,10 +12534,10 @@ class Vitest {
12437
12534
  testModules: [],
12438
12535
  unhandledErrors: []
12439
12536
  };
12440
- if (files.length) {
12537
+ if (specifications.length) {
12441
12538
  // populate once, update cache on watch
12442
- await this.cache.stats.populateStats(this.config.root, files);
12443
- testModules = await this.runFiles(files, true);
12539
+ await this.cache.stats.populateStats(this.config.root, specifications);
12540
+ testModules = await this.runFiles(specifications, true);
12444
12541
  }
12445
12542
  if (this.config.watch) await this.report("onWatcherStart");
12446
12543
  return testModules;
@@ -12499,6 +12596,19 @@ class Vitest {
12499
12596
  return this.runFiles(specifications, allTestsRun);
12500
12597
  }
12501
12598
  /**
12599
+ * Runs tests for the given file paths. This does not trigger `onWatcher*` events.
12600
+ * @param filepaths A list of file paths to run tests for.
12601
+ * @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
12602
+ */
12603
+ async runTestFiles(filepaths, allTestsRun = false) {
12604
+ const specifications = await this.specifications.getRelevantTestSpecifications(filepaths);
12605
+ if (!specifications.length) return {
12606
+ testModules: [],
12607
+ unhandledErrors: []
12608
+ };
12609
+ return this.runFiles(specifications, allTestsRun);
12610
+ }
12611
+ /**
12502
12612
  * Rerun files and trigger `onWatcherRerun`, `onWatcherStart` and `onTestsRerun` events.
12503
12613
  * @param specifications A list of specifications to run.
12504
12614
  * @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
@@ -12989,7 +13099,12 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
12989
13099
  // this is repeated in configResolved where the config is final
12990
13100
  const testConfig = deepMerge({}, configDefaults, removeUndefinedValues(viteConfig.test ?? {}), options);
12991
13101
  testConfig.api = resolveApiServerConfig(testConfig, defaultPort);
12992
- options.defines = deleteDefineConfig(viteConfig);
13102
+ // store defines for globalThis to make them
13103
+ // reassignable when running in worker in src/runtime/setup.ts
13104
+ const originalDefine = { ...viteConfig.define };
13105
+ const defines = deleteDefineConfig(viteConfig);
13106
+ options.defines = defines;
13107
+ options.viteDefine = originalDefine;
12993
13108
  let open = false;
12994
13109
  if (testConfig.ui && testConfig.open) open = testConfig.uiBase ?? "/__vitest__/";
12995
13110
  const resolveOptions = getDefaultResolveOptions();