vitest 4.0.15 → 4.0.17

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 (49) hide show
  1. package/dist/browser.d.ts +3 -2
  2. package/dist/browser.js +2 -1
  3. package/dist/chunks/{base.CTp-EStD.js → base.XJJQZiKB.js} +4 -3
  4. package/dist/chunks/{browser.d.DBzUq_Na.d.ts → browser.d.ChKACdzH.d.ts} +3 -1
  5. package/dist/chunks/{cac.BNNpZQl7.js → cac.jRCLJDDc.js} +6 -6
  6. package/dist/chunks/{cli-api.C7sYjHmQ.js → cli-api.Cx2DW4Bc.js} +176 -89
  7. package/dist/chunks/{config.d.CzIjkicf.d.ts → config.d.Cy95HiCx.d.ts} +5 -0
  8. package/dist/chunks/{coverage.CtyeYmKM.js → coverage.AVPTjMgw.js} +6 -1
  9. package/dist/chunks/{index.bFLgAE-Z.js → index.6Qv1eEA6.js} +2 -2
  10. package/dist/chunks/{index.Drsj_6e7.js → index.C5r1PdPD.js} +1 -1
  11. package/dist/chunks/index.Chj8NDwU.js +206 -0
  12. package/dist/chunks/{index.BspFP3mn.js → index.CyBMJtT7.js} +1 -1
  13. package/dist/chunks/{index.456_DGfR.js → index.M8mOzt4Y.js} +26 -2
  14. package/dist/chunks/{init-forks.CKEYp90N.js → init-forks.BC6ZwHQN.js} +1 -1
  15. package/dist/chunks/{init-threads.D8Ok07M7.js → init-threads.CxSxLC0N.js} +1 -1
  16. package/dist/chunks/{init.B04saIIg.js → init.C9kljSTm.js} +5 -7
  17. package/dist/chunks/{modules.DJPjQW6m.js → modules.BJuCwlRJ.js} +4 -3
  18. package/dist/chunks/{plugin.d.CY7CUjf-.d.ts → plugin.d.CtqpEehP.d.ts} +1 -1
  19. package/dist/chunks/{reporters.d.OXEK7y4s.d.ts → reporters.d.CWXNI2jG.d.ts} +6 -5
  20. package/dist/chunks/{rpc.BytlcPfC.js → rpc.BoxB0q7B.js} +1 -1
  21. package/dist/chunks/{startModuleRunner.Iz2V0ESw.js → startModuleRunner.DEj0jb3e.js} +2 -2
  22. package/dist/chunks/{test.BT8LKgU9.js → test.B8ej_ZHS.js} +1 -1
  23. package/dist/chunks/{traces.U4xDYhzZ.js → traces.CCmnQaNT.js} +46 -1
  24. package/dist/chunks/{vm.BwmD1Rql.js → vm.CMjifoPa.js} +2 -2
  25. package/dist/chunks/worker.d.Dyxm8DEL.d.ts +255 -0
  26. package/dist/cli.js +2 -2
  27. package/dist/config.d.ts +6 -6
  28. package/dist/coverage.d.ts +5 -5
  29. package/dist/coverage.js +1 -1
  30. package/dist/environments.js +1 -1
  31. package/dist/index.d.ts +7 -7
  32. package/dist/module-evaluator.js +3 -11
  33. package/dist/module-runner.js +3 -3
  34. package/dist/node.d.ts +20 -11
  35. package/dist/node.js +11 -11
  36. package/dist/reporters.d.ts +4 -4
  37. package/dist/reporters.js +2 -2
  38. package/dist/runners.d.ts +1 -1
  39. package/dist/runners.js +3 -3
  40. package/dist/worker.d.ts +5 -3
  41. package/dist/worker.js +10 -10
  42. package/dist/workers/forks.js +11 -11
  43. package/dist/workers/runVmTests.js +4 -4
  44. package/dist/workers/threads.js +11 -11
  45. package/dist/workers/vmForks.js +9 -9
  46. package/dist/workers/vmThreads.js +9 -9
  47. package/package.json +13 -13
  48. package/dist/chunks/index.0kCJoeWi.js +0 -220
  49. package/dist/chunks/worker.d.B4A26qg6.d.ts +0 -238
@@ -2,20 +2,20 @@ import fs, { promises, existsSync, mkdirSync, readFileSync, statSync, readdirSyn
2
2
  import { relative, resolve, dirname, join, extname, normalize, 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, createDefer, slash, isExternalUrl, unwrapId, withTrailingSlash, cleanUrl, wrapId, toArray, deepMerge, nanoid, deepClone, isPrimitive, notNullish } from '@vitest/utils/helpers';
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.CtyeYmKM.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.AVPTjMgw.js';
8
8
  import * as vite from 'vite';
9
- import { isFileServingAllowed, parseAst, searchForWorkspaceRoot, fetchModule, version, mergeConfig, createServer } from 'vite';
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';
11
11
  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.BNNpZQl7.js';
15
+ import { v as version$1 } from './cac.jRCLJDDc.js';
16
16
  import { performance as performance$1 } from 'node:perf_hooks';
17
- import { c as createBirpc } from './index.0kCJoeWi.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';
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.M8mOzt4Y.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';
@@ -42,7 +42,7 @@ import url, { fileURLToPath, pathToFileURL } from 'node:url';
42
42
  import { i as isTTY, a as isWindows } from './env.D4Lgay0q.js';
43
43
  import { isatty } from 'node:tty';
44
44
  import EventEmitter$1, { EventEmitter } from 'node:events';
45
- import { t as toBuiltin, i as isBuiltin } from './modules.DJPjQW6m.js';
45
+ import { t as toBuiltin, i as isBuiltin } from './modules.BJuCwlRJ.js';
46
46
  import { fork } from 'node:child_process';
47
47
  import { Worker } from 'node:worker_threads';
48
48
  import pm from 'picomatch';
@@ -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.C5r1PdPD.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';
@@ -5175,7 +5175,7 @@ function setup(ctx, _server) {
5175
5175
  async getExternalResult(moduleId, testFileTaskId) {
5176
5176
  const testModule = ctx.state.getReportedEntityById(testFileTaskId);
5177
5177
  if (!testModule) return;
5178
- if (!isFileServingAllowed(testModule.project.vite.config, moduleId)) return;
5178
+ if (!isFileServingAllowed$1(testModule.project.vite.config, moduleId)) return;
5179
5179
  const result = {};
5180
5180
  try {
5181
5181
  result.source = await promises.readFile(moduleId, "utf-8");
@@ -5185,7 +5185,7 @@ function setup(ctx, _server) {
5185
5185
  async getTransformResult(projectName, moduleId, testFileTaskId, browser = false) {
5186
5186
  const project = ctx.getProjectByName(projectName);
5187
5187
  const testModule = ctx.state.getReportedEntityById(testFileTaskId);
5188
- if (!testModule || !isFileServingAllowed(project.vite.config, moduleId)) return;
5188
+ if (!testModule || !isFileServingAllowed$1(project.vite.config, moduleId)) return;
5189
5189
  const environment = getTestFileEnvironment(project, testModule.moduleId, browser);
5190
5190
  const moduleNode = environment?.moduleGraph.getModuleById(moduleId);
5191
5191
  if (!environment || !moduleNode?.transformResult) return;
@@ -5771,7 +5771,7 @@ class FileSystemModuleCache {
5771
5771
  */
5772
5772
  rootCache;
5773
5773
  metadataFilePath;
5774
- version = "1.0.0-beta.3";
5774
+ version = "1.0.0-beta.4";
5775
5775
  fsCacheRoots = /* @__PURE__ */ new WeakMap();
5776
5776
  fsEnvironmentHashMap = /* @__PURE__ */ new WeakMap();
5777
5777
  fsCacheKeyGenerators = /* @__PURE__ */ new Set();
@@ -5828,18 +5828,16 @@ class FileSystemModuleCache {
5828
5828
  url: meta.url,
5829
5829
  file: meta.file,
5830
5830
  code,
5831
- importers: meta.importers,
5832
5831
  importedUrls: meta.importedUrls,
5833
5832
  mappings: meta.mappings
5834
5833
  };
5835
5834
  }
5836
- async saveCachedModule(cachedFilePath, fetchResult, importers = [], importedUrls = [], mappings = false) {
5835
+ async saveCachedModule(cachedFilePath, fetchResult, importedUrls = [], mappings = false) {
5837
5836
  if ("code" in fetchResult) {
5838
5837
  const result = {
5839
5838
  file: fetchResult.file,
5840
5839
  id: fetchResult.id,
5841
5840
  url: fetchResult.url,
5842
- importers,
5843
5841
  importedUrls,
5844
5842
  mappings
5845
5843
  };
@@ -6082,6 +6080,28 @@ function tryStatSync(file) {
6082
6080
  } catch {}
6083
6081
  }
6084
6082
 
6083
+ // this is copy pasted from vite
6084
+ function normalizeResolvedIdToUrl(environment, resolvedId) {
6085
+ const root = environment.config.root;
6086
+ const depsOptimizer = environment.depsOptimizer;
6087
+ let url;
6088
+ // normalize all imports into resolved URLs
6089
+ // e.g. `import 'foo'` -> `import '/@fs/.../node_modules/foo/index.js'`
6090
+ if (resolvedId.startsWith(withTrailingSlash(root)))
6091
+ // in root: infer short absolute path from root
6092
+ url = resolvedId.slice(root.length);
6093
+ else if (depsOptimizer?.isOptimizedDepFile(resolvedId) || resolvedId !== "/@react-refresh" && path.isAbsolute(resolvedId) && existsSync(cleanUrl(resolvedId)))
6094
+ // an optimized deps may not yet exists in the filesystem, or
6095
+ // a regular file exists but is out of root: rewrite to absolute /@fs/ paths
6096
+ url = path.posix.join("/@fs/", resolvedId);
6097
+ else url = resolvedId;
6098
+ // if the resolved id is not a valid browser import specifier,
6099
+ // prefix it to make it valid. We will strip this before feeding it
6100
+ // back into the transform pipeline
6101
+ if (url[0] !== "." && url[0] !== "/") url = wrapId(resolvedId);
6102
+ return url;
6103
+ }
6104
+
6085
6105
  const saveCachePromises = /* @__PURE__ */ new Map();
6086
6106
  const readFilePromises = /* @__PURE__ */ new Map();
6087
6107
  class ModuleFetcher {
@@ -6117,6 +6137,11 @@ class ModuleFetcher {
6117
6137
  type: "network"
6118
6138
  };
6119
6139
  }
6140
+ // handle unresolved id of dynamic import skipped by Vite import analysis
6141
+ if (url[0] !== "/") {
6142
+ const resolved = await environment.pluginContainer.resolveId(url, importer);
6143
+ if (resolved) url = normalizeResolvedIdToUrl(environment, resolved.id);
6144
+ }
6120
6145
  const moduleGraphModule = await environment.moduleGraph.ensureEntryFromUrl(unwrapId(url));
6121
6146
  const cached = !!moduleGraphModule.transformResult;
6122
6147
  if (moduleGraphModule.file) trace.setAttribute("code.file.path", moduleGraphModule.file);
@@ -6151,17 +6176,16 @@ class ModuleFetcher {
6151
6176
  this.recordResult(trace, result);
6152
6177
  return result;
6153
6178
  });
6154
- const cachedModule = await this.getCachedModule(cachePath, environment, moduleGraphModule);
6179
+ const cachedModule = await this.getCachedModule(cachePath, environment, moduleGraphModule, importer);
6155
6180
  if (cachedModule) {
6156
6181
  this.recordResult(trace, cachedModule);
6157
6182
  return cachedModule;
6158
6183
  }
6159
6184
  const result = await this.fetchAndProcess(environment, url, importer, moduleGraphModule, options);
6160
- const importers = this.getSerializedDependencies(moduleGraphModule);
6161
6185
  const importedUrls = this.getSerializedImports(moduleGraphModule);
6162
6186
  const map = moduleGraphModule.transformResult?.map;
6163
6187
  const mappings = map && !("version" in map) && map.mappings === "";
6164
- return this.cacheResult(result, cachePath, importers, importedUrls, !!mappings);
6188
+ return this.cacheResult(result, cachePath, importedUrls, !!mappings);
6165
6189
  }
6166
6190
  // we need this for UI to be able to show a module graph
6167
6191
  getSerializedImports(node) {
@@ -6171,14 +6195,6 @@ class ModuleFetcher {
6171
6195
  });
6172
6196
  return imports;
6173
6197
  }
6174
- // we need this for the watcher to be able to find the related test file
6175
- getSerializedDependencies(node) {
6176
- const dependencies = [];
6177
- node.importers.forEach((importer) => {
6178
- if (importer.id) dependencies.push(importer.id);
6179
- });
6180
- return dependencies;
6181
- }
6182
6198
  recordResult(trace, result) {
6183
6199
  if ("externalize" in result) trace.setAttributes({
6184
6200
  "vitest.fetched_module.external": result.externalize,
@@ -6215,7 +6231,7 @@ class ModuleFetcher {
6215
6231
  if (loadResult != null) return loadResult.code;
6216
6232
  return "";
6217
6233
  }
6218
- async getCachedModule(cachePath, environment, moduleGraphModule) {
6234
+ async getCachedModule(cachePath, environment, moduleGraphModule, importer) {
6219
6235
  if (moduleGraphModule.transformResult?.__vitestTmp) return {
6220
6236
  cached: true,
6221
6237
  file: moduleGraphModule.file,
@@ -6238,13 +6254,16 @@ class ModuleFetcher {
6238
6254
  __vitestTmp: cachePath
6239
6255
  };
6240
6256
  // we populate the module graph to make the watch mode work because it relies on importers
6241
- cachedModule.importers.forEach((importer) => {
6257
+ if (importer) {
6242
6258
  const environmentNode = environment.moduleGraph.getModuleById(importer);
6243
6259
  if (environmentNode) moduleGraphModule.importers.add(environmentNode);
6244
- });
6260
+ }
6245
6261
  await Promise.all(cachedModule.importedUrls.map(async (url) => {
6246
6262
  const moduleNode = await environment.moduleGraph.ensureEntryFromUrl(url).catch(() => null);
6247
- if (moduleNode) moduleGraphModule.importedModules.add(moduleNode);
6263
+ if (moduleNode) {
6264
+ moduleNode.importers.add(moduleGraphModule);
6265
+ moduleGraphModule.importedModules.add(moduleNode);
6266
+ }
6248
6267
  }));
6249
6268
  return {
6250
6269
  cached: true,
@@ -6261,13 +6280,13 @@ class ModuleFetcher {
6261
6280
  inlineSourceMap: false
6262
6281
  }).catch(handleRollupError));
6263
6282
  }
6264
- async cacheResult(result, cachePath, importers = [], importedUrls = [], mappings = false) {
6283
+ async cacheResult(result, cachePath, importedUrls = [], mappings = false) {
6265
6284
  const returnResult = "code" in result ? getCachedResult(result, cachePath) : result;
6266
6285
  if (saveCachePromises.has(cachePath)) {
6267
6286
  await saveCachePromises.get(cachePath);
6268
6287
  return returnResult;
6269
6288
  }
6270
- const savePromise = this.fsCache.saveCachedModule(cachePath, result, importers, importedUrls, mappings).then(() => result).finally(() => {
6289
+ const savePromise = this.fsCache.saveCachedModule(cachePath, result, importedUrls, mappings).then(() => result).finally(() => {
6271
6290
  saveCachePromises.delete(cachePath);
6272
6291
  });
6273
6292
  saveCachePromises.set(cachePath, savePromise);
@@ -6374,28 +6393,6 @@ function handleRollupError(e) {
6374
6393
  throw e;
6375
6394
  }
6376
6395
 
6377
- // this is copy pasted from vite
6378
- function normalizeResolvedIdToUrl(environment, resolvedId) {
6379
- const root = environment.config.root;
6380
- const depsOptimizer = environment.depsOptimizer;
6381
- let url;
6382
- // normalize all imports into resolved URLs
6383
- // e.g. `import 'foo'` -> `import '/@fs/.../node_modules/foo/index.js'`
6384
- if (resolvedId.startsWith(withTrailingSlash(root)))
6385
- // in root: infer short absolute path from root
6386
- url = resolvedId.slice(root.length);
6387
- else if (depsOptimizer?.isOptimizedDepFile(resolvedId) || resolvedId !== "/@react-refresh" && path.isAbsolute(resolvedId) && existsSync(cleanUrl(resolvedId)))
6388
- // an optimized deps may not yet exists in the filesystem, or
6389
- // a regular file exists but is out of root: rewrite to absolute /@fs/ paths
6390
- url = path.posix.join("/@fs/", resolvedId);
6391
- else url = resolvedId;
6392
- // if the resolved id is not a valid browser import specifier,
6393
- // prefix it to make it valid. We will strip this before feeding it
6394
- // back into the transform pipeline
6395
- if (url[0] !== "." && url[0] !== "/") url = wrapId(resolvedId);
6396
- return url;
6397
- }
6398
-
6399
6396
  class ServerModuleRunner extends ModuleRunner {
6400
6397
  constructor(environment, fetcher, config) {
6401
6398
  super({
@@ -7124,12 +7121,21 @@ class BrowserPool {
7124
7121
  _promise;
7125
7122
  _providedContext;
7126
7123
  readySessions = /* @__PURE__ */ new Set();
7124
+ _traces;
7125
+ _otel;
7127
7126
  constructor(project, options) {
7128
7127
  this.project = project;
7129
7128
  this.options = options;
7129
+ this._traces = project.vitest._traces;
7130
+ this._otel = this._traces.startContextSpan("vitest.browser");
7131
+ this._otel.span.setAttributes({
7132
+ "vitest.project": project.name,
7133
+ "vitest.browser.provider": this.project.browser.provider.name
7134
+ });
7130
7135
  }
7131
7136
  cancel() {
7132
7137
  this._queue = [];
7138
+ this._otel.span.end();
7133
7139
  }
7134
7140
  reject(error) {
7135
7141
  this._promise?.reject(error);
@@ -7167,7 +7173,11 @@ class BrowserPool {
7167
7173
  this.project.vitest._browserSessions.sessionIds.add(sessionId);
7168
7174
  const project = this.project.name;
7169
7175
  debug?.("[%s] creating session for %s", sessionId, project);
7170
- const page = this.openPage(sessionId).then(() => {
7176
+ let page = this._traces.$(`vitest.browser.open`, {
7177
+ context: this._otel.context,
7178
+ attributes: { "vitest.browser.session_id": sessionId }
7179
+ }, () => this.openPage(sessionId));
7180
+ page = page.then(() => {
7171
7181
  // start running tests on the page when it's ready
7172
7182
  this.runNextTest(method, sessionId);
7173
7183
  });
@@ -7182,6 +7192,8 @@ class BrowserPool {
7182
7192
  const browser = this.project.browser;
7183
7193
  const url = new URL("/__vitest_test__/", this.options.origin);
7184
7194
  url.searchParams.set("sessionId", sessionId);
7195
+ const otelCarrier = this._traces.getContextCarrier();
7196
+ if (otelCarrier) url.searchParams.set("otelCarrier", JSON.stringify(otelCarrier));
7185
7197
  const pagePromise = browser.provider.openPage(sessionId, url.toString());
7186
7198
  await Promise.all([sessionPromise, pagePromise]);
7187
7199
  }
@@ -7194,6 +7206,7 @@ class BrowserPool {
7194
7206
  this.readySessions.add(sessionId);
7195
7207
  // the last worker finished running tests
7196
7208
  if (this.readySessions.size === this.orchestrators.size) {
7209
+ this._otel.span.end();
7197
7210
  this._promise?.resolve();
7198
7211
  this._promise = void 0;
7199
7212
  debug?.("[%s] all tests finished running", sessionId);
@@ -7216,11 +7229,16 @@ class BrowserPool {
7216
7229
  const orchestrator = this.getOrchestrator(sessionId);
7217
7230
  debug?.("[%s] run test %s", sessionId, file);
7218
7231
  this.setBreakpoint(sessionId, file.filepath).then(() => {
7219
- // this starts running tests inside the orchestrator
7220
- orchestrator.createTesters({
7221
- method,
7222
- files: [file],
7223
- providedContext: this._providedContext || "[{}]"
7232
+ this._traces.$(`vitest.browser.run`, {
7233
+ context: this._otel.context,
7234
+ attributes: { "code.file.path": file.filepath }
7235
+ }, async () => {
7236
+ return orchestrator.createTesters({
7237
+ method,
7238
+ files: [file],
7239
+ providedContext: this._providedContext || "[{}]",
7240
+ otelCarrier: this._traces.getContextCarrier()
7241
+ });
7224
7242
  }).then(() => {
7225
7243
  debug?.("[%s] test %s finished running", sessionId, file);
7226
7244
  this.runNextTest(method, sessionId);
@@ -7354,6 +7372,7 @@ var RunnerState = /* @__PURE__ */ function(RunnerState) {
7354
7372
  RunnerState["IDLE"] = "idle";
7355
7373
  RunnerState["STARTING"] = "starting";
7356
7374
  RunnerState["STARTED"] = "started";
7375
+ RunnerState["START_FAILURE"] = "start_failure";
7357
7376
  RunnerState["STOPPING"] = "stopping";
7358
7377
  RunnerState["STOPPED"] = "stopped";
7359
7378
  return RunnerState;
@@ -7415,6 +7434,14 @@ class PoolRunner {
7415
7434
  });
7416
7435
  this._offCancel = vitest.onCancel((reason) => this._rpc.onCancel(reason));
7417
7436
  }
7437
+ /**
7438
+ * "reconfigure" can only be called if `environment` is different, since different project always
7439
+ * requires a new PoolRunner instance.
7440
+ */
7441
+ reconfigure(task) {
7442
+ this.environment = task.context.environment;
7443
+ this._otel?.span.setAttribute("vitest.environment", this.environment.name);
7444
+ }
7418
7445
  postMessage(message) {
7419
7446
  // Only send messages when runner is active (not fully stopped)
7420
7447
  // Allow sending during STOPPING state for the 'stop' message itself
@@ -7490,7 +7517,7 @@ class PoolRunner {
7490
7517
  await startPromise;
7491
7518
  this._state = RunnerState.STARTED;
7492
7519
  } catch (error) {
7493
- this._state = RunnerState.IDLE;
7520
+ this._state = RunnerState.START_FAILURE;
7494
7521
  startSpan?.recordException(error);
7495
7522
  throw error;
7496
7523
  } finally {
@@ -7927,6 +7954,9 @@ class VmForksPoolWorker extends ForksPoolWorker {
7927
7954
  /** Loads {@link file://./../../../runtime/workers/vmForks.ts} */
7928
7955
  this.entrypoint = resolve$1(options.distPath, "workers/vmForks.js");
7929
7956
  }
7957
+ canReuse() {
7958
+ return true;
7959
+ }
7930
7960
  }
7931
7961
 
7932
7962
  /** @experimental */
@@ -7942,6 +7972,9 @@ class VmThreadsPoolWorker extends ThreadsPoolWorker {
7942
7972
  /** Loads {@link file://./../../../runtime/workers/vmThreads.ts} */
7943
7973
  this.entrypoint = resolve$1(options.distPath, "workers/vmThreads.js");
7944
7974
  }
7975
+ canReuse() {
7976
+ return true;
7977
+ }
7945
7978
  }
7946
7979
 
7947
7980
  const WORKER_START_TIMEOUT = 9e4;
@@ -8010,17 +8043,15 @@ class Pool {
8010
8043
  resolver.reject(new Error(`[vitest-pool]: Worker ${task.worker} emitted error.`, { cause: error }));
8011
8044
  });
8012
8045
  const id = setTimeout(() => resolver.reject(/* @__PURE__ */ new Error(`[vitest-pool]: Timeout starting ${task.worker} runner.`)), WORKER_START_TIMEOUT);
8013
- await runner.start({ workerId: task.context.workerId }).finally(() => clearTimeout(id));
8046
+ 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));
8014
8047
  }
8015
- const span = runner.startTracesSpan(`vitest.worker.${method}`);
8016
- // Start running the test in the worker
8017
- runner.request(method, task.context);
8018
- await resolver.promise.catch((error) => {
8019
- span.recordException(error);
8020
- throw error;
8021
- }).finally(() => {
8022
- span.end();
8023
- });
8048
+ let span;
8049
+ if (!resolver.isRejected) {
8050
+ span = runner.startTracesSpan(`vitest.worker.${method}`);
8051
+ // Start running the test in the worker
8052
+ runner.request(method, task.context);
8053
+ }
8054
+ await resolver.promise.catch((error) => span?.recordException(error)).finally(() => span?.end());
8024
8055
  const index = this.activeTasks.indexOf(activeTask);
8025
8056
  if (index !== -1) this.activeTasks.splice(index, 1);
8026
8057
  if (!task.isolate && !isMemoryLimitReached && this.queue[0]?.task.isolate === false && isEqualRunner(runner, this.queue[0].task)) {
@@ -8031,7 +8062,7 @@ class Pool {
8031
8062
  // Runner termination can also already start from task cancellation.
8032
8063
  if (!runner.isTerminated) {
8033
8064
  const id = setTimeout(() => this.logger.error(`[vitest-pool]: Timeout terminating ${task.worker} worker for test files ${formatFiles(task)}.`), this.options.teardownTimeout);
8034
- 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)));
8065
+ 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)));
8035
8066
  }
8036
8067
  this.freeWorkerId(poolId);
8037
8068
  }
@@ -8068,13 +8099,17 @@ catch (error) {
8068
8099
  getPoolRunner(task, method) {
8069
8100
  if (task.isolate === false) {
8070
8101
  const index = this.sharedRunners.findIndex((runner) => isEqualRunner(runner, task));
8071
- if (index !== -1) return this.sharedRunners.splice(index, 1)[0];
8102
+ if (index !== -1) {
8103
+ const runner = this.sharedRunners.splice(index, 1)[0];
8104
+ runner.reconfigure(task);
8105
+ return runner;
8106
+ }
8072
8107
  }
8073
8108
  const options = {
8074
8109
  distPath: this.options.distPath,
8075
8110
  project: task.project,
8076
8111
  method,
8077
- environment: task.environment,
8112
+ environment: task.context.environment,
8078
8113
  env: task.env,
8079
8114
  execArgv: task.execArgv
8080
8115
  };
@@ -8106,22 +8141,44 @@ catch (error) {
8106
8141
  function withResolvers() {
8107
8142
  let resolve = () => {};
8108
8143
  let reject = (_error) => {};
8109
- const promise = new Promise((res, rej) => {
8110
- resolve = res;
8111
- reject = rej;
8112
- });
8113
- return {
8144
+ const resolver = {
8145
+ promise: new Promise((res, rej) => {
8146
+ resolve = res;
8147
+ reject = rej;
8148
+ }),
8114
8149
  resolve,
8115
- reject,
8116
- promise
8150
+ reject: (reason) => {
8151
+ resolver.isRejected = true;
8152
+ reject(reason);
8153
+ },
8154
+ isRejected: false
8117
8155
  };
8156
+ return resolver;
8118
8157
  }
8119
8158
  function formatFiles(task) {
8120
8159
  return task.context.files.map((file) => file.filepath).join(", ");
8121
8160
  }
8122
8161
  function isEqualRunner(runner, task) {
8123
8162
  if (task.isolate) throw new Error("Isolated tasks should not share runners");
8124
- return runner.worker.name === task.worker && runner.project === task.project && runner.environment.name === task.environment.name && (!runner.worker.canReuse || runner.worker.canReuse(task));
8163
+ if (runner.worker.name !== task.worker || runner.project !== task.project) return false;
8164
+ // by default, check that the environments are the same
8165
+ // some workers (like vmThreads/vmForks) do not need this check
8166
+ if (!runner.worker.canReuse) return isEnvironmentEqual(task.context.environment, runner.environment);
8167
+ return runner.worker.canReuse(task);
8168
+ }
8169
+ function isEnvironmentEqual(env1, env2) {
8170
+ if (env1.name !== env2.name) return false;
8171
+ return deepEqual(env1.options, env2.options);
8172
+ }
8173
+ function deepEqual(obj1, obj2) {
8174
+ if (obj1 === obj2) return true;
8175
+ if (obj1 == null || obj2 == null) return obj1 === obj2;
8176
+ if (typeof obj1 !== "object" || typeof obj2 !== "object") return false;
8177
+ const keys1 = Object.keys(obj1);
8178
+ const keys2 = Object.keys(obj2);
8179
+ if (keys1.length !== keys2.length) return false;
8180
+ for (const key of keys1) if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) return false;
8181
+ return true;
8125
8182
  }
8126
8183
 
8127
8184
  const suppressWarningsPath = resolve(rootDir, "./suppress-warnings.cjs");
@@ -8194,9 +8251,9 @@ function createPool(ctx) {
8194
8251
  })),
8195
8252
  invalidates,
8196
8253
  providedContext: project.getProvidedContext(),
8197
- workerId: workerId++
8254
+ workerId: workerId++,
8255
+ environment
8198
8256
  },
8199
- environment,
8200
8257
  project,
8201
8258
  env,
8202
8259
  execArgv,
@@ -8463,7 +8520,8 @@ function serializeConfig(project) {
8463
8520
  serializedDefines: config.browser.enabled ? "" : project._serializedDefines || "",
8464
8521
  experimental: {
8465
8522
  fsModuleCache: config.experimental.fsModuleCache ?? false,
8466
- printImportBreakdown: config.experimental.printImportBreakdown
8523
+ printImportBreakdown: config.experimental.printImportBreakdown,
8524
+ openTelemetry: config.experimental.openTelemetry
8467
8525
  }
8468
8526
  };
8469
8527
  }
@@ -9545,6 +9603,7 @@ function WorkspaceVitestPlugin(project, options) {
9545
9603
  this.meta.watchMode = false;
9546
9604
  },
9547
9605
  config(viteConfig) {
9606
+ const originalDefine = { ...viteConfig.define };
9548
9607
  const defines = deleteDefineConfig(viteConfig);
9549
9608
  const testConfig = viteConfig.test || {};
9550
9609
  const root = testConfig.root || viteConfig.root || options.root;
@@ -9581,6 +9640,7 @@ function WorkspaceVitestPlugin(project, options) {
9581
9640
  }
9582
9641
  };
9583
9642
  config.test.defines = defines;
9643
+ config.test.viteDefine = originalDefine;
9584
9644
  const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
9585
9645
  if (classNameStrategy !== "scoped") {
9586
9646
  config.css ??= {};
@@ -9811,6 +9871,21 @@ async function createViteServer(inlineConfig) {
9811
9871
  console.error = error;
9812
9872
  return server;
9813
9873
  }
9874
+ function isFileServingAllowed(configOrUrl, urlOrServer) {
9875
+ const config = typeof urlOrServer === "string" ? configOrUrl : urlOrServer.config;
9876
+ const url = typeof urlOrServer === "string" ? urlOrServer : configOrUrl;
9877
+ if (!config.server.fs.strict) return true;
9878
+ return isFileLoadingAllowed(config, fsPathFromUrl(url));
9879
+ }
9880
+ const FS_PREFIX = "/@fs/";
9881
+ const VOLUME_RE = /^[A-Z]:/i;
9882
+ function fsPathFromId(id) {
9883
+ const fsPath = normalizePath(id.startsWith(FS_PREFIX) ? id.slice(5) : id);
9884
+ return fsPath[0] === "/" || VOLUME_RE.test(fsPath) ? fsPath : `/${fsPath}`;
9885
+ }
9886
+ function fsPathFromUrl(url) {
9887
+ return fsPathFromId(cleanUrl(url));
9888
+ }
9814
9889
 
9815
9890
  class TestProject {
9816
9891
  /**
@@ -10086,7 +10161,7 @@ class TestProject {
10086
10161
  _initParentBrowser = deduped(async (childProject) => {
10087
10162
  if (!this.isBrowserEnabled() || this._parentBrowser) return;
10088
10163
  const provider = this.config.browser.provider || childProject.config.browser.provider;
10089
- 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.`);
10164
+ 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.`);
10090
10165
  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?`);
10091
10166
  const browser = await provider.serverFactory({
10092
10167
  project: this,
@@ -10139,6 +10214,7 @@ class TestProject {
10139
10214
  ...options,
10140
10215
  coverage: this.vitest.config.coverage
10141
10216
  }, server.config);
10217
+ this._config.api.token = this.vitest.config.api.token;
10142
10218
  this._setHash();
10143
10219
  for (const _providedKey in this.config.provide) {
10144
10220
  const providedKey = _providedKey;
@@ -10391,7 +10467,7 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
10391
10467
  return resolvedProjects.filter((project) => !removeProjects.has(project));
10392
10468
  }
10393
10469
  function cloneConfig(project, { browser, ...config }) {
10394
- const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, browser: _browser, name, provider, ...overrideConfig } = config;
10470
+ const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, fileParallelism, browser: _browser, name, provider, ...overrideConfig } = config;
10395
10471
  const currentConfig = project.config.browser;
10396
10472
  const clonedConfig = deepClone(project.config);
10397
10473
  return mergeConfig({
@@ -10405,6 +10481,7 @@ function cloneConfig(project, { browser, ...config }) {
10405
10481
  screenshotFailures: screenshotFailures ?? currentConfig.screenshotFailures,
10406
10482
  headless: headless ?? currentConfig.headless,
10407
10483
  provider: provider ?? currentConfig.provider,
10484
+ fileParallelism: fileParallelism ?? currentConfig.fileParallelism,
10408
10485
  name: browser,
10409
10486
  instances: []
10410
10487
  },
@@ -11747,6 +11824,12 @@ class TestRun {
11747
11824
  const task = this.vitest.state.idMap.get(id);
11748
11825
  const entity = task && this.vitest.state.getReportedEntity(task);
11749
11826
  assert$1(task && entity, `Entity must be found for task ${task?.name || id}`);
11827
+ if (event === "suite-failed-early" && entity.type === "module") {
11828
+ // the file failed during import
11829
+ await this.vitest.report("onTestModuleStart", entity);
11830
+ await this.vitest.report("onTestModuleEnd", entity);
11831
+ return;
11832
+ }
11750
11833
  if (event === "suite-prepare" && entity.type === "suite") return await this.vitest.report("onTestSuiteReady", entity);
11751
11834
  if (event === "suite-prepare" && entity.type === "module") return await this.vitest.report("onTestModuleStart", entity);
11752
11835
  if (event === "suite-finished") {
@@ -12381,7 +12464,7 @@ class Vitest {
12381
12464
  * @param filters String filters to match the test files
12382
12465
  */
12383
12466
  async start(filters) {
12384
- return this._traces.$("vitest.start", async (startSpan) => {
12467
+ return this._traces.$("vitest.start", { context: this._traces.getContextFromEnv(process.env) }, async (startSpan) => {
12385
12468
  startSpan.setAttributes({ config: this.vite.config.configFile });
12386
12469
  try {
12387
12470
  await this._traces.$("vitest.coverage.init", async () => {
@@ -12969,7 +13052,11 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
12969
13052
  // this is repeated in configResolved where the config is final
12970
13053
  const testConfig = deepMerge({}, configDefaults, removeUndefinedValues(viteConfig.test ?? {}), options);
12971
13054
  testConfig.api = resolveApiServerConfig(testConfig, defaultPort);
13055
+ // store defines for globalThis to make them
13056
+ // reassignable when running in worker in src/runtime/setup.ts
13057
+ const originalDefine = { ...viteConfig.define };
12972
13058
  options.defines = deleteDefineConfig(viteConfig);
13059
+ options.viteDefine = originalDefine;
12973
13060
  let open = false;
12974
13061
  if (testConfig.ui && testConfig.open) open = testConfig.uiBase ?? "/__vitest__/";
12975
13062
  const resolveOptions = getDefaultResolveOptions();
@@ -13567,4 +13654,4 @@ var cliApi = /*#__PURE__*/Object.freeze({
13567
13654
  startVitest: startVitest
13568
13655
  });
13569
13656
 
13570
- export { FilesNotFoundError as F, GitNotFoundError as G, ThreadsPoolWorker as T, Vitest as V, VitestPlugin as a, VitestPackageInstaller as b, createVitest as c, createMethodsRPC as d, escapeTestName as e, ForksPoolWorker as f, getFilePoolName as g, TypecheckPoolWorker as h, isValidApiRequest as i, VmForksPoolWorker as j, VmThreadsPoolWorker as k, experimental_getRunnerTask as l, registerConsoleShortcuts as m, createViteLogger as n, createDebugger as o, cliApi as p, resolveFsAllow as r, startVitest as s };
13657
+ export { FilesNotFoundError as F, GitNotFoundError as G, ThreadsPoolWorker as T, Vitest as V, VitestPlugin as a, VitestPackageInstaller as b, createVitest as c, createMethodsRPC as d, escapeTestName as e, ForksPoolWorker as f, getFilePoolName as g, TypecheckPoolWorker as h, isValidApiRequest as i, VmForksPoolWorker as j, VmThreadsPoolWorker as k, experimental_getRunnerTask as l, registerConsoleShortcuts as m, isFileServingAllowed as n, createViteLogger as o, createDebugger as p, cliApi as q, resolveFsAllow as r, startVitest as s };
@@ -183,6 +183,11 @@ interface SerializedConfig {
183
183
  experimental: {
184
184
  fsModuleCache: boolean;
185
185
  printImportBreakdown: boolean | undefined;
186
+ openTelemetry: {
187
+ enabled: boolean;
188
+ sdkPath?: string;
189
+ browserSdkPath?: string;
190
+ } | undefined;
186
191
  };
187
192
  }
188
193
  interface SerializedCoverageConfig {
@@ -2474,6 +2474,7 @@ function resolveConfig$1(vitest, options, viteConfig) {
2474
2474
  resolved.pool = options.pool.name;
2475
2475
  resolved.poolRunner = options.pool;
2476
2476
  }
2477
+ if ("poolOptions" in resolved) logger.deprecate("`test.poolOptions` was removed in Vitest 4. All previous `poolOptions` are now top-level options. Please, refer to the migration guide: https://vitest.dev/guide/migration#pool-rework");
2477
2478
  resolved.pool ??= "forks";
2478
2479
  resolved.project = toArray(resolved.project);
2479
2480
  resolved.provide ??= {};
@@ -2790,13 +2791,17 @@ function resolveConfig$1(vitest, options, viteConfig) {
2790
2791
  const userFolder = resolved.server.debug?.dump || process.env.VITEST_DEBUG_DUMP;
2791
2792
  resolved.dumpDir = resolve(resolved.root, typeof userFolder === "string" && userFolder !== "true" ? userFolder : ".vitest-dump", resolved.name || "root");
2792
2793
  }
2793
- resolved.testTimeout ??= resolved.browser.enabled ? 3e4 : 5e3;
2794
+ resolved.testTimeout ??= resolved.browser.enabled ? 15e3 : 5e3;
2794
2795
  resolved.hookTimeout ??= resolved.browser.enabled ? 3e4 : 1e4;
2795
2796
  resolved.experimental ??= {};
2796
2797
  if (resolved.experimental.openTelemetry?.sdkPath) {
2797
2798
  const sdkPath = resolve(resolved.root, resolved.experimental.openTelemetry.sdkPath);
2798
2799
  resolved.experimental.openTelemetry.sdkPath = pathToFileURL$1(sdkPath).toString();
2799
2800
  }
2801
+ if (resolved.experimental.openTelemetry?.browserSdkPath) {
2802
+ const browserSdkPath = resolve(resolved.root, resolved.experimental.openTelemetry.browserSdkPath);
2803
+ resolved.experimental.openTelemetry.browserSdkPath = browserSdkPath;
2804
+ }
2800
2805
  if (resolved.experimental.fsModuleCachePath) resolved.experimental.fsModuleCachePath = resolve(resolved.root, resolved.experimental.fsModuleCachePath);
2801
2806
  return resolved;
2802
2807
  }
@@ -1,8 +1,8 @@
1
1
  import { chai } from '@vitest/expect';
2
2
  import { l as loadDiffConfig, b as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.Cm-kSBVi.js';
3
- import { r as rpc } from './rpc.BytlcPfC.js';
3
+ import { r as rpc } from './rpc.BoxB0q7B.js';
4
4
  import { g as getWorkerState } from './utils.DvEY5TfP.js';
5
- import { V as VitestTestRunner, N as NodeBenchmarkRunner } from './test.BT8LKgU9.js';
5
+ import { V as VitestTestRunner, N as NodeBenchmarkRunner } from './test.B8ej_ZHS.js';
6
6
 
7
7
  function setupChaiConfig(config) {
8
8
  Object.assign(chai.config, config);