vitest 3.2.0-beta.3 → 3.2.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/LICENSE.md +29 -0
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +2 -2
- package/dist/chunks/{base.D4119yLM.js → base.Cg0miDlQ.js} +10 -14
- package/dist/chunks/{benchmark.Cf_PACH1.js → benchmark.CYdenmiT.js} +4 -6
- package/dist/chunks/{cac.DWaWHIIE.js → cac.6rXCxFY1.js} +66 -136
- package/dist/chunks/{cli-api.CnmEXkxs.js → cli-api.Cej3MBjA.js} +1250 -1335
- package/dist/chunks/{console.Cwr-MFPV.js → console.CtFJOzRO.js} +24 -45
- package/dist/chunks/{coverage.0iPg4Wrz.js → coverage.DVF1vEu8.js} +4 -12
- package/dist/chunks/{coverage.C73DaDgS.js → coverage.EIiagJJP.js} +484 -1003
- package/dist/chunks/{creator.C8WKy2eW.js → creator.GK6I-cL4.js} +29 -76
- package/dist/chunks/{date.ByMsSlOr.js → date.Bq6ZW5rf.js} +3 -8
- package/dist/chunks/{defaults.DpVH7vbg.js → defaults.B7q_naMc.js} +1 -1
- package/dist/chunks/{env.Dq0hM4Xv.js → env.D4Lgay0q.js} +1 -1
- package/dist/chunks/{execute.B3q-2LPV.js → execute.B7h3T_Hc.js} +104 -220
- package/dist/chunks/{git.DXfdBEfR.js → git.BVQ8w_Sw.js} +1 -3
- package/dist/chunks/{global.d.BNLIi6yo.d.ts → global.d.MAmajcmJ.d.ts} +2 -0
- package/dist/chunks/{globals.CI21aWXF.js → globals.DEHgCU4V.js} +5 -5
- package/dist/chunks/{index.Bter3jj9.js → index.BZ0g1JD2.js} +366 -628
- package/dist/chunks/{index.CbT4iuwc.js → index.BbB8_kAK.js} +22 -24
- package/dist/chunks/{index.JOzufsrU.js → index.CIyJn3t1.js} +37 -82
- package/dist/chunks/{index.DNgLEKsQ.js → index.CdQS2e2Q.js} +2 -2
- package/dist/chunks/{index.2jgTs_Q5.js → index.CmSc2RE5.js} +69 -107
- package/dist/chunks/{inspector.BFsh5KO0.js → inspector.C914Efll.js} +1 -1
- package/dist/chunks/{node.Be-ntJnD.js → node.fjCdwEIl.js} +1 -1
- package/dist/chunks/{reporters.d.Bt4IGtsa.d.ts → reporters.d.C1ogPriE.d.ts} +24 -4
- package/dist/chunks/{rpc.BKExFSRG.js → rpc.Iovn4oWe.js} +9 -19
- package/dist/chunks/{runBaseTests.B_M1TTsK.js → runBaseTests.Dd85QTll.js} +18 -31
- package/dist/chunks/{setup-common.CF-O-dZX.js → setup-common.Dd054P77.js} +15 -42
- package/dist/chunks/{typechecker.BgzF-6iO.js → typechecker.DRKU1-1g.js} +106 -186
- package/dist/chunks/{utils.DPCq3gzW.js → utils.CAioKnHs.js} +6 -14
- package/dist/chunks/{utils.BlI4TC7Y.js → utils.XdZDrNZV.js} +5 -13
- package/dist/chunks/{vi.pkoYCV6A.js → vi.bdSIJ99Y.js} +118 -267
- package/dist/chunks/{vite.d.B-Kx3KCF.d.ts → vite.d.DqE4-hhK.d.ts} +1 -1
- package/dist/chunks/{vm.DPYem2so.js → vm.BThCzidc.js} +98 -214
- package/dist/chunks/{worker.d.Bl1O4kuf.d.ts → worker.d.DvqK5Vmu.d.ts} +1 -1
- package/dist/chunks/{worker.d.BKbBp2ga.d.ts → worker.d.tQu2eJQy.d.ts} +3 -1
- package/dist/cli.js +4 -4
- package/dist/config.cjs +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.js +2 -2
- package/dist/coverage.d.ts +2 -2
- package/dist/coverage.js +5 -5
- package/dist/environments.js +1 -1
- package/dist/execute.d.ts +1 -1
- package/dist/execute.js +1 -1
- package/dist/index.d.ts +11 -10
- package/dist/index.js +5 -5
- package/dist/node.d.ts +7 -7
- package/dist/node.js +12 -14
- package/dist/reporters.d.ts +2 -2
- package/dist/reporters.js +4 -4
- package/dist/runners.d.ts +5 -2
- package/dist/runners.js +51 -80
- package/dist/snapshot.js +2 -2
- package/dist/suite.js +2 -2
- package/dist/worker.js +36 -42
- package/dist/workers/forks.js +4 -4
- package/dist/workers/runVmTests.js +15 -21
- 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 +2 -2
- package/dist/workers.js +10 -10
- package/package.json +16 -14
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import fs, { statSync, realpathSync, promises as promises$1, mkdirSync, existsSync, readdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { isAbsolute, join as join$1, dirname as dirname$1, resolve as resolve$1, relative, normalize } from 'pathe';
|
|
3
3
|
import pm from 'picomatch';
|
|
4
4
|
import c from 'tinyrainbow';
|
|
5
|
-
import { c as configDefaults, e as benchmarkConfigDefaults, a as coverageConfigDefaults } from './defaults.
|
|
5
|
+
import { c as configDefaults, e as benchmarkConfigDefaults, a as coverageConfigDefaults } from './defaults.B7q_naMc.js';
|
|
6
6
|
import crypto from 'node:crypto';
|
|
7
|
-
import {
|
|
7
|
+
import { createDefer, shuffle, toArray } from '@vitest/utils';
|
|
8
8
|
import { builtinModules, createRequire } from 'node:module';
|
|
9
|
-
import path, { win32, dirname
|
|
9
|
+
import path, { win32, dirname, join, resolve } from 'node:path';
|
|
10
10
|
import process$1 from 'node:process';
|
|
11
11
|
import fs$1, { writeFile, rename, stat, unlink } from 'node:fs/promises';
|
|
12
12
|
import { fileURLToPath as fileURLToPath$1, pathToFileURL as pathToFileURL$1, URL as URL$1 } from 'node:url';
|
|
@@ -15,20 +15,20 @@ import v8 from 'node:v8';
|
|
|
15
15
|
import { format, inspect } from 'node:util';
|
|
16
16
|
import { version, mergeConfig } from 'vite';
|
|
17
17
|
import { e as extraInlineDeps, d as defaultBrowserPort, b as defaultInspectPort, a as defaultPort } from './constants.DnKduX2e.js';
|
|
18
|
-
import { a as isWindows } from './env.
|
|
18
|
+
import { a as isWindows } from './env.D4Lgay0q.js';
|
|
19
19
|
import * as nodeos from 'node:os';
|
|
20
20
|
import nodeos__default from 'node:os';
|
|
21
21
|
import { isatty } from 'node:tty';
|
|
22
22
|
import EventEmitter from 'node:events';
|
|
23
23
|
import { c as createBirpc } from './index.CJ0plNrh.js';
|
|
24
24
|
import Tinypool$1, { Tinypool } from 'tinypool';
|
|
25
|
-
import { w as wrapSerializableConfig, a as Typechecker } from './typechecker.
|
|
25
|
+
import { w as wrapSerializableConfig, a as Typechecker } from './typechecker.DRKU1-1g.js';
|
|
26
26
|
import { MessageChannel } from 'node:worker_threads';
|
|
27
27
|
import { hasFailed } from '@vitest/runner/utils';
|
|
28
28
|
import { rootDir } from '../path.js';
|
|
29
|
-
import { slash
|
|
29
|
+
import { slash } from 'vite-node/utils';
|
|
30
30
|
import { isCI, provider } from 'std-env';
|
|
31
|
-
import { r as resolveCoverageProviderModule } from './coverage.
|
|
31
|
+
import { r as resolveCoverageProviderModule } from './coverage.DVF1vEu8.js';
|
|
32
32
|
|
|
33
33
|
function groupBy(collection, iteratee) {
|
|
34
34
|
return collection.reduce((acc, item) => {
|
|
@@ -49,146 +49,14 @@ function escapeRegExp(s) {
|
|
|
49
49
|
}
|
|
50
50
|
function wildcardPatternToRegExp(pattern) {
|
|
51
51
|
const negated = pattern.startsWith("!");
|
|
52
|
-
if (negated)
|
|
53
|
-
pattern = pattern.slice(1);
|
|
54
|
-
}
|
|
52
|
+
if (negated) pattern = pattern.slice(1);
|
|
55
53
|
let regexp = `${pattern.split("*").map(escapeRegExp).join(".*")}$`;
|
|
56
|
-
if (negated) {
|
|
57
|
-
regexp = `(?!${regexp})`;
|
|
58
|
-
}
|
|
54
|
+
if (negated) regexp = `(?!${regexp})`;
|
|
59
55
|
return new RegExp(`^${regexp}`, "i");
|
|
60
56
|
}
|
|
61
57
|
|
|
62
58
|
const hash = crypto.hash ?? ((algorithm, data, outputEncoding) => crypto.createHash(algorithm).update(data).digest(outputEncoding));
|
|
63
59
|
|
|
64
|
-
class FilesStatsCache {
|
|
65
|
-
cache = new Map();
|
|
66
|
-
getStats(key) {
|
|
67
|
-
return this.cache.get(key);
|
|
68
|
-
}
|
|
69
|
-
async populateStats(root, specs) {
|
|
70
|
-
const promises = specs.map((spec) => {
|
|
71
|
-
const key = `${spec[0].name}:${relative(root, spec.moduleId)}`;
|
|
72
|
-
return this.updateStats(spec.moduleId, key);
|
|
73
|
-
});
|
|
74
|
-
await Promise.all(promises);
|
|
75
|
-
}
|
|
76
|
-
async updateStats(fsPath, key) {
|
|
77
|
-
if (!fs.existsSync(fsPath)) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const stats = await fs.promises.stat(fsPath);
|
|
81
|
-
this.cache.set(key, { size: stats.size });
|
|
82
|
-
}
|
|
83
|
-
removeStats(fsPath) {
|
|
84
|
-
this.cache.forEach((_, key) => {
|
|
85
|
-
if (key.endsWith(fsPath)) {
|
|
86
|
-
this.cache.delete(key);
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
class ResultsCache {
|
|
93
|
-
cache = new Map();
|
|
94
|
-
workspacesKeyMap = new Map();
|
|
95
|
-
cachePath = null;
|
|
96
|
-
version;
|
|
97
|
-
root = "/";
|
|
98
|
-
constructor(version) {
|
|
99
|
-
this.version = version;
|
|
100
|
-
}
|
|
101
|
-
getCachePath() {
|
|
102
|
-
return this.cachePath;
|
|
103
|
-
}
|
|
104
|
-
setConfig(root, config) {
|
|
105
|
-
this.root = root;
|
|
106
|
-
if (config) {
|
|
107
|
-
this.cachePath = resolve(config.dir, "results.json");
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
getResults(key) {
|
|
111
|
-
return this.cache.get(key);
|
|
112
|
-
}
|
|
113
|
-
async readFromCache() {
|
|
114
|
-
if (!this.cachePath) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (!fs.existsSync(this.cachePath)) {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
const resultsCache = await fs.promises.readFile(this.cachePath, "utf8");
|
|
121
|
-
const { results, version } = JSON.parse(resultsCache || "[]");
|
|
122
|
-
const [major, minor] = version.split(".");
|
|
123
|
-
// handling changed in 0.30.0
|
|
124
|
-
if (major > 0 || Number(minor) >= 30) {
|
|
125
|
-
this.cache = new Map(results);
|
|
126
|
-
this.version = version;
|
|
127
|
-
results.forEach(([spec]) => {
|
|
128
|
-
const [projectName, relativePath] = spec.split(":");
|
|
129
|
-
const keyMap = this.workspacesKeyMap.get(relativePath) || [];
|
|
130
|
-
keyMap.push(projectName);
|
|
131
|
-
this.workspacesKeyMap.set(relativePath, keyMap);
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
updateResults(files) {
|
|
136
|
-
files.forEach((file) => {
|
|
137
|
-
const result = file.result;
|
|
138
|
-
if (!result) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
const duration = result.duration || 0;
|
|
142
|
-
// store as relative, so cache would be the same in CI and locally
|
|
143
|
-
const relativePath = relative(this.root, file.filepath);
|
|
144
|
-
this.cache.set(`${file.projectName || ""}:${relativePath}`, {
|
|
145
|
-
duration: duration >= 0 ? duration : 0,
|
|
146
|
-
failed: result.state === "fail"
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
removeFromCache(filepath) {
|
|
151
|
-
this.cache.forEach((_, key) => {
|
|
152
|
-
if (key.endsWith(filepath)) {
|
|
153
|
-
this.cache.delete(key);
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
async writeToCache() {
|
|
158
|
-
if (!this.cachePath) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
const results = Array.from(this.cache.entries());
|
|
162
|
-
const cacheDirname = dirname(this.cachePath);
|
|
163
|
-
if (!fs.existsSync(cacheDirname)) {
|
|
164
|
-
await fs.promises.mkdir(cacheDirname, { recursive: true });
|
|
165
|
-
}
|
|
166
|
-
const cache = JSON.stringify({
|
|
167
|
-
version: this.version,
|
|
168
|
-
results
|
|
169
|
-
});
|
|
170
|
-
await fs.promises.writeFile(this.cachePath, cache);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
class VitestCache {
|
|
175
|
-
results;
|
|
176
|
-
stats = new FilesStatsCache();
|
|
177
|
-
constructor(version) {
|
|
178
|
-
this.results = new ResultsCache(version);
|
|
179
|
-
}
|
|
180
|
-
getFileTestResults(key) {
|
|
181
|
-
return this.results.getResults(key);
|
|
182
|
-
}
|
|
183
|
-
getFileStats(key) {
|
|
184
|
-
return this.stats.getStats(key);
|
|
185
|
-
}
|
|
186
|
-
static resolveCacheDir(root, dir, projectName) {
|
|
187
|
-
const baseDir = slash(dir || "node_modules/.vite/vitest");
|
|
188
|
-
return projectName ? resolve(root, baseDir, hash("md5", projectName, "hex")) : resolve(root, baseDir);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
60
|
const JOIN_LEADING_SLASH_RE = /^\.?\//;
|
|
193
61
|
function withTrailingSlash(input = "", respectQueryAndFragment) {
|
|
194
62
|
{
|
|
@@ -2459,7 +2327,7 @@ const getPackageInfo = quansync(function* (name, options = {}) {
|
|
|
2459
2327
|
return {
|
|
2460
2328
|
name,
|
|
2461
2329
|
version: packageJson.version,
|
|
2462
|
-
rootPath: dirname
|
|
2330
|
+
rootPath: dirname(packageJsonPath),
|
|
2463
2331
|
packageJsonPath,
|
|
2464
2332
|
packageJson
|
|
2465
2333
|
};
|
|
@@ -2483,7 +2351,7 @@ function searchPackageJSON(dir) {
|
|
|
2483
2351
|
while (true) {
|
|
2484
2352
|
if (!dir)
|
|
2485
2353
|
return;
|
|
2486
|
-
const newDir = dirname
|
|
2354
|
+
const newDir = dirname(dir);
|
|
2487
2355
|
if (newDir === dir)
|
|
2488
2356
|
return;
|
|
2489
2357
|
dir = newDir;
|
|
@@ -2523,13 +2391,9 @@ const envsOrder = [
|
|
|
2523
2391
|
"edge-runtime"
|
|
2524
2392
|
];
|
|
2525
2393
|
function getTransformMode(patterns, filename) {
|
|
2526
|
-
if (patterns.web && pm.isMatch(filename, patterns.web))
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
if (patterns.ssr && pm.isMatch(filename, patterns.ssr)) {
|
|
2530
|
-
return "ssr";
|
|
2531
|
-
}
|
|
2532
|
-
return undefined;
|
|
2394
|
+
if (patterns.web && pm.isMatch(filename, patterns.web)) return "web";
|
|
2395
|
+
if (patterns.ssr && pm.isMatch(filename, patterns.ssr)) return "ssr";
|
|
2396
|
+
return void 0;
|
|
2533
2397
|
}
|
|
2534
2398
|
async function groupFilesByEnv(files) {
|
|
2535
2399
|
const filesWithEnv = await Promise.all(files.map(async ({ moduleId: filepath, project, testLines }) => {
|
|
@@ -2538,21 +2402,18 @@ async function groupFilesByEnv(files) {
|
|
|
2538
2402
|
let env = code.match(/@(?:vitest|jest)-environment\s+([\w-]+)\b/)?.[1];
|
|
2539
2403
|
// 2. Check for globals
|
|
2540
2404
|
if (!env) {
|
|
2541
|
-
for (const [glob, target] of project.config.environmentMatchGlobs || []) {
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
break;
|
|
2545
|
-
}
|
|
2405
|
+
for (const [glob, target] of project.config.environmentMatchGlobs || []) if (pm.isMatch(filepath, glob, { cwd: project.config.root })) {
|
|
2406
|
+
env = target;
|
|
2407
|
+
break;
|
|
2546
2408
|
}
|
|
2547
2409
|
}
|
|
2548
2410
|
// 3. Fallback to global env
|
|
2549
2411
|
env ||= project.config.environment || "node";
|
|
2550
2412
|
const transformMode = getTransformMode(project.config.testTransformMode, filepath);
|
|
2551
2413
|
let envOptionsJson = code.match(/@(?:vitest|jest)-environment-options\s+(.+)/)?.[1];
|
|
2552
|
-
if (envOptionsJson?.endsWith("*/"))
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
}
|
|
2414
|
+
if (envOptionsJson?.endsWith("*/"))
|
|
2415
|
+
// Trim closing Docblock characters the above regex might have captured
|
|
2416
|
+
envOptionsJson = envOptionsJson.slice(0, -2);
|
|
2556
2417
|
const envOptions = JSON.parse(envOptionsJson || "null");
|
|
2557
2418
|
const envKey = env === "happy-dom" ? "happyDOM" : env;
|
|
2558
2419
|
const environment = {
|
|
@@ -2572,8 +2433,8 @@ async function groupFilesByEnv(files) {
|
|
|
2572
2433
|
return groupBy(filesWithEnv, ({ environment }) => environment.name);
|
|
2573
2434
|
}
|
|
2574
2435
|
|
|
2575
|
-
const created = new Set();
|
|
2576
|
-
const promises = new Map();
|
|
2436
|
+
const created = /* @__PURE__ */ new Set();
|
|
2437
|
+
const promises = /* @__PURE__ */ new Map();
|
|
2577
2438
|
function createMethodsRPC(project, options = {}) {
|
|
2578
2439
|
const ctx = project.vitest;
|
|
2579
2440
|
const cacheFs = options.cacheFs ?? false;
|
|
@@ -2587,9 +2448,7 @@ function createMethodsRPC(project, options = {}) {
|
|
|
2587
2448
|
async getSourceMap(id, force) {
|
|
2588
2449
|
if (force) {
|
|
2589
2450
|
const mod = project.vite.moduleGraph.getModuleById(id);
|
|
2590
|
-
if (mod)
|
|
2591
|
-
project.vite.moduleGraph.invalidateModule(mod);
|
|
2592
|
-
}
|
|
2451
|
+
if (mod) project.vite.moduleGraph.invalidateModule(mod);
|
|
2593
2452
|
}
|
|
2594
2453
|
const r = await project.vitenode.transformRequest(id);
|
|
2595
2454
|
return r?.map;
|
|
@@ -2597,15 +2456,9 @@ function createMethodsRPC(project, options = {}) {
|
|
|
2597
2456
|
async fetch(id, transformMode) {
|
|
2598
2457
|
const result = await project.vitenode.fetchResult(id, transformMode).catch(handleRollupError);
|
|
2599
2458
|
const code = result.code;
|
|
2600
|
-
if (!cacheFs || result.externalize)
|
|
2601
|
-
|
|
2602
|
-
}
|
|
2603
|
-
if ("id" in result && typeof result.id === "string") {
|
|
2604
|
-
return { id: result.id };
|
|
2605
|
-
}
|
|
2606
|
-
if (code == null) {
|
|
2607
|
-
throw new Error(`Failed to fetch module ${id}`);
|
|
2608
|
-
}
|
|
2459
|
+
if (!cacheFs || result.externalize) return result;
|
|
2460
|
+
if ("id" in result && typeof result.id === "string") return { id: result.id };
|
|
2461
|
+
if (code == null) throw new Error(`Failed to fetch module ${id}`);
|
|
2609
2462
|
const dir = join$1(project.tmpDir, transformMode);
|
|
2610
2463
|
const name = hash("sha1", id, "hex");
|
|
2611
2464
|
const tmp = join$1(dir, name);
|
|
@@ -2629,35 +2482,26 @@ function createMethodsRPC(project, options = {}) {
|
|
|
2629
2482
|
return project.vitenode.transformModule(id, environment).catch(handleRollupError);
|
|
2630
2483
|
},
|
|
2631
2484
|
async onQueued(file) {
|
|
2632
|
-
if (options.collect)
|
|
2633
|
-
|
|
2634
|
-
} else {
|
|
2635
|
-
await ctx._testRun.enqueued(project, file);
|
|
2636
|
-
}
|
|
2485
|
+
if (options.collect) ctx.state.collectFiles(project, [file]);
|
|
2486
|
+
else await ctx._testRun.enqueued(project, file);
|
|
2637
2487
|
},
|
|
2638
2488
|
async onCollected(files) {
|
|
2639
|
-
if (options.collect)
|
|
2640
|
-
|
|
2641
|
-
} else {
|
|
2642
|
-
await ctx._testRun.collected(project, files);
|
|
2643
|
-
}
|
|
2489
|
+
if (options.collect) ctx.state.collectFiles(project, files);
|
|
2490
|
+
else await ctx._testRun.collected(project, files);
|
|
2644
2491
|
},
|
|
2645
2492
|
onAfterSuiteRun(meta) {
|
|
2646
2493
|
ctx.coverageProvider?.onAfterSuiteRun(meta);
|
|
2647
2494
|
},
|
|
2495
|
+
async onTaskAnnotate(testId, annotation) {
|
|
2496
|
+
return ctx._testRun.annotate(testId, annotation);
|
|
2497
|
+
},
|
|
2648
2498
|
async onTaskUpdate(packs, events) {
|
|
2649
|
-
if (options.collect)
|
|
2650
|
-
|
|
2651
|
-
} else {
|
|
2652
|
-
await ctx._testRun.updated(packs, events);
|
|
2653
|
-
}
|
|
2499
|
+
if (options.collect) ctx.state.updateTasks(packs);
|
|
2500
|
+
else await ctx._testRun.updated(packs, events);
|
|
2654
2501
|
},
|
|
2655
2502
|
async onUserConsoleLog(log) {
|
|
2656
|
-
if (options.collect)
|
|
2657
|
-
|
|
2658
|
-
} else {
|
|
2659
|
-
await ctx._testRun.log(log);
|
|
2660
|
-
}
|
|
2503
|
+
if (options.collect) ctx.state.updateUserLog(log);
|
|
2504
|
+
else await ctx._testRun.log(log);
|
|
2661
2505
|
},
|
|
2662
2506
|
onUnhandledError(err, type) {
|
|
2663
2507
|
ctx.state.catchError(err, type);
|
|
@@ -2672,21 +2516,20 @@ function createMethodsRPC(project, options = {}) {
|
|
|
2672
2516
|
}
|
|
2673
2517
|
// serialize rollup error on server to preserve details as a test error
|
|
2674
2518
|
function handleRollupError(e) {
|
|
2675
|
-
if (e instanceof Error && ("plugin" in e || "frame" in e || "id" in e))
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
}
|
|
2519
|
+
if (e instanceof Error && ("plugin" in e || "frame" in e || "id" in e))
|
|
2520
|
+
// eslint-disable-next-line no-throw-literal
|
|
2521
|
+
throw {
|
|
2522
|
+
name: e.name,
|
|
2523
|
+
message: e.message,
|
|
2524
|
+
stack: e.stack,
|
|
2525
|
+
cause: e.cause,
|
|
2526
|
+
__vitest_rollup_error__: {
|
|
2527
|
+
plugin: e.plugin,
|
|
2528
|
+
id: e.id,
|
|
2529
|
+
loc: e.loc,
|
|
2530
|
+
frame: e.frame
|
|
2531
|
+
}
|
|
2532
|
+
};
|
|
2690
2533
|
throw e;
|
|
2691
2534
|
}
|
|
2692
2535
|
/**
|
|
@@ -2704,30 +2547,28 @@ function handleRollupError(e) {
|
|
|
2704
2547
|
* Added in https://github.com/vitest-dev/vitest/pull/7531
|
|
2705
2548
|
*/
|
|
2706
2549
|
async function atomicWriteFile(realFilePath, data) {
|
|
2707
|
-
const dir = dirname(realFilePath);
|
|
2550
|
+
const dir = dirname$1(realFilePath);
|
|
2708
2551
|
const tmpFilePath = join$1(dir, `.tmp-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
2709
2552
|
try {
|
|
2710
2553
|
await writeFile(tmpFilePath, data, "utf-8");
|
|
2711
2554
|
await rename(tmpFilePath, realFilePath);
|
|
2712
2555
|
} finally {
|
|
2713
2556
|
try {
|
|
2714
|
-
if (await stat(tmpFilePath))
|
|
2715
|
-
await unlink(tmpFilePath);
|
|
2716
|
-
}
|
|
2557
|
+
if (await stat(tmpFilePath)) await unlink(tmpFilePath);
|
|
2717
2558
|
} catch {}
|
|
2718
2559
|
}
|
|
2719
2560
|
}
|
|
2720
2561
|
|
|
2721
2562
|
function createChildProcessChannel$1(project, collect = false) {
|
|
2722
2563
|
const emitter = new EventEmitter();
|
|
2723
|
-
const cleanup = () => emitter.removeAllListeners();
|
|
2724
2564
|
const events = {
|
|
2725
2565
|
message: "message",
|
|
2726
2566
|
response: "response"
|
|
2727
2567
|
};
|
|
2728
2568
|
const channel = {
|
|
2729
2569
|
onMessage: (callback) => emitter.on(events.message, callback),
|
|
2730
|
-
postMessage: (message) => emitter.emit(events.response, message)
|
|
2570
|
+
postMessage: (message) => emitter.emit(events.response, message),
|
|
2571
|
+
onClose: () => emitter.removeAllListeners()
|
|
2731
2572
|
};
|
|
2732
2573
|
const rpc = createBirpc(createMethodsRPC(project, {
|
|
2733
2574
|
cacheFs: true,
|
|
@@ -2746,34 +2587,30 @@ function createChildProcessChannel$1(project, collect = false) {
|
|
|
2746
2587
|
throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`);
|
|
2747
2588
|
}
|
|
2748
2589
|
});
|
|
2749
|
-
project.
|
|
2750
|
-
return
|
|
2751
|
-
channel,
|
|
2752
|
-
cleanup
|
|
2753
|
-
};
|
|
2590
|
+
project.vitest.onCancel((reason) => rpc.onCancel(reason));
|
|
2591
|
+
return channel;
|
|
2754
2592
|
}
|
|
2755
|
-
function createForksPool(
|
|
2593
|
+
function createForksPool(vitest, { execArgv, env }) {
|
|
2756
2594
|
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length;
|
|
2757
|
-
const threadsCount =
|
|
2758
|
-
const poolOptions =
|
|
2759
|
-
const maxThreads = poolOptions.maxForks ??
|
|
2760
|
-
const minThreads = poolOptions.minForks ??
|
|
2761
|
-
const worker = resolve
|
|
2595
|
+
const threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
|
|
2596
|
+
const poolOptions = vitest.config.poolOptions?.forks ?? {};
|
|
2597
|
+
const maxThreads = poolOptions.maxForks ?? vitest.config.maxWorkers ?? threadsCount;
|
|
2598
|
+
const minThreads = poolOptions.minForks ?? vitest.config.minWorkers ?? threadsCount;
|
|
2599
|
+
const worker = resolve(vitest.distPath, "workers/forks.js");
|
|
2762
2600
|
const options = {
|
|
2763
2601
|
runtime: "child_process",
|
|
2764
|
-
filename: resolve
|
|
2602
|
+
filename: resolve(vitest.distPath, "worker.js"),
|
|
2603
|
+
teardown: "teardown",
|
|
2765
2604
|
maxThreads,
|
|
2766
2605
|
minThreads,
|
|
2767
2606
|
env,
|
|
2768
2607
|
execArgv: [...poolOptions.execArgv ?? [], ...execArgv],
|
|
2769
|
-
terminateTimeout:
|
|
2608
|
+
terminateTimeout: vitest.config.teardownTimeout,
|
|
2770
2609
|
concurrentTasksPerWorker: 1
|
|
2771
2610
|
};
|
|
2772
2611
|
const isolated = poolOptions.isolate ?? true;
|
|
2773
|
-
if (isolated)
|
|
2774
|
-
|
|
2775
|
-
}
|
|
2776
|
-
if (poolOptions.singleFork || !ctx.config.fileParallelism) {
|
|
2612
|
+
if (isolated) options.isolateWorkers = true;
|
|
2613
|
+
if (poolOptions.singleFork || !vitest.config.fileParallelism) {
|
|
2777
2614
|
options.maxThreads = 1;
|
|
2778
2615
|
options.minThreads = 1;
|
|
2779
2616
|
}
|
|
@@ -2782,8 +2619,8 @@ function createForksPool(ctx, { execArgv, env }) {
|
|
|
2782
2619
|
let id = 0;
|
|
2783
2620
|
async function runFiles(project, config, files, environment, invalidates = []) {
|
|
2784
2621
|
const paths = files.map((f) => f.filepath);
|
|
2785
|
-
|
|
2786
|
-
const
|
|
2622
|
+
vitest.state.clearFiles(project, paths);
|
|
2623
|
+
const channel = createChildProcessChannel$1(project, name === "collect");
|
|
2787
2624
|
const workerId = ++id;
|
|
2788
2625
|
const data = {
|
|
2789
2626
|
pool: "forks",
|
|
@@ -2803,25 +2640,17 @@ function createForksPool(ctx, { execArgv, env }) {
|
|
|
2803
2640
|
});
|
|
2804
2641
|
} catch (error) {
|
|
2805
2642
|
// Worker got stuck and won't terminate - this may cause process to hang
|
|
2806
|
-
if (error instanceof Error && /Failed to terminate worker/.test(error.message)) {
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
ctx.state.cancelFiles(paths, project);
|
|
2810
|
-
} else {
|
|
2811
|
-
throw error;
|
|
2812
|
-
}
|
|
2813
|
-
} finally {
|
|
2814
|
-
cleanup();
|
|
2643
|
+
if (error instanceof Error && /Failed to terminate worker/.test(error.message)) vitest.state.addProcessTimeoutCause(`Failed to terminate worker while running ${paths.join(", ")}.`);
|
|
2644
|
+
else if (vitest.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) vitest.state.cancelFiles(paths, project);
|
|
2645
|
+
else throw error;
|
|
2815
2646
|
}
|
|
2816
2647
|
}
|
|
2817
2648
|
return async (specs, invalidates) => {
|
|
2818
2649
|
// Cancel pending tasks from pool when possible
|
|
2819
|
-
|
|
2820
|
-
const configs = new WeakMap();
|
|
2650
|
+
vitest.onCancel(() => pool.cancelPendingTasks());
|
|
2651
|
+
const configs = /* @__PURE__ */ new WeakMap();
|
|
2821
2652
|
const getConfig = (project) => {
|
|
2822
|
-
if (configs.has(project))
|
|
2823
|
-
return configs.get(project);
|
|
2824
|
-
}
|
|
2653
|
+
if (configs.has(project)) return configs.get(project);
|
|
2825
2654
|
const _config = project.getSerializableConfig();
|
|
2826
2655
|
const config = wrapSerializableConfig(_config);
|
|
2827
2656
|
configs.set(project, config);
|
|
@@ -2833,9 +2662,8 @@ function createForksPool(ctx, { execArgv, env }) {
|
|
|
2833
2662
|
const filesByEnv = await groupFilesByEnv(multipleForks);
|
|
2834
2663
|
const files = Object.values(filesByEnv).flat();
|
|
2835
2664
|
const results = [];
|
|
2836
|
-
if (isolated) {
|
|
2837
|
-
|
|
2838
|
-
} else {
|
|
2665
|
+
if (isolated) results.push(...await Promise.allSettled(files.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))));
|
|
2666
|
+
else {
|
|
2839
2667
|
// When isolation is disabled, we still need to isolate environments and workspace projects from each other.
|
|
2840
2668
|
// Tasks are still running parallel but environments are isolated between tasks.
|
|
2841
2669
|
const grouped = groupBy(files, ({ project, environment }) => project.name + environment.name + JSON.stringify(environment.options));
|
|
@@ -2849,18 +2677,14 @@ function createForksPool(ctx, { execArgv, env }) {
|
|
|
2849
2677
|
}
|
|
2850
2678
|
}
|
|
2851
2679
|
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2852
|
-
if (errors.length > 0)
|
|
2853
|
-
throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
2854
|
-
}
|
|
2680
|
+
if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
2855
2681
|
}
|
|
2856
2682
|
if (singleFork.length) {
|
|
2857
2683
|
const filesByEnv = await groupFilesByEnv(singleFork);
|
|
2858
2684
|
const envs = envsOrder.concat(Object.keys(filesByEnv).filter((env) => !envsOrder.includes(env)));
|
|
2859
2685
|
for (const env of envs) {
|
|
2860
2686
|
const files = filesByEnv[env];
|
|
2861
|
-
if (!files?.length)
|
|
2862
|
-
continue;
|
|
2863
|
-
}
|
|
2687
|
+
if (!files?.length) continue;
|
|
2864
2688
|
const filesByOptions = groupBy(files, ({ project, environment }) => project.name + JSON.stringify(environment.options));
|
|
2865
2689
|
for (const files of Object.values(filesByOptions)) {
|
|
2866
2690
|
// Always run environments isolated between each other
|
|
@@ -2896,34 +2720,33 @@ function createWorkerChannel$1(project, collect) {
|
|
|
2896
2720
|
throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`);
|
|
2897
2721
|
}
|
|
2898
2722
|
});
|
|
2899
|
-
project.
|
|
2723
|
+
project.vitest.onCancel((reason) => rpc.onCancel(reason));
|
|
2900
2724
|
return {
|
|
2901
2725
|
workerPort,
|
|
2902
2726
|
port
|
|
2903
2727
|
};
|
|
2904
2728
|
}
|
|
2905
|
-
function createThreadsPool(
|
|
2729
|
+
function createThreadsPool(vitest, { execArgv, env }) {
|
|
2906
2730
|
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length;
|
|
2907
|
-
const threadsCount =
|
|
2908
|
-
const poolOptions =
|
|
2909
|
-
const maxThreads = poolOptions.maxThreads ??
|
|
2910
|
-
const minThreads = poolOptions.minThreads ??
|
|
2911
|
-
const worker = resolve
|
|
2731
|
+
const threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
|
|
2732
|
+
const poolOptions = vitest.config.poolOptions?.threads ?? {};
|
|
2733
|
+
const maxThreads = poolOptions.maxThreads ?? vitest.config.maxWorkers ?? threadsCount;
|
|
2734
|
+
const minThreads = poolOptions.minThreads ?? vitest.config.minWorkers ?? threadsCount;
|
|
2735
|
+
const worker = resolve(vitest.distPath, "workers/threads.js");
|
|
2912
2736
|
const options = {
|
|
2913
|
-
filename: resolve
|
|
2737
|
+
filename: resolve(vitest.distPath, "worker.js"),
|
|
2738
|
+
teardown: "teardown",
|
|
2914
2739
|
useAtomics: poolOptions.useAtomics ?? false,
|
|
2915
2740
|
maxThreads,
|
|
2916
2741
|
minThreads,
|
|
2917
2742
|
env,
|
|
2918
2743
|
execArgv: [...poolOptions.execArgv ?? [], ...execArgv],
|
|
2919
|
-
terminateTimeout:
|
|
2744
|
+
terminateTimeout: vitest.config.teardownTimeout,
|
|
2920
2745
|
concurrentTasksPerWorker: 1
|
|
2921
2746
|
};
|
|
2922
2747
|
const isolated = poolOptions.isolate ?? true;
|
|
2923
|
-
if (isolated)
|
|
2924
|
-
|
|
2925
|
-
}
|
|
2926
|
-
if (poolOptions.singleThread || !ctx.config.fileParallelism) {
|
|
2748
|
+
if (isolated) options.isolateWorkers = true;
|
|
2749
|
+
if (poolOptions.singleThread || !vitest.config.fileParallelism) {
|
|
2927
2750
|
options.maxThreads = 1;
|
|
2928
2751
|
options.minThreads = 1;
|
|
2929
2752
|
}
|
|
@@ -2932,8 +2755,12 @@ function createThreadsPool(ctx, { execArgv, env }) {
|
|
|
2932
2755
|
let id = 0;
|
|
2933
2756
|
async function runFiles(project, config, files, environment, invalidates = []) {
|
|
2934
2757
|
const paths = files.map((f) => f.filepath);
|
|
2935
|
-
|
|
2758
|
+
vitest.state.clearFiles(project, paths);
|
|
2936
2759
|
const { workerPort, port } = createWorkerChannel$1(project, name === "collect");
|
|
2760
|
+
const onClose = () => {
|
|
2761
|
+
port.close();
|
|
2762
|
+
workerPort.close();
|
|
2763
|
+
};
|
|
2937
2764
|
const workerId = ++id;
|
|
2938
2765
|
const data = {
|
|
2939
2766
|
pool: "threads",
|
|
@@ -2950,31 +2777,23 @@ function createThreadsPool(ctx, { execArgv, env }) {
|
|
|
2950
2777
|
try {
|
|
2951
2778
|
await pool.run(data, {
|
|
2952
2779
|
transferList: [workerPort],
|
|
2953
|
-
name
|
|
2780
|
+
name,
|
|
2781
|
+
channel: { onClose }
|
|
2954
2782
|
});
|
|
2955
2783
|
} catch (error) {
|
|
2956
2784
|
// Worker got stuck and won't terminate - this may cause process to hang
|
|
2957
|
-
if (error instanceof Error && /Failed to terminate worker/.test(error.message)) {
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
ctx.state.cancelFiles(paths, project);
|
|
2961
|
-
} else {
|
|
2962
|
-
throw error;
|
|
2963
|
-
}
|
|
2964
|
-
} finally {
|
|
2965
|
-
port.close();
|
|
2966
|
-
workerPort.close();
|
|
2785
|
+
if (error instanceof Error && /Failed to terminate worker/.test(error.message)) vitest.state.addProcessTimeoutCause(`Failed to terminate worker while running ${paths.join(", ")}. \nSee https://vitest.dev/guide/common-errors.html#failed-to-terminate-worker for troubleshooting.`);
|
|
2786
|
+
else if (vitest.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) vitest.state.cancelFiles(paths, project);
|
|
2787
|
+
else throw error;
|
|
2967
2788
|
}
|
|
2968
2789
|
}
|
|
2969
2790
|
return async (specs, invalidates) => {
|
|
2970
2791
|
// Cancel pending tasks from pool when possible
|
|
2971
|
-
|
|
2972
|
-
const configs = new WeakMap();
|
|
2792
|
+
vitest.onCancel(() => pool.cancelPendingTasks());
|
|
2793
|
+
const configs = /* @__PURE__ */ new WeakMap();
|
|
2973
2794
|
const getConfig = (project) => {
|
|
2974
|
-
if (configs.has(project))
|
|
2975
|
-
|
|
2976
|
-
}
|
|
2977
|
-
const config = project.getSerializableConfig();
|
|
2795
|
+
if (configs.has(project)) return configs.get(project);
|
|
2796
|
+
const config = project.serializedConfig;
|
|
2978
2797
|
configs.set(project, config);
|
|
2979
2798
|
return config;
|
|
2980
2799
|
};
|
|
@@ -2984,9 +2803,8 @@ function createThreadsPool(ctx, { execArgv, env }) {
|
|
|
2984
2803
|
const filesByEnv = await groupFilesByEnv(multipleThreads);
|
|
2985
2804
|
const files = Object.values(filesByEnv).flat();
|
|
2986
2805
|
const results = [];
|
|
2987
|
-
if (isolated) {
|
|
2988
|
-
|
|
2989
|
-
} else {
|
|
2806
|
+
if (isolated) results.push(...await Promise.allSettled(files.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))));
|
|
2807
|
+
else {
|
|
2990
2808
|
// When isolation is disabled, we still need to isolate environments and workspace projects from each other.
|
|
2991
2809
|
// Tasks are still running parallel but environments are isolated between tasks.
|
|
2992
2810
|
const grouped = groupBy(files, ({ project, environment }) => project.name + environment.name + JSON.stringify(environment.options));
|
|
@@ -3000,18 +2818,14 @@ function createThreadsPool(ctx, { execArgv, env }) {
|
|
|
3000
2818
|
}
|
|
3001
2819
|
}
|
|
3002
2820
|
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3003
|
-
if (errors.length > 0)
|
|
3004
|
-
throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
3005
|
-
}
|
|
2821
|
+
if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
3006
2822
|
}
|
|
3007
2823
|
if (singleThreads.length) {
|
|
3008
2824
|
const filesByEnv = await groupFilesByEnv(singleThreads);
|
|
3009
2825
|
const envs = envsOrder.concat(Object.keys(filesByEnv).filter((env) => !envsOrder.includes(env)));
|
|
3010
2826
|
for (const env of envs) {
|
|
3011
2827
|
const files = filesByEnv[env];
|
|
3012
|
-
if (!files?.length)
|
|
3013
|
-
continue;
|
|
3014
|
-
}
|
|
2828
|
+
if (!files?.length) continue;
|
|
3015
2829
|
const filesByOptions = groupBy(files, ({ project, environment }) => project.name + JSON.stringify(environment.options));
|
|
3016
2830
|
for (const files of Object.values(filesByOptions)) {
|
|
3017
2831
|
// Always run environments isolated between each other
|
|
@@ -3032,15 +2846,13 @@ function createThreadsPool(ctx, { execArgv, env }) {
|
|
|
3032
2846
|
}
|
|
3033
2847
|
|
|
3034
2848
|
function createTypecheckPool(vitest) {
|
|
3035
|
-
const promisesMap = new WeakMap();
|
|
3036
|
-
const rerunTriggered = new WeakSet();
|
|
2849
|
+
const promisesMap = /* @__PURE__ */ new WeakMap();
|
|
2850
|
+
const rerunTriggered = /* @__PURE__ */ new WeakSet();
|
|
3037
2851
|
async function onParseEnd(project, { files, sourceErrors }) {
|
|
3038
2852
|
const checker = project.typechecker;
|
|
3039
2853
|
const { packs, events } = checker.getTestPacksAndEvents();
|
|
3040
2854
|
await vitest._testRun.updated(packs, events);
|
|
3041
|
-
if (!project.config.typecheck.ignoreSourceErrors)
|
|
3042
|
-
sourceErrors.forEach((error) => vitest.state.catchError(error, "Unhandled Source Error"));
|
|
3043
|
-
}
|
|
2855
|
+
if (!project.config.typecheck.ignoreSourceErrors) sourceErrors.forEach((error) => vitest.state.catchError(error, "Unhandled Source Error"));
|
|
3044
2856
|
const processError = !hasFailed(files) && !sourceErrors.length && checker.getExitCode();
|
|
3045
2857
|
if (processError) {
|
|
3046
2858
|
const error = new Error(checker.getOutput());
|
|
@@ -3057,16 +2869,12 @@ function createTypecheckPool(vitest) {
|
|
|
3057
2869
|
}
|
|
3058
2870
|
async function createWorkspaceTypechecker(project, files) {
|
|
3059
2871
|
const checker = project.typechecker ?? new Typechecker(project);
|
|
3060
|
-
if (project.typechecker)
|
|
3061
|
-
return checker;
|
|
3062
|
-
}
|
|
2872
|
+
if (project.typechecker) return checker;
|
|
3063
2873
|
project.typechecker = checker;
|
|
3064
2874
|
checker.setFiles(files);
|
|
3065
2875
|
checker.onParseStart(async () => {
|
|
3066
2876
|
const files = checker.getTestFiles();
|
|
3067
|
-
for (const file of files)
|
|
3068
|
-
await vitest._testRun.enqueued(project, file);
|
|
3069
|
-
}
|
|
2877
|
+
for (const file of files) await vitest._testRun.enqueued(project, file);
|
|
3070
2878
|
await vitest._testRun.collected(project, files);
|
|
3071
2879
|
});
|
|
3072
2880
|
checker.onParseEnd((result) => onParseEnd(project, result));
|
|
@@ -3078,9 +2886,7 @@ function createTypecheckPool(vitest) {
|
|
|
3078
2886
|
}
|
|
3079
2887
|
await checker.collectTests();
|
|
3080
2888
|
const testFiles = checker.getTestFiles();
|
|
3081
|
-
for (const file of testFiles)
|
|
3082
|
-
await vitest._testRun.enqueued(project, file);
|
|
3083
|
-
}
|
|
2889
|
+
for (const file of testFiles) await vitest._testRun.enqueued(project, file);
|
|
3084
2890
|
await vitest._testRun.collected(project, testFiles);
|
|
3085
2891
|
const { packs, events } = checker.getTestPacksAndEvents();
|
|
3086
2892
|
await vitest._testRun.updated(packs, events);
|
|
@@ -3088,9 +2894,7 @@ function createTypecheckPool(vitest) {
|
|
|
3088
2894
|
return checker;
|
|
3089
2895
|
}
|
|
3090
2896
|
async function startTypechecker(project, files) {
|
|
3091
|
-
if (project.typechecker)
|
|
3092
|
-
return;
|
|
3093
|
-
}
|
|
2897
|
+
if (project.typechecker) return;
|
|
3094
2898
|
const checker = await createWorkspaceTypechecker(project, files);
|
|
3095
2899
|
await checker.collectTests();
|
|
3096
2900
|
await checker.start();
|
|
@@ -3130,9 +2934,7 @@ function createTypecheckPool(vitest) {
|
|
|
3130
2934
|
const triggered = await _p;
|
|
3131
2935
|
if (project.typechecker && !triggered) {
|
|
3132
2936
|
const testFiles = project.typechecker.getTestFiles();
|
|
3133
|
-
for (const file of testFiles)
|
|
3134
|
-
await vitest._testRun.enqueued(project, file);
|
|
3135
|
-
}
|
|
2937
|
+
for (const file of testFiles) await vitest._testRun.enqueued(project, file);
|
|
3136
2938
|
await vitest._testRun.collected(project, testFiles);
|
|
3137
2939
|
await onParseEnd(project, project.typechecker.getResult());
|
|
3138
2940
|
continue;
|
|
@@ -3161,16 +2963,12 @@ function getDefaultThreadsCount(config) {
|
|
|
3161
2963
|
function getWorkerMemoryLimit(config, pool) {
|
|
3162
2964
|
if (pool === "vmForks") {
|
|
3163
2965
|
const opts = config.poolOptions?.vmForks ?? {};
|
|
3164
|
-
if (opts.memoryLimit)
|
|
3165
|
-
return opts.memoryLimit;
|
|
3166
|
-
}
|
|
2966
|
+
if (opts.memoryLimit) return opts.memoryLimit;
|
|
3167
2967
|
const workers = opts.maxForks ?? getDefaultThreadsCount(config);
|
|
3168
2968
|
return 1 / workers;
|
|
3169
2969
|
} else {
|
|
3170
2970
|
const opts = config.poolOptions?.vmThreads ?? {};
|
|
3171
|
-
if (opts.memoryLimit)
|
|
3172
|
-
return opts.memoryLimit;
|
|
3173
|
-
}
|
|
2971
|
+
if (opts.memoryLimit) return opts.memoryLimit;
|
|
3174
2972
|
const workers = opts.maxThreads ?? getDefaultThreadsCount(config);
|
|
3175
2973
|
return 1 / workers;
|
|
3176
2974
|
}
|
|
@@ -3182,51 +2980,36 @@ function getWorkerMemoryLimit(config, pool) {
|
|
|
3182
2980
|
* @param percentageReference The reference value to use when a '%' value is supplied.
|
|
3183
2981
|
*/
|
|
3184
2982
|
function stringToBytes(input, percentageReference) {
|
|
3185
|
-
if (input === null || input ===
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
case "gb":
|
|
3205
|
-
case "g": return numericValue * 1e3 * 1e3 * 1e3;
|
|
3206
|
-
case "gib": return numericValue * 1024 * 1024 * 1024;
|
|
3207
|
-
}
|
|
3208
|
-
}
|
|
3209
|
-
} else {
|
|
3210
|
-
input = Number.parseFloat(input);
|
|
3211
|
-
}
|
|
3212
|
-
}
|
|
3213
|
-
if (typeof input === "number") {
|
|
3214
|
-
if (input <= 1 && input > 0) {
|
|
3215
|
-
if (percentageReference) {
|
|
3216
|
-
return Math.floor(input * percentageReference);
|
|
3217
|
-
} else {
|
|
3218
|
-
throw new Error("For a percentage based memory limit a percentageReference must be supplied");
|
|
2983
|
+
if (input === null || input === void 0) return input;
|
|
2984
|
+
if (typeof input === "string") if (Number.isNaN(Number.parseFloat(input.slice(-1)))) {
|
|
2985
|
+
let [, numericString, trailingChars] = input.match(/(.*?)([^0-9.-]+)$/) || [];
|
|
2986
|
+
if (trailingChars && numericString) {
|
|
2987
|
+
const numericValue = Number.parseFloat(numericString);
|
|
2988
|
+
trailingChars = trailingChars.toLowerCase();
|
|
2989
|
+
switch (trailingChars) {
|
|
2990
|
+
case "%":
|
|
2991
|
+
input = numericValue / 100;
|
|
2992
|
+
break;
|
|
2993
|
+
case "kb":
|
|
2994
|
+
case "k": return numericValue * 1e3;
|
|
2995
|
+
case "kib": return numericValue * 1024;
|
|
2996
|
+
case "mb":
|
|
2997
|
+
case "m": return numericValue * 1e3 * 1e3;
|
|
2998
|
+
case "mib": return numericValue * 1024 * 1024;
|
|
2999
|
+
case "gb":
|
|
3000
|
+
case "g": return numericValue * 1e3 * 1e3 * 1e3;
|
|
3001
|
+
case "gib": return numericValue * 1024 * 1024 * 1024;
|
|
3219
3002
|
}
|
|
3220
|
-
} else if (input > 1) {
|
|
3221
|
-
return Math.floor(input);
|
|
3222
|
-
} else {
|
|
3223
|
-
throw new Error("Unexpected numerical input for \"memoryLimit\"");
|
|
3224
3003
|
}
|
|
3225
|
-
}
|
|
3004
|
+
} else input = Number.parseFloat(input);
|
|
3005
|
+
if (typeof input === "number") if (input <= 1 && input > 0) if (percentageReference) return Math.floor(input * percentageReference);
|
|
3006
|
+
else throw new Error("For a percentage based memory limit a percentageReference must be supplied");
|
|
3007
|
+
else if (input > 1) return Math.floor(input);
|
|
3008
|
+
else throw new Error("Unexpected numerical input for \"memoryLimit\"");
|
|
3226
3009
|
return null;
|
|
3227
3010
|
}
|
|
3228
3011
|
|
|
3229
|
-
const suppressWarningsPath$1 = resolve
|
|
3012
|
+
const suppressWarningsPath$1 = resolve(rootDir, "./suppress-warnings.cjs");
|
|
3230
3013
|
function createChildProcessChannel(project, collect) {
|
|
3231
3014
|
const emitter = new EventEmitter();
|
|
3232
3015
|
const cleanup = () => emitter.removeAllListeners();
|
|
@@ -3255,22 +3038,22 @@ function createChildProcessChannel(project, collect) {
|
|
|
3255
3038
|
throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`);
|
|
3256
3039
|
}
|
|
3257
3040
|
});
|
|
3258
|
-
project.
|
|
3041
|
+
project.vitest.onCancel((reason) => rpc.onCancel(reason));
|
|
3259
3042
|
return {
|
|
3260
3043
|
channel,
|
|
3261
3044
|
cleanup
|
|
3262
3045
|
};
|
|
3263
3046
|
}
|
|
3264
|
-
function createVmForksPool(
|
|
3047
|
+
function createVmForksPool(vitest, { execArgv, env }) {
|
|
3265
3048
|
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length;
|
|
3266
|
-
const threadsCount =
|
|
3267
|
-
const poolOptions =
|
|
3268
|
-
const maxThreads = poolOptions.maxForks ??
|
|
3269
|
-
const minThreads = poolOptions.maxForks ??
|
|
3270
|
-
const worker = resolve
|
|
3049
|
+
const threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
|
|
3050
|
+
const poolOptions = vitest.config.poolOptions?.vmForks ?? {};
|
|
3051
|
+
const maxThreads = poolOptions.maxForks ?? vitest.config.maxWorkers ?? threadsCount;
|
|
3052
|
+
const minThreads = poolOptions.maxForks ?? vitest.config.minWorkers ?? threadsCount;
|
|
3053
|
+
const worker = resolve(vitest.distPath, "workers/vmForks.js");
|
|
3271
3054
|
const options = {
|
|
3272
3055
|
runtime: "child_process",
|
|
3273
|
-
filename: resolve
|
|
3056
|
+
filename: resolve(vitest.distPath, "worker.js"),
|
|
3274
3057
|
maxThreads,
|
|
3275
3058
|
minThreads,
|
|
3276
3059
|
env,
|
|
@@ -3282,11 +3065,11 @@ function createVmForksPool(ctx, { execArgv, env }) {
|
|
|
3282
3065
|
...poolOptions.execArgv ?? [],
|
|
3283
3066
|
...execArgv
|
|
3284
3067
|
],
|
|
3285
|
-
terminateTimeout:
|
|
3068
|
+
terminateTimeout: vitest.config.teardownTimeout,
|
|
3286
3069
|
concurrentTasksPerWorker: 1,
|
|
3287
|
-
maxMemoryLimitBeforeRecycle: getMemoryLimit$1(
|
|
3070
|
+
maxMemoryLimitBeforeRecycle: getMemoryLimit$1(vitest.config) || void 0
|
|
3288
3071
|
};
|
|
3289
|
-
if (poolOptions.singleFork || !
|
|
3072
|
+
if (poolOptions.singleFork || !vitest.config.fileParallelism) {
|
|
3290
3073
|
options.maxThreads = 1;
|
|
3291
3074
|
options.minThreads = 1;
|
|
3292
3075
|
}
|
|
@@ -3295,7 +3078,7 @@ function createVmForksPool(ctx, { execArgv, env }) {
|
|
|
3295
3078
|
let id = 0;
|
|
3296
3079
|
async function runFiles(project, config, files, environment, invalidates = []) {
|
|
3297
3080
|
const paths = files.map((f) => f.filepath);
|
|
3298
|
-
|
|
3081
|
+
vitest.state.clearFiles(project, paths);
|
|
3299
3082
|
const { channel, cleanup } = createChildProcessChannel(project, name === "collect");
|
|
3300
3083
|
const workerId = ++id;
|
|
3301
3084
|
const data = {
|
|
@@ -3316,26 +3099,20 @@ function createVmForksPool(ctx, { execArgv, env }) {
|
|
|
3316
3099
|
});
|
|
3317
3100
|
} catch (error) {
|
|
3318
3101
|
// Worker got stuck and won't terminate - this may cause process to hang
|
|
3319
|
-
if (error instanceof Error && /Failed to terminate worker/.test(error.message)) {
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
ctx.state.cancelFiles(paths, project);
|
|
3323
|
-
} else {
|
|
3324
|
-
throw error;
|
|
3325
|
-
}
|
|
3102
|
+
if (error instanceof Error && /Failed to terminate worker/.test(error.message)) vitest.state.addProcessTimeoutCause(`Failed to terminate worker while running ${paths.join(", ")}.`);
|
|
3103
|
+
else if (vitest.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) vitest.state.cancelFiles(paths, project);
|
|
3104
|
+
else throw error;
|
|
3326
3105
|
} finally {
|
|
3327
3106
|
cleanup();
|
|
3328
3107
|
}
|
|
3329
3108
|
}
|
|
3330
3109
|
return async (specs, invalidates) => {
|
|
3331
3110
|
// Cancel pending tasks from pool when possible
|
|
3332
|
-
|
|
3333
|
-
const configs = new Map();
|
|
3111
|
+
vitest.onCancel(() => pool.cancelPendingTasks());
|
|
3112
|
+
const configs = /* @__PURE__ */ new Map();
|
|
3334
3113
|
const getConfig = (project) => {
|
|
3335
|
-
if (configs.has(project))
|
|
3336
|
-
|
|
3337
|
-
}
|
|
3338
|
-
const _config = project.getSerializableConfig();
|
|
3114
|
+
if (configs.has(project)) return configs.get(project);
|
|
3115
|
+
const _config = project.serializedConfig;
|
|
3339
3116
|
const config = wrapSerializableConfig(_config);
|
|
3340
3117
|
configs.set(project, config);
|
|
3341
3118
|
return config;
|
|
@@ -3344,9 +3121,7 @@ function createVmForksPool(ctx, { execArgv, env }) {
|
|
|
3344
3121
|
const promises = Object.values(filesByEnv).flat();
|
|
3345
3122
|
const results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)));
|
|
3346
3123
|
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3347
|
-
if (errors.length > 0)
|
|
3348
|
-
throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
3349
|
-
}
|
|
3124
|
+
if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
3350
3125
|
};
|
|
3351
3126
|
};
|
|
3352
3127
|
return {
|
|
@@ -3359,18 +3134,14 @@ function createVmForksPool(ctx, { execArgv, env }) {
|
|
|
3359
3134
|
function getMemoryLimit$1(config) {
|
|
3360
3135
|
const memory = nodeos.totalmem();
|
|
3361
3136
|
const limit = getWorkerMemoryLimit(config, "vmForks");
|
|
3362
|
-
if (typeof memory === "number")
|
|
3363
|
-
return stringToBytes(limit, config.watch ? memory / 2 : memory);
|
|
3364
|
-
}
|
|
3137
|
+
if (typeof memory === "number") return stringToBytes(limit, config.watch ? memory / 2 : memory);
|
|
3365
3138
|
// If totalmem is not supported we cannot resolve percentage based values like 0.5, "50%"
|
|
3366
|
-
if (typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%")
|
|
3367
|
-
return stringToBytes(limit);
|
|
3368
|
-
}
|
|
3139
|
+
if (typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%") return stringToBytes(limit);
|
|
3369
3140
|
// just ignore "memoryLimit" value because we cannot detect memory limit
|
|
3370
3141
|
return null;
|
|
3371
3142
|
}
|
|
3372
3143
|
|
|
3373
|
-
const suppressWarningsPath = resolve
|
|
3144
|
+
const suppressWarningsPath = resolve(rootDir, "./suppress-warnings.cjs");
|
|
3374
3145
|
function createWorkerChannel(project, collect) {
|
|
3375
3146
|
const channel = new MessageChannel();
|
|
3376
3147
|
const port = channel.port2;
|
|
@@ -3387,21 +3158,21 @@ function createWorkerChannel(project, collect) {
|
|
|
3387
3158
|
throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`);
|
|
3388
3159
|
}
|
|
3389
3160
|
});
|
|
3390
|
-
project.
|
|
3161
|
+
project.vitest.onCancel((reason) => rpc.onCancel(reason));
|
|
3391
3162
|
return {
|
|
3392
3163
|
workerPort,
|
|
3393
3164
|
port
|
|
3394
3165
|
};
|
|
3395
3166
|
}
|
|
3396
|
-
function createVmThreadsPool(
|
|
3167
|
+
function createVmThreadsPool(vitest, { execArgv, env }) {
|
|
3397
3168
|
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length;
|
|
3398
|
-
const threadsCount =
|
|
3399
|
-
const poolOptions =
|
|
3400
|
-
const maxThreads = poolOptions.maxThreads ??
|
|
3401
|
-
const minThreads = poolOptions.minThreads ??
|
|
3402
|
-
const worker = resolve
|
|
3169
|
+
const threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
|
|
3170
|
+
const poolOptions = vitest.config.poolOptions?.vmThreads ?? {};
|
|
3171
|
+
const maxThreads = poolOptions.maxThreads ?? vitest.config.maxWorkers ?? threadsCount;
|
|
3172
|
+
const minThreads = poolOptions.minThreads ?? vitest.config.minWorkers ?? threadsCount;
|
|
3173
|
+
const worker = resolve(vitest.distPath, "workers/vmThreads.js");
|
|
3403
3174
|
const options = {
|
|
3404
|
-
filename: resolve
|
|
3175
|
+
filename: resolve(vitest.distPath, "worker.js"),
|
|
3405
3176
|
useAtomics: poolOptions.useAtomics ?? false,
|
|
3406
3177
|
maxThreads,
|
|
3407
3178
|
minThreads,
|
|
@@ -3414,11 +3185,11 @@ function createVmThreadsPool(ctx, { execArgv, env }) {
|
|
|
3414
3185
|
...poolOptions.execArgv ?? [],
|
|
3415
3186
|
...execArgv
|
|
3416
3187
|
],
|
|
3417
|
-
terminateTimeout:
|
|
3188
|
+
terminateTimeout: vitest.config.teardownTimeout,
|
|
3418
3189
|
concurrentTasksPerWorker: 1,
|
|
3419
|
-
maxMemoryLimitBeforeRecycle: getMemoryLimit(
|
|
3190
|
+
maxMemoryLimitBeforeRecycle: getMemoryLimit(vitest.config) || void 0
|
|
3420
3191
|
};
|
|
3421
|
-
if (poolOptions.singleThread || !
|
|
3192
|
+
if (poolOptions.singleThread || !vitest.config.fileParallelism) {
|
|
3422
3193
|
options.maxThreads = 1;
|
|
3423
3194
|
options.minThreads = 1;
|
|
3424
3195
|
}
|
|
@@ -3427,7 +3198,7 @@ function createVmThreadsPool(ctx, { execArgv, env }) {
|
|
|
3427
3198
|
let id = 0;
|
|
3428
3199
|
async function runFiles(project, config, files, environment, invalidates = []) {
|
|
3429
3200
|
const paths = files.map((f) => f.filepath);
|
|
3430
|
-
|
|
3201
|
+
vitest.state.clearFiles(project, paths);
|
|
3431
3202
|
const { workerPort, port } = createWorkerChannel(project, name === "collect");
|
|
3432
3203
|
const workerId = ++id;
|
|
3433
3204
|
const data = {
|
|
@@ -3449,13 +3220,9 @@ function createVmThreadsPool(ctx, { execArgv, env }) {
|
|
|
3449
3220
|
});
|
|
3450
3221
|
} catch (error) {
|
|
3451
3222
|
// Worker got stuck and won't terminate - this may cause process to hang
|
|
3452
|
-
if (error instanceof Error && /Failed to terminate worker/.test(error.message)) {
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
ctx.state.cancelFiles(paths, project);
|
|
3456
|
-
} else {
|
|
3457
|
-
throw error;
|
|
3458
|
-
}
|
|
3223
|
+
if (error instanceof Error && /Failed to terminate worker/.test(error.message)) vitest.state.addProcessTimeoutCause(`Failed to terminate worker while running ${paths.join(", ")}. \nSee https://vitest.dev/guide/common-errors.html#failed-to-terminate-worker for troubleshooting.`);
|
|
3224
|
+
else if (vitest.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) vitest.state.cancelFiles(paths, project);
|
|
3225
|
+
else throw error;
|
|
3459
3226
|
} finally {
|
|
3460
3227
|
port.close();
|
|
3461
3228
|
workerPort.close();
|
|
@@ -3463,12 +3230,10 @@ function createVmThreadsPool(ctx, { execArgv, env }) {
|
|
|
3463
3230
|
}
|
|
3464
3231
|
return async (specs, invalidates) => {
|
|
3465
3232
|
// Cancel pending tasks from pool when possible
|
|
3466
|
-
|
|
3467
|
-
const configs = new Map();
|
|
3233
|
+
vitest.onCancel(() => pool.cancelPendingTasks());
|
|
3234
|
+
const configs = /* @__PURE__ */ new Map();
|
|
3468
3235
|
const getConfig = (project) => {
|
|
3469
|
-
if (configs.has(project))
|
|
3470
|
-
return configs.get(project);
|
|
3471
|
-
}
|
|
3236
|
+
if (configs.has(project)) return configs.get(project);
|
|
3472
3237
|
const config = project.serializedConfig;
|
|
3473
3238
|
configs.set(project, config);
|
|
3474
3239
|
return config;
|
|
@@ -3477,9 +3242,7 @@ function createVmThreadsPool(ctx, { execArgv, env }) {
|
|
|
3477
3242
|
const promises = Object.values(filesByEnv).flat();
|
|
3478
3243
|
const results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)));
|
|
3479
3244
|
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3480
|
-
if (errors.length > 0)
|
|
3481
|
-
throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
3482
|
-
}
|
|
3245
|
+
if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
3483
3246
|
};
|
|
3484
3247
|
};
|
|
3485
3248
|
return {
|
|
@@ -3492,13 +3255,9 @@ function createVmThreadsPool(ctx, { execArgv, env }) {
|
|
|
3492
3255
|
function getMemoryLimit(config) {
|
|
3493
3256
|
const memory = nodeos.totalmem();
|
|
3494
3257
|
const limit = getWorkerMemoryLimit(config, "vmThreads");
|
|
3495
|
-
if (typeof memory === "number")
|
|
3496
|
-
return stringToBytes(limit, config.watch ? memory / 2 : memory);
|
|
3497
|
-
}
|
|
3258
|
+
if (typeof memory === "number") return stringToBytes(limit, config.watch ? memory / 2 : memory);
|
|
3498
3259
|
// If totalmem is not supported we cannot resolve percentage based values like 0.5, "50%"
|
|
3499
|
-
if (typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%")
|
|
3500
|
-
return stringToBytes(limit);
|
|
3501
|
-
}
|
|
3260
|
+
if (typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%") return stringToBytes(limit);
|
|
3502
3261
|
// just ignore "memoryLimit" value because we cannot detect memory limit
|
|
3503
3262
|
return null;
|
|
3504
3263
|
}
|
|
@@ -3512,19 +3271,13 @@ const builtinPools = [
|
|
|
3512
3271
|
"typescript"
|
|
3513
3272
|
];
|
|
3514
3273
|
function getDefaultPoolName(project) {
|
|
3515
|
-
if (project.config.browser.enabled)
|
|
3516
|
-
return "browser";
|
|
3517
|
-
}
|
|
3274
|
+
if (project.config.browser.enabled) return "browser";
|
|
3518
3275
|
return project.config.pool;
|
|
3519
3276
|
}
|
|
3520
3277
|
function getFilePoolName(project, file) {
|
|
3521
3278
|
for (const [glob, pool] of project.config.poolMatchGlobs) {
|
|
3522
|
-
if (pool === "browser")
|
|
3523
|
-
|
|
3524
|
-
}
|
|
3525
|
-
if (pm.isMatch(file, glob, { cwd: project.config.root })) {
|
|
3526
|
-
return pool;
|
|
3527
|
-
}
|
|
3279
|
+
if (pool === "browser") throw new Error("Since Vitest 0.31.0 \"browser\" pool is not supported in \"poolMatchGlobs\". You can create a project to run some of your tests in browser in parallel. Read more: https://vitest.dev/guide/projects");
|
|
3280
|
+
if (pm.isMatch(file, glob, { cwd: project.config.root })) return pool;
|
|
3528
3281
|
}
|
|
3529
3282
|
return getDefaultPoolName(project);
|
|
3530
3283
|
}
|
|
@@ -3546,17 +3299,11 @@ function createPool(ctx) {
|
|
|
3546
3299
|
...ctx.vite.config.resolve.conditions
|
|
3547
3300
|
]);
|
|
3548
3301
|
const conditions = [...potentialConditions].filter((condition) => {
|
|
3549
|
-
if (condition === "production")
|
|
3550
|
-
|
|
3551
|
-
}
|
|
3552
|
-
if (condition === "development") {
|
|
3553
|
-
return !ctx.vite.config.isProduction;
|
|
3554
|
-
}
|
|
3302
|
+
if (condition === "production") return ctx.vite.config.isProduction;
|
|
3303
|
+
if (condition === "development") return !ctx.vite.config.isProduction;
|
|
3555
3304
|
return true;
|
|
3556
3305
|
}).map((condition) => {
|
|
3557
|
-
if (viteMajor >= 6 && condition === "development|production")
|
|
3558
|
-
return ctx.vite.config.isProduction ? "production" : "development";
|
|
3559
|
-
}
|
|
3306
|
+
if (viteMajor >= 6 && condition === "development|production") return ctx.vite.config.isProduction ? "production" : "development";
|
|
3560
3307
|
return condition;
|
|
3561
3308
|
}).flatMap((c) => ["--conditions", c]);
|
|
3562
3309
|
// Instead of passing whole process.execArgv to the workers, pick allowed options.
|
|
@@ -3576,35 +3323,21 @@ function createPool(ctx) {
|
|
|
3576
3323
|
}
|
|
3577
3324
|
};
|
|
3578
3325
|
// env are case-insensitive on Windows, but spawned processes don't support it
|
|
3579
|
-
if (isWindows)
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
}
|
|
3583
|
-
}
|
|
3584
|
-
const poolConcurrentPromises = new Map();
|
|
3585
|
-
const customPools = new Map();
|
|
3326
|
+
if (isWindows) for (const name in options.env) options.env[name.toUpperCase()] = options.env[name];
|
|
3327
|
+
const poolConcurrentPromises = /* @__PURE__ */ new Map();
|
|
3328
|
+
const customPools = /* @__PURE__ */ new Map();
|
|
3586
3329
|
async function resolveCustomPool(filepath) {
|
|
3587
|
-
if (customPools.has(filepath))
|
|
3588
|
-
return customPools.get(filepath);
|
|
3589
|
-
}
|
|
3330
|
+
if (customPools.has(filepath)) return customPools.get(filepath);
|
|
3590
3331
|
const pool = await ctx.runner.executeId(filepath);
|
|
3591
|
-
if (typeof pool.default !== "function") {
|
|
3592
|
-
throw new TypeError(`Custom pool "${filepath}" must export a function as default export`);
|
|
3593
|
-
}
|
|
3332
|
+
if (typeof pool.default !== "function") throw new TypeError(`Custom pool "${filepath}" must export a function as default export`);
|
|
3594
3333
|
const poolInstance = await pool.default(ctx, options);
|
|
3595
|
-
if (typeof poolInstance?.name !== "string") {
|
|
3596
|
-
|
|
3597
|
-
}
|
|
3598
|
-
if (typeof poolInstance?.[method] !== "function") {
|
|
3599
|
-
throw new TypeError(`Custom pool "${filepath}" should return an object with "${method}" method`);
|
|
3600
|
-
}
|
|
3334
|
+
if (typeof poolInstance?.name !== "string") throw new TypeError(`Custom pool "${filepath}" should return an object with "name" property`);
|
|
3335
|
+
if (typeof poolInstance?.[method] !== "function") throw new TypeError(`Custom pool "${filepath}" should return an object with "${method}" method`);
|
|
3601
3336
|
customPools.set(filepath, poolInstance);
|
|
3602
3337
|
return poolInstance;
|
|
3603
3338
|
}
|
|
3604
3339
|
function getConcurrentPool(pool, fn) {
|
|
3605
|
-
if (poolConcurrentPromises.has(pool))
|
|
3606
|
-
return poolConcurrentPromises.get(pool);
|
|
3607
|
-
}
|
|
3340
|
+
if (poolConcurrentPromises.has(pool)) return poolConcurrentPromises.get(pool);
|
|
3608
3341
|
const promise = fn().finally(() => {
|
|
3609
3342
|
poolConcurrentPromises.delete(pool);
|
|
3610
3343
|
});
|
|
@@ -3621,7 +3354,7 @@ function createPool(ctx) {
|
|
|
3621
3354
|
});
|
|
3622
3355
|
}
|
|
3623
3356
|
const groupedSpecifications = {};
|
|
3624
|
-
const groups = new Set();
|
|
3357
|
+
const groups = /* @__PURE__ */ new Set();
|
|
3625
3358
|
const factories = {
|
|
3626
3359
|
vmThreads: () => createVmThreadsPool(ctx, options),
|
|
3627
3360
|
vmForks: () => createVmForksPool(ctx, options),
|
|
@@ -3638,17 +3371,13 @@ function createPool(ctx) {
|
|
|
3638
3371
|
const Sequencer = ctx.config.sequence.sequencer;
|
|
3639
3372
|
const sequencer = new Sequencer(ctx);
|
|
3640
3373
|
async function sortSpecs(specs) {
|
|
3641
|
-
if (ctx.config.shard)
|
|
3642
|
-
specs = await sequencer.shard(specs);
|
|
3643
|
-
}
|
|
3374
|
+
if (ctx.config.shard) specs = await sequencer.shard(specs);
|
|
3644
3375
|
return sequencer.sort(specs);
|
|
3645
3376
|
}
|
|
3646
3377
|
const sortedGroups = Array.from(groups).sort();
|
|
3647
3378
|
for (const group of sortedGroups) {
|
|
3648
3379
|
const specifications = groupedSpecifications[group];
|
|
3649
|
-
if (!specifications?.length)
|
|
3650
|
-
continue;
|
|
3651
|
-
}
|
|
3380
|
+
if (!specifications?.length) continue;
|
|
3652
3381
|
const filesByPool = {
|
|
3653
3382
|
forks: [],
|
|
3654
3383
|
threads: [],
|
|
@@ -3663,9 +3392,7 @@ function createPool(ctx) {
|
|
|
3663
3392
|
});
|
|
3664
3393
|
await Promise.all(Object.entries(filesByPool).map(async (entry) => {
|
|
3665
3394
|
const [pool, files] = entry;
|
|
3666
|
-
if (!files.length)
|
|
3667
|
-
return null;
|
|
3668
|
-
}
|
|
3395
|
+
if (!files.length) return null;
|
|
3669
3396
|
const specs = await sortSpecs(files);
|
|
3670
3397
|
if (pool in factories) {
|
|
3671
3398
|
const factory = factories[pool];
|
|
@@ -3705,7 +3432,7 @@ class BaseSequencer {
|
|
|
3705
3432
|
const shardStart = shardSize * (index - 1);
|
|
3706
3433
|
const shardEnd = shardSize * index;
|
|
3707
3434
|
return [...files].map((spec) => {
|
|
3708
|
-
const fullPath = resolve
|
|
3435
|
+
const fullPath = resolve$1(slash(config.root), slash(spec.moduleId));
|
|
3709
3436
|
const specPath = fullPath?.slice(config.root.length);
|
|
3710
3437
|
return {
|
|
3711
3438
|
spec,
|
|
@@ -3725,19 +3452,13 @@ class BaseSequencer {
|
|
|
3725
3452
|
const statsA = cache.getFileStats(keyA);
|
|
3726
3453
|
const statsB = cache.getFileStats(keyB);
|
|
3727
3454
|
// run unknown first
|
|
3728
|
-
if (!statsA || !statsB)
|
|
3729
|
-
return !statsA && statsB ? -1 : !statsB && statsA ? 1 : 0;
|
|
3730
|
-
}
|
|
3455
|
+
if (!statsA || !statsB) return !statsA && statsB ? -1 : !statsB && statsA ? 1 : 0;
|
|
3731
3456
|
// run larger files first
|
|
3732
3457
|
return statsB.size - statsA.size;
|
|
3733
3458
|
}
|
|
3734
3459
|
// run failed first
|
|
3735
|
-
if (aState.failed && !bState.failed)
|
|
3736
|
-
|
|
3737
|
-
}
|
|
3738
|
-
if (!aState.failed && bState.failed) {
|
|
3739
|
-
return 1;
|
|
3740
|
-
}
|
|
3460
|
+
if (aState.failed && !bState.failed) return -1;
|
|
3461
|
+
if (!aState.failed && bState.failed) return 1;
|
|
3741
3462
|
// run longer first
|
|
3742
3463
|
return bState.duration - aState.duration;
|
|
3743
3464
|
});
|
|
@@ -3752,22 +3473,14 @@ class RandomSequencer extends BaseSequencer {
|
|
|
3752
3473
|
}
|
|
3753
3474
|
|
|
3754
3475
|
function resolvePath(path, root) {
|
|
3755
|
-
return normalize(/* @__PURE__ */ resolveModule(path, { paths: [root] }) ?? resolve(root, path));
|
|
3476
|
+
return normalize(/* @__PURE__ */ resolveModule(path, { paths: [root] }) ?? resolve$1(root, path));
|
|
3756
3477
|
}
|
|
3757
3478
|
function parseInspector(inspect) {
|
|
3758
|
-
if (typeof inspect === "boolean" || inspect ===
|
|
3759
|
-
|
|
3760
|
-
}
|
|
3761
|
-
if (typeof inspect === "number") {
|
|
3762
|
-
return { port: inspect };
|
|
3763
|
-
}
|
|
3764
|
-
if (inspect.match(/https?:\//)) {
|
|
3765
|
-
throw new Error(`Inspector host cannot be a URL. Use "host:port" instead of "${inspect}"`);
|
|
3766
|
-
}
|
|
3479
|
+
if (typeof inspect === "boolean" || inspect === void 0) return {};
|
|
3480
|
+
if (typeof inspect === "number") return { port: inspect };
|
|
3481
|
+
if (inspect.match(/https?:\//)) throw new Error(`Inspector host cannot be a URL. Use "host:port" instead of "${inspect}"`);
|
|
3767
3482
|
const [host, port] = inspect.split(":");
|
|
3768
|
-
if (!port) {
|
|
3769
|
-
return { host };
|
|
3770
|
-
}
|
|
3483
|
+
if (!port) return { host };
|
|
3771
3484
|
return {
|
|
3772
3485
|
host,
|
|
3773
3486
|
port: Number(port) || defaultInspectPort
|
|
@@ -3775,51 +3488,28 @@ function parseInspector(inspect) {
|
|
|
3775
3488
|
}
|
|
3776
3489
|
function resolveApiServerConfig(options, defaultPort) {
|
|
3777
3490
|
let api;
|
|
3778
|
-
if (options.ui && !options.api) {
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
api =
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
if (api) {
|
|
3787
|
-
if (options.api.port) {
|
|
3788
|
-
api.port = options.api.port;
|
|
3789
|
-
}
|
|
3790
|
-
if (options.api.strictPort) {
|
|
3791
|
-
api.strictPort = options.api.strictPort;
|
|
3792
|
-
}
|
|
3793
|
-
if (options.api.host) {
|
|
3794
|
-
api.host = options.api.host;
|
|
3795
|
-
}
|
|
3796
|
-
} else {
|
|
3797
|
-
api = { ...options.api };
|
|
3798
|
-
}
|
|
3799
|
-
}
|
|
3491
|
+
if (options.ui && !options.api) api = { port: defaultPort };
|
|
3492
|
+
else if (options.api === true) api = { port: defaultPort };
|
|
3493
|
+
else if (typeof options.api === "number") api = { port: options.api };
|
|
3494
|
+
if (typeof options.api === "object") if (api) {
|
|
3495
|
+
if (options.api.port) api.port = options.api.port;
|
|
3496
|
+
if (options.api.strictPort) api.strictPort = options.api.strictPort;
|
|
3497
|
+
if (options.api.host) api.host = options.api.host;
|
|
3498
|
+
} else api = { ...options.api };
|
|
3800
3499
|
if (api) {
|
|
3801
|
-
if (!api.port && !api.middlewareMode)
|
|
3802
|
-
|
|
3803
|
-
}
|
|
3804
|
-
} else {
|
|
3805
|
-
api = { middlewareMode: true };
|
|
3806
|
-
}
|
|
3500
|
+
if (!api.port && !api.middlewareMode) api.port = defaultPort;
|
|
3501
|
+
} else api = { middlewareMode: true };
|
|
3807
3502
|
return api;
|
|
3808
3503
|
}
|
|
3809
3504
|
function resolveInlineWorkerOption(value) {
|
|
3810
|
-
if (typeof value === "string" && value.trim().endsWith("%"))
|
|
3811
|
-
|
|
3812
|
-
} else {
|
|
3813
|
-
return Number(value);
|
|
3814
|
-
}
|
|
3505
|
+
if (typeof value === "string" && value.trim().endsWith("%")) return getWorkersCountByPercentage(value);
|
|
3506
|
+
else return Number(value);
|
|
3815
3507
|
}
|
|
3816
3508
|
function resolveConfig$1(vitest, options, viteConfig) {
|
|
3817
3509
|
const mode = vitest.mode;
|
|
3818
3510
|
const logger = vitest.logger;
|
|
3819
3511
|
if (options.dom) {
|
|
3820
|
-
if (viteConfig.test?.environment != null && viteConfig.test.environment !== "happy-dom") {
|
|
3821
|
-
logger.console.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} Your config.test.environment ("${viteConfig.test.environment}") conflicts with --dom flag ("happy-dom"), ignoring "${viteConfig.test.environment}"`));
|
|
3822
|
-
}
|
|
3512
|
+
if (viteConfig.test?.environment != null && viteConfig.test.environment !== "happy-dom") logger.console.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} Your config.test.environment ("${viteConfig.test.environment}") conflicts with --dom flag ("happy-dom"), ignoring "${viteConfig.test.environment}"`));
|
|
3823
3513
|
options.environment = "happy-dom";
|
|
3824
3514
|
}
|
|
3825
3515
|
const resolved = {
|
|
@@ -3831,7 +3521,7 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
3831
3521
|
resolved.project = toArray(resolved.project);
|
|
3832
3522
|
resolved.provide ??= {};
|
|
3833
3523
|
resolved.name = typeof options.name === "string" ? options.name : options.name?.label || "";
|
|
3834
|
-
resolved.color = typeof options.name !== "string" ? options.name?.color :
|
|
3524
|
+
resolved.color = typeof options.name !== "string" ? options.name?.color : void 0;
|
|
3835
3525
|
const inspector = resolved.inspect || resolved.inspectBrk;
|
|
3836
3526
|
resolved.inspector = {
|
|
3837
3527
|
...resolved.inspector,
|
|
@@ -3839,40 +3529,24 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
3839
3529
|
enabled: !!inspector,
|
|
3840
3530
|
waitForDebugger: options.inspector?.waitForDebugger ?? !!resolved.inspectBrk
|
|
3841
3531
|
};
|
|
3842
|
-
if (viteConfig.base !== "/")
|
|
3843
|
-
resolved.base = viteConfig.base;
|
|
3844
|
-
}
|
|
3532
|
+
if (viteConfig.base !== "/") resolved.base = viteConfig.base;
|
|
3845
3533
|
resolved.clearScreen = resolved.clearScreen ?? viteConfig.clearScreen ?? true;
|
|
3846
3534
|
if (options.shard) {
|
|
3847
|
-
if (resolved.watch)
|
|
3848
|
-
throw new Error("You cannot use --shard option with enabled watch");
|
|
3849
|
-
}
|
|
3535
|
+
if (resolved.watch) throw new Error("You cannot use --shard option with enabled watch");
|
|
3850
3536
|
const [indexString, countString] = options.shard.split("/");
|
|
3851
3537
|
const index = Math.abs(Number.parseInt(indexString, 10));
|
|
3852
3538
|
const count = Math.abs(Number.parseInt(countString, 10));
|
|
3853
|
-
if (Number.isNaN(count) || count <= 0)
|
|
3854
|
-
|
|
3855
|
-
}
|
|
3856
|
-
if (Number.isNaN(index) || index <= 0 || index > count) {
|
|
3857
|
-
throw new Error("--shard <index> must be a positive number less then <count>");
|
|
3858
|
-
}
|
|
3539
|
+
if (Number.isNaN(count) || count <= 0) throw new Error("--shard <count> must be a positive number");
|
|
3540
|
+
if (Number.isNaN(index) || index <= 0 || index > count) throw new Error("--shard <index> must be a positive number less then <count>");
|
|
3859
3541
|
resolved.shard = {
|
|
3860
3542
|
index,
|
|
3861
3543
|
count
|
|
3862
3544
|
};
|
|
3863
3545
|
}
|
|
3864
|
-
if (resolved.standalone && !resolved.watch)
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
if (resolved.
|
|
3868
|
-
throw new Error(`Cannot merge reports with --watch enabled`);
|
|
3869
|
-
}
|
|
3870
|
-
if (resolved.maxWorkers) {
|
|
3871
|
-
resolved.maxWorkers = resolveInlineWorkerOption(resolved.maxWorkers);
|
|
3872
|
-
}
|
|
3873
|
-
if (resolved.minWorkers) {
|
|
3874
|
-
resolved.minWorkers = resolveInlineWorkerOption(resolved.minWorkers);
|
|
3875
|
-
}
|
|
3546
|
+
if (resolved.standalone && !resolved.watch) throw new Error(`Vitest standalone mode requires --watch`);
|
|
3547
|
+
if (resolved.mergeReports && resolved.watch) throw new Error(`Cannot merge reports with --watch enabled`);
|
|
3548
|
+
if (resolved.maxWorkers) resolved.maxWorkers = resolveInlineWorkerOption(resolved.maxWorkers);
|
|
3549
|
+
if (resolved.minWorkers) resolved.minWorkers = resolveInlineWorkerOption(resolved.minWorkers);
|
|
3876
3550
|
// run benchmark sequentially by default
|
|
3877
3551
|
resolved.fileParallelism ??= mode !== "benchmark";
|
|
3878
3552
|
if (!resolved.fileParallelism) {
|
|
@@ -3893,23 +3567,16 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
3893
3567
|
}
|
|
3894
3568
|
}
|
|
3895
3569
|
// apply browser CLI options only if the config already has the browser config and not disabled manually
|
|
3896
|
-
if (vitest._cliOptions.browser && resolved.browser && (resolved.browser.enabled !== false || vitest._cliOptions.browser.enabled))
|
|
3897
|
-
resolved.browser = mergeConfig(resolved.browser, vitest._cliOptions.browser);
|
|
3898
|
-
}
|
|
3570
|
+
if (vitest._cliOptions.browser && resolved.browser && (resolved.browser.enabled !== false || vitest._cliOptions.browser.enabled)) resolved.browser = mergeConfig(resolved.browser, vitest._cliOptions.browser);
|
|
3899
3571
|
resolved.browser ??= {};
|
|
3900
3572
|
const browser = resolved.browser;
|
|
3901
3573
|
if (browser.enabled) {
|
|
3902
|
-
if (!browser.name && !browser.instances)
|
|
3903
|
-
throw new Error(`Vitest Browser Mode requires "browser.name" (deprecated) or "browser.instances" options, none were set.`);
|
|
3904
|
-
}
|
|
3574
|
+
if (!browser.name && !browser.instances) throw new Error(`Vitest Browser Mode requires "browser.name" (deprecated) or "browser.instances" options, none were set.`);
|
|
3905
3575
|
const instances = browser.instances;
|
|
3906
|
-
if (browser.name && browser.instances)
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
}
|
|
3910
|
-
if (browser.instances && !browser.instances.length) {
|
|
3911
|
-
throw new Error([`"browser.instances" was set in the config, but the array is empty. Define at least one browser config.`, browser.name && instances?.length ? ` The "browser.name" was set to "${browser.name}" which filtered all configs (${instances.map((c) => c.browser).join(", ")}). Did you mean to use another name?` : ""].join(""));
|
|
3912
|
-
}
|
|
3576
|
+
if (browser.name && browser.instances)
|
|
3577
|
+
// --browser=chromium filters configs to a single one
|
|
3578
|
+
browser.instances = browser.instances.filter((instance) => instance.browser === browser.name);
|
|
3579
|
+
if (browser.instances && !browser.instances.length) throw new Error([`"browser.instances" was set in the config, but the array is empty. Define at least one browser config.`, browser.name && instances?.length ? ` The "browser.name" was set to "${browser.name}" which filtered all configs (${instances.map((c) => c.browser).join(", ")}). Did you mean to use another name?` : ""].join(""));
|
|
3913
3580
|
}
|
|
3914
3581
|
const playwrightChromiumOnly = isPlaywrightChromiumOnly(vitest, resolved);
|
|
3915
3582
|
// Browser-mode "Playwright + Chromium" only features:
|
|
@@ -3919,45 +3586,33 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
3919
3586
|
name: browser.name,
|
|
3920
3587
|
instances: browser.instances?.map((i) => ({ browser: i.browser }))
|
|
3921
3588
|
} };
|
|
3922
|
-
if (resolved.coverage.enabled && resolved.coverage.provider === "v8") {
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
} }, null, 2)}` + `\n\n...or change your coverage provider to:\n${JSON.stringify({ coverage: { provider: "istanbul" } }, null, 2)}\n`);
|
|
3927
|
-
}
|
|
3589
|
+
if (resolved.coverage.enabled && resolved.coverage.provider === "v8") throw new Error(`@vitest/coverage-v8 does not work with\n${JSON.stringify(browserConfig, null, 2)}\n\nUse either:\n${JSON.stringify({ browser: {
|
|
3590
|
+
provider: "playwright",
|
|
3591
|
+
instances: [{ browser: "chromium" }]
|
|
3592
|
+
} }, null, 2)}\n\n...or change your coverage provider to:\n${JSON.stringify({ coverage: { provider: "istanbul" } }, null, 2)}\n`);
|
|
3928
3593
|
if (resolved.inspect || resolved.inspectBrk) {
|
|
3929
3594
|
const inspectOption = `--inspect${resolved.inspectBrk ? "-brk" : ""}`;
|
|
3930
|
-
throw new Error(`${inspectOption} does not work with\n${JSON.stringify(browserConfig, null, 2)}\n
|
|
3595
|
+
throw new Error(`${inspectOption} does not work with\n${JSON.stringify(browserConfig, null, 2)}\n\nUse either:\n${JSON.stringify({ browser: {
|
|
3931
3596
|
provider: "playwright",
|
|
3932
3597
|
instances: [{ browser: "chromium" }]
|
|
3933
|
-
} }, null, 2)}
|
|
3598
|
+
} }, null, 2)}\n\n...or disable ${inspectOption}\n`);
|
|
3934
3599
|
}
|
|
3935
3600
|
}
|
|
3936
3601
|
resolved.coverage.reporter = resolveCoverageReporters(resolved.coverage.reporter);
|
|
3937
3602
|
if (resolved.coverage.enabled && resolved.coverage.reportsDirectory) {
|
|
3938
|
-
const reportsDirectory = resolve(resolved.root, resolved.coverage.reportsDirectory);
|
|
3939
|
-
if (reportsDirectory === resolved.root || reportsDirectory === process.cwd()) {
|
|
3940
|
-
throw new Error(`You cannot set "coverage.reportsDirectory" as ${reportsDirectory}. Vitest needs to be able to remove this directory before test run`);
|
|
3941
|
-
}
|
|
3942
|
-
}
|
|
3943
|
-
if (resolved.coverage.enabled && resolved.coverage.provider === "custom" && resolved.coverage.customProviderModule) {
|
|
3944
|
-
resolved.coverage.customProviderModule = resolvePath(resolved.coverage.customProviderModule, resolved.root);
|
|
3603
|
+
const reportsDirectory = resolve$1(resolved.root, resolved.coverage.reportsDirectory);
|
|
3604
|
+
if (reportsDirectory === resolved.root || reportsDirectory === process.cwd()) throw new Error(`You cannot set "coverage.reportsDirectory" as ${reportsDirectory}. Vitest needs to be able to remove this directory before test run`);
|
|
3945
3605
|
}
|
|
3606
|
+
if (resolved.coverage.enabled && resolved.coverage.provider === "custom" && resolved.coverage.customProviderModule) resolved.coverage.customProviderModule = resolvePath(resolved.coverage.customProviderModule, resolved.root);
|
|
3946
3607
|
resolved.expect ??= {};
|
|
3947
3608
|
resolved.deps ??= {};
|
|
3948
3609
|
resolved.deps.moduleDirectories ??= [];
|
|
3949
3610
|
resolved.deps.moduleDirectories = resolved.deps.moduleDirectories.map((dir) => {
|
|
3950
|
-
if (!dir.startsWith("/")) {
|
|
3951
|
-
|
|
3952
|
-
}
|
|
3953
|
-
if (!dir.endsWith("/")) {
|
|
3954
|
-
dir += "/";
|
|
3955
|
-
}
|
|
3611
|
+
if (!dir.startsWith("/")) dir = `/${dir}`;
|
|
3612
|
+
if (!dir.endsWith("/")) dir += "/";
|
|
3956
3613
|
return normalize(dir);
|
|
3957
3614
|
});
|
|
3958
|
-
if (!resolved.deps.moduleDirectories.includes("/node_modules/"))
|
|
3959
|
-
resolved.deps.moduleDirectories.push("/node_modules/");
|
|
3960
|
-
}
|
|
3615
|
+
if (!resolved.deps.moduleDirectories.includes("/node_modules/")) resolved.deps.moduleDirectories.push("/node_modules/");
|
|
3961
3616
|
resolved.deps.optimizer ??= {};
|
|
3962
3617
|
resolved.deps.optimizer.ssr ??= {};
|
|
3963
3618
|
resolved.deps.optimizer.ssr.enabled ??= true;
|
|
@@ -3984,29 +3639,21 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
3984
3639
|
"fallbackCJS"
|
|
3985
3640
|
];
|
|
3986
3641
|
deprecatedDepsOptions.forEach((option) => {
|
|
3987
|
-
if (resolved.deps[option] ===
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
if (option === "fallbackCJS") {
|
|
3991
|
-
logger.console.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} "deps.${option}" is deprecated. Use "server.deps.${option}" instead`));
|
|
3992
|
-
} else {
|
|
3642
|
+
if (resolved.deps[option] === void 0) return;
|
|
3643
|
+
if (option === "fallbackCJS") logger.console.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} "deps.${option}" is deprecated. Use "server.deps.${option}" instead`));
|
|
3644
|
+
else {
|
|
3993
3645
|
const transformMode = resolved.environment === "happy-dom" || resolved.environment === "jsdom" ? "web" : "ssr";
|
|
3994
3646
|
logger.console.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} "deps.${option}" is deprecated. If you rely on vite-node directly, use "server.deps.${option}" instead. Otherwise, consider using "deps.optimizer.${transformMode}.${option === "external" ? "exclude" : "include"}"`));
|
|
3995
3647
|
}
|
|
3996
|
-
if (resolved.server.deps[option] ===
|
|
3997
|
-
resolved.server.deps[option] = resolved.deps[option];
|
|
3998
|
-
}
|
|
3648
|
+
if (resolved.server.deps[option] === void 0) resolved.server.deps[option] = resolved.deps[option];
|
|
3999
3649
|
});
|
|
4000
|
-
if (resolved.cliExclude)
|
|
4001
|
-
resolved.exclude.push(...resolved.cliExclude);
|
|
4002
|
-
}
|
|
3650
|
+
if (resolved.cliExclude) resolved.exclude.push(...resolved.cliExclude);
|
|
4003
3651
|
// vitenode will try to import such file with native node,
|
|
4004
3652
|
// but then our mocker will not work properly
|
|
4005
3653
|
if (resolved.server.deps.inline !== true) {
|
|
4006
3654
|
const ssrOptions = viteConfig.ssr;
|
|
4007
|
-
if (ssrOptions?.noExternal === true && resolved.server.deps.inline == null)
|
|
4008
|
-
|
|
4009
|
-
} else {
|
|
3655
|
+
if (ssrOptions?.noExternal === true && resolved.server.deps.inline == null) resolved.server.deps.inline = true;
|
|
3656
|
+
else {
|
|
4010
3657
|
resolved.server.deps.inline ??= [];
|
|
4011
3658
|
resolved.server.deps.inline.push(...extraInlineDeps);
|
|
4012
3659
|
}
|
|
@@ -4015,16 +3662,11 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
4015
3662
|
resolved.server.deps.inlineFiles.push(...resolved.setupFiles);
|
|
4016
3663
|
resolved.server.deps.moduleDirectories ??= [];
|
|
4017
3664
|
resolved.server.deps.moduleDirectories.push(...resolved.deps.moduleDirectories);
|
|
4018
|
-
if (resolved.runner)
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
}
|
|
4024
|
-
resolved.testNamePattern = resolved.testNamePattern ? resolved.testNamePattern instanceof RegExp ? resolved.testNamePattern : new RegExp(resolved.testNamePattern) : undefined;
|
|
4025
|
-
if (resolved.snapshotFormat && "plugins" in resolved.snapshotFormat) {
|
|
4026
|
-
resolved.snapshotFormat.plugins = [];
|
|
4027
|
-
}
|
|
3665
|
+
if (resolved.runner) resolved.runner = resolvePath(resolved.runner, resolved.root);
|
|
3666
|
+
resolved.attachmentsDir = resolve$1(resolved.root, resolved.attachmentsDir ?? ".vitest-attachments");
|
|
3667
|
+
if (resolved.snapshotEnvironment) resolved.snapshotEnvironment = resolvePath(resolved.snapshotEnvironment, resolved.root);
|
|
3668
|
+
resolved.testNamePattern = resolved.testNamePattern ? resolved.testNamePattern instanceof RegExp ? resolved.testNamePattern : new RegExp(resolved.testNamePattern) : void 0;
|
|
3669
|
+
if (resolved.snapshotFormat && "plugins" in resolved.snapshotFormat) resolved.snapshotFormat.plugins = [];
|
|
4028
3670
|
const UPDATE_SNAPSHOT = resolved.update || process.env.UPDATE_SNAPSHOT;
|
|
4029
3671
|
resolved.snapshotOptions = {
|
|
4030
3672
|
expand: resolved.expandSnapshotDiff ?? false,
|
|
@@ -4036,98 +3678,73 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
4036
3678
|
resolved.snapshotSerializers ??= [];
|
|
4037
3679
|
resolved.snapshotSerializers = resolved.snapshotSerializers.map((file) => resolvePath(file, resolved.root));
|
|
4038
3680
|
resolved.forceRerunTriggers.push(...resolved.snapshotSerializers);
|
|
4039
|
-
if (options.resolveSnapshotPath)
|
|
4040
|
-
delete resolved.resolveSnapshotPath;
|
|
4041
|
-
}
|
|
3681
|
+
if (options.resolveSnapshotPath) delete resolved.resolveSnapshotPath;
|
|
4042
3682
|
resolved.pool ??= "threads";
|
|
4043
|
-
if (process.env.VITEST_MAX_THREADS) {
|
|
4044
|
-
resolved.poolOptions
|
|
4045
|
-
|
|
4046
|
-
threads
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
vmThreads
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
minForks: Number.parseInt(process.env.VITEST_MIN_FORKS)
|
|
4088
|
-
},
|
|
4089
|
-
vmForks: {
|
|
4090
|
-
...resolved.poolOptions?.vmForks,
|
|
4091
|
-
minForks: Number.parseInt(process.env.VITEST_MIN_FORKS)
|
|
4092
|
-
}
|
|
4093
|
-
};
|
|
4094
|
-
}
|
|
3683
|
+
if (process.env.VITEST_MAX_THREADS) resolved.poolOptions = {
|
|
3684
|
+
...resolved.poolOptions,
|
|
3685
|
+
threads: {
|
|
3686
|
+
...resolved.poolOptions?.threads,
|
|
3687
|
+
maxThreads: Number.parseInt(process.env.VITEST_MAX_THREADS)
|
|
3688
|
+
},
|
|
3689
|
+
vmThreads: {
|
|
3690
|
+
...resolved.poolOptions?.vmThreads,
|
|
3691
|
+
maxThreads: Number.parseInt(process.env.VITEST_MAX_THREADS)
|
|
3692
|
+
}
|
|
3693
|
+
};
|
|
3694
|
+
if (process.env.VITEST_MIN_THREADS) resolved.poolOptions = {
|
|
3695
|
+
...resolved.poolOptions,
|
|
3696
|
+
threads: {
|
|
3697
|
+
...resolved.poolOptions?.threads,
|
|
3698
|
+
minThreads: Number.parseInt(process.env.VITEST_MIN_THREADS)
|
|
3699
|
+
},
|
|
3700
|
+
vmThreads: {
|
|
3701
|
+
...resolved.poolOptions?.vmThreads,
|
|
3702
|
+
minThreads: Number.parseInt(process.env.VITEST_MIN_THREADS)
|
|
3703
|
+
}
|
|
3704
|
+
};
|
|
3705
|
+
if (process.env.VITEST_MAX_FORKS) resolved.poolOptions = {
|
|
3706
|
+
...resolved.poolOptions,
|
|
3707
|
+
forks: {
|
|
3708
|
+
...resolved.poolOptions?.forks,
|
|
3709
|
+
maxForks: Number.parseInt(process.env.VITEST_MAX_FORKS)
|
|
3710
|
+
},
|
|
3711
|
+
vmForks: {
|
|
3712
|
+
...resolved.poolOptions?.vmForks,
|
|
3713
|
+
maxForks: Number.parseInt(process.env.VITEST_MAX_FORKS)
|
|
3714
|
+
}
|
|
3715
|
+
};
|
|
3716
|
+
if (process.env.VITEST_MIN_FORKS) resolved.poolOptions = {
|
|
3717
|
+
...resolved.poolOptions,
|
|
3718
|
+
forks: {
|
|
3719
|
+
...resolved.poolOptions?.forks,
|
|
3720
|
+
minForks: Number.parseInt(process.env.VITEST_MIN_FORKS)
|
|
3721
|
+
},
|
|
3722
|
+
vmForks: {
|
|
3723
|
+
...resolved.poolOptions?.vmForks,
|
|
3724
|
+
minForks: Number.parseInt(process.env.VITEST_MIN_FORKS)
|
|
3725
|
+
}
|
|
3726
|
+
};
|
|
4095
3727
|
const poolThreadsOptions = [
|
|
4096
3728
|
["threads", "minThreads"],
|
|
4097
3729
|
["threads", "maxThreads"],
|
|
4098
3730
|
["vmThreads", "minThreads"],
|
|
4099
3731
|
["vmThreads", "maxThreads"]
|
|
4100
3732
|
];
|
|
4101
|
-
for (const [poolOptionKey, workerOptionKey] of poolThreadsOptions)
|
|
4102
|
-
if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) {
|
|
4103
|
-
resolved.poolOptions[poolOptionKey][workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey][workerOptionKey]);
|
|
4104
|
-
}
|
|
4105
|
-
}
|
|
3733
|
+
for (const [poolOptionKey, workerOptionKey] of poolThreadsOptions) if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) resolved.poolOptions[poolOptionKey][workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey][workerOptionKey]);
|
|
4106
3734
|
const poolForksOptions = [
|
|
4107
3735
|
["forks", "minForks"],
|
|
4108
3736
|
["forks", "maxForks"],
|
|
4109
3737
|
["vmForks", "minForks"],
|
|
4110
3738
|
["vmForks", "maxForks"]
|
|
4111
3739
|
];
|
|
4112
|
-
for (const [poolOptionKey, workerOptionKey] of poolForksOptions)
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
if (
|
|
4118
|
-
// if passed down from the CLI and it's relative, resolve relative to CWD
|
|
4119
|
-
resolved.workspace = typeof options.workspace === "string" && options.workspace[0] === "." ? resolve(process.cwd(), options.workspace) : resolvePath(resolved.workspace, resolved.root);
|
|
4120
|
-
}
|
|
4121
|
-
if (!builtinPools.includes(resolved.pool)) {
|
|
4122
|
-
resolved.pool = resolvePath(resolved.pool, resolved.root);
|
|
4123
|
-
}
|
|
4124
|
-
if (resolved.poolMatchGlobs) {
|
|
4125
|
-
logger.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} "poolMatchGlobs" is deprecated. Use "workspace" to define different configurations instead.`));
|
|
4126
|
-
}
|
|
3740
|
+
for (const [poolOptionKey, workerOptionKey] of poolForksOptions) if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) resolved.poolOptions[poolOptionKey][workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey][workerOptionKey]);
|
|
3741
|
+
if (typeof resolved.workspace === "string")
|
|
3742
|
+
// if passed down from the CLI and it's relative, resolve relative to CWD
|
|
3743
|
+
resolved.workspace = typeof options.workspace === "string" && options.workspace[0] === "." ? resolve$1(process.cwd(), options.workspace) : resolvePath(resolved.workspace, resolved.root);
|
|
3744
|
+
if (!builtinPools.includes(resolved.pool)) resolved.pool = resolvePath(resolved.pool, resolved.root);
|
|
3745
|
+
if (resolved.poolMatchGlobs) logger.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} "poolMatchGlobs" is deprecated. Use "workspace" to define different configurations instead.`));
|
|
4127
3746
|
resolved.poolMatchGlobs = (resolved.poolMatchGlobs || []).map(([glob, pool]) => {
|
|
4128
|
-
if (!builtinPools.includes(pool))
|
|
4129
|
-
pool = resolvePath(pool, resolved.root);
|
|
4130
|
-
}
|
|
3747
|
+
if (!builtinPools.includes(pool)) pool = resolvePath(pool, resolved.root);
|
|
4131
3748
|
return [glob, pool];
|
|
4132
3749
|
});
|
|
4133
3750
|
if (mode === "benchmark") {
|
|
@@ -4142,21 +3759,12 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
4142
3759
|
resolved.exclude = resolved.benchmark.exclude;
|
|
4143
3760
|
resolved.includeSource = resolved.benchmark.includeSource;
|
|
4144
3761
|
const reporters = Array.from(new Set([...toArray(resolved.benchmark.reporters), ...toArray(options.reporter)])).filter(Boolean);
|
|
4145
|
-
if (reporters.length)
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
resolved.benchmark.reporters = ["default"];
|
|
4149
|
-
}
|
|
4150
|
-
if (options.outputFile) {
|
|
4151
|
-
resolved.benchmark.outputFile = options.outputFile;
|
|
4152
|
-
}
|
|
3762
|
+
if (reporters.length) resolved.benchmark.reporters = reporters;
|
|
3763
|
+
else resolved.benchmark.reporters = ["default"];
|
|
3764
|
+
if (options.outputFile) resolved.benchmark.outputFile = options.outputFile;
|
|
4153
3765
|
// --compare from cli
|
|
4154
|
-
if (options.compare)
|
|
4155
|
-
|
|
4156
|
-
}
|
|
4157
|
-
if (options.outputJson) {
|
|
4158
|
-
resolved.benchmark.outputJson = options.outputJson;
|
|
4159
|
-
}
|
|
3766
|
+
if (options.compare) resolved.benchmark.compare = options.compare;
|
|
3767
|
+
if (options.outputJson) resolved.benchmark.outputJson = options.outputJson;
|
|
4160
3768
|
}
|
|
4161
3769
|
if (typeof resolved.diff === "string") {
|
|
4162
3770
|
resolved.diff = resolvePath(resolved.diff, resolved.root);
|
|
@@ -4168,9 +3776,7 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
4168
3776
|
...api,
|
|
4169
3777
|
token: crypto.randomUUID()
|
|
4170
3778
|
};
|
|
4171
|
-
if (options.related)
|
|
4172
|
-
resolved.related = toArray(options.related).map((file) => resolve(resolved.root, file));
|
|
4173
|
-
}
|
|
3779
|
+
if (options.related) resolved.related = toArray(options.related).map((file) => resolve$1(resolved.root, file));
|
|
4174
3780
|
/*
|
|
4175
3781
|
* Reporters can be defined in many different ways:
|
|
4176
3782
|
* { reporter: 'json' }
|
|
@@ -4180,29 +3786,21 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
4180
3786
|
* { reporter: [[ 'json' ], 'html'] }
|
|
4181
3787
|
* { reporter: [[ 'json', { outputFile: 'test.json' } ], 'html'] }
|
|
4182
3788
|
*/
|
|
4183
|
-
if (options.reporters)
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
// Reporter name in array, e.g. { reporters: ["html", "json"]}
|
|
4199
|
-
resolved.reporters.push([reporter, {}]);
|
|
4200
|
-
} else {
|
|
4201
|
-
// Inline reporter, e.g. { reporter: [{ onFinish() { method() } }] }
|
|
4202
|
-
resolved.reporters.push(reporter);
|
|
4203
|
-
}
|
|
4204
|
-
}
|
|
4205
|
-
}
|
|
3789
|
+
if (options.reporters) if (!Array.isArray(options.reporters))
|
|
3790
|
+
// Reporter name, e.g. { reporters: 'json' }
|
|
3791
|
+
if (typeof options.reporters === "string") resolved.reporters = [[options.reporters, {}]];
|
|
3792
|
+
else resolved.reporters = [options.reporters];
|
|
3793
|
+
else {
|
|
3794
|
+
resolved.reporters = [];
|
|
3795
|
+
for (const reporter of options.reporters) if (Array.isArray(reporter))
|
|
3796
|
+
// Reporter with options, e.g. { reporters: [ [ 'json', { outputFile: 'test.json' } ] ] }
|
|
3797
|
+
resolved.reporters.push([reporter[0], reporter[1] || {}]);
|
|
3798
|
+
else if (typeof reporter === "string")
|
|
3799
|
+
// Reporter name in array, e.g. { reporters: ["html", "json"]}
|
|
3800
|
+
resolved.reporters.push([reporter, {}]);
|
|
3801
|
+
else
|
|
3802
|
+
// Inline reporter, e.g. { reporter: [{ onFinish() { method() } }] }
|
|
3803
|
+
resolved.reporters.push(reporter);
|
|
4206
3804
|
}
|
|
4207
3805
|
if (mode !== "benchmark") {
|
|
4208
3806
|
// @ts-expect-error "reporter" is from CLI, should be absolute to the running directory
|
|
@@ -4210,37 +3808,25 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
4210
3808
|
const reportersFromCLI = resolved.reporter;
|
|
4211
3809
|
const cliReporters = toArray(reportersFromCLI || []).map((reporter) => {
|
|
4212
3810
|
// ./reporter.js || ../reporter.js, but not .reporters/reporter.js
|
|
4213
|
-
if (/^\.\.?\//.test(reporter))
|
|
4214
|
-
return resolve(process.cwd(), reporter);
|
|
4215
|
-
}
|
|
3811
|
+
if (/^\.\.?\//.test(reporter)) return resolve$1(process.cwd(), reporter);
|
|
4216
3812
|
return reporter;
|
|
4217
3813
|
});
|
|
4218
|
-
if (cliReporters.length) {
|
|
4219
|
-
resolved.reporters = Array.from(new Set(toArray(cliReporters))).filter(Boolean).map((reporter) => [reporter, {}]);
|
|
4220
|
-
}
|
|
3814
|
+
if (cliReporters.length) resolved.reporters = Array.from(new Set(toArray(cliReporters))).filter(Boolean).map((reporter) => [reporter, {}]);
|
|
4221
3815
|
}
|
|
4222
3816
|
if (!resolved.reporters.length) {
|
|
4223
3817
|
resolved.reporters.push(["default", {}]);
|
|
4224
3818
|
// also enable github-actions reporter as a default
|
|
4225
|
-
if (process.env.GITHUB_ACTIONS === "true") {
|
|
4226
|
-
resolved.reporters.push(["github-actions", {}]);
|
|
4227
|
-
}
|
|
4228
|
-
}
|
|
4229
|
-
if (resolved.changed) {
|
|
4230
|
-
resolved.passWithNoTests ??= true;
|
|
3819
|
+
if (process.env.GITHUB_ACTIONS === "true") resolved.reporters.push(["github-actions", {}]);
|
|
4231
3820
|
}
|
|
3821
|
+
if (resolved.changed) resolved.passWithNoTests ??= true;
|
|
4232
3822
|
resolved.css ??= {};
|
|
4233
3823
|
if (typeof resolved.css === "object") {
|
|
4234
3824
|
resolved.css.modules ??= {};
|
|
4235
3825
|
resolved.css.modules.classNameStrategy ??= "stable";
|
|
4236
3826
|
}
|
|
4237
3827
|
if (resolved.cache !== false) {
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
logger.console.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} "cache.dir" is deprecated, use Vite's "cacheDir" instead if you want to change the cache director. Note caches will be written to "cacheDir\/vitest"`));
|
|
4241
|
-
cacheDir = VitestCache.resolveCacheDir(resolved.root, resolved.cache.dir, resolved.name);
|
|
4242
|
-
}
|
|
4243
|
-
resolved.cache = { dir: cacheDir };
|
|
3828
|
+
if (resolved.cache && typeof resolved.cache.dir === "string") vitest.logger.deprecate(`"cache.dir" is deprecated, use Vite's "cacheDir" instead if you want to change the cache director. Note caches will be written to "cacheDir\/vitest"`);
|
|
3829
|
+
resolved.cache = { dir: viteConfig.cacheDir };
|
|
4244
3830
|
}
|
|
4245
3831
|
resolved.sequence ??= {};
|
|
4246
3832
|
if (resolved.sequence.shuffle && typeof resolved.sequence.shuffle === "object") {
|
|
@@ -4248,37 +3834,28 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
4248
3834
|
resolved.sequence.sequencer ??= files ? RandomSequencer : BaseSequencer;
|
|
4249
3835
|
resolved.sequence.shuffle = tests;
|
|
4250
3836
|
}
|
|
4251
|
-
if (!resolved.sequence?.sequencer)
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
}
|
|
3837
|
+
if (!resolved.sequence?.sequencer)
|
|
3838
|
+
// CLI flag has higher priority
|
|
3839
|
+
resolved.sequence.sequencer = resolved.sequence.shuffle ? RandomSequencer : BaseSequencer;
|
|
4255
3840
|
resolved.sequence.groupOrder ??= 0;
|
|
4256
3841
|
resolved.sequence.hooks ??= "stack";
|
|
4257
|
-
if (resolved.sequence.sequencer === RandomSequencer)
|
|
4258
|
-
resolved.sequence.seed ??= Date.now();
|
|
4259
|
-
}
|
|
3842
|
+
if (resolved.sequence.sequencer === RandomSequencer) resolved.sequence.seed ??= Date.now();
|
|
4260
3843
|
resolved.typecheck = {
|
|
4261
3844
|
...configDefaults.typecheck,
|
|
4262
3845
|
...resolved.typecheck
|
|
4263
3846
|
};
|
|
4264
|
-
if (resolved.environmentMatchGlobs) {
|
|
4265
|
-
|
|
4266
|
-
}
|
|
4267
|
-
resolved.environmentMatchGlobs = (resolved.environmentMatchGlobs || []).map((i) => [resolve(resolved.root, i[0]), i[1]]);
|
|
3847
|
+
if (resolved.environmentMatchGlobs) logger.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} "environmentMatchGlobs" is deprecated. Use "workspace" to define different configurations instead.`));
|
|
3848
|
+
resolved.environmentMatchGlobs = (resolved.environmentMatchGlobs || []).map((i) => [resolve$1(resolved.root, i[0]), i[1]]);
|
|
4268
3849
|
resolved.typecheck ??= {};
|
|
4269
3850
|
resolved.typecheck.enabled ??= false;
|
|
4270
|
-
if (resolved.typecheck.enabled)
|
|
4271
|
-
logger.console.warn(c.yellow("Testing types with tsc and vue-tsc is an experimental feature.\nBreaking changes might not follow SemVer, please pin Vitest's version when using it."));
|
|
4272
|
-
}
|
|
3851
|
+
if (resolved.typecheck.enabled) logger.console.warn(c.yellow("Testing types with tsc and vue-tsc is an experimental feature.\nBreaking changes might not follow SemVer, please pin Vitest's version when using it."));
|
|
4273
3852
|
resolved.browser.enabled ??= false;
|
|
4274
3853
|
resolved.browser.headless ??= isCI;
|
|
4275
3854
|
resolved.browser.isolate ??= true;
|
|
4276
3855
|
resolved.browser.fileParallelism ??= options.fileParallelism ?? mode !== "benchmark";
|
|
4277
3856
|
// disable in headless mode by default, and if CI is detected
|
|
4278
3857
|
resolved.browser.ui ??= resolved.browser.headless === true ? false : !isCI;
|
|
4279
|
-
if (resolved.browser.screenshotDirectory)
|
|
4280
|
-
resolved.browser.screenshotDirectory = resolve(resolved.root, resolved.browser.screenshotDirectory);
|
|
4281
|
-
}
|
|
3858
|
+
if (resolved.browser.screenshotDirectory) resolved.browser.screenshotDirectory = resolve$1(resolved.root, resolved.browser.screenshotDirectory);
|
|
4282
3859
|
const isPreview = resolved.browser.provider === "preview";
|
|
4283
3860
|
if (isPreview && resolved.browser.screenshotFailures === true) {
|
|
4284
3861
|
console.warn(c.yellow([
|
|
@@ -4287,35 +3864,23 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
4287
3864
|
`Set "browser.screenshotFailures" to false or remove it from the config to suppress this warning.`
|
|
4288
3865
|
].join("")));
|
|
4289
3866
|
resolved.browser.screenshotFailures = false;
|
|
4290
|
-
} else
|
|
4291
|
-
resolved.browser.screenshotFailures ??= !isPreview && !resolved.browser.ui;
|
|
4292
|
-
}
|
|
3867
|
+
} else resolved.browser.screenshotFailures ??= !isPreview && !resolved.browser.ui;
|
|
4293
3868
|
resolved.browser.viewport ??= {};
|
|
4294
3869
|
resolved.browser.viewport.width ??= 414;
|
|
4295
3870
|
resolved.browser.viewport.height ??= 896;
|
|
4296
3871
|
resolved.browser.locators ??= {};
|
|
4297
3872
|
resolved.browser.locators.testIdAttribute ??= "data-testid";
|
|
4298
|
-
if (resolved.browser.enabled && provider === "stackblitz")
|
|
4299
|
-
resolved.browser.provider = "preview";
|
|
4300
|
-
}
|
|
3873
|
+
if (resolved.browser.enabled && provider === "stackblitz") resolved.browser.provider = "preview";
|
|
4301
3874
|
resolved.browser.api = resolveApiServerConfig(resolved.browser, defaultBrowserPort) || { port: defaultBrowserPort };
|
|
4302
3875
|
// enable includeTaskLocation by default in UI mode
|
|
4303
3876
|
if (resolved.browser.enabled) {
|
|
4304
|
-
if (resolved.browser.ui)
|
|
4305
|
-
|
|
4306
|
-
}
|
|
4307
|
-
} else if (resolved.ui) {
|
|
4308
|
-
resolved.includeTaskLocation ??= true;
|
|
4309
|
-
}
|
|
3877
|
+
if (resolved.browser.ui) resolved.includeTaskLocation ??= true;
|
|
3878
|
+
} else if (resolved.ui) resolved.includeTaskLocation ??= true;
|
|
4310
3879
|
const htmlReporter = toArray(resolved.reporters).some((reporter) => {
|
|
4311
|
-
if (Array.isArray(reporter))
|
|
4312
|
-
return reporter[0] === "html";
|
|
4313
|
-
}
|
|
3880
|
+
if (Array.isArray(reporter)) return reporter[0] === "html";
|
|
4314
3881
|
return false;
|
|
4315
3882
|
});
|
|
4316
|
-
if (htmlReporter)
|
|
4317
|
-
resolved.includeTaskLocation ??= true;
|
|
4318
|
-
}
|
|
3883
|
+
if (htmlReporter) resolved.includeTaskLocation ??= true;
|
|
4319
3884
|
resolved.testTransformMode ??= {};
|
|
4320
3885
|
resolved.testTimeout ??= resolved.browser.enabled ? 15e3 : 5e3;
|
|
4321
3886
|
resolved.hookTimeout ??= resolved.browser.enabled ? 3e4 : 1e4;
|
|
@@ -4326,41 +3891,26 @@ function isBrowserEnabled(config) {
|
|
|
4326
3891
|
}
|
|
4327
3892
|
function resolveCoverageReporters(configReporters) {
|
|
4328
3893
|
// E.g. { reporter: "html" }
|
|
4329
|
-
if (!Array.isArray(configReporters)) {
|
|
4330
|
-
return [[configReporters, {}]];
|
|
4331
|
-
}
|
|
3894
|
+
if (!Array.isArray(configReporters)) return [[configReporters, {}]];
|
|
4332
3895
|
const resolvedReporters = [];
|
|
4333
|
-
for (const reporter of configReporters)
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
resolvedReporters.push([reporter, {}]);
|
|
4340
|
-
}
|
|
4341
|
-
}
|
|
3896
|
+
for (const reporter of configReporters) if (Array.isArray(reporter))
|
|
3897
|
+
// E.g. { reporter: [ ["html", { skipEmpty: true }], ["lcov"], ["json", { file: "map.json" }] ]}
|
|
3898
|
+
resolvedReporters.push([reporter[0], reporter[1] || {}]);
|
|
3899
|
+
else
|
|
3900
|
+
// E.g. { reporter: ["html", "json"]}
|
|
3901
|
+
resolvedReporters.push([reporter, {}]);
|
|
4342
3902
|
return resolvedReporters;
|
|
4343
3903
|
}
|
|
4344
3904
|
function isPlaywrightChromiumOnly(vitest, config) {
|
|
4345
3905
|
const browser = config.browser;
|
|
4346
|
-
if (!browser || browser.provider !== "playwright" || !browser.enabled)
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
if (browser.name) {
|
|
4350
|
-
return browser.name === "chromium";
|
|
4351
|
-
}
|
|
4352
|
-
if (!browser.instances) {
|
|
4353
|
-
return false;
|
|
4354
|
-
}
|
|
3906
|
+
if (!browser || browser.provider !== "playwright" || !browser.enabled) return false;
|
|
3907
|
+
if (browser.name) return browser.name === "chromium";
|
|
3908
|
+
if (!browser.instances) return false;
|
|
4355
3909
|
for (const instance of browser.instances) {
|
|
4356
3910
|
const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser);
|
|
4357
3911
|
// browser config is filtered out
|
|
4358
|
-
if (!vitest.matchesProjectFilter(name))
|
|
4359
|
-
|
|
4360
|
-
}
|
|
4361
|
-
if (instance.browser !== "chromium") {
|
|
4362
|
-
return false;
|
|
4363
|
-
}
|
|
3912
|
+
if (!vitest.matchesProjectFilter(name)) continue;
|
|
3913
|
+
if (instance.browser !== "chromium") return false;
|
|
4364
3914
|
}
|
|
4365
3915
|
return true;
|
|
4366
3916
|
}
|
|
@@ -4376,9 +3926,7 @@ const DEFAULT_PROJECT = Symbol.for("default-project");
|
|
|
4376
3926
|
let uniqueId = 0;
|
|
4377
3927
|
async function getCoverageProvider(options, loader) {
|
|
4378
3928
|
const coverageModule = await resolveCoverageProviderModule(options, loader);
|
|
4379
|
-
if (coverageModule)
|
|
4380
|
-
return coverageModule.getProvider();
|
|
4381
|
-
}
|
|
3929
|
+
if (coverageModule) return coverageModule.getProvider();
|
|
4382
3930
|
return null;
|
|
4383
3931
|
}
|
|
4384
3932
|
class BaseCoverageProvider {
|
|
@@ -4386,20 +3934,20 @@ class BaseCoverageProvider {
|
|
|
4386
3934
|
name;
|
|
4387
3935
|
version;
|
|
4388
3936
|
options;
|
|
4389
|
-
coverageFiles = new Map();
|
|
3937
|
+
coverageFiles = /* @__PURE__ */ new Map();
|
|
4390
3938
|
pendingPromises = [];
|
|
4391
3939
|
coverageFilesDirectory;
|
|
4392
3940
|
_initialize(ctx) {
|
|
4393
3941
|
this.ctx = ctx;
|
|
4394
|
-
if (ctx.version !== this.version) {
|
|
4395
|
-
|
|
4396
|
-
|
|
3942
|
+
if (ctx.version !== this.version) ctx.logger.warn(c.yellow(`Loaded ${c.inverse(c.yellow(` vitest@${ctx.version} `))} and ${c.inverse(c.yellow(` @vitest/coverage-${this.name}@${this.version} `))}.
|
|
3943
|
+
Running mixed versions is not supported and may lead into bugs
|
|
3944
|
+
Update your dependencies and make sure the versions match.`));
|
|
4397
3945
|
const config = ctx.config.coverage;
|
|
4398
3946
|
this.options = {
|
|
4399
3947
|
...coverageConfigDefaults,
|
|
4400
3948
|
...config,
|
|
4401
3949
|
provider: this.name,
|
|
4402
|
-
reportsDirectory: resolve(ctx.config.root, config.reportsDirectory || coverageConfigDefaults.reportsDirectory),
|
|
3950
|
+
reportsDirectory: resolve$1(ctx.config.root, config.reportsDirectory || coverageConfigDefaults.reportsDirectory),
|
|
4403
3951
|
reporter: resolveCoverageReporters(config.reporter || coverageConfigDefaults.reporter),
|
|
4404
3952
|
thresholds: config.thresholds && {
|
|
4405
3953
|
...config.thresholds,
|
|
@@ -4411,7 +3959,7 @@ class BaseCoverageProvider {
|
|
|
4411
3959
|
};
|
|
4412
3960
|
const shard = this.ctx.config.shard;
|
|
4413
3961
|
const tempDirectory = `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`;
|
|
4414
|
-
this.coverageFilesDirectory = resolve(this.options.reportsDirectory, tempDirectory);
|
|
3962
|
+
this.coverageFilesDirectory = resolve$1(this.options.reportsDirectory, tempDirectory);
|
|
4415
3963
|
}
|
|
4416
3964
|
createCoverageMap() {
|
|
4417
3965
|
throw new Error("BaseReporter's createCoverageMap was not overwritten");
|
|
@@ -4426,31 +3974,23 @@ class BaseCoverageProvider {
|
|
|
4426
3974
|
return this.options;
|
|
4427
3975
|
}
|
|
4428
3976
|
async clean(clean = true) {
|
|
4429
|
-
if (clean && existsSync(this.options.reportsDirectory)) {
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
force: true,
|
|
4440
|
-
maxRetries: 10
|
|
4441
|
-
});
|
|
4442
|
-
}
|
|
3977
|
+
if (clean && existsSync(this.options.reportsDirectory)) await promises$1.rm(this.options.reportsDirectory, {
|
|
3978
|
+
recursive: true,
|
|
3979
|
+
force: true,
|
|
3980
|
+
maxRetries: 10
|
|
3981
|
+
});
|
|
3982
|
+
if (existsSync(this.coverageFilesDirectory)) await promises$1.rm(this.coverageFilesDirectory, {
|
|
3983
|
+
recursive: true,
|
|
3984
|
+
force: true,
|
|
3985
|
+
maxRetries: 10
|
|
3986
|
+
});
|
|
4443
3987
|
await promises$1.mkdir(this.coverageFilesDirectory, { recursive: true });
|
|
4444
|
-
this.coverageFiles = new Map();
|
|
3988
|
+
this.coverageFiles = /* @__PURE__ */ new Map();
|
|
4445
3989
|
this.pendingPromises = [];
|
|
4446
3990
|
}
|
|
4447
3991
|
onAfterSuiteRun({ coverage, transformMode, projectName, testFiles }) {
|
|
4448
|
-
if (!coverage)
|
|
4449
|
-
|
|
4450
|
-
}
|
|
4451
|
-
if (transformMode !== "web" && transformMode !== "ssr" && transformMode !== "browser") {
|
|
4452
|
-
throw new Error(`Invalid transform mode: ${transformMode}`);
|
|
4453
|
-
}
|
|
3992
|
+
if (!coverage) return;
|
|
3993
|
+
if (transformMode !== "web" && transformMode !== "ssr" && transformMode !== "browser") throw new Error(`Invalid transform mode: ${transformMode}`);
|
|
4454
3994
|
let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT);
|
|
4455
3995
|
if (!entry) {
|
|
4456
3996
|
entry = {
|
|
@@ -4461,7 +4001,7 @@ class BaseCoverageProvider {
|
|
|
4461
4001
|
this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
|
|
4462
4002
|
}
|
|
4463
4003
|
const testFilenames = testFiles.join();
|
|
4464
|
-
const filename = resolve(this.coverageFilesDirectory, `coverage-${uniqueId++}.json`);
|
|
4004
|
+
const filename = resolve$1(this.coverageFilesDirectory, `coverage-${uniqueId++}.json`);
|
|
4465
4005
|
// If there's a result from previous run, overwrite it
|
|
4466
4006
|
entry[transformMode][testFilenames] = filename;
|
|
4467
4007
|
const promise = promises$1.writeFile(filename, JSON.stringify(coverage), "utf-8");
|
|
@@ -4472,53 +4012,43 @@ class BaseCoverageProvider {
|
|
|
4472
4012
|
const total = this.pendingPromises.length;
|
|
4473
4013
|
await Promise.all(this.pendingPromises);
|
|
4474
4014
|
this.pendingPromises = [];
|
|
4475
|
-
for (const [projectName, coveragePerProject] of this.coverageFiles.entries()) {
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
onDebug(`Reading coverage results ${index}/${total}`);
|
|
4483
|
-
}
|
|
4484
|
-
await Promise.all(chunk.map(async (filename) => {
|
|
4485
|
-
const contents = await promises$1.readFile(filename, "utf-8");
|
|
4486
|
-
const coverage = JSON.parse(contents);
|
|
4487
|
-
onFileRead(coverage);
|
|
4488
|
-
}));
|
|
4015
|
+
for (const [projectName, coveragePerProject] of this.coverageFiles.entries()) for (const [transformMode, coverageByTestfiles] of Object.entries(coveragePerProject)) {
|
|
4016
|
+
const filenames = Object.values(coverageByTestfiles);
|
|
4017
|
+
const project = this.ctx.getProjectByName(projectName);
|
|
4018
|
+
for (const chunk of this.toSlices(filenames, this.options.processingConcurrency)) {
|
|
4019
|
+
if (onDebug.enabled) {
|
|
4020
|
+
index += chunk.length;
|
|
4021
|
+
onDebug(`Reading coverage results ${index}/${total}`);
|
|
4489
4022
|
}
|
|
4490
|
-
await
|
|
4023
|
+
await Promise.all(chunk.map(async (filename) => {
|
|
4024
|
+
const contents = await promises$1.readFile(filename, "utf-8");
|
|
4025
|
+
const coverage = JSON.parse(contents);
|
|
4026
|
+
onFileRead(coverage);
|
|
4027
|
+
}));
|
|
4491
4028
|
}
|
|
4029
|
+
await onFinished(project, transformMode);
|
|
4492
4030
|
}
|
|
4493
4031
|
}
|
|
4494
4032
|
async cleanAfterRun() {
|
|
4495
|
-
this.coverageFiles = new Map();
|
|
4033
|
+
this.coverageFiles = /* @__PURE__ */ new Map();
|
|
4496
4034
|
await promises$1.rm(this.coverageFilesDirectory, { recursive: true });
|
|
4497
4035
|
// Remove empty reports directory, e.g. when only text-reporter is used
|
|
4498
|
-
if (readdirSync(this.options.reportsDirectory).length === 0) {
|
|
4499
|
-
await promises$1.rm(this.options.reportsDirectory, { recursive: true });
|
|
4500
|
-
}
|
|
4036
|
+
if (readdirSync(this.options.reportsDirectory).length === 0) await promises$1.rm(this.options.reportsDirectory, { recursive: true });
|
|
4501
4037
|
}
|
|
4502
4038
|
async onTestFailure() {
|
|
4503
|
-
if (!this.options.reportOnFailure)
|
|
4504
|
-
await this.cleanAfterRun();
|
|
4505
|
-
}
|
|
4039
|
+
if (!this.options.reportOnFailure) await this.cleanAfterRun();
|
|
4506
4040
|
}
|
|
4507
4041
|
async reportCoverage(coverageMap, { allTestsRun }) {
|
|
4508
4042
|
await this.generateReports(coverageMap || this.createCoverageMap(), allTestsRun);
|
|
4509
4043
|
// In watch mode we need to preserve the previous results if cleanOnRerun is disabled
|
|
4510
4044
|
const keepResults = !this.options.cleanOnRerun && this.ctx.config.watch;
|
|
4511
|
-
if (!keepResults)
|
|
4512
|
-
await this.cleanAfterRun();
|
|
4513
|
-
}
|
|
4045
|
+
if (!keepResults) await this.cleanAfterRun();
|
|
4514
4046
|
}
|
|
4515
4047
|
async reportThresholds(coverageMap, allTestsRun) {
|
|
4516
4048
|
const resolvedThresholds = this.resolveThresholds(coverageMap);
|
|
4517
4049
|
this.checkThresholds(resolvedThresholds);
|
|
4518
4050
|
if (this.options.thresholds?.autoUpdate && allTestsRun) {
|
|
4519
|
-
if (!this.ctx.server.config.configFile)
|
|
4520
|
-
throw new Error("Missing configurationFile. The \"coverage.thresholds.autoUpdate\" can only be enabled when configuration file is used.");
|
|
4521
|
-
}
|
|
4051
|
+
if (!this.ctx.server.config.configFile) throw new Error("Missing configurationFile. The \"coverage.thresholds.autoUpdate\" can only be enabled when configuration file is used.");
|
|
4522
4052
|
const configFilePath = this.ctx.server.config.configFile;
|
|
4523
4053
|
const configModule = await this.parseConfigModule(configFilePath);
|
|
4524
4054
|
await this.updateThresholds({
|
|
@@ -4538,9 +4068,7 @@ class BaseCoverageProvider {
|
|
|
4538
4068
|
const files = coverageMap.files();
|
|
4539
4069
|
const globalCoverageMap = this.createCoverageMap();
|
|
4540
4070
|
for (const key of Object.keys(this.options.thresholds)) {
|
|
4541
|
-
if (key === "perFile" || key === "autoUpdate" || key === "100" || THRESHOLD_KEYS.includes(key))
|
|
4542
|
-
continue;
|
|
4543
|
-
}
|
|
4071
|
+
if (key === "perFile" || key === "autoUpdate" || key === "100" || THRESHOLD_KEYS.includes(key)) continue;
|
|
4544
4072
|
const glob = key;
|
|
4545
4073
|
const globThresholds = resolveGlobThresholds(this.options.thresholds[glob]);
|
|
4546
4074
|
const globCoverageMap = this.createCoverageMap();
|
|
@@ -4578,9 +4106,7 @@ class BaseCoverageProvider {
|
|
|
4578
4106
|
*/
|
|
4579
4107
|
checkThresholds(allThresholds) {
|
|
4580
4108
|
for (const { coverageMap, thresholds, name } of allThresholds) {
|
|
4581
|
-
if (thresholds.branches ===
|
|
4582
|
-
continue;
|
|
4583
|
-
}
|
|
4109
|
+
if (thresholds.branches === void 0 && thresholds.functions === void 0 && thresholds.lines === void 0 && thresholds.statements === void 0) continue;
|
|
4584
4110
|
// Construct list of coverage summaries where thresholds are compared against
|
|
4585
4111
|
const summaries = this.options.thresholds?.perFile ? coverageMap.files().map((file) => ({
|
|
4586
4112
|
file,
|
|
@@ -4590,47 +4116,39 @@ class BaseCoverageProvider {
|
|
|
4590
4116
|
summary: coverageMap.getCoverageSummary()
|
|
4591
4117
|
}];
|
|
4592
4118
|
// Check thresholds of each summary
|
|
4593
|
-
for (const { summary, file } of summaries) {
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4119
|
+
for (const { summary, file } of summaries) for (const thresholdKey of THRESHOLD_KEYS) {
|
|
4120
|
+
const threshold = thresholds[thresholdKey];
|
|
4121
|
+
if (threshold === void 0) continue;
|
|
4122
|
+
/**
|
|
4123
|
+
* Positive thresholds are treated as minimum coverage percentages (X means: X% of lines must be covered),
|
|
4124
|
+
* while negative thresholds are treated as maximum uncovered counts (-X means: X lines may be uncovered).
|
|
4125
|
+
*/
|
|
4126
|
+
if (threshold >= 0) {
|
|
4127
|
+
const coverage = summary.data[thresholdKey].pct;
|
|
4128
|
+
if (coverage < threshold) {
|
|
4129
|
+
process.exitCode = 1;
|
|
4130
|
+
/**
|
|
4131
|
+
* Generate error message based on perFile flag:
|
|
4132
|
+
* - ERROR: Coverage for statements (33.33%) does not meet threshold (85%) for src/math.ts
|
|
4133
|
+
* - ERROR: Coverage for statements (50%) does not meet global threshold (85%)
|
|
4134
|
+
*/
|
|
4135
|
+
let errorMessage = `ERROR: Coverage for ${thresholdKey} (${coverage}%) does not meet ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${threshold}%)`;
|
|
4136
|
+
if (this.options.thresholds?.perFile && file) errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
|
|
4137
|
+
this.ctx.logger.error(errorMessage);
|
|
4598
4138
|
}
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
let errorMessage = `ERROR: Coverage for ${thresholdKey} (${coverage}%) does not meet ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${threshold}%)`;
|
|
4613
|
-
if (this.options.thresholds?.perFile && file) {
|
|
4614
|
-
errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
|
|
4615
|
-
}
|
|
4616
|
-
this.ctx.logger.error(errorMessage);
|
|
4617
|
-
}
|
|
4618
|
-
} else {
|
|
4619
|
-
const uncovered = summary.data[thresholdKey].total - summary.data[thresholdKey].covered;
|
|
4620
|
-
const absoluteThreshold = threshold * -1;
|
|
4621
|
-
if (uncovered > absoluteThreshold) {
|
|
4622
|
-
process.exitCode = 1;
|
|
4623
|
-
/**
|
|
4624
|
-
* Generate error message based on perFile flag:
|
|
4625
|
-
* - ERROR: Uncovered statements (33) exceed threshold (30) for src/math.ts
|
|
4626
|
-
* - ERROR: Uncovered statements (33) exceed global threshold (30)
|
|
4627
|
-
*/
|
|
4628
|
-
let errorMessage = `ERROR: Uncovered ${thresholdKey} (${uncovered}) exceed ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${absoluteThreshold})`;
|
|
4629
|
-
if (this.options.thresholds?.perFile && file) {
|
|
4630
|
-
errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
|
|
4631
|
-
}
|
|
4632
|
-
this.ctx.logger.error(errorMessage);
|
|
4633
|
-
}
|
|
4139
|
+
} else {
|
|
4140
|
+
const uncovered = summary.data[thresholdKey].total - summary.data[thresholdKey].covered;
|
|
4141
|
+
const absoluteThreshold = threshold * -1;
|
|
4142
|
+
if (uncovered > absoluteThreshold) {
|
|
4143
|
+
process.exitCode = 1;
|
|
4144
|
+
/**
|
|
4145
|
+
* Generate error message based on perFile flag:
|
|
4146
|
+
* - ERROR: Uncovered statements (33) exceed threshold (30) for src/math.ts
|
|
4147
|
+
* - ERROR: Uncovered statements (33) exceed global threshold (30)
|
|
4148
|
+
*/
|
|
4149
|
+
let errorMessage = `ERROR: Uncovered ${thresholdKey} (${uncovered}) exceed ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${absoluteThreshold})`;
|
|
4150
|
+
if (this.options.thresholds?.perFile && file) errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
|
|
4151
|
+
this.ctx.logger.error(errorMessage);
|
|
4634
4152
|
}
|
|
4635
4153
|
}
|
|
4636
4154
|
}
|
|
@@ -4654,9 +4172,7 @@ class BaseCoverageProvider {
|
|
|
4654
4172
|
*/
|
|
4655
4173
|
if (threshold >= 0) {
|
|
4656
4174
|
const actual = Math.min(...summaries.map((summary) => summary[key].pct));
|
|
4657
|
-
if (actual > threshold)
|
|
4658
|
-
thresholdsToUpdate.push([key, actual]);
|
|
4659
|
-
}
|
|
4175
|
+
if (actual > threshold) thresholdsToUpdate.push([key, actual]);
|
|
4660
4176
|
} else {
|
|
4661
4177
|
const absoluteThreshold = threshold * -1;
|
|
4662
4178
|
const actual = Math.max(...summaries.map((summary) => summary[key].total - summary[key].covered));
|
|
@@ -4667,17 +4183,12 @@ class BaseCoverageProvider {
|
|
|
4667
4183
|
}
|
|
4668
4184
|
}
|
|
4669
4185
|
}
|
|
4670
|
-
if (thresholdsToUpdate.length === 0)
|
|
4671
|
-
continue;
|
|
4672
|
-
}
|
|
4186
|
+
if (thresholdsToUpdate.length === 0) continue;
|
|
4673
4187
|
updatedThresholds = true;
|
|
4674
|
-
for (const [threshold, newValue] of thresholdsToUpdate)
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
const glob = config.test.coverage.thresholds[name];
|
|
4679
|
-
glob[threshold] = newValue;
|
|
4680
|
-
}
|
|
4188
|
+
for (const [threshold, newValue] of thresholdsToUpdate) if (name === GLOBAL_THRESHOLDS_KEY) config.test.coverage.thresholds[threshold] = newValue;
|
|
4189
|
+
else {
|
|
4190
|
+
const glob = config.test.coverage.thresholds[name];
|
|
4191
|
+
glob[threshold] = newValue;
|
|
4681
4192
|
}
|
|
4682
4193
|
}
|
|
4683
4194
|
if (updatedThresholds) {
|
|
@@ -4687,9 +4198,7 @@ class BaseCoverageProvider {
|
|
|
4687
4198
|
}
|
|
4688
4199
|
async mergeReports(coverageMaps) {
|
|
4689
4200
|
const coverageMap = this.createCoverageMap();
|
|
4690
|
-
for (const coverage of coverageMaps)
|
|
4691
|
-
coverageMap.merge(coverage);
|
|
4692
|
-
}
|
|
4201
|
+
for (const coverage of coverageMaps) coverageMap.merge(coverage);
|
|
4693
4202
|
await this.generateReports(coverageMap, true);
|
|
4694
4203
|
}
|
|
4695
4204
|
hasTerminalReporter(reporters) {
|
|
@@ -4700,11 +4209,8 @@ class BaseCoverageProvider {
|
|
|
4700
4209
|
const index = Math.max(0, chunks.length - 1);
|
|
4701
4210
|
const lastChunk = chunks[index] || [];
|
|
4702
4211
|
chunks[index] = lastChunk;
|
|
4703
|
-
if (lastChunk.length >= size)
|
|
4704
|
-
|
|
4705
|
-
} else {
|
|
4706
|
-
lastChunk.push(item);
|
|
4707
|
-
}
|
|
4212
|
+
if (lastChunk.length >= size) chunks.push([item]);
|
|
4213
|
+
else lastChunk.push(item);
|
|
4708
4214
|
return chunks;
|
|
4709
4215
|
}, []);
|
|
4710
4216
|
}
|
|
@@ -4722,14 +4228,10 @@ class BaseCoverageProvider {
|
|
|
4722
4228
|
let lastError;
|
|
4723
4229
|
for (const { root, vitenode, isBrowserEnabled } of servers) {
|
|
4724
4230
|
// On Windows root doesn't start with "/" while filenames do
|
|
4725
|
-
if (!filename.startsWith(root) && !filename.startsWith(`/${root}`))
|
|
4726
|
-
continue;
|
|
4727
|
-
}
|
|
4231
|
+
if (!filename.startsWith(root) && !filename.startsWith(`/${root}`)) continue;
|
|
4728
4232
|
if (isBrowserEnabled) {
|
|
4729
|
-
const result = await vitenode.transformRequest(filename,
|
|
4730
|
-
if (result)
|
|
4731
|
-
return result;
|
|
4732
|
-
}
|
|
4233
|
+
const result = await vitenode.transformRequest(filename, void 0, "web").catch(() => null);
|
|
4234
|
+
if (result) return result;
|
|
4733
4235
|
}
|
|
4734
4236
|
try {
|
|
4735
4237
|
return await vitenode.transformRequest(filename);
|
|
@@ -4746,30 +4248,24 @@ class BaseCoverageProvider {
|
|
|
4746
4248
|
* Narrow down `unknown` glob thresholds to resolved ones
|
|
4747
4249
|
*/
|
|
4748
4250
|
function resolveGlobThresholds(thresholds) {
|
|
4749
|
-
if (!thresholds || typeof thresholds !== "object") {
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
functions: 100,
|
|
4757
|
-
statements: 100
|
|
4758
|
-
};
|
|
4759
|
-
}
|
|
4251
|
+
if (!thresholds || typeof thresholds !== "object") return {};
|
|
4252
|
+
if (100 in thresholds && thresholds[100] === true) return {
|
|
4253
|
+
lines: 100,
|
|
4254
|
+
branches: 100,
|
|
4255
|
+
functions: 100,
|
|
4256
|
+
statements: 100
|
|
4257
|
+
};
|
|
4760
4258
|
return {
|
|
4761
|
-
lines: "lines" in thresholds && typeof thresholds.lines === "number" ? thresholds.lines :
|
|
4762
|
-
branches: "branches" in thresholds && typeof thresholds.branches === "number" ? thresholds.branches :
|
|
4763
|
-
functions: "functions" in thresholds && typeof thresholds.functions === "number" ? thresholds.functions :
|
|
4764
|
-
statements: "statements" in thresholds && typeof thresholds.statements === "number" ? thresholds.statements :
|
|
4259
|
+
lines: "lines" in thresholds && typeof thresholds.lines === "number" ? thresholds.lines : void 0,
|
|
4260
|
+
branches: "branches" in thresholds && typeof thresholds.branches === "number" ? thresholds.branches : void 0,
|
|
4261
|
+
functions: "functions" in thresholds && typeof thresholds.functions === "number" ? thresholds.functions : void 0,
|
|
4262
|
+
statements: "statements" in thresholds && typeof thresholds.statements === "number" ? thresholds.statements : void 0
|
|
4765
4263
|
};
|
|
4766
4264
|
}
|
|
4767
4265
|
function assertConfigurationModule(config) {
|
|
4768
4266
|
try {
|
|
4769
4267
|
// @ts-expect-error -- Intentional unsafe null pointer check as wrapped in try-catch
|
|
4770
|
-
if (typeof config.test.coverage.thresholds !== "object")
|
|
4771
|
-
throw new TypeError("Expected config.test.coverage.thresholds to be an object");
|
|
4772
|
-
}
|
|
4268
|
+
if (typeof config.test.coverage.thresholds !== "object") throw new TypeError("Expected config.test.coverage.thresholds to be an object");
|
|
4773
4269
|
} catch (error) {
|
|
4774
4270
|
const message = error instanceof Error ? error.message : String(error);
|
|
4775
4271
|
throw new Error(`Unable to parse thresholds from configuration file: ${message}`);
|
|
@@ -4779,20 +4275,14 @@ function resolveConfig(configModule) {
|
|
|
4779
4275
|
const mod = configModule.exports.default;
|
|
4780
4276
|
try {
|
|
4781
4277
|
// Check for "export default { test: {...} }"
|
|
4782
|
-
if (mod.$type === "object")
|
|
4783
|
-
return mod;
|
|
4784
|
-
}
|
|
4278
|
+
if (mod.$type === "object") return mod;
|
|
4785
4279
|
// "export default defineConfig(...)"
|
|
4786
4280
|
let config = resolveDefineConfig(mod);
|
|
4787
|
-
if (config)
|
|
4788
|
-
return config;
|
|
4789
|
-
}
|
|
4281
|
+
if (config) return config;
|
|
4790
4282
|
// "export default mergeConfig(..., defineConfig(...))"
|
|
4791
4283
|
if (mod.$type === "function-call" && mod.$callee === "mergeConfig") {
|
|
4792
4284
|
config = resolveMergeConfig(mod);
|
|
4793
|
-
if (config)
|
|
4794
|
-
return config;
|
|
4795
|
-
}
|
|
4285
|
+
if (config) return config;
|
|
4796
4286
|
}
|
|
4797
4287
|
} catch (error) {
|
|
4798
4288
|
// Reduce magicast's verbose errors to readable ones
|
|
@@ -4803,31 +4293,22 @@ function resolveConfig(configModule) {
|
|
|
4803
4293
|
function resolveDefineConfig(mod) {
|
|
4804
4294
|
if (mod.$type === "function-call" && mod.$callee === "defineConfig") {
|
|
4805
4295
|
// "export default defineConfig({ test: {...} })"
|
|
4806
|
-
if (mod.$args[0].$type === "object")
|
|
4807
|
-
return mod.$args[0];
|
|
4808
|
-
}
|
|
4296
|
+
if (mod.$args[0].$type === "object") return mod.$args[0];
|
|
4809
4297
|
if (mod.$args[0].$type === "arrow-function-expression") {
|
|
4810
|
-
if (mod.$args[0].$body.$type === "object")
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
}
|
|
4298
|
+
if (mod.$args[0].$body.$type === "object")
|
|
4299
|
+
// "export default defineConfig(() => ({ test: {...} }))"
|
|
4300
|
+
return mod.$args[0].$body;
|
|
4814
4301
|
// "export default defineConfig(() => mergeConfig({...}, ...))"
|
|
4815
4302
|
const config = resolveMergeConfig(mod.$args[0].$body);
|
|
4816
|
-
if (config)
|
|
4817
|
-
return config;
|
|
4818
|
-
}
|
|
4303
|
+
if (config) return config;
|
|
4819
4304
|
}
|
|
4820
4305
|
}
|
|
4821
4306
|
}
|
|
4822
4307
|
function resolveMergeConfig(mod) {
|
|
4823
|
-
if (mod.$type === "function-call" && mod.$callee === "mergeConfig") {
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
if (config) {
|
|
4827
|
-
return config;
|
|
4828
|
-
}
|
|
4829
|
-
}
|
|
4308
|
+
if (mod.$type === "function-call" && mod.$callee === "mergeConfig") for (const arg of mod.$args) {
|
|
4309
|
+
const config = resolveDefineConfig(arg);
|
|
4310
|
+
if (config) return config;
|
|
4830
4311
|
}
|
|
4831
4312
|
}
|
|
4832
4313
|
|
|
4833
|
-
export { BaseCoverageProvider as B, RandomSequencer as R,
|
|
4314
|
+
export { BaseCoverageProvider as B, RandomSequencer as R, resolveApiServerConfig as a, BaseSequencer as b, createMethodsRPC as c, isBrowserEnabled as d, groupBy as e, getCoverageProvider as f, getFilePoolName as g, hash as h, isPackageExists as i, createPool as j, resolveConfig$1 as r, stdout as s, wildcardPatternToRegExp as w };
|