vitest 1.5.2 → 1.6.0
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.
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/chunks/environments-node.vcoXCoKs.js +19 -0
- package/dist/chunks/{integrations-globals.k0N5-dd1.js → integrations-globals.kw4co3rx.js} +7 -6
- package/dist/chunks/{runtime-console.kbFEN7E-.js → runtime-console.EO5ha7qv.js} +3 -3
- package/dist/chunks/{runtime-runBaseTests.-x-nNuJ_.js → runtime-runBaseTests.oAvMKtQC.js} +16 -16
- package/dist/cli.js +2 -2
- package/dist/config.cjs +3 -2
- package/dist/config.d.ts +1 -1
- package/dist/config.js +3 -2
- package/dist/coverage.d.ts +1 -1
- package/dist/environments.d.ts +1 -1
- package/dist/execute.d.ts +6 -4
- package/dist/execute.js +3 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +8 -7
- package/dist/node.d.ts +2 -2
- package/dist/node.js +12 -11
- package/dist/{reporters-xEmem8D4.d.ts → reporters-yx5ZTtEV.d.ts} +101 -26
- package/dist/reporters.d.ts +1 -1
- package/dist/reporters.js +11 -10
- package/dist/runners.d.ts +1 -1
- package/dist/runners.js +8 -7
- package/dist/snapshot.d.ts +9 -0
- package/dist/snapshot.js +8 -0
- package/dist/{suite-HPAKvIxA.d.ts → suite-IbNSsUWN.d.ts} +1 -1
- package/dist/suite.d.ts +3 -3
- package/dist/suite.js +5 -4
- package/dist/vendor/{base.Xt0Omgh7.js → base.5NT-gWu5.js} +9 -1
- package/dist/vendor/{base.gAwDs8Jc.js → base.Ybri3C14.js} +2 -2
- package/dist/vendor/{benchmark.eeqk2rd8.js → benchmark.yGkUTKnC.js} +1 -1
- package/dist/vendor/{cac.8mXc9Oj6.js → cac.EdDItJD-.js} +38 -15
- package/dist/vendor/{cli-api._n4_Wp_j.js → cli-api.E07AF1Yq.js} +155 -46
- package/dist/vendor/env.AtSIuHFg.js +7 -0
- package/dist/vendor/{execute.2_yoIC01.js → execute.fL3szUAI.js} +8 -3
- package/dist/vendor/{index.gHZzsRJQ.js → index.DpVgvm2P.js} +17 -18
- package/dist/vendor/{index.GlXSU9xI.js → index.Q04MCqDO.js} +690 -645
- package/dist/vendor/{index.ir9i0ywP.js → index.SMVOaj7F.js} +2 -6
- package/dist/vendor/{index.0RrMQKD8.js → index.dI9lHwVn.js} +2 -2
- package/dist/vendor/{setup-common.7SXMSI--.js → setup-common.8nJLd4ay.js} +1 -1
- package/dist/vendor/{utils.VYmeMh-u.js → utils.dEtNIEgr.js} +1 -1
- package/dist/vendor/{vi.Y_w82WR8.js → vi.YFlodzP_.js} +1 -1
- package/dist/vendor/{vm.I_IsyNig.js → vm.QEE48c0T.js} +135 -43
- package/dist/worker.js +8 -2
- package/dist/workers/forks.js +4 -4
- package/dist/workers/runVmTests.js +13 -10
- package/dist/workers/threads.js +4 -4
- package/dist/workers/vmForks.js +7 -7
- package/dist/workers/vmThreads.js +7 -7
- package/dist/workers.d.ts +1 -1
- package/dist/workers.js +8 -8
- package/package.json +13 -9
- package/snapshot.d.ts +1 -0
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import { existsSync, promises, readFileSync } from 'node:fs';
|
|
2
|
-
import { basename, dirname, resolve, join, relative, extname, normalize } from 'pathe';
|
|
3
|
-
import { a as isNode, r as relativePath } from './index.ir9i0ywP.js';
|
|
4
|
-
import { generateHash, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, getTasks, getTests, hasFailed, getSuites } from '@vitest/runner/utils';
|
|
1
|
+
import fs, { existsSync, promises, readFileSync } from 'node:fs';
|
|
5
2
|
import c from 'picocolors';
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
3
|
+
import * as pathe from 'pathe';
|
|
4
|
+
import { basename, dirname, resolve, join, relative, extname, normalize } from 'pathe';
|
|
8
5
|
import { g as getFullName, h as hasFailedSnapshot } from './tasks.IknbGB2n.js';
|
|
6
|
+
import { getSafeTimers, notNullish, highlight, shuffle, inspect, positionToOffset, lineSplitRE } from '@vitest/utils';
|
|
7
|
+
import { i as isNode } from './env.AtSIuHFg.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
|
-
import {
|
|
11
|
-
import {
|
|
11
|
+
import { r as relativePath } from './index.SMVOaj7F.js';
|
|
12
|
+
import { UNKNOWN_TEST_ID } from '../chunks/runtime-console.EO5ha7qv.js';
|
|
13
|
+
import { t as toArray, b as isPrimitive } from './base.5NT-gWu5.js';
|
|
12
14
|
import { isCI } from 'std-env';
|
|
13
15
|
import { TraceMap, generatedPositionFor, parseErrorStacktrace } from '@vitest/utils/source-map';
|
|
14
16
|
import nodeos__default, { hostname } from 'node:os';
|
|
15
|
-
import { createRequire } from 'node:module';
|
|
16
17
|
import { Writable } from 'node:stream';
|
|
17
18
|
import { writeFile, rm } from 'node:fs/promises';
|
|
18
19
|
import { execa } from 'execa';
|
|
@@ -29,6 +30,7 @@ import require$$0$2 from 'assert';
|
|
|
29
30
|
import require$$0$1 from 'events';
|
|
30
31
|
import { createHash } from 'node:crypto';
|
|
31
32
|
import { slash } from 'vite-node/utils';
|
|
33
|
+
import { createRequire } from 'node:module';
|
|
32
34
|
|
|
33
35
|
const REGEXP_WRAP_PREFIX = "$$vitest:";
|
|
34
36
|
function getOutputFile(config, reporter) {
|
|
@@ -747,7 +749,7 @@ ${log.content}
|
|
|
747
749
|
var _a2;
|
|
748
750
|
return acc + Math.max(0, ((_a2 = test.result) == null ? void 0 : _a2.duration) || 0);
|
|
749
751
|
}, 0);
|
|
750
|
-
const transformTime = this.ctx.projects.flatMap((w) =>
|
|
752
|
+
const transformTime = this.ctx.projects.flatMap((w) => w.vitenode.getTotalDuration()).reduce((a, b) => a + b, 0);
|
|
751
753
|
const environmentTime = files.reduce((acc, file) => acc + Math.max(0, file.environmentLoad || 0), 0);
|
|
752
754
|
const prepareTime = files.reduce((acc, file) => acc + Math.max(0, file.prepareDuration || 0), 0);
|
|
753
755
|
const threadTime = collectTime + testsTime + setupTime;
|
|
@@ -2185,7 +2187,7 @@ const StatusMap = {
|
|
|
2185
2187
|
skip: "skipped",
|
|
2186
2188
|
todo: "todo"
|
|
2187
2189
|
};
|
|
2188
|
-
|
|
2190
|
+
class JsonReporter {
|
|
2189
2191
|
start = 0;
|
|
2190
2192
|
ctx;
|
|
2191
2193
|
options;
|
|
@@ -2325,7 +2327,7 @@ let JsonReporter$1 = class JsonReporter {
|
|
|
2325
2327
|
return;
|
|
2326
2328
|
return { line: frame.line, column: frame.column };
|
|
2327
2329
|
}
|
|
2328
|
-
}
|
|
2330
|
+
}
|
|
2329
2331
|
|
|
2330
2332
|
class VerboseReporter extends DefaultReporter {
|
|
2331
2333
|
constructor() {
|
|
@@ -2454,499 +2456,13 @@ class TapReporter {
|
|
|
2454
2456
|
}
|
|
2455
2457
|
}
|
|
2456
2458
|
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
return [{
|
|
2463
|
-
...task,
|
|
2464
|
-
name: `${base}${task.name}`
|
|
2465
|
-
}];
|
|
2466
|
-
}
|
|
2467
|
-
}
|
|
2468
|
-
function removeInvalidXMLCharacters(value, removeDiscouragedChars) {
|
|
2469
|
-
let regex = /((?:[\0-\x08\x0B\f\x0E-\x1F\uFFFD\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/g;
|
|
2470
|
-
value = String(value || "").replace(regex, "");
|
|
2471
|
-
if (removeDiscouragedChars) {
|
|
2472
|
-
regex = new RegExp(
|
|
2473
|
-
"([\\x7F-\\x84]|[\\x86-\\x9F]|[\\uFDD0-\\uFDEF]|(?:\\uD83F[\\uDFFE\\uDFFF])|(?:\\uD87F[\\uDFFE\\uDFFF])|(?:\\uD8BF[\\uDFFE\\uDFFF])|(?:\\uD8FF[\\uDFFE\\uDFFF])|(?:\\uD93F[\\uDFFE\\uDFFF])|(?:\\uD97F[\\uDFFE\\uDFFF])|(?:\\uD9BF[\\uDFFE\\uDFFF])|(?:\\uD9FF[\\uDFFE\\uDFFF])|(?:\\uDA3F[\\uDFFE\\uDFFF])|(?:\\uDA7F[\\uDFFE\\uDFFF])|(?:\\uDABF[\\uDFFE\\uDFFF])|(?:\\uDAFF[\\uDFFE\\uDFFF])|(?:\\uDB3F[\\uDFFE\\uDFFF])|(?:\\uDB7F[\\uDFFE\\uDFFF])|(?:\\uDBBF[\\uDFFE\\uDFFF])|(?:\\uDBFF[\\uDFFE\\uDFFF])(?:[\\0-\\t\\x0B\\f\\x0E-\\u2027\\u202A-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]))",
|
|
2474
|
-
"g"
|
|
2475
|
-
);
|
|
2476
|
-
value = value.replace(regex, "");
|
|
2477
|
-
}
|
|
2478
|
-
return value;
|
|
2479
|
-
}
|
|
2480
|
-
function escapeXML(value) {
|
|
2481
|
-
return removeInvalidXMLCharacters(
|
|
2482
|
-
String(value).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">"),
|
|
2483
|
-
true
|
|
2484
|
-
);
|
|
2485
|
-
}
|
|
2486
|
-
function executionTime(durationMS) {
|
|
2487
|
-
return (durationMS / 1e3).toLocaleString("en-US", { useGrouping: false, maximumFractionDigits: 10 });
|
|
2488
|
-
}
|
|
2489
|
-
function getDuration(task) {
|
|
2490
|
-
var _a;
|
|
2491
|
-
const duration = ((_a = task.result) == null ? void 0 : _a.duration) ?? 0;
|
|
2492
|
-
return executionTime(duration);
|
|
2493
|
-
}
|
|
2494
|
-
class JUnitReporter {
|
|
2495
|
-
ctx;
|
|
2496
|
-
reportFile;
|
|
2497
|
-
baseLog;
|
|
2498
|
-
logger;
|
|
2499
|
-
_timeStart = /* @__PURE__ */ new Date();
|
|
2500
|
-
fileFd;
|
|
2501
|
-
options;
|
|
2502
|
-
constructor(options) {
|
|
2503
|
-
this.options = options;
|
|
2504
|
-
}
|
|
2505
|
-
async onInit(ctx) {
|
|
2506
|
-
this.ctx = ctx;
|
|
2507
|
-
const outputFile = this.options.outputFile ?? getOutputFile(this.ctx.config, "junit");
|
|
2508
|
-
if (outputFile) {
|
|
2509
|
-
this.reportFile = resolve(this.ctx.config.root, outputFile);
|
|
2510
|
-
const outputDirectory = dirname(this.reportFile);
|
|
2511
|
-
if (!existsSync(outputDirectory))
|
|
2512
|
-
await promises.mkdir(outputDirectory, { recursive: true });
|
|
2513
|
-
const fileFd = await promises.open(this.reportFile, "w+");
|
|
2514
|
-
this.fileFd = fileFd;
|
|
2515
|
-
this.baseLog = async (text) => {
|
|
2516
|
-
if (!this.fileFd)
|
|
2517
|
-
this.fileFd = await promises.open(this.reportFile, "w+");
|
|
2518
|
-
await promises.writeFile(this.fileFd, `${text}
|
|
2519
|
-
`);
|
|
2520
|
-
};
|
|
2521
|
-
} else {
|
|
2522
|
-
this.baseLog = async (text) => this.ctx.logger.log(text);
|
|
2523
|
-
}
|
|
2524
|
-
this._timeStart = /* @__PURE__ */ new Date();
|
|
2525
|
-
this.logger = new IndentedLogger(this.baseLog);
|
|
2526
|
-
}
|
|
2527
|
-
async writeElement(name, attrs, children) {
|
|
2528
|
-
const pairs = [];
|
|
2529
|
-
for (const key in attrs) {
|
|
2530
|
-
const attr = attrs[key];
|
|
2531
|
-
if (attr === void 0)
|
|
2532
|
-
continue;
|
|
2533
|
-
pairs.push(`${key}="${escapeXML(attr)}"`);
|
|
2534
|
-
}
|
|
2535
|
-
await this.logger.log(`<${name}${pairs.length ? ` ${pairs.join(" ")}` : ""}>`);
|
|
2536
|
-
this.logger.indent();
|
|
2537
|
-
await children.call(this);
|
|
2538
|
-
this.logger.unindent();
|
|
2539
|
-
await this.logger.log(`</${name}>`);
|
|
2540
|
-
}
|
|
2541
|
-
async writeErrorDetails(task, error) {
|
|
2542
|
-
const errorName = error.name ?? error.nameStr ?? "Unknown Error";
|
|
2543
|
-
const errorDetails = `${errorName}: ${error.message}`;
|
|
2544
|
-
await this.baseLog(escapeXML(errorDetails));
|
|
2545
|
-
const project = this.ctx.getProjectByTaskId(task.id);
|
|
2546
|
-
const stack = parseErrorStacktrace(error, {
|
|
2547
|
-
getSourceMap: (file) => project.getBrowserSourceMapModuleById(file),
|
|
2548
|
-
frameFilter: this.ctx.config.onStackTrace
|
|
2549
|
-
});
|
|
2550
|
-
for (const frame of stack) {
|
|
2551
|
-
const path = relative(this.ctx.config.root, frame.file);
|
|
2552
|
-
await this.baseLog(escapeXML(` ${F_POINTER} ${[frame.method, `${path}:${frame.line}:${frame.column}`].filter(Boolean).join(" ")}`));
|
|
2553
|
-
if (frame.file in this.ctx.state.filesMap)
|
|
2554
|
-
break;
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
async writeLogs(task, type) {
|
|
2558
|
-
if (task.logs == null || task.logs.length === 0)
|
|
2559
|
-
return;
|
|
2560
|
-
const logType = type === "err" ? "stderr" : "stdout";
|
|
2561
|
-
const logs = task.logs.filter((log) => log.type === logType);
|
|
2562
|
-
if (logs.length === 0)
|
|
2563
|
-
return;
|
|
2564
|
-
await this.writeElement(`system-${type}`, {}, async () => {
|
|
2565
|
-
for (const log of logs)
|
|
2566
|
-
await this.baseLog(escapeXML(log.content));
|
|
2567
|
-
});
|
|
2568
|
-
}
|
|
2569
|
-
async writeTasks(tasks, filename) {
|
|
2570
|
-
for (const task of tasks) {
|
|
2571
|
-
await this.writeElement("testcase", {
|
|
2572
|
-
// TODO: v2.0.0 Remove env variable in favor of custom reporter options, e.g. "reporters: [['json', { classname: 'something' }]]"
|
|
2573
|
-
classname: this.options.classname ?? process.env.VITEST_JUNIT_CLASSNAME ?? filename,
|
|
2574
|
-
name: task.name,
|
|
2575
|
-
time: getDuration(task)
|
|
2576
|
-
}, async () => {
|
|
2577
|
-
var _a;
|
|
2578
|
-
await this.writeLogs(task, "out");
|
|
2579
|
-
await this.writeLogs(task, "err");
|
|
2580
|
-
if (task.mode === "skip" || task.mode === "todo")
|
|
2581
|
-
await this.logger.log("<skipped/>");
|
|
2582
|
-
if (((_a = task.result) == null ? void 0 : _a.state) === "fail") {
|
|
2583
|
-
const errors = task.result.errors || [];
|
|
2584
|
-
for (const error of errors) {
|
|
2585
|
-
await this.writeElement("failure", {
|
|
2586
|
-
message: error == null ? void 0 : error.message,
|
|
2587
|
-
type: (error == null ? void 0 : error.name) ?? (error == null ? void 0 : error.nameStr)
|
|
2588
|
-
}, async () => {
|
|
2589
|
-
if (!error)
|
|
2590
|
-
return;
|
|
2591
|
-
await this.writeErrorDetails(task, error);
|
|
2592
|
-
});
|
|
2593
|
-
}
|
|
2594
|
-
}
|
|
2595
|
-
});
|
|
2596
|
-
}
|
|
2597
|
-
}
|
|
2598
|
-
async onFinished(files = this.ctx.state.getFiles()) {
|
|
2599
|
-
var _a;
|
|
2600
|
-
await this.logger.log('<?xml version="1.0" encoding="UTF-8" ?>');
|
|
2601
|
-
const transformed = files.map((file) => {
|
|
2602
|
-
var _a2, _b;
|
|
2603
|
-
const tasks = file.tasks.flatMap((task) => flattenTasks$1(task));
|
|
2604
|
-
const stats2 = tasks.reduce((stats3, task) => {
|
|
2605
|
-
var _a3, _b2;
|
|
2606
|
-
return {
|
|
2607
|
-
passed: stats3.passed + Number(((_a3 = task.result) == null ? void 0 : _a3.state) === "pass"),
|
|
2608
|
-
failures: stats3.failures + Number(((_b2 = task.result) == null ? void 0 : _b2.state) === "fail"),
|
|
2609
|
-
skipped: stats3.skipped + Number(task.mode === "skip" || task.mode === "todo")
|
|
2610
|
-
};
|
|
2611
|
-
}, {
|
|
2612
|
-
passed: 0,
|
|
2613
|
-
failures: 0,
|
|
2614
|
-
skipped: 0
|
|
2615
|
-
});
|
|
2616
|
-
const suites = getSuites(file);
|
|
2617
|
-
for (const suite of suites) {
|
|
2618
|
-
if ((_a2 = suite.result) == null ? void 0 : _a2.errors) {
|
|
2619
|
-
tasks.push(suite);
|
|
2620
|
-
stats2.failures += 1;
|
|
2621
|
-
}
|
|
2622
|
-
}
|
|
2623
|
-
if (tasks.length === 0 && ((_b = file.result) == null ? void 0 : _b.state) === "fail") {
|
|
2624
|
-
stats2.failures = 1;
|
|
2625
|
-
tasks.push({
|
|
2626
|
-
id: file.id,
|
|
2627
|
-
type: "test",
|
|
2628
|
-
name: file.name,
|
|
2629
|
-
mode: "run",
|
|
2630
|
-
result: file.result,
|
|
2631
|
-
meta: {},
|
|
2632
|
-
// NOTE: not used in JUnitReporter
|
|
2633
|
-
context: null,
|
|
2634
|
-
suite: null
|
|
2635
|
-
});
|
|
2636
|
-
}
|
|
2637
|
-
return {
|
|
2638
|
-
...file,
|
|
2639
|
-
tasks,
|
|
2640
|
-
stats: stats2
|
|
2641
|
-
};
|
|
2642
|
-
});
|
|
2643
|
-
const stats = transformed.reduce((stats2, file) => {
|
|
2644
|
-
stats2.tests += file.tasks.length;
|
|
2645
|
-
stats2.failures += file.stats.failures;
|
|
2646
|
-
return stats2;
|
|
2647
|
-
}, {
|
|
2648
|
-
// TODO: v2.0.0 Remove env variable in favor of custom reporter options, e.g. "reporters: [['json', { suiteName: 'something' }]]"
|
|
2649
|
-
name: this.options.suiteName || process.env.VITEST_JUNIT_SUITE_NAME || "vitest tests",
|
|
2650
|
-
tests: 0,
|
|
2651
|
-
failures: 0,
|
|
2652
|
-
errors: 0,
|
|
2653
|
-
// we cannot detect those
|
|
2654
|
-
time: executionTime((/* @__PURE__ */ new Date()).getTime() - this._timeStart.getTime())
|
|
2655
|
-
});
|
|
2656
|
-
await this.writeElement("testsuites", stats, async () => {
|
|
2657
|
-
for (const file of transformed) {
|
|
2658
|
-
await this.writeElement("testsuite", {
|
|
2659
|
-
name: relative(this.ctx.config.root, file.filepath),
|
|
2660
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2661
|
-
hostname: hostname(),
|
|
2662
|
-
tests: file.tasks.length,
|
|
2663
|
-
failures: file.stats.failures,
|
|
2664
|
-
errors: 0,
|
|
2665
|
-
// An errored test is one that had an unanticipated problem. We cannot detect those.
|
|
2666
|
-
skipped: file.stats.skipped,
|
|
2667
|
-
time: getDuration(file)
|
|
2668
|
-
}, async () => {
|
|
2669
|
-
await this.writeTasks(file.tasks, file.name);
|
|
2670
|
-
});
|
|
2671
|
-
}
|
|
2672
|
-
});
|
|
2673
|
-
if (this.reportFile)
|
|
2674
|
-
this.ctx.logger.log(`JUNIT report written to ${this.reportFile}`);
|
|
2675
|
-
await ((_a = this.fileFd) == null ? void 0 : _a.close());
|
|
2676
|
-
this.fileFd = void 0;
|
|
2677
|
-
}
|
|
2678
|
-
}
|
|
2679
|
-
|
|
2680
|
-
function flattenTasks(task, baseName = "") {
|
|
2681
|
-
const base = baseName ? `${baseName} > ` : "";
|
|
2682
|
-
if (task.type === "suite" && task.tasks.length > 0) {
|
|
2683
|
-
return task.tasks.flatMap((child) => flattenTasks(child, `${base}${task.name}`));
|
|
2684
|
-
} else {
|
|
2685
|
-
return [{
|
|
2686
|
-
...task,
|
|
2687
|
-
name: `${base}${task.name}`
|
|
2688
|
-
}];
|
|
2689
|
-
}
|
|
2690
|
-
}
|
|
2691
|
-
class TapFlatReporter extends TapReporter {
|
|
2692
|
-
onInit(ctx) {
|
|
2693
|
-
super.onInit(ctx);
|
|
2694
|
-
}
|
|
2695
|
-
async onFinished(files = this.ctx.state.getFiles()) {
|
|
2696
|
-
this.ctx.logger.log("TAP version 13");
|
|
2697
|
-
const flatTasks = files.flatMap((task) => flattenTasks(task));
|
|
2698
|
-
this.logTasks(flatTasks);
|
|
2699
|
-
}
|
|
2700
|
-
}
|
|
2459
|
+
const ESC$1 = '\u001B[';
|
|
2460
|
+
const OSC = '\u001B]';
|
|
2461
|
+
const BEL = '\u0007';
|
|
2462
|
+
const SEP = ';';
|
|
2463
|
+
const isTerminalApp = process.env.TERM_PROGRAM === 'Apple_Terminal';
|
|
2701
2464
|
|
|
2702
|
-
|
|
2703
|
-
whyRunning;
|
|
2704
|
-
onInit() {
|
|
2705
|
-
const _require = createRequire(import.meta.url);
|
|
2706
|
-
this.whyRunning = _require("why-is-node-running");
|
|
2707
|
-
}
|
|
2708
|
-
onProcessTimeout() {
|
|
2709
|
-
var _a;
|
|
2710
|
-
(_a = this.whyRunning) == null ? void 0 : _a.call(this);
|
|
2711
|
-
}
|
|
2712
|
-
}
|
|
2713
|
-
|
|
2714
|
-
async function printError(error, project, options) {
|
|
2715
|
-
const { showCodeFrame = true, fullStack = false, type } = options;
|
|
2716
|
-
const logger = options.logger;
|
|
2717
|
-
let e = error;
|
|
2718
|
-
if (isPrimitive(e)) {
|
|
2719
|
-
e = {
|
|
2720
|
-
message: String(error).split(/\n/g)[0],
|
|
2721
|
-
stack: String(error)
|
|
2722
|
-
};
|
|
2723
|
-
}
|
|
2724
|
-
if (!e) {
|
|
2725
|
-
const error2 = new Error("unknown error");
|
|
2726
|
-
e = {
|
|
2727
|
-
message: e ?? error2.message,
|
|
2728
|
-
stack: error2.stack
|
|
2729
|
-
};
|
|
2730
|
-
}
|
|
2731
|
-
if (!project) {
|
|
2732
|
-
printErrorMessage(e, logger);
|
|
2733
|
-
return;
|
|
2734
|
-
}
|
|
2735
|
-
const parserOptions = {
|
|
2736
|
-
// only browser stack traces require remapping
|
|
2737
|
-
getSourceMap: (file) => project.getBrowserSourceMapModuleById(file),
|
|
2738
|
-
frameFilter: project.config.onStackTrace
|
|
2739
|
-
};
|
|
2740
|
-
if (fullStack)
|
|
2741
|
-
parserOptions.ignoreStackEntries = [];
|
|
2742
|
-
const stacks = parseErrorStacktrace(e, parserOptions);
|
|
2743
|
-
const nearest = error instanceof TypeCheckError ? error.stacks[0] : stacks.find(
|
|
2744
|
-
(stack) => {
|
|
2745
|
-
try {
|
|
2746
|
-
return project.server && project.getModuleById(stack.file) && existsSync(stack.file);
|
|
2747
|
-
} catch {
|
|
2748
|
-
return false;
|
|
2749
|
-
}
|
|
2750
|
-
}
|
|
2751
|
-
);
|
|
2752
|
-
const errorProperties = getErrorProperties(e);
|
|
2753
|
-
if (type)
|
|
2754
|
-
printErrorType(type, project.ctx);
|
|
2755
|
-
printErrorMessage(e, logger);
|
|
2756
|
-
if (e.codeFrame)
|
|
2757
|
-
logger.error(`${e.codeFrame}
|
|
2758
|
-
`);
|
|
2759
|
-
if (e.diff)
|
|
2760
|
-
displayDiff(e.diff, logger.console);
|
|
2761
|
-
if (e.frame) {
|
|
2762
|
-
logger.error(c.yellow(e.frame));
|
|
2763
|
-
} else {
|
|
2764
|
-
printStack(logger, project, stacks, nearest, errorProperties, (s) => {
|
|
2765
|
-
if (showCodeFrame && s === nearest && nearest) {
|
|
2766
|
-
const sourceCode = readFileSync(nearest.file, "utf-8");
|
|
2767
|
-
logger.error(generateCodeFrame(sourceCode.length > 1e5 ? sourceCode : logger.highlight(nearest.file, sourceCode), 4, s));
|
|
2768
|
-
}
|
|
2769
|
-
});
|
|
2770
|
-
}
|
|
2771
|
-
const testPath = e.VITEST_TEST_PATH;
|
|
2772
|
-
const testName = e.VITEST_TEST_NAME;
|
|
2773
|
-
const afterEnvTeardown = e.VITEST_AFTER_ENV_TEARDOWN;
|
|
2774
|
-
if (testPath)
|
|
2775
|
-
logger.error(c.red(`This error originated in "${c.bold(testPath)}" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.`));
|
|
2776
|
-
if (testName) {
|
|
2777
|
-
logger.error(c.red(`The latest test that might've caused the error is "${c.bold(testName)}". It might mean one of the following:
|
|
2778
|
-
- The error was thrown, while Vitest was running this test.
|
|
2779
|
-
- If the error occurred after the test had been completed, this was the last documented test before it was thrown.`));
|
|
2780
|
-
}
|
|
2781
|
-
if (afterEnvTeardown) {
|
|
2782
|
-
logger.error(c.red("This error was caught after test environment was torn down. Make sure to cancel any running tasks before test finishes:\n- cancel timeouts using clearTimeout and clearInterval\n- wait for promises to resolve using the await keyword"));
|
|
2783
|
-
}
|
|
2784
|
-
if (typeof e.cause === "object" && e.cause && "name" in e.cause) {
|
|
2785
|
-
e.cause.name = `Caused by: ${e.cause.name}`;
|
|
2786
|
-
await printError(e.cause, project, { fullStack, showCodeFrame: false, logger: options.logger });
|
|
2787
|
-
}
|
|
2788
|
-
handleImportOutsideModuleError(e.stack || e.stackStr || "", logger);
|
|
2789
|
-
return { nearest };
|
|
2790
|
-
}
|
|
2791
|
-
function printErrorType(type, ctx) {
|
|
2792
|
-
ctx.logger.error(`
|
|
2793
|
-
${c.red(divider(c.bold(c.inverse(` ${type} `))))}`);
|
|
2794
|
-
}
|
|
2795
|
-
const skipErrorProperties = /* @__PURE__ */ new Set([
|
|
2796
|
-
"nameStr",
|
|
2797
|
-
"stack",
|
|
2798
|
-
"cause",
|
|
2799
|
-
"stacks",
|
|
2800
|
-
"stackStr",
|
|
2801
|
-
"type",
|
|
2802
|
-
"showDiff",
|
|
2803
|
-
"diff",
|
|
2804
|
-
"codeFrame",
|
|
2805
|
-
"actual",
|
|
2806
|
-
"expected",
|
|
2807
|
-
"diffOptions",
|
|
2808
|
-
"VITEST_TEST_NAME",
|
|
2809
|
-
"VITEST_TEST_PATH",
|
|
2810
|
-
"VITEST_AFTER_ENV_TEARDOWN",
|
|
2811
|
-
...Object.getOwnPropertyNames(Error.prototype),
|
|
2812
|
-
...Object.getOwnPropertyNames(Object.prototype)
|
|
2813
|
-
]);
|
|
2814
|
-
function getErrorProperties(e) {
|
|
2815
|
-
const errorObject = /* @__PURE__ */ Object.create(null);
|
|
2816
|
-
if (e.name === "AssertionError")
|
|
2817
|
-
return errorObject;
|
|
2818
|
-
for (const key of Object.getOwnPropertyNames(e)) {
|
|
2819
|
-
if (!skipErrorProperties.has(key))
|
|
2820
|
-
errorObject[key] = e[key];
|
|
2821
|
-
}
|
|
2822
|
-
return errorObject;
|
|
2823
|
-
}
|
|
2824
|
-
const esmErrors = [
|
|
2825
|
-
"Cannot use import statement outside a module",
|
|
2826
|
-
"Unexpected token 'export'"
|
|
2827
|
-
];
|
|
2828
|
-
function handleImportOutsideModuleError(stack, logger) {
|
|
2829
|
-
if (!esmErrors.some((e) => stack.includes(e)))
|
|
2830
|
-
return;
|
|
2831
|
-
const path = normalize(stack.split("\n")[0].trim());
|
|
2832
|
-
let name = path.split("/node_modules/").pop() || "";
|
|
2833
|
-
if (name == null ? void 0 : name.startsWith("@"))
|
|
2834
|
-
name = name.split("/").slice(0, 2).join("/");
|
|
2835
|
-
else
|
|
2836
|
-
name = name.split("/")[0];
|
|
2837
|
-
if (name)
|
|
2838
|
-
printModuleWarningForPackage(logger, path, name);
|
|
2839
|
-
else
|
|
2840
|
-
printModuleWarningForSourceCode(logger, path);
|
|
2841
|
-
}
|
|
2842
|
-
function printModuleWarningForPackage(logger, path, name) {
|
|
2843
|
-
logger.error(c.yellow(
|
|
2844
|
-
`Module ${path} seems to be an ES Module but shipped in a CommonJS package. You might want to create an issue to the package ${c.bold(`"${name}"`)} asking them to ship the file in .mjs extension or add "type": "module" in their package.json.
|
|
2845
|
-
|
|
2846
|
-
As a temporary workaround you can try to inline the package by updating your config:
|
|
2847
|
-
|
|
2848
|
-
` + c.gray(c.dim("// vitest.config.js")) + "\n" + c.green(`export default {
|
|
2849
|
-
test: {
|
|
2850
|
-
server: {
|
|
2851
|
-
deps: {
|
|
2852
|
-
inline: [
|
|
2853
|
-
${c.yellow(c.bold(`"${name}"`))}
|
|
2854
|
-
]
|
|
2855
|
-
}
|
|
2856
|
-
}
|
|
2857
|
-
}
|
|
2858
|
-
}
|
|
2859
|
-
`)
|
|
2860
|
-
));
|
|
2861
|
-
}
|
|
2862
|
-
function printModuleWarningForSourceCode(logger, path) {
|
|
2863
|
-
logger.error(c.yellow(
|
|
2864
|
-
`Module ${path} seems to be an ES Module but shipped in a CommonJS package. To fix this issue, change the file extension to .mjs or add "type": "module" in your package.json.`
|
|
2865
|
-
));
|
|
2866
|
-
}
|
|
2867
|
-
function displayDiff(diff, console) {
|
|
2868
|
-
if (diff)
|
|
2869
|
-
console.error(`
|
|
2870
|
-
${diff}
|
|
2871
|
-
`);
|
|
2872
|
-
}
|
|
2873
|
-
function printErrorMessage(error, logger) {
|
|
2874
|
-
const errorName = error.name || error.nameStr || "Unknown Error";
|
|
2875
|
-
if (!error.message) {
|
|
2876
|
-
logger.error(error);
|
|
2877
|
-
return;
|
|
2878
|
-
}
|
|
2879
|
-
if (error.message.length > 5e3) {
|
|
2880
|
-
logger.error(`${c.red(c.bold(errorName))}: ${error.message}`);
|
|
2881
|
-
} else {
|
|
2882
|
-
logger.error(c.red(`${c.bold(errorName)}: ${error.message}`));
|
|
2883
|
-
}
|
|
2884
|
-
}
|
|
2885
|
-
function printStack(logger, project, stack, highlight, errorProperties, onStack) {
|
|
2886
|
-
for (const frame of stack) {
|
|
2887
|
-
const color = frame === highlight ? c.cyan : c.gray;
|
|
2888
|
-
const path = relative(project.config.root, frame.file);
|
|
2889
|
-
logger.error(color(` ${c.dim(F_POINTER)} ${[frame.method, `${path}:${c.dim(`${frame.line}:${frame.column}`)}`].filter(Boolean).join(" ")}`));
|
|
2890
|
-
onStack == null ? void 0 : onStack(frame);
|
|
2891
|
-
}
|
|
2892
|
-
if (stack.length)
|
|
2893
|
-
logger.error();
|
|
2894
|
-
const hasProperties = Object.keys(errorProperties).length > 0;
|
|
2895
|
-
if (hasProperties) {
|
|
2896
|
-
logger.error(c.red(c.dim(divider())));
|
|
2897
|
-
const propertiesString = inspect(errorProperties);
|
|
2898
|
-
logger.error(c.red(c.bold("Serialized Error:")), c.gray(propertiesString));
|
|
2899
|
-
}
|
|
2900
|
-
}
|
|
2901
|
-
function generateCodeFrame(source, indent = 0, loc, range = 2) {
|
|
2902
|
-
var _a;
|
|
2903
|
-
const start = typeof loc === "object" ? positionToOffset(source, loc.line, loc.column) : loc;
|
|
2904
|
-
const end = start;
|
|
2905
|
-
const lines = source.split(lineSplitRE);
|
|
2906
|
-
const nl = /\r\n/.test(source) ? 2 : 1;
|
|
2907
|
-
let count = 0;
|
|
2908
|
-
let res = [];
|
|
2909
|
-
const columns = ((_a = process.stdout) == null ? void 0 : _a.columns) || 80;
|
|
2910
|
-
function lineNo(no = "") {
|
|
2911
|
-
return c.gray(`${String(no).padStart(3, " ")}| `);
|
|
2912
|
-
}
|
|
2913
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2914
|
-
count += lines[i].length + nl;
|
|
2915
|
-
if (count >= start) {
|
|
2916
|
-
for (let j = i - range; j <= i + range || end > count; j++) {
|
|
2917
|
-
if (j < 0 || j >= lines.length)
|
|
2918
|
-
continue;
|
|
2919
|
-
const lineLength = lines[j].length;
|
|
2920
|
-
if (stripAnsi(lines[j]).length > 200)
|
|
2921
|
-
return "";
|
|
2922
|
-
res.push(lineNo(j + 1) + cliTruncate(lines[j].replace(/\t/g, " "), columns - 5 - indent));
|
|
2923
|
-
if (j === i) {
|
|
2924
|
-
const pad = start - (count - lineLength) + (nl - 1);
|
|
2925
|
-
const length = Math.max(1, end > count ? lineLength - pad : end - start);
|
|
2926
|
-
res.push(lineNo() + " ".repeat(pad) + c.red("^".repeat(length)));
|
|
2927
|
-
} else if (j > i) {
|
|
2928
|
-
if (end > count) {
|
|
2929
|
-
const length = Math.max(1, Math.min(end - count, lineLength));
|
|
2930
|
-
res.push(lineNo() + c.red("^".repeat(length)));
|
|
2931
|
-
}
|
|
2932
|
-
count += lineLength + 1;
|
|
2933
|
-
}
|
|
2934
|
-
}
|
|
2935
|
-
break;
|
|
2936
|
-
}
|
|
2937
|
-
}
|
|
2938
|
-
if (indent)
|
|
2939
|
-
res = res.map((line) => " ".repeat(indent) + line);
|
|
2940
|
-
return res.join("\n");
|
|
2941
|
-
}
|
|
2942
|
-
|
|
2943
|
-
const ESC$1 = '\u001B[';
|
|
2944
|
-
const OSC = '\u001B]';
|
|
2945
|
-
const BEL = '\u0007';
|
|
2946
|
-
const SEP = ';';
|
|
2947
|
-
const isTerminalApp = process.env.TERM_PROGRAM === 'Apple_Terminal';
|
|
2948
|
-
|
|
2949
|
-
const ansiEscapes = {};
|
|
2465
|
+
const ansiEscapes = {};
|
|
2950
2466
|
|
|
2951
2467
|
ansiEscapes.cursorTo = (x, y) => {
|
|
2952
2468
|
if (typeof x !== 'number') {
|
|
@@ -4139,7 +3655,7 @@ createLogUpdate(process$2.stdout);
|
|
|
4139
3655
|
|
|
4140
3656
|
createLogUpdate(process$2.stderr);
|
|
4141
3657
|
|
|
4142
|
-
var version = "1.
|
|
3658
|
+
var version = "1.6.0";
|
|
4143
3659
|
|
|
4144
3660
|
const HIGHLIGHT_SUPPORTED_EXTS = new Set(["js", "ts"].flatMap((lang) => [
|
|
4145
3661
|
`.${lang}`,
|
|
@@ -4350,7 +3866,11 @@ No ${config.mode} files found, exiting with code 1`));
|
|
|
4350
3866
|
}
|
|
4351
3867
|
if (this.ctx.coverageProvider)
|
|
4352
3868
|
this.log(c.dim(" Coverage enabled with ") + c.yellow(this.ctx.coverageProvider.name));
|
|
4353
|
-
this.
|
|
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();
|
|
4354
3874
|
}
|
|
4355
3875
|
async printUnhandledErrors(errors) {
|
|
4356
3876
|
const errorMessage = c.red(c.bold(
|
|
@@ -4379,24 +3899,519 @@ Vitest found ${errors.length} error${errors.length > 1 ? "s" : ""} not related t
|
|
|
4379
3899
|
}
|
|
4380
3900
|
}
|
|
4381
3901
|
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
3902
|
+
async function captuerPrintError(error, ctx, project) {
|
|
3903
|
+
let output = "";
|
|
3904
|
+
const writable = new Writable({
|
|
3905
|
+
write(chunk, _encoding, callback) {
|
|
3906
|
+
output += String(chunk);
|
|
3907
|
+
callback();
|
|
3908
|
+
}
|
|
3909
|
+
});
|
|
3910
|
+
const result = await printError(error, project, {
|
|
3911
|
+
showCodeFrame: false,
|
|
3912
|
+
logger: new Logger(ctx, writable, writable)
|
|
3913
|
+
});
|
|
3914
|
+
return { nearest: result == null ? void 0 : result.nearest, output };
|
|
3915
|
+
}
|
|
3916
|
+
async function printError(error, project, options) {
|
|
3917
|
+
const { showCodeFrame = true, fullStack = false, type } = options;
|
|
3918
|
+
const logger = options.logger;
|
|
3919
|
+
let e = error;
|
|
3920
|
+
if (isPrimitive(e)) {
|
|
3921
|
+
e = {
|
|
3922
|
+
message: String(error).split(/\n/g)[0],
|
|
3923
|
+
stack: String(error)
|
|
3924
|
+
};
|
|
3925
|
+
}
|
|
3926
|
+
if (!e) {
|
|
3927
|
+
const error2 = new Error("unknown error");
|
|
3928
|
+
e = {
|
|
3929
|
+
message: e ?? error2.message,
|
|
3930
|
+
stack: error2.stack
|
|
3931
|
+
};
|
|
3932
|
+
}
|
|
3933
|
+
if (!project) {
|
|
3934
|
+
printErrorMessage(e, logger);
|
|
3935
|
+
return;
|
|
3936
|
+
}
|
|
3937
|
+
const parserOptions = {
|
|
3938
|
+
// only browser stack traces require remapping
|
|
3939
|
+
getSourceMap: (file) => project.getBrowserSourceMapModuleById(file),
|
|
3940
|
+
frameFilter: project.config.onStackTrace
|
|
3941
|
+
};
|
|
3942
|
+
if (fullStack)
|
|
3943
|
+
parserOptions.ignoreStackEntries = [];
|
|
3944
|
+
const stacks = parseErrorStacktrace(e, parserOptions);
|
|
3945
|
+
const nearest = error instanceof TypeCheckError ? error.stacks[0] : stacks.find(
|
|
3946
|
+
(stack) => {
|
|
3947
|
+
try {
|
|
3948
|
+
return project.server && project.getModuleById(stack.file) && existsSync(stack.file);
|
|
3949
|
+
} catch {
|
|
3950
|
+
return false;
|
|
3951
|
+
}
|
|
3952
|
+
}
|
|
3953
|
+
);
|
|
3954
|
+
const errorProperties = getErrorProperties(e);
|
|
3955
|
+
if (type)
|
|
3956
|
+
printErrorType(type, project.ctx);
|
|
3957
|
+
printErrorMessage(e, logger);
|
|
3958
|
+
if (e.codeFrame)
|
|
3959
|
+
logger.error(`${e.codeFrame}
|
|
3960
|
+
`);
|
|
3961
|
+
if (e.diff)
|
|
3962
|
+
displayDiff(e.diff, logger.console);
|
|
3963
|
+
if (e.frame) {
|
|
3964
|
+
logger.error(c.yellow(e.frame));
|
|
3965
|
+
} else {
|
|
3966
|
+
printStack(logger, project, stacks, nearest, errorProperties, (s) => {
|
|
3967
|
+
if (showCodeFrame && s === nearest && nearest) {
|
|
3968
|
+
const sourceCode = readFileSync(nearest.file, "utf-8");
|
|
3969
|
+
logger.error(generateCodeFrame(sourceCode.length > 1e5 ? sourceCode : logger.highlight(nearest.file, sourceCode), 4, s));
|
|
3970
|
+
}
|
|
3971
|
+
});
|
|
3972
|
+
}
|
|
3973
|
+
const testPath = e.VITEST_TEST_PATH;
|
|
3974
|
+
const testName = e.VITEST_TEST_NAME;
|
|
3975
|
+
const afterEnvTeardown = e.VITEST_AFTER_ENV_TEARDOWN;
|
|
3976
|
+
if (testPath)
|
|
3977
|
+
logger.error(c.red(`This error originated in "${c.bold(testPath)}" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.`));
|
|
3978
|
+
if (testName) {
|
|
3979
|
+
logger.error(c.red(`The latest test that might've caused the error is "${c.bold(testName)}". It might mean one of the following:
|
|
3980
|
+
- The error was thrown, while Vitest was running this test.
|
|
3981
|
+
- If the error occurred after the test had been completed, this was the last documented test before it was thrown.`));
|
|
3982
|
+
}
|
|
3983
|
+
if (afterEnvTeardown) {
|
|
3984
|
+
logger.error(c.red("This error was caught after test environment was torn down. Make sure to cancel any running tasks before test finishes:\n- cancel timeouts using clearTimeout and clearInterval\n- wait for promises to resolve using the await keyword"));
|
|
3985
|
+
}
|
|
3986
|
+
if (typeof e.cause === "object" && e.cause && "name" in e.cause) {
|
|
3987
|
+
e.cause.name = `Caused by: ${e.cause.name}`;
|
|
3988
|
+
await printError(e.cause, project, { fullStack, showCodeFrame: false, logger: options.logger });
|
|
3989
|
+
}
|
|
3990
|
+
handleImportOutsideModuleError(e.stack || e.stackStr || "", logger);
|
|
3991
|
+
return { nearest };
|
|
3992
|
+
}
|
|
3993
|
+
function printErrorType(type, ctx) {
|
|
3994
|
+
ctx.logger.error(`
|
|
3995
|
+
${c.red(divider(c.bold(c.inverse(` ${type} `))))}`);
|
|
3996
|
+
}
|
|
3997
|
+
const skipErrorProperties = /* @__PURE__ */ new Set([
|
|
3998
|
+
"nameStr",
|
|
3999
|
+
"stack",
|
|
4000
|
+
"cause",
|
|
4001
|
+
"stacks",
|
|
4002
|
+
"stackStr",
|
|
4003
|
+
"type",
|
|
4004
|
+
"showDiff",
|
|
4005
|
+
"diff",
|
|
4006
|
+
"codeFrame",
|
|
4007
|
+
"actual",
|
|
4008
|
+
"expected",
|
|
4009
|
+
"diffOptions",
|
|
4010
|
+
"VITEST_TEST_NAME",
|
|
4011
|
+
"VITEST_TEST_PATH",
|
|
4012
|
+
"VITEST_AFTER_ENV_TEARDOWN",
|
|
4013
|
+
...Object.getOwnPropertyNames(Error.prototype),
|
|
4014
|
+
...Object.getOwnPropertyNames(Object.prototype)
|
|
4015
|
+
]);
|
|
4016
|
+
function getErrorProperties(e) {
|
|
4017
|
+
const errorObject = /* @__PURE__ */ Object.create(null);
|
|
4018
|
+
if (e.name === "AssertionError")
|
|
4019
|
+
return errorObject;
|
|
4020
|
+
for (const key of Object.getOwnPropertyNames(e)) {
|
|
4021
|
+
if (!skipErrorProperties.has(key))
|
|
4022
|
+
errorObject[key] = e[key];
|
|
4023
|
+
}
|
|
4024
|
+
return errorObject;
|
|
4025
|
+
}
|
|
4026
|
+
const esmErrors = [
|
|
4027
|
+
"Cannot use import statement outside a module",
|
|
4028
|
+
"Unexpected token 'export'"
|
|
4029
|
+
];
|
|
4030
|
+
function handleImportOutsideModuleError(stack, logger) {
|
|
4031
|
+
if (!esmErrors.some((e) => stack.includes(e)))
|
|
4032
|
+
return;
|
|
4033
|
+
const path = normalize(stack.split("\n")[0].trim());
|
|
4034
|
+
let name = path.split("/node_modules/").pop() || "";
|
|
4035
|
+
if (name == null ? void 0 : name.startsWith("@"))
|
|
4036
|
+
name = name.split("/").slice(0, 2).join("/");
|
|
4037
|
+
else
|
|
4038
|
+
name = name.split("/")[0];
|
|
4039
|
+
if (name)
|
|
4040
|
+
printModuleWarningForPackage(logger, path, name);
|
|
4041
|
+
else
|
|
4042
|
+
printModuleWarningForSourceCode(logger, path);
|
|
4043
|
+
}
|
|
4044
|
+
function printModuleWarningForPackage(logger, path, name) {
|
|
4045
|
+
logger.error(c.yellow(
|
|
4046
|
+
`Module ${path} seems to be an ES Module but shipped in a CommonJS package. You might want to create an issue to the package ${c.bold(`"${name}"`)} asking them to ship the file in .mjs extension or add "type": "module" in their package.json.
|
|
4047
|
+
|
|
4048
|
+
As a temporary workaround you can try to inline the package by updating your config:
|
|
4049
|
+
|
|
4050
|
+
` + c.gray(c.dim("// vitest.config.js")) + "\n" + c.green(`export default {
|
|
4051
|
+
test: {
|
|
4052
|
+
server: {
|
|
4053
|
+
deps: {
|
|
4054
|
+
inline: [
|
|
4055
|
+
${c.yellow(c.bold(`"${name}"`))}
|
|
4056
|
+
]
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
`)
|
|
4062
|
+
));
|
|
4063
|
+
}
|
|
4064
|
+
function printModuleWarningForSourceCode(logger, path) {
|
|
4065
|
+
logger.error(c.yellow(
|
|
4066
|
+
`Module ${path} seems to be an ES Module but shipped in a CommonJS package. To fix this issue, change the file extension to .mjs or add "type": "module" in your package.json.`
|
|
4067
|
+
));
|
|
4068
|
+
}
|
|
4069
|
+
function displayDiff(diff, console) {
|
|
4070
|
+
if (diff)
|
|
4071
|
+
console.error(`
|
|
4072
|
+
${diff}
|
|
4073
|
+
`);
|
|
4074
|
+
}
|
|
4075
|
+
function printErrorMessage(error, logger) {
|
|
4076
|
+
const errorName = error.name || error.nameStr || "Unknown Error";
|
|
4077
|
+
if (!error.message) {
|
|
4078
|
+
logger.error(error);
|
|
4079
|
+
return;
|
|
4080
|
+
}
|
|
4081
|
+
if (error.message.length > 5e3) {
|
|
4082
|
+
logger.error(`${c.red(c.bold(errorName))}: ${error.message}`);
|
|
4083
|
+
} else {
|
|
4084
|
+
logger.error(c.red(`${c.bold(errorName)}: ${error.message}`));
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
function printStack(logger, project, stack, highlight, errorProperties, onStack) {
|
|
4088
|
+
for (const frame of stack) {
|
|
4089
|
+
const color = frame === highlight ? c.cyan : c.gray;
|
|
4090
|
+
const path = relative(project.config.root, frame.file);
|
|
4091
|
+
logger.error(color(` ${c.dim(F_POINTER)} ${[frame.method, `${path}:${c.dim(`${frame.line}:${frame.column}`)}`].filter(Boolean).join(" ")}`));
|
|
4092
|
+
onStack == null ? void 0 : onStack(frame);
|
|
4093
|
+
}
|
|
4094
|
+
if (stack.length)
|
|
4095
|
+
logger.error();
|
|
4096
|
+
const hasProperties = Object.keys(errorProperties).length > 0;
|
|
4097
|
+
if (hasProperties) {
|
|
4098
|
+
logger.error(c.red(c.dim(divider())));
|
|
4099
|
+
const propertiesString = inspect(errorProperties);
|
|
4100
|
+
logger.error(c.red(c.bold("Serialized Error:")), c.gray(propertiesString));
|
|
4101
|
+
}
|
|
4102
|
+
}
|
|
4103
|
+
function generateCodeFrame(source, indent = 0, loc, range = 2) {
|
|
4104
|
+
var _a;
|
|
4105
|
+
const start = typeof loc === "object" ? positionToOffset(source, loc.line, loc.column) : loc;
|
|
4106
|
+
const end = start;
|
|
4107
|
+
const lines = source.split(lineSplitRE);
|
|
4108
|
+
const nl = /\r\n/.test(source) ? 2 : 1;
|
|
4109
|
+
let count = 0;
|
|
4110
|
+
let res = [];
|
|
4111
|
+
const columns = ((_a = process.stdout) == null ? void 0 : _a.columns) || 80;
|
|
4112
|
+
function lineNo(no = "") {
|
|
4113
|
+
return c.gray(`${String(no).padStart(3, " ")}| `);
|
|
4114
|
+
}
|
|
4115
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4116
|
+
count += lines[i].length + nl;
|
|
4117
|
+
if (count >= start) {
|
|
4118
|
+
for (let j = i - range; j <= i + range || end > count; j++) {
|
|
4119
|
+
if (j < 0 || j >= lines.length)
|
|
4120
|
+
continue;
|
|
4121
|
+
const lineLength = lines[j].length;
|
|
4122
|
+
if (stripAnsi(lines[j]).length > 200)
|
|
4123
|
+
return "";
|
|
4124
|
+
res.push(lineNo(j + 1) + cliTruncate(lines[j].replace(/\t/g, " "), columns - 5 - indent));
|
|
4125
|
+
if (j === i) {
|
|
4126
|
+
const pad = start - (count - lineLength) + (nl - 1);
|
|
4127
|
+
const length = Math.max(1, end > count ? lineLength - pad : end - start);
|
|
4128
|
+
res.push(lineNo() + " ".repeat(pad) + c.red("^".repeat(length)));
|
|
4129
|
+
} else if (j > i) {
|
|
4130
|
+
if (end > count) {
|
|
4131
|
+
const length = Math.max(1, Math.min(end - count, lineLength));
|
|
4132
|
+
res.push(lineNo() + c.red("^".repeat(length)));
|
|
4133
|
+
}
|
|
4134
|
+
count += lineLength + 1;
|
|
4135
|
+
}
|
|
4136
|
+
}
|
|
4137
|
+
break;
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4140
|
+
if (indent)
|
|
4141
|
+
res = res.map((line) => " ".repeat(indent) + line);
|
|
4142
|
+
return res.join("\n");
|
|
4143
|
+
}
|
|
4144
|
+
|
|
4145
|
+
function flattenTasks$1(task, baseName = "") {
|
|
4146
|
+
const base = baseName ? `${baseName} > ` : "";
|
|
4147
|
+
if (task.type === "suite") {
|
|
4148
|
+
return task.tasks.flatMap((child) => flattenTasks$1(child, `${base}${task.name}`));
|
|
4149
|
+
} else {
|
|
4150
|
+
return [{
|
|
4151
|
+
...task,
|
|
4152
|
+
name: `${base}${task.name}`
|
|
4153
|
+
}];
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
function removeInvalidXMLCharacters(value, removeDiscouragedChars) {
|
|
4157
|
+
let regex = /((?:[\0-\x08\x0B\f\x0E-\x1F\uFFFD\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/g;
|
|
4158
|
+
value = String(value || "").replace(regex, "");
|
|
4159
|
+
if (removeDiscouragedChars) {
|
|
4160
|
+
regex = new RegExp(
|
|
4161
|
+
"([\\x7F-\\x84]|[\\x86-\\x9F]|[\\uFDD0-\\uFDEF]|(?:\\uD83F[\\uDFFE\\uDFFF])|(?:\\uD87F[\\uDFFE\\uDFFF])|(?:\\uD8BF[\\uDFFE\\uDFFF])|(?:\\uD8FF[\\uDFFE\\uDFFF])|(?:\\uD93F[\\uDFFE\\uDFFF])|(?:\\uD97F[\\uDFFE\\uDFFF])|(?:\\uD9BF[\\uDFFE\\uDFFF])|(?:\\uD9FF[\\uDFFE\\uDFFF])|(?:\\uDA3F[\\uDFFE\\uDFFF])|(?:\\uDA7F[\\uDFFE\\uDFFF])|(?:\\uDABF[\\uDFFE\\uDFFF])|(?:\\uDAFF[\\uDFFE\\uDFFF])|(?:\\uDB3F[\\uDFFE\\uDFFF])|(?:\\uDB7F[\\uDFFE\\uDFFF])|(?:\\uDBBF[\\uDFFE\\uDFFF])|(?:\\uDBFF[\\uDFFE\\uDFFF])(?:[\\0-\\t\\x0B\\f\\x0E-\\u2027\\u202A-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]))",
|
|
4162
|
+
"g"
|
|
4163
|
+
);
|
|
4164
|
+
value = value.replace(regex, "");
|
|
4165
|
+
}
|
|
4166
|
+
return value;
|
|
4167
|
+
}
|
|
4168
|
+
function escapeXML(value) {
|
|
4169
|
+
return removeInvalidXMLCharacters(
|
|
4170
|
+
String(value).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">"),
|
|
4171
|
+
true
|
|
4172
|
+
);
|
|
4173
|
+
}
|
|
4174
|
+
function executionTime(durationMS) {
|
|
4175
|
+
return (durationMS / 1e3).toLocaleString("en-US", { useGrouping: false, maximumFractionDigits: 10 });
|
|
4176
|
+
}
|
|
4177
|
+
function getDuration(task) {
|
|
4178
|
+
var _a;
|
|
4179
|
+
const duration = ((_a = task.result) == null ? void 0 : _a.duration) ?? 0;
|
|
4180
|
+
return executionTime(duration);
|
|
4181
|
+
}
|
|
4182
|
+
class JUnitReporter {
|
|
4183
|
+
ctx;
|
|
4184
|
+
reportFile;
|
|
4185
|
+
baseLog;
|
|
4186
|
+
logger;
|
|
4187
|
+
_timeStart = /* @__PURE__ */ new Date();
|
|
4188
|
+
fileFd;
|
|
4189
|
+
options;
|
|
4190
|
+
constructor(options) {
|
|
4191
|
+
var _a;
|
|
4192
|
+
this.options = { ...options };
|
|
4193
|
+
(_a = this.options).includeConsoleOutput ?? (_a.includeConsoleOutput = true);
|
|
4194
|
+
}
|
|
4195
|
+
async onInit(ctx) {
|
|
4196
|
+
this.ctx = ctx;
|
|
4197
|
+
const outputFile = this.options.outputFile ?? getOutputFile(this.ctx.config, "junit");
|
|
4198
|
+
if (outputFile) {
|
|
4199
|
+
this.reportFile = resolve(this.ctx.config.root, outputFile);
|
|
4200
|
+
const outputDirectory = dirname(this.reportFile);
|
|
4201
|
+
if (!existsSync(outputDirectory))
|
|
4202
|
+
await promises.mkdir(outputDirectory, { recursive: true });
|
|
4203
|
+
const fileFd = await promises.open(this.reportFile, "w+");
|
|
4204
|
+
this.fileFd = fileFd;
|
|
4205
|
+
this.baseLog = async (text) => {
|
|
4206
|
+
if (!this.fileFd)
|
|
4207
|
+
this.fileFd = await promises.open(this.reportFile, "w+");
|
|
4208
|
+
await promises.writeFile(this.fileFd, `${text}
|
|
4209
|
+
`);
|
|
4210
|
+
};
|
|
4211
|
+
} else {
|
|
4212
|
+
this.baseLog = async (text) => this.ctx.logger.log(text);
|
|
4213
|
+
}
|
|
4214
|
+
this._timeStart = /* @__PURE__ */ new Date();
|
|
4215
|
+
this.logger = new IndentedLogger(this.baseLog);
|
|
4216
|
+
}
|
|
4217
|
+
async writeElement(name, attrs, children) {
|
|
4218
|
+
const pairs = [];
|
|
4219
|
+
for (const key in attrs) {
|
|
4220
|
+
const attr = attrs[key];
|
|
4221
|
+
if (attr === void 0)
|
|
4222
|
+
continue;
|
|
4223
|
+
pairs.push(`${key}="${escapeXML(attr)}"`);
|
|
4224
|
+
}
|
|
4225
|
+
await this.logger.log(`<${name}${pairs.length ? ` ${pairs.join(" ")}` : ""}>`);
|
|
4226
|
+
this.logger.indent();
|
|
4227
|
+
await children.call(this);
|
|
4228
|
+
this.logger.unindent();
|
|
4229
|
+
await this.logger.log(`</${name}>`);
|
|
4230
|
+
}
|
|
4231
|
+
async writeLogs(task, type) {
|
|
4232
|
+
if (task.logs == null || task.logs.length === 0)
|
|
4233
|
+
return;
|
|
4234
|
+
const logType = type === "err" ? "stderr" : "stdout";
|
|
4235
|
+
const logs = task.logs.filter((log) => log.type === logType);
|
|
4236
|
+
if (logs.length === 0)
|
|
4237
|
+
return;
|
|
4238
|
+
await this.writeElement(`system-${type}`, {}, async () => {
|
|
4239
|
+
for (const log of logs)
|
|
4240
|
+
await this.baseLog(escapeXML(log.content));
|
|
4241
|
+
});
|
|
4242
|
+
}
|
|
4243
|
+
async writeTasks(tasks, filename) {
|
|
4244
|
+
for (const task of tasks) {
|
|
4245
|
+
await this.writeElement("testcase", {
|
|
4246
|
+
// TODO: v2.0.0 Remove env variable in favor of custom reporter options, e.g. "reporters: [['json', { classname: 'something' }]]"
|
|
4247
|
+
classname: this.options.classname ?? process.env.VITEST_JUNIT_CLASSNAME ?? filename,
|
|
4248
|
+
file: this.options.addFileAttribute ? filename : void 0,
|
|
4249
|
+
name: task.name,
|
|
4250
|
+
time: getDuration(task)
|
|
4251
|
+
}, async () => {
|
|
4252
|
+
var _a;
|
|
4253
|
+
if (this.options.includeConsoleOutput) {
|
|
4254
|
+
await this.writeLogs(task, "out");
|
|
4255
|
+
await this.writeLogs(task, "err");
|
|
4256
|
+
}
|
|
4257
|
+
if (task.mode === "skip" || task.mode === "todo")
|
|
4258
|
+
await this.logger.log("<skipped/>");
|
|
4259
|
+
if (((_a = task.result) == null ? void 0 : _a.state) === "fail") {
|
|
4260
|
+
const errors = task.result.errors || [];
|
|
4261
|
+
for (const error of errors) {
|
|
4262
|
+
await this.writeElement("failure", {
|
|
4263
|
+
message: error == null ? void 0 : error.message,
|
|
4264
|
+
type: (error == null ? void 0 : error.name) ?? (error == null ? void 0 : error.nameStr)
|
|
4265
|
+
}, async () => {
|
|
4266
|
+
if (!error)
|
|
4267
|
+
return;
|
|
4268
|
+
const result = await captuerPrintError(
|
|
4269
|
+
error,
|
|
4270
|
+
this.ctx,
|
|
4271
|
+
this.ctx.getProjectByTaskId(task.id)
|
|
4272
|
+
);
|
|
4273
|
+
await this.baseLog(escapeXML(stripAnsi(result.output.trim())));
|
|
4274
|
+
});
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
});
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
4280
|
+
async onFinished(files = this.ctx.state.getFiles()) {
|
|
4281
|
+
var _a;
|
|
4282
|
+
await this.logger.log('<?xml version="1.0" encoding="UTF-8" ?>');
|
|
4283
|
+
const transformed = files.map((file) => {
|
|
4284
|
+
var _a2, _b;
|
|
4285
|
+
const tasks = file.tasks.flatMap((task) => flattenTasks$1(task));
|
|
4286
|
+
const stats2 = tasks.reduce((stats3, task) => {
|
|
4287
|
+
var _a3, _b2;
|
|
4288
|
+
return {
|
|
4289
|
+
passed: stats3.passed + Number(((_a3 = task.result) == null ? void 0 : _a3.state) === "pass"),
|
|
4290
|
+
failures: stats3.failures + Number(((_b2 = task.result) == null ? void 0 : _b2.state) === "fail"),
|
|
4291
|
+
skipped: stats3.skipped + Number(task.mode === "skip" || task.mode === "todo")
|
|
4292
|
+
};
|
|
4293
|
+
}, {
|
|
4294
|
+
passed: 0,
|
|
4295
|
+
failures: 0,
|
|
4296
|
+
skipped: 0
|
|
4297
|
+
});
|
|
4298
|
+
const suites = getSuites(file);
|
|
4299
|
+
for (const suite of suites) {
|
|
4300
|
+
if ((_a2 = suite.result) == null ? void 0 : _a2.errors) {
|
|
4301
|
+
tasks.push(suite);
|
|
4302
|
+
stats2.failures += 1;
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
if (tasks.length === 0 && ((_b = file.result) == null ? void 0 : _b.state) === "fail") {
|
|
4306
|
+
stats2.failures = 1;
|
|
4307
|
+
tasks.push({
|
|
4308
|
+
id: file.id,
|
|
4309
|
+
type: "test",
|
|
4310
|
+
name: file.name,
|
|
4311
|
+
mode: "run",
|
|
4312
|
+
result: file.result,
|
|
4313
|
+
meta: {},
|
|
4314
|
+
// NOTE: not used in JUnitReporter
|
|
4315
|
+
context: null,
|
|
4316
|
+
suite: null
|
|
4317
|
+
});
|
|
4318
|
+
}
|
|
4319
|
+
return {
|
|
4320
|
+
...file,
|
|
4321
|
+
tasks,
|
|
4322
|
+
stats: stats2
|
|
4323
|
+
};
|
|
4324
|
+
});
|
|
4325
|
+
const stats = transformed.reduce((stats2, file) => {
|
|
4326
|
+
stats2.tests += file.tasks.length;
|
|
4327
|
+
stats2.failures += file.stats.failures;
|
|
4328
|
+
return stats2;
|
|
4329
|
+
}, {
|
|
4330
|
+
// TODO: v2.0.0 Remove env variable in favor of custom reporter options, e.g. "reporters: [['json', { suiteName: 'something' }]]"
|
|
4331
|
+
name: this.options.suiteName || process.env.VITEST_JUNIT_SUITE_NAME || "vitest tests",
|
|
4332
|
+
tests: 0,
|
|
4333
|
+
failures: 0,
|
|
4334
|
+
errors: 0,
|
|
4335
|
+
// we cannot detect those
|
|
4336
|
+
time: executionTime((/* @__PURE__ */ new Date()).getTime() - this._timeStart.getTime())
|
|
4337
|
+
});
|
|
4338
|
+
await this.writeElement("testsuites", stats, async () => {
|
|
4339
|
+
for (const file of transformed) {
|
|
4340
|
+
const filename = relative(this.ctx.config.root, file.filepath);
|
|
4341
|
+
await this.writeElement("testsuite", {
|
|
4342
|
+
name: filename,
|
|
4343
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4344
|
+
hostname: hostname(),
|
|
4345
|
+
tests: file.tasks.length,
|
|
4346
|
+
failures: file.stats.failures,
|
|
4347
|
+
errors: 0,
|
|
4348
|
+
// An errored test is one that had an unanticipated problem. We cannot detect those.
|
|
4349
|
+
skipped: file.stats.skipped,
|
|
4350
|
+
time: getDuration(file)
|
|
4351
|
+
}, async () => {
|
|
4352
|
+
await this.writeTasks(file.tasks, filename);
|
|
4353
|
+
});
|
|
4354
|
+
}
|
|
4355
|
+
});
|
|
4356
|
+
if (this.reportFile)
|
|
4357
|
+
this.ctx.logger.log(`JUNIT report written to ${this.reportFile}`);
|
|
4358
|
+
await ((_a = this.fileFd) == null ? void 0 : _a.close());
|
|
4359
|
+
this.fileFd = void 0;
|
|
4360
|
+
}
|
|
4361
|
+
}
|
|
4362
|
+
|
|
4363
|
+
function flattenTasks(task, baseName = "") {
|
|
4364
|
+
const base = baseName ? `${baseName} > ` : "";
|
|
4365
|
+
if (task.type === "suite" && task.tasks.length > 0) {
|
|
4366
|
+
return task.tasks.flatMap((child) => flattenTasks(child, `${base}${task.name}`));
|
|
4367
|
+
} else {
|
|
4368
|
+
return [{
|
|
4369
|
+
...task,
|
|
4370
|
+
name: `${base}${task.name}`
|
|
4371
|
+
}];
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
4374
|
+
class TapFlatReporter extends TapReporter {
|
|
4375
|
+
onInit(ctx) {
|
|
4376
|
+
super.onInit(ctx);
|
|
4377
|
+
}
|
|
4378
|
+
async onFinished(files = this.ctx.state.getFiles()) {
|
|
4379
|
+
this.ctx.logger.log("TAP version 13");
|
|
4380
|
+
const flatTasks = files.flatMap((task) => flattenTasks(task));
|
|
4381
|
+
this.logTasks(flatTasks);
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
|
|
4385
|
+
class HangingProcessReporter {
|
|
4386
|
+
whyRunning;
|
|
4387
|
+
onInit() {
|
|
4388
|
+
const _require = createRequire(import.meta.url);
|
|
4389
|
+
this.whyRunning = _require("why-is-node-running");
|
|
4390
|
+
}
|
|
4391
|
+
onProcessTimeout() {
|
|
4392
|
+
var _a;
|
|
4393
|
+
(_a = this.whyRunning) == null ? void 0 : _a.call(this);
|
|
4394
|
+
}
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
class GithubActionsReporter {
|
|
4398
|
+
ctx = void 0;
|
|
4399
|
+
onInit(ctx) {
|
|
4400
|
+
this.ctx = ctx;
|
|
4401
|
+
}
|
|
4402
|
+
async onFinished(files = [], errors = []) {
|
|
4403
|
+
var _a, _b;
|
|
4404
|
+
const projectErrors = new Array();
|
|
4405
|
+
for (const error of errors) {
|
|
4406
|
+
projectErrors.push({
|
|
4407
|
+
project: this.ctx.getCoreWorkspaceProject(),
|
|
4408
|
+
title: "Unhandled error",
|
|
4409
|
+
error
|
|
4410
|
+
});
|
|
4411
|
+
}
|
|
4412
|
+
for (const file of files) {
|
|
4413
|
+
const tasks = getTasks(file);
|
|
4414
|
+
const project = this.ctx.getProjectByTaskId(file.id);
|
|
4400
4415
|
for (const task of tasks) {
|
|
4401
4416
|
if (((_a = task.result) == null ? void 0 : _a.state) !== "fail")
|
|
4402
4417
|
continue;
|
|
@@ -4411,7 +4426,7 @@ class GithubActionsReporter {
|
|
|
4411
4426
|
}
|
|
4412
4427
|
}
|
|
4413
4428
|
for (const { project, title, error } of projectErrors) {
|
|
4414
|
-
const result = await
|
|
4429
|
+
const result = await captuerPrintError(error, this.ctx, project);
|
|
4415
4430
|
const stack = result == null ? void 0 : result.nearest;
|
|
4416
4431
|
if (!stack)
|
|
4417
4432
|
continue;
|
|
@@ -4430,20 +4445,6 @@ ${formatted}`);
|
|
|
4430
4445
|
}
|
|
4431
4446
|
}
|
|
4432
4447
|
}
|
|
4433
|
-
async function printErrorWrapper(error, ctx, project) {
|
|
4434
|
-
let output = "";
|
|
4435
|
-
const writable = new Writable({
|
|
4436
|
-
write(chunk, _encoding, callback) {
|
|
4437
|
-
output += String(chunk);
|
|
4438
|
-
callback();
|
|
4439
|
-
}
|
|
4440
|
-
});
|
|
4441
|
-
const result = await printError(error, project, {
|
|
4442
|
-
showCodeFrame: false,
|
|
4443
|
-
logger: new Logger(ctx, writable, writable)
|
|
4444
|
-
});
|
|
4445
|
-
return { nearest: result == null ? void 0 : result.nearest, output };
|
|
4446
|
-
}
|
|
4447
4448
|
function formatMessage({
|
|
4448
4449
|
command,
|
|
4449
4450
|
properties,
|
|
@@ -4464,67 +4465,6 @@ function escapeProperty(s) {
|
|
|
4464
4465
|
return s.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A").replace(/:/g, "%3A").replace(/,/g, "%2C");
|
|
4465
4466
|
}
|
|
4466
4467
|
|
|
4467
|
-
class JsonReporter {
|
|
4468
|
-
start = 0;
|
|
4469
|
-
ctx;
|
|
4470
|
-
onInit(ctx) {
|
|
4471
|
-
this.ctx = ctx;
|
|
4472
|
-
}
|
|
4473
|
-
async logTasks(files) {
|
|
4474
|
-
var _a;
|
|
4475
|
-
const suites = getSuites(files);
|
|
4476
|
-
const numTotalTestSuites = suites.length;
|
|
4477
|
-
const tests = getTests(files);
|
|
4478
|
-
const numTotalTests = tests.length;
|
|
4479
|
-
const testResults = {};
|
|
4480
|
-
const outputFile = getOutputFile(this.ctx.config.benchmark, "json");
|
|
4481
|
-
for (const file of files) {
|
|
4482
|
-
const tests2 = getTests([file]);
|
|
4483
|
-
for (const test of tests2) {
|
|
4484
|
-
const res = (_a = test.result) == null ? void 0 : _a.benchmark;
|
|
4485
|
-
if (!res || test.mode === "skip")
|
|
4486
|
-
continue;
|
|
4487
|
-
if (!outputFile)
|
|
4488
|
-
res.samples = "ignore on terminal";
|
|
4489
|
-
testResults[test.suite.name] = (testResults[test.suite.name] || []).concat(res);
|
|
4490
|
-
}
|
|
4491
|
-
if (tests2.some((t) => {
|
|
4492
|
-
var _a2;
|
|
4493
|
-
return ((_a2 = t.result) == null ? void 0 : _a2.state) === "run";
|
|
4494
|
-
})) {
|
|
4495
|
-
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");
|
|
4496
|
-
}
|
|
4497
|
-
}
|
|
4498
|
-
const result = {
|
|
4499
|
-
numTotalTestSuites,
|
|
4500
|
-
numTotalTests,
|
|
4501
|
-
testResults
|
|
4502
|
-
};
|
|
4503
|
-
await this.writeReport(JSON.stringify(result, null, 2));
|
|
4504
|
-
}
|
|
4505
|
-
async onFinished(files = this.ctx.state.getFiles()) {
|
|
4506
|
-
await this.logTasks(files);
|
|
4507
|
-
}
|
|
4508
|
-
/**
|
|
4509
|
-
* Writes the report to an output file if specified in the config,
|
|
4510
|
-
* or logs it to the console otherwise.
|
|
4511
|
-
* @param report
|
|
4512
|
-
*/
|
|
4513
|
-
async writeReport(report) {
|
|
4514
|
-
const outputFile = getOutputFile(this.ctx.config.benchmark, "json");
|
|
4515
|
-
if (outputFile) {
|
|
4516
|
-
const reportFile = resolve(this.ctx.config.root, outputFile);
|
|
4517
|
-
const outputDirectory = dirname(reportFile);
|
|
4518
|
-
if (!existsSync(outputDirectory))
|
|
4519
|
-
await promises.mkdir(outputDirectory, { recursive: true });
|
|
4520
|
-
await promises.writeFile(reportFile, report, "utf-8");
|
|
4521
|
-
this.ctx.logger.log(`json report written to ${reportFile}`);
|
|
4522
|
-
} else {
|
|
4523
|
-
this.ctx.logger.log(report);
|
|
4524
|
-
}
|
|
4525
|
-
}
|
|
4526
|
-
}
|
|
4527
|
-
|
|
4528
4468
|
const outputMap = /* @__PURE__ */ new WeakMap();
|
|
4529
4469
|
function formatFilepath(path) {
|
|
4530
4470
|
const lastSlash = Math.max(path.lastIndexOf("/") + 1, 0);
|
|
@@ -4540,17 +4480,6 @@ function formatNumber(number) {
|
|
|
4540
4480
|
return res[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ",") + (res[1] ? `.${res[1]}` : "");
|
|
4541
4481
|
}
|
|
4542
4482
|
const tableHead = ["name", "hz", "min", "max", "mean", "p75", "p99", "p995", "p999", "rme", "samples"];
|
|
4543
|
-
function renderTableHead(tasks) {
|
|
4544
|
-
const benches = tasks.map((i) => {
|
|
4545
|
-
var _a, _b;
|
|
4546
|
-
return ((_a = i.meta) == null ? void 0 : _a.benchmark) ? (_b = i.result) == null ? void 0 : _b.benchmark : void 0;
|
|
4547
|
-
}).filter(notNullish);
|
|
4548
|
-
const allItems = benches.map(renderBenchmarkItems).concat([tableHead]);
|
|
4549
|
-
return `${" ".repeat(3)}${tableHead.map((i, idx) => {
|
|
4550
|
-
const width = Math.max(...allItems.map((i2) => i2[idx].length));
|
|
4551
|
-
return idx ? i.padStart(width, " ") : i.padEnd(width, " ");
|
|
4552
|
-
}).map(c.bold).join(" ")}`;
|
|
4553
|
-
}
|
|
4554
4483
|
function renderBenchmarkItems(result) {
|
|
4555
4484
|
return [
|
|
4556
4485
|
result.name,
|
|
@@ -4566,21 +4495,27 @@ function renderBenchmarkItems(result) {
|
|
|
4566
4495
|
result.samples.length.toString()
|
|
4567
4496
|
];
|
|
4568
4497
|
}
|
|
4569
|
-
function
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
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);
|
|
4584
4519
|
return [
|
|
4585
4520
|
padded[0],
|
|
4586
4521
|
// name
|
|
@@ -4602,20 +4537,38 @@ function renderBenchmark(task, tasks) {
|
|
|
4602
4537
|
// p999
|
|
4603
4538
|
c.dim(padded[9]),
|
|
4604
4539
|
// rem
|
|
4605
|
-
c.dim(padded[10])
|
|
4540
|
+
c.dim(padded[10])
|
|
4606
4541
|
// sample
|
|
4607
|
-
result.rank === 1 ? c.bold(c.green(" fastest")) : result.rank === benches.length && benches.length > 2 ? c.bold(c.gray(" slowest")) : ""
|
|
4608
4542
|
].join(" ");
|
|
4609
4543
|
}
|
|
4610
4544
|
function renderTree(tasks, options, level = 0, shallow = false) {
|
|
4611
|
-
var _a, _b, _c, _d, _e, _f;
|
|
4545
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
4612
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
|
+
);
|
|
4613
4566
|
let idx = 0;
|
|
4614
4567
|
for (const task of tasks) {
|
|
4615
4568
|
const padding = " ".repeat(level ? 1 : 0);
|
|
4616
4569
|
let prefix = "";
|
|
4617
|
-
if (idx === 0 && ((
|
|
4618
|
-
prefix += `${renderTableHead(
|
|
4570
|
+
if (idx === 0 && ((_c = task.meta) == null ? void 0 : _c.benchmark))
|
|
4571
|
+
prefix += `${renderTableHead(columnWidths)}
|
|
4619
4572
|
${padding}`;
|
|
4620
4573
|
prefix += ` ${getStateSymbol(task)} `;
|
|
4621
4574
|
let suffix = "";
|
|
@@ -4623,18 +4576,43 @@ ${padding}`;
|
|
|
4623
4576
|
suffix += c.dim(` (${getTests(task).length})`);
|
|
4624
4577
|
if (task.mode === "skip" || task.mode === "todo")
|
|
4625
4578
|
suffix += ` ${c.dim(c.gray("[skipped]"))}`;
|
|
4626
|
-
if (((
|
|
4579
|
+
if (((_d = task.result) == null ? void 0 : _d.duration) != null) {
|
|
4627
4580
|
if (task.result.duration > options.slowTestThreshold)
|
|
4628
4581
|
suffix += c.yellow(` ${Math.round(task.result.duration)}${c.dim("ms")}`);
|
|
4629
4582
|
}
|
|
4630
|
-
if (options.showHeap && ((
|
|
4583
|
+
if (options.showHeap && ((_e = task.result) == null ? void 0 : _e.heap) != null)
|
|
4631
4584
|
suffix += c.magenta(` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`);
|
|
4632
4585
|
let name = task.name;
|
|
4633
4586
|
if (level === 0)
|
|
4634
4587
|
name = formatFilepath(name);
|
|
4635
|
-
const
|
|
4636
|
-
|
|
4637
|
-
|
|
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) {
|
|
4638
4616
|
let data = outputMap.get(task);
|
|
4639
4617
|
if (typeof data === "string") {
|
|
4640
4618
|
data = stripAnsi(data.trim().split("\n").filter(Boolean).pop());
|
|
@@ -4647,7 +4625,7 @@ ${padding}`;
|
|
|
4647
4625
|
}
|
|
4648
4626
|
}
|
|
4649
4627
|
if (!shallow && task.type === "suite" && task.tasks.length > 0) {
|
|
4650
|
-
if ((
|
|
4628
|
+
if ((_g = task.result) == null ? void 0 : _g.state)
|
|
4651
4629
|
output.push(renderTree(task.tasks, options, level + 1));
|
|
4652
4630
|
}
|
|
4653
4631
|
idx++;
|
|
@@ -4701,11 +4679,24 @@ class TableReporter extends BaseReporter {
|
|
|
4701
4679
|
await super.reportSummary(files, this.ctx.state.getUnhandledErrors());
|
|
4702
4680
|
super.onWatcherStart();
|
|
4703
4681
|
}
|
|
4704
|
-
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
|
+
}
|
|
4705
4699
|
if (this.isTTY) {
|
|
4706
|
-
this.rendererOptions.logger = this.ctx.logger;
|
|
4707
|
-
this.rendererOptions.showHeap = this.ctx.config.logHeapUsage;
|
|
4708
|
-
this.rendererOptions.slowTestThreshold = this.ctx.config.slowTestThreshold;
|
|
4709
4700
|
const files = this.ctx.state.getFiles(this.watchFilters);
|
|
4710
4701
|
if (!this.renderer)
|
|
4711
4702
|
this.renderer = createTableRenderer(files, this.rendererOptions).start();
|
|
@@ -4735,9 +4726,20 @@ class TableReporter extends BaseReporter {
|
|
|
4735
4726
|
}
|
|
4736
4727
|
}
|
|
4737
4728
|
async onFinished(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
|
|
4729
|
+
var _a;
|
|
4738
4730
|
await this.stopListRender();
|
|
4739
4731
|
this.ctx.logger.log();
|
|
4740
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
|
+
}
|
|
4741
4743
|
}
|
|
4742
4744
|
async onWatcherStart() {
|
|
4743
4745
|
await this.stopListRender();
|
|
@@ -4760,11 +4762,54 @@ class TableReporter extends BaseReporter {
|
|
|
4760
4762
|
super.onUserConsoleLog(log);
|
|
4761
4763
|
}
|
|
4762
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
|
+
}
|
|
4763
4809
|
|
|
4764
4810
|
const BenchmarkReportsMap = {
|
|
4765
4811
|
default: TableReporter,
|
|
4766
|
-
verbose: VerboseReporter
|
|
4767
|
-
json: JsonReporter
|
|
4812
|
+
verbose: VerboseReporter
|
|
4768
4813
|
};
|
|
4769
4814
|
|
|
4770
4815
|
const ReportersMap = {
|
|
@@ -4772,7 +4817,7 @@ const ReportersMap = {
|
|
|
4772
4817
|
"basic": BasicReporter,
|
|
4773
4818
|
"verbose": VerboseReporter,
|
|
4774
4819
|
"dot": DotReporter,
|
|
4775
|
-
"json": JsonReporter
|
|
4820
|
+
"json": JsonReporter,
|
|
4776
4821
|
"tap": TapReporter,
|
|
4777
4822
|
"tap-flat": TapFlatReporter,
|
|
4778
4823
|
"junit": JUnitReporter,
|
|
@@ -4780,4 +4825,4 @@ const ReportersMap = {
|
|
|
4780
4825
|
"github-actions": GithubActionsReporter
|
|
4781
4826
|
};
|
|
4782
4827
|
|
|
4783
|
-
export { BaseSequencer as B, DefaultReporter as D, GithubActionsReporter as G, HangingProcessReporter as H, JsonReporter
|
|
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 };
|