vitest 3.2.0-beta.1 → 3.2.0-beta.3
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/LICENSE.md +0 -232
- package/dist/browser.d.ts +5 -3
- package/dist/browser.js +3 -4
- package/dist/chunks/{base.SfTiRNZf.js → base.D4119yLM.js} +4 -3
- package/dist/chunks/{benchmark.BoF7jW0Q.js → benchmark.Cf_PACH1.js} +1 -1
- package/dist/chunks/{cac.TfX2-DVH.js → cac.DWaWHIIE.js} +21 -16
- package/dist/chunks/{cli-api.2970Nj9J.js → cli-api.CnmEXkxs.js} +292 -59
- package/dist/chunks/{config.d.UqE-KR0o.d.ts → config.d.D2ROskhv.d.ts} +2 -0
- package/dist/chunks/{console.K1NMVOSc.js → console.Cwr-MFPV.js} +3 -2
- package/dist/chunks/{constants.BZZyIeIE.js → constants.DnKduX2e.js} +1 -0
- package/dist/chunks/{coverage.z0LVMxgb.js → coverage.C73DaDgS.js} +241 -4226
- package/dist/chunks/{creator.CuL7xDWI.js → creator.C8WKy2eW.js} +26 -44
- package/dist/chunks/{date.CDOsz-HY.js → date.ByMsSlOr.js} +25 -0
- package/dist/chunks/{defaults.DSxsTG0h.js → defaults.DpVH7vbg.js} +1 -0
- package/dist/chunks/{environment.d.D8YDy2v5.d.ts → environment.d.cL3nLXbE.d.ts} +1 -0
- package/dist/chunks/{execute.BpmIjFTD.js → execute.B3q-2LPV.js} +28 -5
- package/dist/chunks/{global.d.BCOHQEpR.d.ts → global.d.BNLIi6yo.d.ts} +13 -11
- package/dist/chunks/{globals.Cg4NtV4P.js → globals.CI21aWXF.js} +7 -7
- package/dist/chunks/{index.DFXFpH3w.js → index.2jgTs_Q5.js} +19 -1
- package/dist/chunks/{index.CUacZlWG.js → index.Bter3jj9.js} +954 -954
- package/dist/chunks/{index.DbWBPwtH.js → index.CbT4iuwc.js} +7 -4
- package/dist/chunks/index.D3XRDfWc.js +213 -0
- package/dist/chunks/{index.BPc7M5ni.js → index.DNgLEKsQ.js} +5 -15
- package/dist/chunks/index.JOzufsrU.js +276 -0
- package/dist/chunks/{index.DBIGubLC.js → index.X0nbfr6-.js} +7 -7
- package/dist/chunks/{inspector.DbDkSkFn.js → inspector.BFsh5KO0.js} +3 -0
- package/dist/chunks/{node.3xsWotC9.js → node.Be-ntJnD.js} +1 -1
- package/dist/chunks/{reporters.d.DGm4k1Wx.d.ts → reporters.d.Bt4IGtsa.d.ts} +41 -6
- package/dist/chunks/{rpc.D9_013TY.js → rpc.BKExFSRG.js} +2 -1
- package/dist/chunks/{runBaseTests.CguliJB5.js → runBaseTests.B_M1TTsK.js} +19 -11
- package/dist/chunks/{setup-common.BP6KrF_Z.js → setup-common.CF-O-dZX.js} +2 -3
- package/dist/chunks/typechecker.BgzF-6iO.js +954 -0
- package/dist/chunks/{utils.CgTj3MsC.js → utils.BlI4TC7Y.js} +1 -0
- package/dist/chunks/{utils.BfxieIyZ.js → utils.DPCq3gzW.js} +3 -0
- package/dist/chunks/{vi.BFR5YIgu.js → vi.pkoYCV6A.js} +25 -2
- package/dist/chunks/{vite.d.DjP_ALCZ.d.ts → vite.d.B-Kx3KCF.d.ts} +3 -1
- package/dist/chunks/{vm.CuLHT1BG.js → vm.DPYem2so.js} +72 -4
- package/dist/chunks/{worker.d.CoCI7hzP.d.ts → worker.d.BKbBp2ga.d.ts} +2 -2
- package/dist/chunks/{worker.d.D5Xdi-Zr.d.ts → worker.d.Bl1O4kuf.d.ts} +1 -1
- package/dist/cli.js +21 -2
- package/dist/config.cjs +2 -0
- package/dist/config.d.ts +7 -6
- package/dist/config.js +2 -2
- package/dist/coverage.d.ts +4 -4
- package/dist/coverage.js +7 -10
- package/dist/environments.d.ts +6 -2
- package/dist/environments.js +1 -1
- package/dist/execute.d.ts +9 -3
- package/dist/execute.js +1 -1
- package/dist/index.d.ts +25 -35
- package/dist/index.js +5 -6
- package/dist/node.d.ts +18 -10
- package/dist/node.js +22 -22
- package/dist/reporters.d.ts +4 -4
- package/dist/reporters.js +14 -14
- package/dist/runners.d.ts +1 -1
- package/dist/runners.js +13 -5
- package/dist/snapshot.js +2 -2
- package/dist/suite.js +2 -2
- package/dist/worker.js +9 -5
- package/dist/workers/forks.js +6 -4
- package/dist/workers/runVmTests.js +14 -10
- package/dist/workers/threads.js +4 -4
- package/dist/workers/vmForks.js +6 -6
- package/dist/workers/vmThreads.js +6 -6
- package/dist/workers.d.ts +4 -4
- package/dist/workers.js +10 -10
- package/package.json +22 -26
- package/dist/chunks/index.Bw6JxgX8.js +0 -143
- package/dist/chunks/run-once.Dimr7O9f.js +0 -47
- package/dist/chunks/typechecker.DYQbn8uK.js +0 -956
- package/dist/chunks/utils.8gfOgtry.js +0 -207
- package/dist/utils.d.ts +0 -3
- package/dist/utils.js +0 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as chai from 'chai';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
|
-
import { l as loadDiffConfig, b as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.
|
|
3
|
+
import { l as loadDiffConfig, b as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.CF-O-dZX.js';
|
|
4
4
|
import { distDir } from '../path.js';
|
|
5
|
-
import { r as rpc } from './rpc.
|
|
6
|
-
import { g as getWorkerState } from './utils.
|
|
5
|
+
import { r as rpc } from './rpc.BKExFSRG.js';
|
|
6
|
+
import { g as getWorkerState } from './utils.BlI4TC7Y.js';
|
|
7
7
|
|
|
8
8
|
function setupChaiConfig(config) {
|
|
9
9
|
Object.assign(chai.config, config);
|
|
@@ -11,7 +11,7 @@ function setupChaiConfig(config) {
|
|
|
11
11
|
|
|
12
12
|
async function resolveSnapshotEnvironment(config, executor) {
|
|
13
13
|
if (!config.snapshotEnvironment) {
|
|
14
|
-
const { VitestNodeSnapshotEnvironment } = await import('./node.
|
|
14
|
+
const { VitestNodeSnapshotEnvironment } = await import('./node.Be-ntJnD.js');
|
|
15
15
|
return new VitestNodeSnapshotEnvironment();
|
|
16
16
|
}
|
|
17
17
|
const mod = await executor.executeId(config.snapshotEnvironment);
|
|
@@ -36,6 +36,7 @@ async function getTestRunnerConstructor(config, executor) {
|
|
|
36
36
|
async function resolveTestRunner(config, executor) {
|
|
37
37
|
const TestRunner = await getTestRunnerConstructor(config, executor);
|
|
38
38
|
const testRunner = new TestRunner(config);
|
|
39
|
+
// inject private executor to every runner
|
|
39
40
|
Object.defineProperty(testRunner, "__vitest_executor", {
|
|
40
41
|
value: executor,
|
|
41
42
|
enumerable: false,
|
|
@@ -49,6 +50,7 @@ async function resolveTestRunner(config, executor) {
|
|
|
49
50
|
}
|
|
50
51
|
const [diffOptions] = await Promise.all([loadDiffConfig(config, executor), loadSnapshotSerializers(config, executor)]);
|
|
51
52
|
testRunner.config.diffOptions = diffOptions;
|
|
53
|
+
// patch some methods, so custom runners don't need to call RPC
|
|
52
54
|
const originalOnTaskUpdate = testRunner.onTaskUpdate;
|
|
53
55
|
testRunner.onTaskUpdate = async (task, events) => {
|
|
54
56
|
const p = rpc().onTaskUpdate(task, events);
|
|
@@ -66,6 +68,7 @@ async function resolveTestRunner(config, executor) {
|
|
|
66
68
|
files.forEach((file) => {
|
|
67
69
|
file.prepareDuration = state.durations.prepare;
|
|
68
70
|
file.environmentLoad = state.durations.environment;
|
|
71
|
+
// should be collected only for a single test file in a batch
|
|
69
72
|
state.durations.prepare = 0;
|
|
70
73
|
state.durations.environment = 0;
|
|
71
74
|
});
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path, { resolve } from 'node:path';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { x } from 'tinyexec';
|
|
6
|
+
|
|
7
|
+
const AGENTS = [
|
|
8
|
+
"npm",
|
|
9
|
+
"yarn",
|
|
10
|
+
"yarn@berry",
|
|
11
|
+
"pnpm",
|
|
12
|
+
"pnpm@6",
|
|
13
|
+
"bun",
|
|
14
|
+
"deno"
|
|
15
|
+
];
|
|
16
|
+
const LOCKS = {
|
|
17
|
+
"bun.lock": "bun",
|
|
18
|
+
"bun.lockb": "bun",
|
|
19
|
+
"deno.lock": "deno",
|
|
20
|
+
"pnpm-lock.yaml": "pnpm",
|
|
21
|
+
"pnpm-workspace.yaml": "pnpm",
|
|
22
|
+
"yarn.lock": "yarn",
|
|
23
|
+
"package-lock.json": "npm",
|
|
24
|
+
"npm-shrinkwrap.json": "npm"
|
|
25
|
+
};
|
|
26
|
+
const INSTALL_METADATA = {
|
|
27
|
+
"node_modules/.deno/": "deno",
|
|
28
|
+
"node_modules/.pnpm/": "pnpm",
|
|
29
|
+
"node_modules/.yarn-state.yml": "yarn",
|
|
30
|
+
// yarn v2+ (node-modules)
|
|
31
|
+
"node_modules/.yarn_integrity": "yarn",
|
|
32
|
+
// yarn v1
|
|
33
|
+
"node_modules/.package-lock.json": "npm",
|
|
34
|
+
".pnp.cjs": "yarn",
|
|
35
|
+
// yarn v3+ (pnp)
|
|
36
|
+
".pnp.js": "yarn",
|
|
37
|
+
// yarn v2 (pnp)
|
|
38
|
+
"bun.lock": "bun",
|
|
39
|
+
"bun.lockb": "bun"
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
async function pathExists(path2, type) {
|
|
43
|
+
try {
|
|
44
|
+
const stat = await fs.stat(path2);
|
|
45
|
+
return type === "file" ? stat.isFile() : stat.isDirectory();
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function* lookup(cwd = process.cwd()) {
|
|
51
|
+
let directory = path.resolve(cwd);
|
|
52
|
+
const { root } = path.parse(directory);
|
|
53
|
+
while (directory && directory !== root) {
|
|
54
|
+
yield directory;
|
|
55
|
+
directory = path.dirname(directory);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function parsePackageJson(filepath, onUnknown) {
|
|
59
|
+
return !filepath || !pathExists(filepath, "file") ? null : await handlePackageManager(filepath, onUnknown);
|
|
60
|
+
}
|
|
61
|
+
async function detect(options = {}) {
|
|
62
|
+
const {
|
|
63
|
+
cwd,
|
|
64
|
+
strategies = ["lockfile", "packageManager-field", "devEngines-field"],
|
|
65
|
+
onUnknown
|
|
66
|
+
} = options;
|
|
67
|
+
let stopDir;
|
|
68
|
+
if (typeof options.stopDir === "string") {
|
|
69
|
+
const resolved = path.resolve(options.stopDir);
|
|
70
|
+
stopDir = (dir) => dir === resolved;
|
|
71
|
+
} else {
|
|
72
|
+
stopDir = options.stopDir;
|
|
73
|
+
}
|
|
74
|
+
for (const directory of lookup(cwd)) {
|
|
75
|
+
for (const strategy of strategies) {
|
|
76
|
+
switch (strategy) {
|
|
77
|
+
case "lockfile": {
|
|
78
|
+
for (const lock of Object.keys(LOCKS)) {
|
|
79
|
+
if (await pathExists(path.join(directory, lock), "file")) {
|
|
80
|
+
const name = LOCKS[lock];
|
|
81
|
+
const result = await parsePackageJson(path.join(directory, "package.json"), onUnknown);
|
|
82
|
+
if (result)
|
|
83
|
+
return result;
|
|
84
|
+
else
|
|
85
|
+
return { name, agent: name };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
case "packageManager-field":
|
|
91
|
+
case "devEngines-field": {
|
|
92
|
+
const result = await parsePackageJson(path.join(directory, "package.json"), onUnknown);
|
|
93
|
+
if (result)
|
|
94
|
+
return result;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case "install-metadata": {
|
|
98
|
+
for (const metadata of Object.keys(INSTALL_METADATA)) {
|
|
99
|
+
const fileOrDir = metadata.endsWith("/") ? "dir" : "file";
|
|
100
|
+
if (await pathExists(path.join(directory, metadata), fileOrDir)) {
|
|
101
|
+
const name = INSTALL_METADATA[metadata];
|
|
102
|
+
const agent = name === "yarn" ? isMetadataYarnClassic(metadata) ? "yarn" : "yarn@berry" : name;
|
|
103
|
+
return { name, agent };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (stopDir?.(directory))
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
function getNameAndVer(pkg) {
|
|
116
|
+
const handelVer = (version) => version?.match(/\d+(\.\d+){0,2}/)?.[0] ?? version;
|
|
117
|
+
if (typeof pkg.packageManager === "string") {
|
|
118
|
+
const [name, ver] = pkg.packageManager.replace(/^\^/, "").split("@");
|
|
119
|
+
return { name, ver: handelVer(ver) };
|
|
120
|
+
}
|
|
121
|
+
if (typeof pkg.devEngines?.packageManager?.name === "string") {
|
|
122
|
+
return {
|
|
123
|
+
name: pkg.devEngines.packageManager.name,
|
|
124
|
+
ver: handelVer(pkg.devEngines.packageManager.version)
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return void 0;
|
|
128
|
+
}
|
|
129
|
+
async function handlePackageManager(filepath, onUnknown) {
|
|
130
|
+
try {
|
|
131
|
+
const pkg = JSON.parse(await fs.readFile(filepath, "utf8"));
|
|
132
|
+
let agent;
|
|
133
|
+
const nameAndVer = getNameAndVer(pkg);
|
|
134
|
+
if (nameAndVer) {
|
|
135
|
+
const name = nameAndVer.name;
|
|
136
|
+
const ver = nameAndVer.ver;
|
|
137
|
+
let version = ver;
|
|
138
|
+
if (name === "yarn" && ver && Number.parseInt(ver) > 1) {
|
|
139
|
+
agent = "yarn@berry";
|
|
140
|
+
version = "berry";
|
|
141
|
+
return { name, agent, version };
|
|
142
|
+
} else if (name === "pnpm" && ver && Number.parseInt(ver) < 7) {
|
|
143
|
+
agent = "pnpm@6";
|
|
144
|
+
return { name, agent, version };
|
|
145
|
+
} else if (AGENTS.includes(name)) {
|
|
146
|
+
agent = name;
|
|
147
|
+
return { name, agent, version };
|
|
148
|
+
} else {
|
|
149
|
+
return onUnknown?.(pkg.packageManager) ?? null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
function isMetadataYarnClassic(metadataPath) {
|
|
157
|
+
return metadataPath.endsWith(".yarn_integrity");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/detect.ts
|
|
161
|
+
async function detectPackageManager(cwd = process.cwd()) {
|
|
162
|
+
const result = await detect({
|
|
163
|
+
cwd,
|
|
164
|
+
onUnknown(packageManager) {
|
|
165
|
+
console.warn("[@antfu/install-pkg] Unknown packageManager:", packageManager);
|
|
166
|
+
return void 0;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
return result?.agent || null;
|
|
170
|
+
}
|
|
171
|
+
async function installPackage(names, options = {}) {
|
|
172
|
+
const detectedAgent = options.packageManager || await detectPackageManager(options.cwd) || "npm";
|
|
173
|
+
const [agent] = detectedAgent.split("@");
|
|
174
|
+
if (!Array.isArray(names))
|
|
175
|
+
names = [names];
|
|
176
|
+
const args = (typeof options.additionalArgs === "function" ? options.additionalArgs(agent, detectedAgent) : options.additionalArgs) || [];
|
|
177
|
+
if (options.preferOffline) {
|
|
178
|
+
if (detectedAgent === "yarn@berry")
|
|
179
|
+
args.unshift("--cached");
|
|
180
|
+
else
|
|
181
|
+
args.unshift("--prefer-offline");
|
|
182
|
+
}
|
|
183
|
+
if (agent === "pnpm") {
|
|
184
|
+
args.unshift(
|
|
185
|
+
/**
|
|
186
|
+
* Prevent pnpm from removing installed devDeps while `NODE_ENV` is `production`
|
|
187
|
+
* @see https://pnpm.io/cli/install#--prod--p
|
|
188
|
+
*/
|
|
189
|
+
"--prod=false"
|
|
190
|
+
);
|
|
191
|
+
if (existsSync(resolve(options.cwd ?? process.cwd(), "pnpm-workspace.yaml"))) {
|
|
192
|
+
args.unshift("-w");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return x(
|
|
196
|
+
agent,
|
|
197
|
+
[
|
|
198
|
+
agent === "yarn" ? "add" : "install",
|
|
199
|
+
options.dev ? "-D" : "",
|
|
200
|
+
...args,
|
|
201
|
+
...names
|
|
202
|
+
].filter(Boolean),
|
|
203
|
+
{
|
|
204
|
+
nodeOptions: {
|
|
205
|
+
stdio: options.silent ? "ignore" : "inherit",
|
|
206
|
+
cwd: options.cwd
|
|
207
|
+
},
|
|
208
|
+
throwOnError: true
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export { detectPackageManager, installPackage };
|
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
import { c as createExpect, a as globalExpect, i as inject, v as vi, b as vitest } from './vi.
|
|
2
|
-
import {
|
|
3
|
-
import { b as bench } from './benchmark.BoF7jW0Q.js';
|
|
1
|
+
import { c as createExpect, a as globalExpect, i as inject, v as vi, b as vitest } from './vi.pkoYCV6A.js';
|
|
2
|
+
import { b as bench } from './benchmark.Cf_PACH1.js';
|
|
4
3
|
import { expectTypeOf } from 'expect-type';
|
|
5
4
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, suite, test } from '@vitest/runner';
|
|
6
5
|
import * as chai from 'chai';
|
|
7
6
|
import { assert, should } from 'chai';
|
|
8
7
|
|
|
9
|
-
function getRunningMode() {
|
|
10
|
-
return process.env.VITEST_MODE === "WATCH" ? "watch" : "run";
|
|
11
|
-
}
|
|
12
|
-
function isWatchMode() {
|
|
13
|
-
return getRunningMode() === "watch";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
8
|
const assertType = function assertType() {};
|
|
17
9
|
|
|
10
|
+
// TODO: deprecate <reference types="vitest" /> in favor of `<reference types="vitest/config" />`
|
|
11
|
+
|
|
18
12
|
var VitestIndex = /*#__PURE__*/Object.freeze({
|
|
19
13
|
__proto__: null,
|
|
20
14
|
afterAll: afterAll,
|
|
@@ -29,14 +23,10 @@ var VitestIndex = /*#__PURE__*/Object.freeze({
|
|
|
29
23
|
describe: describe,
|
|
30
24
|
expect: globalExpect,
|
|
31
25
|
expectTypeOf: expectTypeOf,
|
|
32
|
-
getRunningMode: getRunningMode,
|
|
33
26
|
inject: inject,
|
|
34
|
-
isFirstRun: isFirstRun,
|
|
35
|
-
isWatchMode: isWatchMode,
|
|
36
27
|
it: it,
|
|
37
28
|
onTestFailed: onTestFailed,
|
|
38
29
|
onTestFinished: onTestFinished,
|
|
39
|
-
runOnce: runOnce,
|
|
40
30
|
should: should,
|
|
41
31
|
suite: suite,
|
|
42
32
|
test: test,
|
|
@@ -44,4 +34,4 @@ var VitestIndex = /*#__PURE__*/Object.freeze({
|
|
|
44
34
|
vitest: vitest
|
|
45
35
|
});
|
|
46
36
|
|
|
47
|
-
export { VitestIndex as V, assertType as a
|
|
37
|
+
export { VitestIndex as V, assertType as a };
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { getTasks, getFullName, getTests } from '@vitest/runner/utils';
|
|
3
|
+
import * as pathe from 'pathe';
|
|
4
|
+
import c from 'tinyrainbow';
|
|
5
|
+
import { g as getStateSymbol, t as truncateString, F as F_RIGHT, D as DefaultReporter, f as formatProjectName } from './index.Bter3jj9.js';
|
|
6
|
+
import { stripVTControlCharacters } from 'node:util';
|
|
7
|
+
import { notNullish } from '@vitest/utils';
|
|
8
|
+
|
|
9
|
+
function createBenchmarkJsonReport(files) {
|
|
10
|
+
const report = { files: [] };
|
|
11
|
+
for (const file of files) {
|
|
12
|
+
const groups = [];
|
|
13
|
+
for (const task of getTasks(file)) {
|
|
14
|
+
if (task?.type === "suite") {
|
|
15
|
+
const benchmarks = [];
|
|
16
|
+
for (const t of task.tasks) {
|
|
17
|
+
const benchmark = t.meta.benchmark && t.result?.benchmark;
|
|
18
|
+
if (benchmark) {
|
|
19
|
+
benchmarks.push({
|
|
20
|
+
id: t.id,
|
|
21
|
+
...benchmark,
|
|
22
|
+
samples: []
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (benchmarks.length) {
|
|
27
|
+
groups.push({
|
|
28
|
+
fullName: getFullName(task, " > "),
|
|
29
|
+
benchmarks
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
report.files.push({
|
|
35
|
+
filepath: file.filepath,
|
|
36
|
+
groups
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return report;
|
|
40
|
+
}
|
|
41
|
+
function flattenFormattedBenchmarkReport(report) {
|
|
42
|
+
const flat = {};
|
|
43
|
+
for (const file of report.files) {
|
|
44
|
+
for (const group of file.groups) {
|
|
45
|
+
for (const t of group.benchmarks) {
|
|
46
|
+
flat[t.id] = t;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return flat;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const outputMap = new WeakMap();
|
|
54
|
+
function formatNumber(number) {
|
|
55
|
+
const res = String(number.toFixed(number < 100 ? 4 : 2)).split(".");
|
|
56
|
+
return res[0].replace(/(?=(?:\d{3})+$)\B/g, ",") + (res[1] ? `.${res[1]}` : "");
|
|
57
|
+
}
|
|
58
|
+
const tableHead = [
|
|
59
|
+
"name",
|
|
60
|
+
"hz",
|
|
61
|
+
"min",
|
|
62
|
+
"max",
|
|
63
|
+
"mean",
|
|
64
|
+
"p75",
|
|
65
|
+
"p99",
|
|
66
|
+
"p995",
|
|
67
|
+
"p999",
|
|
68
|
+
"rme",
|
|
69
|
+
"samples"
|
|
70
|
+
];
|
|
71
|
+
function renderBenchmarkItems(result) {
|
|
72
|
+
return [
|
|
73
|
+
result.name,
|
|
74
|
+
formatNumber(result.hz || 0),
|
|
75
|
+
formatNumber(result.min || 0),
|
|
76
|
+
formatNumber(result.max || 0),
|
|
77
|
+
formatNumber(result.mean || 0),
|
|
78
|
+
formatNumber(result.p75 || 0),
|
|
79
|
+
formatNumber(result.p99 || 0),
|
|
80
|
+
formatNumber(result.p995 || 0),
|
|
81
|
+
formatNumber(result.p999 || 0),
|
|
82
|
+
`±${(result.rme || 0).toFixed(2)}%`,
|
|
83
|
+
(result.sampleCount || 0).toString()
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
function computeColumnWidths(results) {
|
|
87
|
+
const rows = [tableHead, ...results.map((v) => renderBenchmarkItems(v))];
|
|
88
|
+
return Array.from(tableHead, (_, i) => Math.max(...rows.map((row) => stripVTControlCharacters(row[i]).length)));
|
|
89
|
+
}
|
|
90
|
+
function padRow(row, widths) {
|
|
91
|
+
return row.map((v, i) => i ? v.padStart(widths[i], " ") : v.padEnd(widths[i], " "));
|
|
92
|
+
}
|
|
93
|
+
function renderTableHead(widths) {
|
|
94
|
+
return " ".repeat(3) + padRow(tableHead, widths).map(c.bold).join(" ");
|
|
95
|
+
}
|
|
96
|
+
function renderBenchmark(result, widths) {
|
|
97
|
+
const padded = padRow(renderBenchmarkItems(result), widths);
|
|
98
|
+
return [
|
|
99
|
+
padded[0],
|
|
100
|
+
c.blue(padded[1]),
|
|
101
|
+
c.cyan(padded[2]),
|
|
102
|
+
c.cyan(padded[3]),
|
|
103
|
+
c.cyan(padded[4]),
|
|
104
|
+
c.cyan(padded[5]),
|
|
105
|
+
c.cyan(padded[6]),
|
|
106
|
+
c.cyan(padded[7]),
|
|
107
|
+
c.cyan(padded[8]),
|
|
108
|
+
c.dim(padded[9]),
|
|
109
|
+
c.dim(padded[10])
|
|
110
|
+
].join(" ");
|
|
111
|
+
}
|
|
112
|
+
function renderTable(options) {
|
|
113
|
+
const output = [];
|
|
114
|
+
const benchMap = {};
|
|
115
|
+
for (const task of options.tasks) {
|
|
116
|
+
if (task.meta.benchmark && task.result?.benchmark) {
|
|
117
|
+
benchMap[task.id] = {
|
|
118
|
+
current: task.result.benchmark,
|
|
119
|
+
baseline: options.compare?.[task.id]
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const benchCount = Object.entries(benchMap).length;
|
|
124
|
+
const columnWidths = computeColumnWidths(Object.values(benchMap).flatMap((v) => [v.current, v.baseline]).filter(notNullish));
|
|
125
|
+
let idx = 0;
|
|
126
|
+
const padding = " ".repeat(1 );
|
|
127
|
+
for (const task of options.tasks) {
|
|
128
|
+
const duration = task.result?.duration;
|
|
129
|
+
const bench = benchMap[task.id];
|
|
130
|
+
let prefix = "";
|
|
131
|
+
if (idx === 0 && task.meta?.benchmark) {
|
|
132
|
+
prefix += `${renderTableHead(columnWidths)}\n${padding}`;
|
|
133
|
+
}
|
|
134
|
+
prefix += ` ${getStateSymbol(task)} `;
|
|
135
|
+
let suffix = "";
|
|
136
|
+
if (task.type === "suite") {
|
|
137
|
+
suffix += c.dim(` (${getTests(task).length})`);
|
|
138
|
+
}
|
|
139
|
+
if (task.mode === "skip" || task.mode === "todo") {
|
|
140
|
+
suffix += c.dim(c.gray(" [skipped]"));
|
|
141
|
+
}
|
|
142
|
+
if (duration != null) {
|
|
143
|
+
const color = duration > options.slowTestThreshold ? c.yellow : c.green;
|
|
144
|
+
suffix += color(` ${Math.round(duration)}${c.dim("ms")}`);
|
|
145
|
+
}
|
|
146
|
+
if (options.showHeap && task.result?.heap != null) {
|
|
147
|
+
suffix += c.magenta(` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`);
|
|
148
|
+
}
|
|
149
|
+
if (bench) {
|
|
150
|
+
let body = renderBenchmark(bench.current, columnWidths);
|
|
151
|
+
if (options.compare && bench.baseline) {
|
|
152
|
+
if (bench.current.hz) {
|
|
153
|
+
const diff = bench.current.hz / bench.baseline.hz;
|
|
154
|
+
const diffFixed = diff.toFixed(2);
|
|
155
|
+
if (diffFixed === "1.0.0") {
|
|
156
|
+
body += c.gray(` [${diffFixed}x]`);
|
|
157
|
+
}
|
|
158
|
+
if (diff > 1) {
|
|
159
|
+
body += c.blue(` [${diffFixed}x] ⇑`);
|
|
160
|
+
} else {
|
|
161
|
+
body += c.red(` [${diffFixed}x] ⇓`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
output.push(padding + prefix + body + suffix);
|
|
165
|
+
const bodyBaseline = renderBenchmark(bench.baseline, columnWidths);
|
|
166
|
+
output.push(`${padding} ${bodyBaseline} ${c.dim("(baseline)")}`);
|
|
167
|
+
} else {
|
|
168
|
+
if (bench.current.rank === 1 && benchCount > 1) {
|
|
169
|
+
body += c.bold(c.green(" fastest"));
|
|
170
|
+
}
|
|
171
|
+
if (bench.current.rank === benchCount && benchCount > 2) {
|
|
172
|
+
body += c.bold(c.gray(" slowest"));
|
|
173
|
+
}
|
|
174
|
+
output.push(padding + prefix + body + suffix);
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
output.push(padding + prefix + task.name + suffix);
|
|
178
|
+
}
|
|
179
|
+
if (task.result?.state !== "pass" && outputMap.get(task) != null) {
|
|
180
|
+
let data = outputMap.get(task);
|
|
181
|
+
if (typeof data === "string") {
|
|
182
|
+
data = stripVTControlCharacters(data.trim().split("\n").filter(Boolean).pop());
|
|
183
|
+
if (data === "") {
|
|
184
|
+
data = undefined;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (data != null) {
|
|
188
|
+
const out = ` ${" ".repeat(options.level)}${F_RIGHT} ${data}`;
|
|
189
|
+
output.push(c.gray(truncateString(out, options.columns)));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
idx++;
|
|
193
|
+
}
|
|
194
|
+
return output.filter(Boolean).join("\n");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
class BenchmarkReporter extends DefaultReporter {
|
|
198
|
+
compare;
|
|
199
|
+
async onInit(ctx) {
|
|
200
|
+
super.onInit(ctx);
|
|
201
|
+
if (this.ctx.config.benchmark?.compare) {
|
|
202
|
+
const compareFile = pathe.resolve(this.ctx.config.root, this.ctx.config.benchmark?.compare);
|
|
203
|
+
try {
|
|
204
|
+
this.compare = flattenFormattedBenchmarkReport(JSON.parse(await fs.promises.readFile(compareFile, "utf-8")));
|
|
205
|
+
} catch (e) {
|
|
206
|
+
this.error(`Failed to read '${compareFile}'`, e);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
onTaskUpdate(packs) {
|
|
211
|
+
for (const pack of packs) {
|
|
212
|
+
const task = this.ctx.state.idMap.get(pack[0]);
|
|
213
|
+
if (task?.type === "suite" && task.result?.state !== "run") {
|
|
214
|
+
task.tasks.filter((task) => task.result?.benchmark).sort((benchA, benchB) => benchA.result.benchmark.mean - benchB.result.benchmark.mean).forEach((bench, idx) => {
|
|
215
|
+
bench.result.benchmark.rank = Number(idx) + 1;
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
onTestSuiteResult(testSuite) {
|
|
221
|
+
super.onTestSuiteResult(testSuite);
|
|
222
|
+
this.printSuiteTable(testSuite);
|
|
223
|
+
}
|
|
224
|
+
printTestModule(testModule) {
|
|
225
|
+
this.printSuiteTable(testModule);
|
|
226
|
+
}
|
|
227
|
+
printSuiteTable(testTask) {
|
|
228
|
+
const state = testTask.state();
|
|
229
|
+
if (state === "pending" || state === "queued") {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const benches = testTask.task.tasks.filter((t) => t.meta.benchmark);
|
|
233
|
+
const duration = testTask.task.result?.duration || 0;
|
|
234
|
+
if (benches.length > 0 && benches.every((t) => t.result?.state !== "run" && t.result?.state !== "queued")) {
|
|
235
|
+
let title = `\n ${getStateSymbol(testTask.task)} ${formatProjectName(testTask.project)}${getFullName(testTask.task, c.dim(" > "))}`;
|
|
236
|
+
if (duration != null && duration > this.ctx.config.slowTestThreshold) {
|
|
237
|
+
title += c.yellow(` ${Math.round(duration)}${c.dim("ms")}`);
|
|
238
|
+
}
|
|
239
|
+
this.log(title);
|
|
240
|
+
this.log(renderTable({
|
|
241
|
+
tasks: benches,
|
|
242
|
+
level: 1,
|
|
243
|
+
columns: this.ctx.logger.getColumns(),
|
|
244
|
+
compare: this.compare,
|
|
245
|
+
showHeap: this.ctx.config.logHeapUsage,
|
|
246
|
+
slowTestThreshold: this.ctx.config.slowTestThreshold
|
|
247
|
+
}));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async onFinished(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
|
|
251
|
+
super.onFinished(files, errors);
|
|
252
|
+
// write output for future comparison
|
|
253
|
+
let outputFile = this.ctx.config.benchmark?.outputJson;
|
|
254
|
+
if (outputFile) {
|
|
255
|
+
outputFile = pathe.resolve(this.ctx.config.root, outputFile);
|
|
256
|
+
const outputDirectory = pathe.dirname(outputFile);
|
|
257
|
+
if (!fs.existsSync(outputDirectory)) {
|
|
258
|
+
await fs.promises.mkdir(outputDirectory, { recursive: true });
|
|
259
|
+
}
|
|
260
|
+
const output = createBenchmarkJsonReport(files);
|
|
261
|
+
await fs.promises.writeFile(outputFile, JSON.stringify(output, null, 2));
|
|
262
|
+
this.log(`Benchmark report written to ${outputFile}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
class VerboseBenchmarkReporter extends BenchmarkReporter {
|
|
268
|
+
verbose = true;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const BenchmarkReportsMap = {
|
|
272
|
+
default: BenchmarkReporter,
|
|
273
|
+
verbose: VerboseBenchmarkReporter
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
export { BenchmarkReporter as B, VerboseBenchmarkReporter as V, BenchmarkReportsMap as a };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from 'node:path';
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
import process$1 from 'node:process';
|
|
4
4
|
import { promises } from 'node:fs';
|
|
@@ -237,7 +237,7 @@ async function locatePath(
|
|
|
237
237
|
|
|
238
238
|
return pLocate(paths, async path_ => {
|
|
239
239
|
try {
|
|
240
|
-
const stat = await statFunction(
|
|
240
|
+
const stat = await statFunction(path.resolve(cwd, path_));
|
|
241
241
|
return matchType(type, stat);
|
|
242
242
|
} catch {
|
|
243
243
|
return false;
|
|
@@ -250,9 +250,9 @@ const toPath = urlOrPath => urlOrPath instanceof URL ? fileURLToPath(urlOrPath)
|
|
|
250
250
|
const findUpStop = Symbol('findUpStop');
|
|
251
251
|
|
|
252
252
|
async function findUpMultiple(name, options = {}) {
|
|
253
|
-
let directory =
|
|
254
|
-
const {root} =
|
|
255
|
-
const stopAt =
|
|
253
|
+
let directory = path.resolve(toPath(options.cwd) || '');
|
|
254
|
+
const {root} = path.parse(directory);
|
|
255
|
+
const stopAt = path.resolve(directory, options.stopAt || root);
|
|
256
256
|
const limit = options.limit || Number.POSITIVE_INFINITY;
|
|
257
257
|
const paths = [name].flat();
|
|
258
258
|
|
|
@@ -280,14 +280,14 @@ async function findUpMultiple(name, options = {}) {
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
if (foundPath) {
|
|
283
|
-
matches.push(
|
|
283
|
+
matches.push(path.resolve(directory, foundPath));
|
|
284
284
|
}
|
|
285
285
|
|
|
286
286
|
if (directory === stopAt || matches.length >= limit) {
|
|
287
287
|
break;
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
directory =
|
|
290
|
+
directory = path.dirname(directory);
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
return matches;
|
|
@@ -13,11 +13,13 @@ function setupInspect(ctx) {
|
|
|
13
13
|
const isEnabled = config.inspector.enabled;
|
|
14
14
|
if (isEnabled) {
|
|
15
15
|
inspector = __require("node:inspector");
|
|
16
|
+
// Inspector may be open already if "isolate: false" is used
|
|
16
17
|
const isOpen = inspector.url() !== undefined;
|
|
17
18
|
if (!isOpen) {
|
|
18
19
|
inspector.open(config.inspector.port, config.inspector.host, config.inspector.waitForDebugger);
|
|
19
20
|
if (config.inspectBrk) {
|
|
20
21
|
const firstTestFile = typeof ctx.files[0] === "string" ? ctx.files[0] : ctx.files[0].filepath;
|
|
22
|
+
// Stop at first test file
|
|
21
23
|
if (firstTestFile) {
|
|
22
24
|
session = new inspector.Session();
|
|
23
25
|
session.connect();
|
|
@@ -46,6 +48,7 @@ function closeInspector(config) {
|
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
function shouldKeepOpen(config) {
|
|
51
|
+
// In watch mode the inspector can persist re-runs if isolation is disabled and a single worker is used
|
|
49
52
|
const isIsolatedSingleThread = config.pool === "threads" && config.poolOptions?.threads?.isolate === false && config.poolOptions?.threads?.singleThread;
|
|
50
53
|
const isIsolatedSingleFork = config.pool === "forks" && config.poolOptions?.forks?.isolate === false && config.poolOptions?.forks?.singleFork;
|
|
51
54
|
return config.watch && (isIsolatedSingleFork || isIsolatedSingleThread);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NodeSnapshotEnvironment } from '@vitest/snapshot/environment';
|
|
2
|
-
import { g as getWorkerState } from './utils.
|
|
2
|
+
import { g as getWorkerState } from './utils.BlI4TC7Y.js';
|
|
3
3
|
import '@vitest/utils';
|
|
4
4
|
|
|
5
5
|
class VitestNodeSnapshotEnvironment extends NodeSnapshotEnvironment {
|