vitest 1.5.3 → 1.6.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 (48) hide show
  1. package/dist/browser.d.ts +1 -1
  2. package/dist/browser.js +1 -1
  3. package/dist/chunks/environments-node.vcoXCoKs.js +19 -0
  4. package/dist/chunks/{integrations-globals.Hr6znn-f.js → integrations-globals.kw4co3rx.js} +3 -3
  5. package/dist/chunks/{runtime-runBaseTests.l6qXp5eU.js → runtime-runBaseTests.oAvMKtQC.js} +8 -9
  6. package/dist/cli.js +2 -2
  7. package/dist/config.cjs +1 -1
  8. package/dist/config.d.ts +1 -1
  9. package/dist/config.js +1 -1
  10. package/dist/coverage.d.ts +1 -1
  11. package/dist/environments.d.ts +1 -1
  12. package/dist/execute.d.ts +6 -4
  13. package/dist/execute.js +3 -3
  14. package/dist/index.d.ts +4 -3
  15. package/dist/index.js +4 -4
  16. package/dist/node.d.ts +2 -2
  17. package/dist/node.js +7 -7
  18. package/dist/{reporters-BXNXFKfg.d.ts → reporters-w_64AS5f.d.ts} +103 -25
  19. package/dist/reporters.d.ts +1 -1
  20. package/dist/reporters.js +5 -5
  21. package/dist/runners.d.ts +1 -1
  22. package/dist/runners.js +2 -2
  23. package/dist/snapshot.d.ts +9 -0
  24. package/dist/snapshot.js +8 -0
  25. package/dist/{suite-KPWE530F.d.ts → suite-dWqIFb_-.d.ts} +1 -1
  26. package/dist/suite.d.ts +2 -2
  27. package/dist/vendor/{base.Xt0Omgh7.js → base.5NT-gWu5.js} +9 -1
  28. package/dist/vendor/{base.oIzAvGLe.js → base.Ybri3C14.js} +2 -2
  29. package/dist/vendor/{cac.RDd_SGOd.js → cac.cdAtVkJZ.js} +38 -15
  30. package/dist/vendor/{cli-api.AmIc1Dmz.js → cli-api.OdDWuB7Y.js} +159 -42
  31. package/dist/vendor/{execute.2_yoIC01.js → execute.fL3szUAI.js} +8 -3
  32. package/dist/vendor/{index.X7lgIMc_.js → index.-xs08BYx.js} +177 -122
  33. package/dist/vendor/{index.Fm6OikHU.js → index.DpVgvm2P.js} +17 -18
  34. package/dist/vendor/{index.QVcwRDVW.js → index.dI9lHwVn.js} +1 -1
  35. package/dist/vendor/{setup-common.5nUd4r76.js → setup-common.8nJLd4ay.js} +1 -1
  36. package/dist/vendor/{utils.VYmeMh-u.js → utils.dEtNIEgr.js} +1 -1
  37. package/dist/vendor/{vi.Y_w82WR8.js → vi.YFlodzP_.js} +1 -1
  38. package/dist/vendor/{vm.i4FO5N37.js → vm.QEE48c0T.js} +131 -41
  39. package/dist/worker.js +8 -2
  40. package/dist/workers/forks.js +4 -4
  41. package/dist/workers/runVmTests.js +10 -8
  42. package/dist/workers/threads.js +4 -4
  43. package/dist/workers/vmForks.js +4 -4
  44. package/dist/workers/vmThreads.js +4 -4
  45. package/dist/workers.d.ts +1 -1
  46. package/dist/workers.js +5 -5
  47. package/package.json +13 -9
  48. package/snapshot.d.ts +1 -0
@@ -1,15 +1,16 @@
1
- import { existsSync, promises, readFileSync } from 'node:fs';
1
+ import fs, { existsSync, promises, readFileSync } from 'node:fs';
2
+ import c from 'picocolors';
3
+ import * as pathe from 'pathe';
2
4
  import { basename, dirname, resolve, join, relative, extname, normalize } from 'pathe';
3
- import { generateHash, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, getTasks, getTests, hasFailed, getSuites } from '@vitest/runner/utils';
5
+ import { g as getFullName, h as hasFailedSnapshot } from './tasks.IknbGB2n.js';
4
6
  import { getSafeTimers, notNullish, highlight, shuffle, inspect, positionToOffset, lineSplitRE } from '@vitest/utils';
5
7
  import { i as isNode } from './env.AtSIuHFg.js';
6
- import c from 'picocolors';
7
- import { g as getFullName, h as hasFailedSnapshot } from './tasks.IknbGB2n.js';
8
- import { g as getStateSymbol, f as formatProjectName, p as pointer, F as F_RIGHT, r as renderSnapshotSummary, a as getStateString, b as formatTimeString, c as countTestErrors, d as divider, s as stripAnsi, e as getCols, h as getHookStateSymbol, i as F_POINTER } from './utils.VYmeMh-u.js';
8
+ import { g as getStateSymbol, f as formatProjectName, p as pointer, F as F_RIGHT, r as renderSnapshotSummary, a as getStateString, b as formatTimeString, c as countTestErrors, d as divider, s as stripAnsi, e as getCols, h as getHookStateSymbol, i as F_POINTER } from './utils.dEtNIEgr.js';
9
+ import { generateHash, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, getTasks, getTests, hasFailed, getSuites } from '@vitest/runner/utils';
9
10
  import { performance } from 'node:perf_hooks';
10
11
  import { r as relativePath } from './index.SMVOaj7F.js';
11
12
  import { UNKNOWN_TEST_ID } from '../chunks/runtime-console.EO5ha7qv.js';
12
- import { t as toArray, b as isPrimitive } from './base.Xt0Omgh7.js';
13
+ import { t as toArray, b as isPrimitive } from './base.5NT-gWu5.js';
13
14
  import { isCI } from 'std-env';
14
15
  import { TraceMap, generatedPositionFor, parseErrorStacktrace } from '@vitest/utils/source-map';
15
16
  import nodeos__default, { hostname } from 'node:os';
@@ -748,7 +749,7 @@ ${log.content}
748
749
  var _a2;
749
750
  return acc + Math.max(0, ((_a2 = test.result) == null ? void 0 : _a2.duration) || 0);
750
751
  }, 0);
751
- const transformTime = this.ctx.projects.flatMap((w) => Array.from(w.vitenode.fetchCache.values()).map((i) => i.duration || 0)).reduce((a, b) => a + b, 0);
752
+ const transformTime = this.ctx.projects.flatMap((w) => w.vitenode.getTotalDuration()).reduce((a, b) => a + b, 0);
752
753
  const environmentTime = files.reduce((acc, file) => acc + Math.max(0, file.environmentLoad || 0), 0);
753
754
  const prepareTime = files.reduce((acc, file) => acc + Math.max(0, file.prepareDuration || 0), 0);
754
755
  const threadTime = collectTime + testsTime + setupTime;
@@ -2186,7 +2187,7 @@ const StatusMap = {
2186
2187
  skip: "skipped",
2187
2188
  todo: "todo"
2188
2189
  };
2189
- let JsonReporter$1 = class JsonReporter {
2190
+ class JsonReporter {
2190
2191
  start = 0;
2191
2192
  ctx;
2192
2193
  options;
@@ -2326,7 +2327,7 @@ let JsonReporter$1 = class JsonReporter {
2326
2327
  return;
2327
2328
  return { line: frame.line, column: frame.column };
2328
2329
  }
2329
- };
2330
+ }
2330
2331
 
2331
2332
  class VerboseReporter extends DefaultReporter {
2332
2333
  constructor() {
@@ -3654,7 +3655,7 @@ createLogUpdate(process$2.stdout);
3654
3655
 
3655
3656
  createLogUpdate(process$2.stderr);
3656
3657
 
3657
- var version = "1.5.3";
3658
+ var version = "1.6.1";
3658
3659
 
3659
3660
  const HIGHLIGHT_SUPPORTED_EXTS = new Set(["js", "ts"].flatMap((lang) => [
3660
3661
  `.${lang}`,
@@ -3865,7 +3866,11 @@ No ${config.mode} files found, exiting with code 1`));
3865
3866
  }
3866
3867
  if (this.ctx.coverageProvider)
3867
3868
  this.log(c.dim(" Coverage enabled with ") + c.yellow(this.ctx.coverageProvider.name));
3868
- this.log();
3869
+ if (this.ctx.config.standalone)
3870
+ this.log(c.yellow(`
3871
+ Vitest is running in standalone mode. Edit a test file to rerun tests.`));
3872
+ else
3873
+ this.log();
3869
3874
  }
3870
3875
  async printUnhandledErrors(errors) {
3871
3876
  const errorMessage = c.red(c.bold(
@@ -4183,7 +4188,9 @@ class JUnitReporter {
4183
4188
  fileFd;
4184
4189
  options;
4185
4190
  constructor(options) {
4186
- this.options = options;
4191
+ var _a;
4192
+ this.options = { ...options };
4193
+ (_a = this.options).includeConsoleOutput ?? (_a.includeConsoleOutput = true);
4187
4194
  }
4188
4195
  async onInit(ctx) {
4189
4196
  this.ctx = ctx;
@@ -4238,12 +4245,15 @@ class JUnitReporter {
4238
4245
  await this.writeElement("testcase", {
4239
4246
  // TODO: v2.0.0 Remove env variable in favor of custom reporter options, e.g. "reporters: [['json', { classname: 'something' }]]"
4240
4247
  classname: this.options.classname ?? process.env.VITEST_JUNIT_CLASSNAME ?? filename,
4248
+ file: this.options.addFileAttribute ? filename : void 0,
4241
4249
  name: task.name,
4242
4250
  time: getDuration(task)
4243
4251
  }, async () => {
4244
4252
  var _a;
4245
- await this.writeLogs(task, "out");
4246
- await this.writeLogs(task, "err");
4253
+ if (this.options.includeConsoleOutput) {
4254
+ await this.writeLogs(task, "out");
4255
+ await this.writeLogs(task, "err");
4256
+ }
4247
4257
  if (task.mode === "skip" || task.mode === "todo")
4248
4258
  await this.logger.log("<skipped/>");
4249
4259
  if (((_a = task.result) == null ? void 0 : _a.state) === "fail") {
@@ -4327,8 +4337,9 @@ class JUnitReporter {
4327
4337
  });
4328
4338
  await this.writeElement("testsuites", stats, async () => {
4329
4339
  for (const file of transformed) {
4340
+ const filename = relative(this.ctx.config.root, file.filepath);
4330
4341
  await this.writeElement("testsuite", {
4331
- name: relative(this.ctx.config.root, file.filepath),
4342
+ name: filename,
4332
4343
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4333
4344
  hostname: hostname(),
4334
4345
  tests: file.tasks.length,
@@ -4338,7 +4349,7 @@ class JUnitReporter {
4338
4349
  skipped: file.stats.skipped,
4339
4350
  time: getDuration(file)
4340
4351
  }, async () => {
4341
- await this.writeTasks(file.tasks, file.name);
4352
+ await this.writeTasks(file.tasks, filename);
4342
4353
  });
4343
4354
  }
4344
4355
  });
@@ -4454,67 +4465,6 @@ function escapeProperty(s) {
4454
4465
  return s.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A").replace(/:/g, "%3A").replace(/,/g, "%2C");
4455
4466
  }
4456
4467
 
4457
- class JsonReporter {
4458
- start = 0;
4459
- ctx;
4460
- onInit(ctx) {
4461
- this.ctx = ctx;
4462
- }
4463
- async logTasks(files) {
4464
- var _a;
4465
- const suites = getSuites(files);
4466
- const numTotalTestSuites = suites.length;
4467
- const tests = getTests(files);
4468
- const numTotalTests = tests.length;
4469
- const testResults = {};
4470
- const outputFile = getOutputFile(this.ctx.config.benchmark, "json");
4471
- for (const file of files) {
4472
- const tests2 = getTests([file]);
4473
- for (const test of tests2) {
4474
- const res = (_a = test.result) == null ? void 0 : _a.benchmark;
4475
- if (!res || test.mode === "skip")
4476
- continue;
4477
- if (!outputFile)
4478
- res.samples = "ignore on terminal";
4479
- testResults[test.suite.name] = (testResults[test.suite.name] || []).concat(res);
4480
- }
4481
- if (tests2.some((t) => {
4482
- var _a2;
4483
- return ((_a2 = t.result) == null ? void 0 : _a2.state) === "run";
4484
- })) {
4485
- this.ctx.logger.warn("WARNING: Some tests are still running when generating the json report.This is likely an internal bug in Vitest.Please report it to https://github.com/vitest-dev/vitest/issues");
4486
- }
4487
- }
4488
- const result = {
4489
- numTotalTestSuites,
4490
- numTotalTests,
4491
- testResults
4492
- };
4493
- await this.writeReport(JSON.stringify(result, null, 2));
4494
- }
4495
- async onFinished(files = this.ctx.state.getFiles()) {
4496
- await this.logTasks(files);
4497
- }
4498
- /**
4499
- * Writes the report to an output file if specified in the config,
4500
- * or logs it to the console otherwise.
4501
- * @param report
4502
- */
4503
- async writeReport(report) {
4504
- const outputFile = getOutputFile(this.ctx.config.benchmark, "json");
4505
- if (outputFile) {
4506
- const reportFile = resolve(this.ctx.config.root, outputFile);
4507
- const outputDirectory = dirname(reportFile);
4508
- if (!existsSync(outputDirectory))
4509
- await promises.mkdir(outputDirectory, { recursive: true });
4510
- await promises.writeFile(reportFile, report, "utf-8");
4511
- this.ctx.logger.log(`json report written to ${reportFile}`);
4512
- } else {
4513
- this.ctx.logger.log(report);
4514
- }
4515
- }
4516
- }
4517
-
4518
4468
  const outputMap = /* @__PURE__ */ new WeakMap();
4519
4469
  function formatFilepath(path) {
4520
4470
  const lastSlash = Math.max(path.lastIndexOf("/") + 1, 0);
@@ -4530,17 +4480,6 @@ function formatNumber(number) {
4530
4480
  return res[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ",") + (res[1] ? `.${res[1]}` : "");
4531
4481
  }
4532
4482
  const tableHead = ["name", "hz", "min", "max", "mean", "p75", "p99", "p995", "p999", "rme", "samples"];
4533
- function renderTableHead(tasks) {
4534
- const benches = tasks.map((i) => {
4535
- var _a, _b;
4536
- return ((_a = i.meta) == null ? void 0 : _a.benchmark) ? (_b = i.result) == null ? void 0 : _b.benchmark : void 0;
4537
- }).filter(notNullish);
4538
- const allItems = benches.map(renderBenchmarkItems).concat([tableHead]);
4539
- return `${" ".repeat(3)}${tableHead.map((i, idx) => {
4540
- const width = Math.max(...allItems.map((i2) => i2[idx].length));
4541
- return idx ? i.padStart(width, " ") : i.padEnd(width, " ");
4542
- }).map(c.bold).join(" ")}`;
4543
- }
4544
4483
  function renderBenchmarkItems(result) {
4545
4484
  return [
4546
4485
  result.name,
@@ -4556,21 +4495,27 @@ function renderBenchmarkItems(result) {
4556
4495
  result.samples.length.toString()
4557
4496
  ];
4558
4497
  }
4559
- function renderBenchmark(task, tasks) {
4560
- var _a;
4561
- const result = (_a = task.result) == null ? void 0 : _a.benchmark;
4562
- if (!result)
4563
- return task.name;
4564
- const benches = tasks.map((i) => {
4565
- var _a2, _b;
4566
- return ((_a2 = i.meta) == null ? void 0 : _a2.benchmark) ? (_b = i.result) == null ? void 0 : _b.benchmark : void 0;
4567
- }).filter(notNullish);
4568
- const allItems = benches.map(renderBenchmarkItems).concat([tableHead]);
4569
- const items = renderBenchmarkItems(result);
4570
- const padded = items.map((i, idx) => {
4571
- const width = Math.max(...allItems.map((i2) => i2[idx].length));
4572
- return idx ? i.padStart(width, " ") : i.padEnd(width, " ");
4573
- });
4498
+ function computeColumnWidths(results) {
4499
+ const rows = [
4500
+ tableHead,
4501
+ ...results.map((v) => renderBenchmarkItems(v))
4502
+ ];
4503
+ return Array.from(
4504
+ tableHead,
4505
+ (_, i) => Math.max(...rows.map((row) => stripAnsi(row[i]).length))
4506
+ );
4507
+ }
4508
+ function padRow(row, widths) {
4509
+ return row.map(
4510
+ (v, i) => i ? v.padStart(widths[i], " ") : v.padEnd(widths[i], " ")
4511
+ // name
4512
+ );
4513
+ }
4514
+ function renderTableHead(widths) {
4515
+ return " ".repeat(3) + padRow(tableHead, widths).map(c.bold).join(" ");
4516
+ }
4517
+ function renderBenchmark(result, widths) {
4518
+ const padded = padRow(renderBenchmarkItems(result), widths);
4574
4519
  return [
4575
4520
  padded[0],
4576
4521
  // name
@@ -4592,20 +4537,38 @@ function renderBenchmark(task, tasks) {
4592
4537
  // p999
4593
4538
  c.dim(padded[9]),
4594
4539
  // rem
4595
- c.dim(padded[10]),
4540
+ c.dim(padded[10])
4596
4541
  // sample
4597
- result.rank === 1 ? c.bold(c.green(" fastest")) : result.rank === benches.length && benches.length > 2 ? c.bold(c.gray(" slowest")) : ""
4598
4542
  ].join(" ");
4599
4543
  }
4600
4544
  function renderTree(tasks, options, level = 0, shallow = false) {
4601
- var _a, _b, _c, _d, _e, _f;
4545
+ var _a, _b, _c, _d, _e, _f, _g;
4602
4546
  const output = [];
4547
+ const benchMap = {};
4548
+ for (const t of tasks) {
4549
+ if (t.meta.benchmark && ((_a = t.result) == null ? void 0 : _a.benchmark)) {
4550
+ benchMap[t.id] = {
4551
+ current: t.result.benchmark
4552
+ };
4553
+ const baseline = (_b = options.compare) == null ? void 0 : _b[t.id];
4554
+ if (baseline) {
4555
+ benchMap[t.id].baseline = {
4556
+ ...baseline,
4557
+ samples: Array(baseline.sampleCount)
4558
+ };
4559
+ }
4560
+ }
4561
+ }
4562
+ const benchCount = Object.entries(benchMap).length;
4563
+ const columnWidths = computeColumnWidths(
4564
+ Object.values(benchMap).flatMap((v) => [v.current, v.baseline]).filter(notNullish)
4565
+ );
4603
4566
  let idx = 0;
4604
4567
  for (const task of tasks) {
4605
4568
  const padding = " ".repeat(level ? 1 : 0);
4606
4569
  let prefix = "";
4607
- if (idx === 0 && ((_a = task.meta) == null ? void 0 : _a.benchmark))
4608
- prefix += `${renderTableHead(tasks)}
4570
+ if (idx === 0 && ((_c = task.meta) == null ? void 0 : _c.benchmark))
4571
+ prefix += `${renderTableHead(columnWidths)}
4609
4572
  ${padding}`;
4610
4573
  prefix += ` ${getStateSymbol(task)} `;
4611
4574
  let suffix = "";
@@ -4613,18 +4576,43 @@ ${padding}`;
4613
4576
  suffix += c.dim(` (${getTests(task).length})`);
4614
4577
  if (task.mode === "skip" || task.mode === "todo")
4615
4578
  suffix += ` ${c.dim(c.gray("[skipped]"))}`;
4616
- if (((_b = task.result) == null ? void 0 : _b.duration) != null) {
4579
+ if (((_d = task.result) == null ? void 0 : _d.duration) != null) {
4617
4580
  if (task.result.duration > options.slowTestThreshold)
4618
4581
  suffix += c.yellow(` ${Math.round(task.result.duration)}${c.dim("ms")}`);
4619
4582
  }
4620
- if (options.showHeap && ((_c = task.result) == null ? void 0 : _c.heap) != null)
4583
+ if (options.showHeap && ((_e = task.result) == null ? void 0 : _e.heap) != null)
4621
4584
  suffix += c.magenta(` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`);
4622
4585
  let name = task.name;
4623
4586
  if (level === 0)
4624
4587
  name = formatFilepath(name);
4625
- const body = ((_d = task.meta) == null ? void 0 : _d.benchmark) ? renderBenchmark(task, tasks) : name;
4626
- output.push(padding + prefix + body + suffix);
4627
- if (((_e = task.result) == null ? void 0 : _e.state) !== "pass" && outputMap.get(task) != null) {
4588
+ const bench = benchMap[task.id];
4589
+ if (bench) {
4590
+ let body = renderBenchmark(bench.current, columnWidths);
4591
+ if (options.compare && bench.baseline) {
4592
+ if (bench.current.hz) {
4593
+ const diff = bench.current.hz / bench.baseline.hz;
4594
+ const diffFixed = diff.toFixed(2);
4595
+ if (diffFixed === "1.0.0")
4596
+ body += ` ${c.gray(`[${diffFixed}x]`)}`;
4597
+ if (diff > 1)
4598
+ body += ` ${c.blue(`[${diffFixed}x] \u21D1`)}`;
4599
+ else
4600
+ body += ` ${c.red(`[${diffFixed}x] \u21D3`)}`;
4601
+ }
4602
+ output.push(padding + prefix + body + suffix);
4603
+ const bodyBaseline = renderBenchmark(bench.baseline, columnWidths);
4604
+ output.push(`${padding} ${bodyBaseline} ${c.dim("(baseline)")}`);
4605
+ } else {
4606
+ if (bench.current.rank === 1 && benchCount > 1)
4607
+ body += ` ${c.bold(c.green(" fastest"))}`;
4608
+ if (bench.current.rank === benchCount && benchCount > 2)
4609
+ body += ` ${c.bold(c.gray(" slowest"))}`;
4610
+ output.push(padding + prefix + body + suffix);
4611
+ }
4612
+ } else {
4613
+ output.push(padding + prefix + name + suffix);
4614
+ }
4615
+ if (((_f = task.result) == null ? void 0 : _f.state) !== "pass" && outputMap.get(task) != null) {
4628
4616
  let data = outputMap.get(task);
4629
4617
  if (typeof data === "string") {
4630
4618
  data = stripAnsi(data.trim().split("\n").filter(Boolean).pop());
@@ -4637,7 +4625,7 @@ ${padding}`;
4637
4625
  }
4638
4626
  }
4639
4627
  if (!shallow && task.type === "suite" && task.tasks.length > 0) {
4640
- if ((_f = task.result) == null ? void 0 : _f.state)
4628
+ if ((_g = task.result) == null ? void 0 : _g.state)
4641
4629
  output.push(renderTree(task.tasks, options, level + 1));
4642
4630
  }
4643
4631
  idx++;
@@ -4691,11 +4679,24 @@ class TableReporter extends BaseReporter {
4691
4679
  await super.reportSummary(files, this.ctx.state.getUnhandledErrors());
4692
4680
  super.onWatcherStart();
4693
4681
  }
4694
- onCollected() {
4682
+ async onCollected() {
4683
+ var _a, _b;
4684
+ this.rendererOptions.logger = this.ctx.logger;
4685
+ this.rendererOptions.showHeap = this.ctx.config.logHeapUsage;
4686
+ this.rendererOptions.slowTestThreshold = this.ctx.config.slowTestThreshold;
4687
+ if ((_a = this.ctx.config.benchmark) == null ? void 0 : _a.compare) {
4688
+ const compareFile = pathe.resolve(this.ctx.config.root, (_b = this.ctx.config.benchmark) == null ? void 0 : _b.compare);
4689
+ try {
4690
+ this.rendererOptions.compare = flattenFormattedBenchamrkReport(
4691
+ JSON.parse(
4692
+ await fs.promises.readFile(compareFile, "utf-8")
4693
+ )
4694
+ );
4695
+ } catch (e) {
4696
+ this.ctx.logger.error(`Failed to read '${compareFile}'`, e);
4697
+ }
4698
+ }
4695
4699
  if (this.isTTY) {
4696
- this.rendererOptions.logger = this.ctx.logger;
4697
- this.rendererOptions.showHeap = this.ctx.config.logHeapUsage;
4698
- this.rendererOptions.slowTestThreshold = this.ctx.config.slowTestThreshold;
4699
4700
  const files = this.ctx.state.getFiles(this.watchFilters);
4700
4701
  if (!this.renderer)
4701
4702
  this.renderer = createTableRenderer(files, this.rendererOptions).start();
@@ -4725,9 +4726,20 @@ class TableReporter extends BaseReporter {
4725
4726
  }
4726
4727
  }
4727
4728
  async onFinished(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
4729
+ var _a;
4728
4730
  await this.stopListRender();
4729
4731
  this.ctx.logger.log();
4730
4732
  await super.onFinished(files, errors);
4733
+ let outputFile = (_a = this.ctx.config.benchmark) == null ? void 0 : _a.outputJson;
4734
+ if (outputFile) {
4735
+ outputFile = pathe.resolve(this.ctx.config.root, outputFile);
4736
+ const outputDirectory = pathe.dirname(outputFile);
4737
+ if (!fs.existsSync(outputDirectory))
4738
+ await fs.promises.mkdir(outputDirectory, { recursive: true });
4739
+ const output = createFormattedBenchamrkReport(files);
4740
+ await fs.promises.writeFile(outputFile, JSON.stringify(output, null, 2));
4741
+ this.ctx.logger.log(`Benchmark report written to ${outputFile}`);
4742
+ }
4731
4743
  }
4732
4744
  async onWatcherStart() {
4733
4745
  await this.stopListRender();
@@ -4750,11 +4762,54 @@ class TableReporter extends BaseReporter {
4750
4762
  super.onUserConsoleLog(log);
4751
4763
  }
4752
4764
  }
4765
+ function createFormattedBenchamrkReport(files) {
4766
+ var _a;
4767
+ const report = { files: [] };
4768
+ for (const file of files) {
4769
+ const groups = [];
4770
+ for (const task of getTasks(file)) {
4771
+ if (task && task.type === "suite") {
4772
+ const benchmarks = [];
4773
+ for (const t of task.tasks) {
4774
+ const benchmark = t.meta.benchmark && ((_a = t.result) == null ? void 0 : _a.benchmark);
4775
+ if (benchmark) {
4776
+ const { samples, ...rest } = benchmark;
4777
+ benchmarks.push({
4778
+ id: t.id,
4779
+ sampleCount: samples.length,
4780
+ ...rest
4781
+ });
4782
+ }
4783
+ }
4784
+ if (benchmarks.length) {
4785
+ groups.push({
4786
+ fullName: getFullName(task, " > "),
4787
+ benchmarks
4788
+ });
4789
+ }
4790
+ }
4791
+ }
4792
+ report.files.push({
4793
+ filepath: file.filepath,
4794
+ groups
4795
+ });
4796
+ }
4797
+ return report;
4798
+ }
4799
+ function flattenFormattedBenchamrkReport(report) {
4800
+ const flat = {};
4801
+ for (const file of report.files) {
4802
+ for (const group of file.groups) {
4803
+ for (const t of group.benchmarks)
4804
+ flat[t.id] = t;
4805
+ }
4806
+ }
4807
+ return flat;
4808
+ }
4753
4809
 
4754
4810
  const BenchmarkReportsMap = {
4755
4811
  default: TableReporter,
4756
- verbose: VerboseReporter,
4757
- json: JsonReporter
4812
+ verbose: VerboseReporter
4758
4813
  };
4759
4814
 
4760
4815
  const ReportersMap = {
@@ -4762,7 +4817,7 @@ const ReportersMap = {
4762
4817
  "basic": BasicReporter,
4763
4818
  "verbose": VerboseReporter,
4764
4819
  "dot": DotReporter,
4765
- "json": JsonReporter$1,
4820
+ "json": JsonReporter,
4766
4821
  "tap": TapReporter,
4767
4822
  "tap-flat": TapFlatReporter,
4768
4823
  "junit": JUnitReporter,
@@ -4770,4 +4825,4 @@ const ReportersMap = {
4770
4825
  "github-actions": GithubActionsReporter
4771
4826
  };
4772
4827
 
4773
- export { BaseSequencer as B, DefaultReporter as D, GithubActionsReporter as G, HangingProcessReporter as H, JsonReporter$1 as J, Logger as L, ReportersMap as R, TapReporter as T, VerboseReporter as V, BasicReporter as a, DotReporter as b, JUnitReporter as c, TapFlatReporter as d, BenchmarkReportsMap as e, Typechecker as f, RandomSequencer as g, generateCodeFrame as h, highlightCode as i, wrapSerializableConfig as w };
4828
+ export { BaseSequencer as B, DefaultReporter as D, GithubActionsReporter as G, HangingProcessReporter as H, JsonReporter as J, Logger as L, ReportersMap as R, TapReporter as T, VerboseReporter as V, BasicReporter as a, DotReporter as b, JUnitReporter as c, TapFlatReporter as d, BenchmarkReportsMap as e, Typechecker as f, RandomSequencer as g, generateCodeFrame as h, highlightCode as i, wrapSerializableConfig as w };
@@ -1,27 +1,24 @@
1
1
  import * as chai from 'chai';
2
- import { NodeSnapshotEnvironment } from '@vitest/snapshot/environment';
3
2
  import { resolve } from 'pathe';
4
3
  import { distDir } from '../path.js';
5
4
  import { g as getWorkerState } from './global.CkGT_TMy.js';
6
5
  import { r as rpc } from './rpc.joBhAkyK.js';
7
6
  import { t as takeCoverageInsideWorker } from './coverage.E7sG1b3r.js';
8
- import { l as loadDiffConfig, a as loadSnapshotSerializers } from './setup-common.5nUd4r76.js';
7
+ import { l as loadDiffConfig, a as loadSnapshotSerializers } from './setup-common.8nJLd4ay.js';
9
8
 
10
9
  function setupChaiConfig(config) {
11
10
  Object.assign(chai.config, config);
12
11
  }
13
12
 
14
- class VitestSnapshotEnvironment extends NodeSnapshotEnvironment {
15
- constructor(rpc) {
16
- super();
17
- this.rpc = rpc;
18
- }
19
- getHeader() {
20
- return `// Vitest Snapshot v${this.getVersion()}, https://vitest.dev/guide/snapshot.html`;
21
- }
22
- resolvePath(filepath) {
23
- return this.rpc.resolveSnapshotPath(filepath);
13
+ async function resolveSnapshotEnvironment(config, executor) {
14
+ if (!config.snapshotEnvironment) {
15
+ const { VitestNodeSnapshotEnvironment } = await import('../chunks/environments-node.vcoXCoKs.js');
16
+ return new VitestNodeSnapshotEnvironment();
24
17
  }
18
+ const mod = await executor.executeId(config.snapshotEnvironment);
19
+ if (typeof mod.default !== "object" || !mod.default)
20
+ throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`");
21
+ return mod.default;
25
22
  }
26
23
 
27
24
  const runnersFile = resolve(distDir, "runners.js");
@@ -74,11 +71,13 @@ async function resolveTestRunner(config, executor) {
74
71
  testRunner.onAfterRunFiles = async (files) => {
75
72
  const state = getWorkerState();
76
73
  const coverage = await takeCoverageInsideWorker(config.coverage, executor);
77
- rpc().onAfterSuiteRun({
78
- coverage,
79
- transformMode: state.environment.transformMode,
80
- projectName: state.ctx.projectName
81
- });
74
+ if (coverage) {
75
+ rpc().onAfterSuiteRun({
76
+ coverage,
77
+ transformMode: state.environment.transformMode,
78
+ projectName: state.ctx.projectName
79
+ });
80
+ }
82
81
  await (originalOnAfterRun == null ? void 0 : originalOnAfterRun.call(testRunner, files));
83
82
  };
84
83
  const originalOnAfterRunTask = testRunner.onAfterRunTask;
@@ -97,4 +96,4 @@ async function resolveTestRunner(config, executor) {
97
96
  return testRunner;
98
97
  }
99
98
 
100
- export { VitestSnapshotEnvironment as V, resolveTestRunner as r, setupChaiConfig as s };
99
+ export { resolveSnapshotEnvironment as a, resolveTestRunner as r, setupChaiConfig as s };
@@ -1,7 +1,7 @@
1
1
  import { afterAll, afterEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, suite, test } from '@vitest/runner';
2
2
  import { b as bench } from './benchmark.yGkUTKnC.js';
3
3
  import { i as isFirstRun, a as runOnce } from './run-once.Olz_Zkd8.js';
4
- import { c as createExpect, a as globalExpect, v as vi, b as vitest } from './vi.Y_w82WR8.js';
4
+ import { c as createExpect, a as globalExpect, v as vi, b as vitest } from './vi.YFlodzP_.js';
5
5
  import { g as getWorkerState } from './global.CkGT_TMy.js';
6
6
  import * as chai from 'chai';
7
7
  import { assert, should } from 'chai';
@@ -12,7 +12,7 @@ async function setupCommonEnv(config) {
12
12
  globalSetup = true;
13
13
  setSafeTimers();
14
14
  if (config.globals)
15
- (await import('../chunks/integrations-globals.Hr6znn-f.js')).registerApiGlobally();
15
+ (await import('../chunks/integrations-globals.kw4co3rx.js')).registerApiGlobally();
16
16
  }
17
17
  function setupDefines(defines) {
18
18
  for (const key in defines)
@@ -1,6 +1,6 @@
1
1
  import { isAbsolute, relative, dirname, basename } from 'pathe';
2
2
  import c from 'picocolors';
3
- import { a as slash } from './base.Xt0Omgh7.js';
3
+ import { a as slash } from './base.5NT-gWu5.js';
4
4
 
5
5
  const F_RIGHT = "\u2192";
6
6
  const F_DOWN = "\u2193";
@@ -9,7 +9,7 @@ import { g as getFullName } from './tasks.IknbGB2n.js';
9
9
  import { g as getWorkerState, a as getCurrentEnvironment } from './global.CkGT_TMy.js';
10
10
  import { getSafeTimers, assertTypes, createSimpleStackTrace } from '@vitest/utils';
11
11
  import { parseSingleStack } from '@vitest/utils/source-map';
12
- import { i as isChildProcess } from './base.Xt0Omgh7.js';
12
+ import { i as isChildProcess } from './base.5NT-gWu5.js';
13
13
  import { R as RealDate, r as resetDate, m as mockDate } from './date.Ns1pGd_X.js';
14
14
  import { spyOn, fn, isMockFunction, mocks } from '@vitest/spy';
15
15