vitest 4.0.13 → 4.0.15

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 (50) hide show
  1. package/dist/browser.d.ts +1 -1
  2. package/dist/browser.js +1 -1
  3. package/dist/chunks/{base.Dqf2QAxh.js → base.CTp-EStD.js} +6 -6
  4. package/dist/chunks/browser.d.DBzUq_Na.d.ts +57 -0
  5. package/dist/chunks/{cac.L-UbQ_Ix.js → cac.BNNpZQl7.js} +10 -25
  6. package/dist/chunks/{cli-api.CdZ6wo9-.js → cli-api.C7sYjHmQ.js} +442 -110
  7. package/dist/chunks/{config.d.g6OOauRt.d.ts → config.d.CzIjkicf.d.ts} +1 -0
  8. package/dist/chunks/evaluatedModules.d.BxJ5omdx.d.ts +7 -0
  9. package/dist/chunks/{globals.C0izxiX3.js → globals.DOayXfHP.js} +3 -3
  10. package/dist/chunks/{index.DWDW6mLz.js → index.456_DGfR.js} +137 -22
  11. package/dist/chunks/{index.QWbK7rHY.js → index.BspFP3mn.js} +12 -7
  12. package/dist/chunks/{index.CMvpbrsJ.js → index.Drsj_6e7.js} +1 -1
  13. package/dist/chunks/{index.DBx1AtPJ.js → index.Z5E_ObnR.js} +1 -1
  14. package/dist/chunks/{index.CQwQ_SLL.js → index.bFLgAE-Z.js} +2 -2
  15. package/dist/chunks/{init-forks.CglOH45c.js → init-forks.CKEYp90N.js} +11 -2
  16. package/dist/chunks/{init-threads.BuMdIy1r.js → init-threads.D8Ok07M7.js} +1 -1
  17. package/dist/chunks/{init.MkYs5nmh.js → init.B04saIIg.js} +4 -4
  18. package/dist/chunks/modules.DJPjQW6m.js +35 -0
  19. package/dist/chunks/{plugin.d.B4l3vYM_.d.ts → plugin.d.CY7CUjf-.d.ts} +1 -1
  20. package/dist/chunks/{reporters.d.J2RlBlp9.d.ts → reporters.d.OXEK7y4s.d.ts} +29 -6
  21. package/dist/chunks/{setup-common.DGHc_BUK.js → setup-common.Cm-kSBVi.js} +1 -1
  22. package/dist/chunks/{startModuleRunner.W28wBIgJ.js → startModuleRunner.Iz2V0ESw.js} +8 -9
  23. package/dist/chunks/{test.DqQZzsWf.js → test.BT8LKgU9.js} +8 -3
  24. package/dist/chunks/{vi.BiaV1qII.js → vi.2VT5v0um.js} +40 -30
  25. package/dist/chunks/{vm.Y19jrZy2.js → vm.BwmD1Rql.js} +2 -2
  26. package/dist/chunks/{worker.d.DCy61tzi.d.ts → worker.d.B4A26qg6.d.ts} +2 -2
  27. package/dist/cli.js +2 -2
  28. package/dist/config.d.ts +7 -7
  29. package/dist/coverage.d.ts +8 -8
  30. package/dist/environments.js +1 -1
  31. package/dist/index.d.ts +22 -14
  32. package/dist/index.js +3 -3
  33. package/dist/module-evaluator.d.ts +5 -0
  34. package/dist/module-evaluator.js +23 -5
  35. package/dist/module-runner.js +2 -1
  36. package/dist/node.d.ts +8 -8
  37. package/dist/node.js +7 -6
  38. package/dist/reporters.d.ts +7 -7
  39. package/dist/reporters.js +2 -2
  40. package/dist/runners.d.ts +2 -1
  41. package/dist/runners.js +2 -2
  42. package/dist/worker.d.ts +2 -2
  43. package/dist/worker.js +10 -9
  44. package/dist/workers/forks.js +11 -10
  45. package/dist/workers/runVmTests.js +5 -5
  46. package/dist/workers/threads.js +11 -10
  47. package/dist/workers/vmForks.js +6 -5
  48. package/dist/workers/vmThreads.js +6 -5
  49. package/package.json +15 -20
  50. package/dist/chunks/browser.d.CDvMh6F9.d.ts +0 -18
@@ -182,6 +182,7 @@ interface SerializedConfig {
182
182
  serializedDefines: string;
183
183
  experimental: {
184
184
  fsModuleCache: boolean;
185
+ printImportBreakdown: boolean | undefined;
185
186
  };
186
187
  }
187
188
  interface SerializedCoverageConfig {
@@ -0,0 +1,7 @@
1
+ import { EvaluatedModules } from 'vite/module-runner';
2
+
3
+ declare class VitestEvaluatedModules extends EvaluatedModules {
4
+ getModuleSourceMapById(id: string): any;
5
+ }
6
+
7
+ export { VitestEvaluatedModules as V };
@@ -1,11 +1,11 @@
1
1
  import { g as globalApis } from './constants.D_Q9UYh-.js';
2
- import { i as index } from './index.DBx1AtPJ.js';
3
- import './vi.BiaV1qII.js';
2
+ import { i as index } from './index.Z5E_ObnR.js';
3
+ import './vi.2VT5v0um.js';
4
4
  import '@vitest/expect';
5
5
  import '@vitest/runner';
6
- import '@vitest/runner/utils';
7
6
  import './utils.DvEY5TfP.js';
8
7
  import '@vitest/utils/timers';
8
+ import '@vitest/runner/utils';
9
9
  import '@vitest/snapshot';
10
10
  import '@vitest/utils/error';
11
11
  import '@vitest/utils/helpers';
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, promises } from 'node:fs';
2
2
  import { mkdir, writeFile, readdir, stat, readFile } from 'node:fs/promises';
3
3
  import { resolve as resolve$1, dirname, isAbsolute, relative, basename, join, normalize } from 'pathe';
4
4
  import { performance as performance$1 } from 'node:perf_hooks';
5
- import { getTests, getTestName, hasFailed, getSuites, generateHash, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, getTasks, getFullName } from '@vitest/runner/utils';
5
+ import { getTests, getTestName, hasFailed, getSuites, generateHash, createTaskName, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, getTasks, getFullName } from '@vitest/runner/utils';
6
6
  import { slash, toArray, isPrimitive } from '@vitest/utils/helpers';
7
7
  import { parseStacktrace, defaultStackIgnorePatterns, parseErrorStacktrace } from '@vitest/utils/source-map';
8
8
  import c from 'tinyrainbow';
@@ -285,6 +285,62 @@ async function readBlobs(currentVersion, blobsDirectory, projectsArray) {
285
285
  };
286
286
  }
287
287
 
288
+ function groupBy(collection, iteratee) {
289
+ return collection.reduce((acc, item) => {
290
+ const key = iteratee(item);
291
+ acc[key] ||= [];
292
+ acc[key].push(item);
293
+ return acc;
294
+ }, {});
295
+ }
296
+ function stdout() {
297
+ // @ts-expect-error Node.js maps process.stdout to console._stdout
298
+ // eslint-disable-next-line no-console
299
+ return console._stdout || process.stdout;
300
+ }
301
+ function escapeRegExp(s) {
302
+ // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
303
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
304
+ }
305
+ function wildcardPatternToRegExp(pattern) {
306
+ const negated = pattern[0] === "!";
307
+ if (negated) pattern = pattern.slice(1);
308
+ let regexp = `${pattern.split("*").map(escapeRegExp).join(".*")}$`;
309
+ if (negated) regexp = `(?!${regexp})`;
310
+ return new RegExp(`^${regexp}`, "i");
311
+ }
312
+ function createIndexLocationsMap(source) {
313
+ const map = /* @__PURE__ */ new Map();
314
+ let index = 0;
315
+ let line = 1;
316
+ let column = 1;
317
+ for (const char of source) {
318
+ map.set(index++, {
319
+ line,
320
+ column
321
+ });
322
+ if (char === "\n" || char === "\r\n") {
323
+ line++;
324
+ column = 0;
325
+ } else column++;
326
+ }
327
+ return map;
328
+ }
329
+ function createLocationsIndexMap(source) {
330
+ const map = /* @__PURE__ */ new Map();
331
+ let index = 0;
332
+ let line = 1;
333
+ let column = 1;
334
+ for (const char of source) {
335
+ map.set(`${line}:${column}`, index++);
336
+ if (char === "\n" || char === "\r\n") {
337
+ line++;
338
+ column = 0;
339
+ } else column++;
340
+ }
341
+ return map;
342
+ }
343
+
288
344
  function hasFailedSnapshot(suite) {
289
345
  return getTests(suite).some((s) => {
290
346
  return s.result?.errors?.some((e) => typeof e?.message === "string" && e.message.match(/Snapshot .* mismatched/));
@@ -795,23 +851,90 @@ class BaseReporter {
795
851
  // Execution time is either sum of all runs of `--merge-reports` or the current run's time
796
852
  const executionTime = blobs?.executionTimes ? sum(blobs.executionTimes, (time) => time) : this.end - this.start;
797
853
  const environmentTime = sum(files, (file) => file.environmentLoad);
798
- const prepareTime = sum(files, (file) => file.prepareDuration);
799
854
  const transformTime = this.ctx.state.transformTime;
800
855
  const typecheck = sum(this.ctx.projects, (project) => project.typechecker?.getResult().time);
801
856
  const timers = [
802
857
  `transform ${formatTime(transformTime)}`,
803
858
  `setup ${formatTime(setupTime)}`,
804
- `collect ${formatTime(collectTime)}`,
859
+ `import ${formatTime(collectTime)}`,
805
860
  `tests ${formatTime(testsTime)}`,
806
861
  `environment ${formatTime(environmentTime)}`,
807
- `prepare ${formatTime(prepareTime)}`,
808
862
  typecheck && `typecheck ${formatTime(typecheck)}`
809
863
  ].filter(Boolean).join(", ");
810
864
  this.log(padSummaryTitle("Duration"), formatTime(executionTime) + c.dim(` (${timers})`));
811
865
  if (blobs?.executionTimes) this.log(padSummaryTitle("Per blob") + blobs.executionTimes.map((time) => ` ${formatTime(time)}`).join(""));
812
866
  }
867
+ if (this.ctx.config.experimental.printImportBreakdown) this.printImportsBreakdown();
813
868
  this.log();
814
869
  }
870
+ printImportsBreakdown() {
871
+ const testModules = this.ctx.state.getTestModules();
872
+ const allImports = [];
873
+ for (const testModule of testModules) {
874
+ const importDurations = testModule.diagnostic().importDurations;
875
+ for (const filePath in importDurations) {
876
+ const duration = importDurations[filePath];
877
+ allImports.push({
878
+ importedModuleId: filePath,
879
+ testModule,
880
+ selfTime: duration.selfTime,
881
+ totalTime: duration.totalTime,
882
+ external: duration.external
883
+ });
884
+ }
885
+ }
886
+ if (allImports.length === 0) return;
887
+ const sortedImports = allImports.sort((a, b) => b.totalTime - a.totalTime);
888
+ const maxTotalTime = sortedImports[0].totalTime;
889
+ const topImports = sortedImports.slice(0, 10);
890
+ const totalSelfTime = allImports.reduce((sum, imp) => sum + imp.selfTime, 0);
891
+ const totalTotalTime = allImports.reduce((sum, imp) => sum + imp.totalTime, 0);
892
+ const slowestImport = sortedImports[0];
893
+ this.log();
894
+ this.log(c.bold("Import Duration Breakdown") + c.dim(" (ordered by Total Time) (Top 10)"));
895
+ // if there are multiple files, it's highly possible that some of them will import the same large file
896
+ // we group them to show the distinction between those files more easily
897
+ // Import Duration Breakdown (ordered by Total Time) (Top 10)
898
+ // .../fields/FieldFile/__tests__/FieldFile.spec.ts self: 7ms total: 1.01s ████████████████████
899
+ // ↳ tests/support/components/index.ts self: 0ms total: 861ms █████████████████░░░
900
+ // ↳ tests/support/components/renderComponent.ts self: 59ms total: 861ms █████████████████░░░
901
+ // ...s__/apps/desktop/form-updater.desktop.spec.ts self: 8ms total: 991ms ████████████████████
902
+ // ...sts__/apps/mobile/form-updater.mobile.spec.ts self: 11ms total: 990ms ████████████████████
903
+ // shared/components/Form/__tests__/Form.spec.ts self: 5ms total: 988ms ████████████████████
904
+ // ↳ tests/support/components/index.ts self: 0ms total: 935ms ███████████████████░
905
+ // ↳ tests/support/components/renderComponent.ts self: 61ms total: 935ms ███████████████████░
906
+ // ...ditor/features/link/__test__/LinkForm.spec.ts self: 7ms total: 972ms ███████████████████░
907
+ // ↳ tests/support/components/renderComponent.ts self: 56ms total: 936ms ███████████████████░
908
+ const groupedImports = Object.entries(
909
+ groupBy(topImports, (i) => i.testModule.id)
910
+ // the first one is always the highest because the modules are already sorted
911
+ ).sort(([, imps1], [, imps2]) => imps2[0].totalTime - imps1[0].totalTime);
912
+ for (const [_, group] of groupedImports) group.forEach((imp, index) => {
913
+ const barWidth = 20;
914
+ const filledWidth = Math.round(imp.totalTime / maxTotalTime * barWidth);
915
+ const bar = c.cyan("█".repeat(filledWidth)) + c.dim("░".repeat(barWidth - filledWidth));
916
+ // only show the arrow if there is more than 1 group
917
+ const pathDisplay = this.ellipsisPath(imp.importedModuleId, imp.external, groupedImports.length > 1 && index > 0);
918
+ this.log(`${pathDisplay} ${c.dim("self:")} ${this.importDurationTime(imp.selfTime)} ${c.dim("total:")} ${this.importDurationTime(imp.totalTime)} ${bar}`);
919
+ });
920
+ this.log();
921
+ this.log(c.dim("Total imports: ") + allImports.length);
922
+ this.log(c.dim("Slowest import (total-time): ") + formatTime(slowestImport.totalTime));
923
+ this.log(c.dim("Total import time (self/total): ") + formatTime(totalSelfTime) + c.dim(" / ") + formatTime(totalTotalTime));
924
+ }
925
+ importDurationTime(duration) {
926
+ return (duration >= 500 ? c.red : duration >= 100 ? c.yellow : (c) => c)(formatTime(duration).padStart(6));
927
+ }
928
+ ellipsisPath(path, external, nested) {
929
+ const pathDisplay = this.relative(path);
930
+ const color = external ? c.magenta : (c) => c;
931
+ const slicedPath = pathDisplay.slice(-44);
932
+ let title = "";
933
+ if (pathDisplay.length > slicedPath.length) title += "...";
934
+ if (nested) title = ` ${F_DOWN_RIGHT} ${title}`;
935
+ title += slicedPath;
936
+ return color(title.padEnd(50));
937
+ }
815
938
  printErrorsSummary(files, errors) {
816
939
  const suites = getSuites(files);
817
940
  const tests = getTests(files);
@@ -2350,6 +2473,7 @@ async function collectTests(ctx, filepath) {
2350
2473
  type: "suite",
2351
2474
  id: generateHash(`${testFilepath}${projectName ? `${projectName}:__typecheck__` : "__typecheck__"}`),
2352
2475
  name: testFilepath,
2476
+ fullName: testFilepath,
2353
2477
  mode: "run",
2354
2478
  tasks: [],
2355
2479
  start: ast.start,
@@ -2442,6 +2566,8 @@ async function collectTests(ctx, filepath) {
2442
2566
  tasks: [],
2443
2567
  mode,
2444
2568
  name: definition.name,
2569
+ fullName: createTaskName([lastSuite.fullName, definition.name]),
2570
+ fullTestName: createTaskName([lastSuite.fullTestName, definition.name]),
2445
2571
  end: definition.end,
2446
2572
  start: definition.start,
2447
2573
  meta: { typecheck: true }
@@ -2460,6 +2586,8 @@ async function collectTests(ctx, filepath) {
2460
2586
  timeout: 0,
2461
2587
  context: {},
2462
2588
  name: definition.name,
2589
+ fullName: createTaskName([lastSuite.fullName, definition.name]),
2590
+ fullTestName: createTaskName([lastSuite.fullTestName, definition.name]),
2463
2591
  end: definition.end,
2464
2592
  start: definition.start,
2465
2593
  annotations: [],
@@ -2523,21 +2651,6 @@ async function getRawErrsMapFromTsCompile(tscErrorStdout) {
2523
2651
  return rawErrsMap;
2524
2652
  }
2525
2653
 
2526
- function createIndexMap(source) {
2527
- const map = /* @__PURE__ */ new Map();
2528
- let index = 0;
2529
- let line = 1;
2530
- let column = 1;
2531
- for (const char of source) {
2532
- map.set(`${line}:${column}`, index++);
2533
- if (char === "\n" || char === "\r\n") {
2534
- line++;
2535
- column = 0;
2536
- } else column++;
2537
- }
2538
- return map;
2539
- }
2540
-
2541
2654
  class TypeCheckError extends Error {
2542
2655
  name = "TypeCheckError";
2543
2656
  constructor(message, stacks) {
@@ -2617,7 +2730,7 @@ class Typechecker {
2617
2730
  const sortedDefinitions = [...definitions.sort((a, b) => b.start - a.start)];
2618
2731
  // has no map for ".js" files that use // @ts-check
2619
2732
  const traceMap = map && new TraceMap(map);
2620
- const indexMap = createIndexMap(parsed);
2733
+ const indexMap = createLocationsIndexMap(parsed);
2621
2734
  const markState = (task, state) => {
2622
2735
  task.result = { state: task.mode === "run" || task.mode === "only" ? state : task.mode };
2623
2736
  if (task.suite) markState(task.suite, state);
@@ -3138,7 +3251,7 @@ class GithubActionsReporter {
3138
3251
  const title = getFullName(task, " > ");
3139
3252
  for (const error of task.result?.errors ?? []) projectErrors.push({
3140
3253
  project,
3141
- title,
3254
+ title: project.name ? `[${project.name}] ${title}` : title,
3142
3255
  error,
3143
3256
  file
3144
3257
  });
@@ -3500,6 +3613,8 @@ class JUnitReporter {
3500
3613
  id: file.id,
3501
3614
  type: "test",
3502
3615
  name: file.name,
3616
+ fullName: file.name,
3617
+ fullTestName: file.name,
3503
3618
  mode: "run",
3504
3619
  result: file.result,
3505
3620
  meta: {},
@@ -3697,4 +3812,4 @@ const ReportersMap = {
3697
3812
  "github-actions": GithubActionsReporter
3698
3813
  };
3699
3814
 
3700
- export { BlobReporter as B, DefaultReporter as D, F_RIGHT as F, GithubActionsReporter as G, HangingProcessReporter as H, JsonReporter as J, ReportersMap as R, TapFlatReporter as T, VerboseReporter as V, DotReporter as a, JUnitReporter as b, TapReporter as c, stringify as d, TraceMap as e, formatProjectName as f, getStateSymbol as g, ancestor as h, printError as i, errorBanner as j, divider as k, Typechecker as l, generateCodeFrame as m, createDefinesScript as n, originalPositionFor as o, parse$1 as p, convertTasksToEvents as q, readBlobs as r, separator as s, truncateString as t, utils as u, withLabel as w };
3815
+ export { utils as A, BlobReporter as B, DefaultReporter as D, F_RIGHT as F, GithubActionsReporter as G, HangingProcessReporter as H, JsonReporter as J, ReportersMap as R, TapFlatReporter as T, VerboseReporter as V, DotReporter as a, JUnitReporter as b, TapReporter as c, stringify as d, createIndexLocationsMap as e, formatProjectName as f, getStateSymbol as g, TraceMap as h, ancestor as i, printError as j, errorBanner as k, divider as l, Typechecker as m, generateCodeFrame as n, originalPositionFor as o, parse$1 as p, escapeRegExp as q, createDefinesScript as r, separator as s, truncateString as t, groupBy as u, readBlobs as v, withLabel as w, convertTasksToEvents as x, wildcardPatternToRegExp as y, stdout as z };
@@ -588,9 +588,20 @@ function createCompatUtils(window) {
588
588
  return utils;
589
589
  }
590
590
  function patchAddEventListener(window) {
591
+ const abortControllers = /* @__PURE__ */ new WeakMap();
591
592
  const JSDOMAbortSignal = window.AbortSignal;
592
593
  const JSDOMAbortController = window.AbortController;
593
594
  const originalAddEventListener = window.EventTarget.prototype.addEventListener;
595
+ function getJsdomAbortController(signal) {
596
+ if (!abortControllers.has(signal)) {
597
+ const jsdomAbortController = new JSDOMAbortController();
598
+ signal.addEventListener("abort", () => {
599
+ jsdomAbortController.abort(signal.reason);
600
+ });
601
+ abortControllers.set(signal, jsdomAbortController);
602
+ }
603
+ return abortControllers.get(signal);
604
+ }
594
605
  window.EventTarget.prototype.addEventListener = function addEventListener(type, callback, options) {
595
606
  if (typeof options === "object" && options.signal != null) {
596
607
  const { signal, ...otherOptions } = options;
@@ -601,13 +612,7 @@ function patchAddEventListener(window) {
601
612
  if (!(signal instanceof JSDOMAbortSignal)) {
602
613
  const jsdomCompatOptions = Object.create(null);
603
614
  Object.assign(jsdomCompatOptions, otherOptions);
604
- // use jsdom-native abort controller instead and forward the
605
- // previous one with `addEventListener`
606
- const jsdomAbortController = new JSDOMAbortController();
607
- signal.addEventListener("abort", () => {
608
- jsdomAbortController.abort(signal.reason);
609
- });
610
- jsdomCompatOptions.signal = jsdomAbortController.signal;
615
+ jsdomCompatOptions.signal = getJsdomAbortController(signal).signal;
611
616
  return originalAddEventListener.call(this, type, callback, jsdomCompatOptions);
612
617
  }
613
618
  }
@@ -2,7 +2,7 @@ import fs from 'node:fs';
2
2
  import { getTasks, getFullName, getTests } from '@vitest/runner/utils';
3
3
  import * as pathe from 'pathe';
4
4
  import c from 'tinyrainbow';
5
- import { g as getStateSymbol, t as truncateString, F as F_RIGHT, D as DefaultReporter, f as formatProjectName, s as separator } from './index.DWDW6mLz.js';
5
+ import { g as getStateSymbol, t as truncateString, F as F_RIGHT, D as DefaultReporter, f as formatProjectName, s as separator } from './index.456_DGfR.js';
6
6
  import { stripVTControlCharacters } from 'node:util';
7
7
  import { notNullish } from '@vitest/utils/helpers';
8
8
 
@@ -1,4 +1,4 @@
1
- import { b as assert, c as createExpect, g as globalExpect, i as inject, s as should, v as vi, d as vitest } from './vi.BiaV1qII.js';
1
+ import { b as assert, c as createExpect, g as globalExpect, i as inject, s as should, v as vi, d as vitest } from './vi.2VT5v0um.js';
2
2
  import { b as bench } from './benchmark.B3N2zMcH.js';
3
3
  import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js';
4
4
  import { expectTypeOf } from 'expect-type';
@@ -1,8 +1,8 @@
1
1
  import { chai } from '@vitest/expect';
2
- import { l as loadDiffConfig, b as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.DGHc_BUK.js';
2
+ import { l as loadDiffConfig, b as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.Cm-kSBVi.js';
3
3
  import { r as rpc } from './rpc.BytlcPfC.js';
4
4
  import { g as getWorkerState } from './utils.DvEY5TfP.js';
5
- import { V as VitestTestRunner, N as NodeBenchmarkRunner } from './test.DqQZzsWf.js';
5
+ import { V as VitestTestRunner, N as NodeBenchmarkRunner } from './test.BT8LKgU9.js';
6
6
 
7
7
  function setupChaiConfig(config) {
8
8
  Object.assign(chai.config, config);
@@ -1,4 +1,4 @@
1
- import { i as init } from './init.MkYs5nmh.js';
1
+ import { i as init } from './init.B04saIIg.js';
2
2
 
3
3
  if (!process.send) throw new Error("Expected worker to be run in node:child_process");
4
4
  // Store globals in case tests overwrite them
@@ -9,13 +9,17 @@ const processOff = process.off.bind(process);
9
9
  const processRemoveAllListeners = process.removeAllListeners.bind(process);
10
10
  // Work-around for nodejs/node#55094
11
11
  if (process.execArgv.some((execArg) => execArg.startsWith("--prof") || execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"))) processOn("SIGTERM", () => processExit());
12
+ processOn("error", onError);
12
13
  function workerInit(options) {
13
14
  const { runTests } = options;
14
15
  init({
15
16
  post: (v) => processSend(v),
16
17
  on: (cb) => processOn("message", cb),
17
18
  off: (cb) => processOff("message", cb),
18
- teardown: () => processRemoveAllListeners("message"),
19
+ teardown: () => {
20
+ processRemoveAllListeners("message");
21
+ processOff("error", onError);
22
+ },
19
23
  runTests: (state, traces) => executeTests("run", state, traces),
20
24
  collectTests: (state, traces) => executeTests("collect", state, traces),
21
25
  setup: options.setup
@@ -28,5 +32,10 @@ function workerInit(options) {
28
32
  }
29
33
  }
30
34
  }
35
+ // Prevent leaving worker in loops where it tries to send message to closed main
36
+ // thread, errors, and tries to send the error.
37
+ function onError(error) {
38
+ if (error?.code === "ERR_IPC_CHANNEL_CLOSED" || error?.code === "EPIPE") processExit(1);
39
+ }
31
40
 
32
41
  export { workerInit as w };
@@ -1,5 +1,5 @@
1
1
  import { isMainThread, parentPort } from 'node:worker_threads';
2
- import { i as init } from './init.MkYs5nmh.js';
2
+ import { i as init } from './init.B04saIIg.js';
3
3
 
4
4
  if (isMainThread || !parentPort) throw new Error("Expected worker to be run in node:worker_threads");
5
5
  function workerInit(options) {
@@ -3,8 +3,8 @@ import { isBuiltin } from 'node:module';
3
3
  import { pathToFileURL } from 'node:url';
4
4
  import { resolve } from 'pathe';
5
5
  import { ModuleRunner } from 'vite/module-runner';
6
- import { b as VitestTransport } from './startModuleRunner.W28wBIgJ.js';
7
- import { e as environments } from './index.QWbK7rHY.js';
6
+ import { b as VitestTransport } from './startModuleRunner.Iz2V0ESw.js';
7
+ import { e as environments } from './index.BspFP3mn.js';
8
8
  import { serializeError } from '@vitest/utils/error';
9
9
  import { T as Traces } from './traces.U4xDYhzZ.js';
10
10
  import { o as onCancel, a as rpcDone, c as createRuntimeRpc } from './rpc.BytlcPfC.js';
@@ -158,6 +158,8 @@ function init(worker) {
158
158
  if (message?.__vitest_worker_request__ !== true) return;
159
159
  switch (message.type) {
160
160
  case "start": {
161
+ process.env.VITEST_POOL_ID = String(message.poolId);
162
+ process.env.VITEST_WORKER_ID = String(message.workerId);
161
163
  reportMemory = message.options.reportMemory;
162
164
  const tracesStart = performance.now();
163
165
  traces ??= await new Traces({
@@ -203,7 +205,6 @@ function init(worker) {
203
205
  return;
204
206
  }
205
207
  try {
206
- process.env.VITEST_POOL_ID = String(message.poolId);
207
208
  process.env.VITEST_WORKER_ID = String(message.context.workerId);
208
209
  } catch (error) {
209
210
  return send({
@@ -248,7 +249,6 @@ function init(worker) {
248
249
  return;
249
250
  }
250
251
  try {
251
- process.env.VITEST_POOL_ID = String(message.poolId);
252
252
  process.env.VITEST_WORKER_ID = String(message.context.workerId);
253
253
  } catch (error) {
254
254
  return send({
@@ -0,0 +1,35 @@
1
+ import { builtinModules } from 'node:module';
2
+
3
+ // copied from vite
4
+ // https://github.com/vitejs/vite/blob/814120f2ad387ca3d1e16c7dd403b04ca4b97f75/packages/vite/src/node/utils.ts#L106
5
+ // Supported by Node, Deno, Bun
6
+ const NODE_BUILTIN_NAMESPACE = "node:";
7
+ // Supported by Deno
8
+ const NPM_BUILTIN_NAMESPACE = "npm:";
9
+ // Supported by Bun
10
+ const BUN_BUILTIN_NAMESPACE = "bun:";
11
+ // Some runtimes like Bun injects namespaced modules here, which is not a node builtin
12
+ const nodeBuiltins = builtinModules.filter((id) => !id.includes(":"));
13
+ // TODO: Use `isBuiltin` from `node:module`, but Deno doesn't support it
14
+ function isBuiltin(id) {
15
+ if (process.versions.deno && id.startsWith(NPM_BUILTIN_NAMESPACE)) return true;
16
+ if (process.versions.bun && id.startsWith(BUN_BUILTIN_NAMESPACE)) return true;
17
+ return isNodeBuiltin(id);
18
+ }
19
+ function isNodeBuiltin(id) {
20
+ if (id.startsWith(NODE_BUILTIN_NAMESPACE)) return true;
21
+ return nodeBuiltins.includes(id);
22
+ }
23
+ const browserExternalId = "__vite-browser-external";
24
+ const browserExternalLength = 24;
25
+ function isBrowserExternal(id) {
26
+ return id.startsWith(browserExternalId);
27
+ }
28
+ function toBuiltin(id) {
29
+ if (id.startsWith(browserExternalId)) id = id.slice(browserExternalLength);
30
+ if (id.startsWith(NPM_BUILTIN_NAMESPACE) || id.startsWith(BUN_BUILTIN_NAMESPACE) || id.startsWith(NODE_BUILTIN_NAMESPACE)) return id;
31
+ if (process.versions.deno || process.versions.bun) return id;
32
+ return `node:${id}`;
33
+ }
34
+
35
+ export { isBrowserExternal as a, isBuiltin as i, toBuiltin as t };
@@ -1,5 +1,5 @@
1
1
  import { DevEnvironment } from 'vite';
2
- import { V as Vitest, T as TestProject, b as TestProjectConfiguration } from './reporters.d.J2RlBlp9.js';
2
+ import { V as Vitest, T as TestProject, b as TestProjectConfiguration } from './reporters.d.OXEK7y4s.js';
3
3
 
4
4
  /**
5
5
  * Generate a unique cache identifier.
@@ -2,18 +2,18 @@ import { TaskMeta, Suite, File, TestAnnotation, TestArtifact, ImportDuration, Te
2
2
  import { TestError, SerializedError, Arrayable, ParsedStack, Awaitable } from '@vitest/utils';
3
3
  import { A as AfterSuiteRunMeta, U as UserConsoleLog, P as ProvidedContext, L as LabelColor } from './rpc.d.RH3apGEf.js';
4
4
  import { Writable } from 'node:stream';
5
- import { TransformResult as TransformResult$1, ViteDevServer, Plugin, UserConfig as UserConfig$1, DepOptimizationConfig, ServerOptions, ConfigEnv, AliasOptions } from 'vite';
5
+ import { DevEnvironment, TransformResult as TransformResult$1, ViteDevServer, Plugin, UserConfig as UserConfig$1, DepOptimizationConfig, ServerOptions, ConfigEnv, AliasOptions } from 'vite';
6
+ import { S as SerializedTestSpecification, c as SourceModuleDiagnostic, B as BrowserTesterOptions } from './browser.d.DBzUq_Na.js';
6
7
  import { MockedModule } from '@vitest/mocker';
7
8
  import { StackTraceParserOptions } from '@vitest/utils/source-map';
8
9
  import { BrowserCommands } from 'vitest/browser';
9
- import { B as BrowserTraceViewMode, S as SerializedConfig, F as FakeTimerInstallOpts } from './config.d.g6OOauRt.js';
10
- import { S as SerializedTestSpecification, B as BrowserTesterOptions } from './browser.d.CDvMh6F9.js';
10
+ import { B as BrowserTraceViewMode, S as SerializedConfig, F as FakeTimerInstallOpts } from './config.d.CzIjkicf.js';
11
11
  import { PrettyFormatOptions } from '@vitest/pretty-format';
12
12
  import { SnapshotSummary, SnapshotStateOptions } from '@vitest/snapshot';
13
13
  import { SerializedDiffOptions } from '@vitest/utils/diff';
14
14
  import { chai } from '@vitest/expect';
15
15
  import { happyDomTypes, jsdomTypes } from 'vitest/optional-types.js';
16
- import { c as ContextTestEnvironment, d as WorkerTestEnvironment, e as WorkerExecuteContext } from './worker.d.DCy61tzi.js';
16
+ import { c as ContextTestEnvironment, d as WorkerExecuteContext, e as WorkerTestEnvironment } from './worker.d.B4A26qg6.js';
17
17
  import { O as OTELCarrier } from './traces.d.402V_yFI.js';
18
18
  import { B as BenchmarkResult } from './benchmark.d.DAaHLpsq.js';
19
19
  import { a as RuntimeCoverageProviderModule } from './coverage.d.BZtK59WP.js';
@@ -239,6 +239,12 @@ declare class TestModule extends SuiteImplementation {
239
239
  readonly location: undefined;
240
240
  readonly type = "module";
241
241
  /**
242
+ * The Vite environment that processes files on the server.
243
+ *
244
+ * Can be empty if test module did not run yet.
245
+ */
246
+ readonly viteEnvironment: DevEnvironment | undefined;
247
+ /**
242
248
  * This is usually an absolute UNIX file path.
243
249
  * It can be a virtual ID if the file is not on the disk.
244
250
  * This value corresponds to the ID in the Vite's module graph.
@@ -1278,6 +1284,14 @@ declare class Vitest {
1278
1284
  */
1279
1285
  rerunTestSpecifications(specifications: TestSpecification[], allTestsRun?: boolean): Promise<TestRunResult>;
1280
1286
  private runFiles;
1287
+ /**
1288
+ * Returns module's diagnostic. If `testModule` is not provided, `selfTime` and `totalTime` will be aggregated across all tests.
1289
+ *
1290
+ * If the module was not transformed or executed, the diagnostic will be empty.
1291
+ * @experimental
1292
+ * @see {@link https://vitest.dev/api/advanced/vitest#getsourcemodulediagnostic}
1293
+ */
1294
+ experimental_getSourceModuleDiagnostic(moduleId: string, testModule?: TestModule): Promise<SourceModuleDiagnostic>;
1281
1295
  experimental_parseSpecifications(specifications: TestSpecification[], options?: {
1282
1296
  /** @default os.availableParallelism() */
1283
1297
  concurrency?: number;
@@ -1937,6 +1951,8 @@ type WorkerRequest = {
1937
1951
  __vitest_worker_request__: true;
1938
1952
  } & ({
1939
1953
  type: "start";
1954
+ poolId: number;
1955
+ workerId: WorkerExecuteContext["workerId"];
1940
1956
  options: {
1941
1957
  reportMemory: boolean;
1942
1958
  };
@@ -1956,12 +1972,10 @@ type WorkerRequest = {
1956
1972
  } | {
1957
1973
  type: "run";
1958
1974
  context: WorkerExecuteContext;
1959
- poolId: number;
1960
1975
  otelCarrier?: OTELCarrier;
1961
1976
  } | {
1962
1977
  type: "collect";
1963
1978
  context: WorkerExecuteContext;
1964
- poolId: number;
1965
1979
  otelCarrier?: OTELCarrier;
1966
1980
  } | {
1967
1981
  type: "cancel";
@@ -2025,6 +2039,9 @@ declare abstract class BaseReporter implements Reporter {
2025
2039
  onServerRestart(reason?: string): void;
2026
2040
  reportSummary(files: File[], errors: unknown[]): void;
2027
2041
  reportTestSummary(files: File[], errors: unknown[]): void;
2042
+ private printImportsBreakdown;
2043
+ private importDurationTime;
2044
+ private ellipsisPath;
2028
2045
  private printErrorsSummary;
2029
2046
  reportBenchmarkSummary(files: File[]): void;
2030
2047
  private printTaskErrors;
@@ -3019,6 +3036,12 @@ interface InlineConfig {
3019
3036
  enabled: boolean;
3020
3037
  sdkPath?: string;
3021
3038
  };
3039
+ /**
3040
+ * Show imports (top 10) that take a long time.
3041
+ *
3042
+ * Enabling this will also show a breakdown by default in UI, but you can always press a button to toggle it.
3043
+ */
3044
+ printImportBreakdown?: boolean;
3022
3045
  };
3023
3046
  }
3024
3047
  interface TypecheckConfig {
@@ -26,7 +26,7 @@ async function setupCommonEnv(config) {
26
26
  if (globalSetup) return;
27
27
  globalSetup = true;
28
28
  setSafeTimers();
29
- if (config.globals) (await import('./globals.C0izxiX3.js')).registerApiGlobally();
29
+ if (config.globals) (await import('./globals.DOayXfHP.js')).registerApiGlobally();
30
30
  }
31
31
  function setupDefines(config) {
32
32
  for (const key in config.defines) globalThis[key] = config.defines[key];
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
- import nodeModule, { isBuiltin } from 'node:module';
3
2
  import { isBareImport } from '@vitest/utils/helpers';
3
+ import { i as isBuiltin, a as isBrowserExternal, t as toBuiltin } from './modules.DJPjQW6m.js';
4
4
  import { pathToFileURL } from 'node:url';
5
5
  import { normalize as normalize$1, join as join$1 } from 'pathe';
6
6
  import { distDir } from '../path.js';
@@ -9,6 +9,7 @@ import { VitestModuleEvaluator, unwrapId } from '../module-evaluator.js';
9
9
  import { resolve as resolve$1, isAbsolute as isAbsolute$1 } from 'node:path';
10
10
  import vm from 'node:vm';
11
11
  import { MockerRegistry, mockObject, RedirectedModule, AutomockedModule } from '@vitest/mocker';
12
+ import nodeModule from 'node:module';
12
13
  import * as viteModuleRunner from 'vite/module-runner';
13
14
  import { T as Traces } from './traces.U4xDYhzZ.js';
14
15
 
@@ -754,8 +755,6 @@ function listenForErrors(state) {
754
755
  }
755
756
 
756
757
  const { readFileSync } = fs;
757
- const browserExternalId = "__vite-browser-external";
758
- const browserExternalLength = 24;
759
758
  const VITEST_VM_CONTEXT_SYMBOL = "__vitest_vm_context__";
760
759
  const cwd = process.cwd();
761
760
  const isWindows = process.platform === "win32";
@@ -777,6 +776,7 @@ function startVitestModuleRunner(options) {
777
776
  } : void 0;
778
777
  const evaluator = options.evaluator || new VitestModuleEvaluator(vm, {
779
778
  traces,
779
+ evaluatedModules: options.evaluatedModules,
780
780
  get moduleExecutionInfo() {
781
781
  return state().moduleExecutionInfo;
782
782
  },
@@ -817,7 +817,11 @@ function startVitestModuleRunner(options) {
817
817
  invalidate: false,
818
818
  mockedModule: resolvedMock
819
819
  };
820
- if (isBuiltin(rawId) || rawId.startsWith(browserExternalId)) return {
820
+ if (isBuiltin(rawId)) return {
821
+ externalize: rawId,
822
+ type: "builtin"
823
+ };
824
+ if (isBrowserExternal(rawId)) return {
821
825
  externalize: toBuiltin(rawId),
822
826
  type: "builtin"
823
827
  };
@@ -853,10 +857,5 @@ function startVitestModuleRunner(options) {
853
857
  });
854
858
  return moduleRunner;
855
859
  }
856
- function toBuiltin(id) {
857
- if (id.startsWith(browserExternalId)) id = id.slice(browserExternalLength);
858
- if (!id.startsWith("node:")) id = `node:${id}`;
859
- return id;
860
- }
861
860
 
862
861
  export { VitestModuleRunner as V, VITEST_VM_CONTEXT_SYMBOL as a, VitestTransport as b, createNodeImportMeta as c, startVitestModuleRunner as s };