vitest 4.0.0-beta.4 → 4.0.0-beta.6
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 +1 -1
- package/dist/browser.d.ts +8 -9
- package/dist/browser.js +3 -2
- package/dist/chunks/base.BXI97p6t.js +39 -0
- package/dist/chunks/{benchmark.CYdenmiT.js → benchmark.UW6Ezvxy.js} +6 -8
- package/dist/chunks/{browser.d.BRP8scJf.d.ts → browser.d.Cawq_X_N.d.ts} +1 -1
- package/dist/chunks/{cac.CY0IAxC4.js → cac.WE-urWw5.js} +38 -115
- package/dist/chunks/{cli-api.B8xRY9Zt.js → cli-api.CZz3evYC.js} +931 -1439
- package/dist/chunks/{config.d.DZo8c7fw.d.ts → config.d.CKNVOKm0.d.ts} +3 -8
- package/dist/chunks/{console.DoJHFxmj.js → console.B0quX7yH.js} +32 -68
- package/dist/chunks/{constants.CXzqaLmq.js → constants.D_Q9UYh-.js} +1 -6
- package/dist/chunks/{coverage.C84l9G-M.js → coverage.BPRS6xgn.js} +395 -665
- package/dist/chunks/{coverage.DVF1vEu8.js → coverage.D_JHT54q.js} +2 -2
- package/dist/chunks/{coverage.d.CNYjU4GF.d.ts → coverage.d.BZtK59WP.d.ts} +7 -5
- package/dist/chunks/{creator.yfA2ExGt.js → creator.KEg6n5IC.js} +29 -75
- package/dist/chunks/{date.Bq6ZW5rf.js → date.-jtEtIeV.js} +6 -17
- package/dist/chunks/{environment.d.Bhm9oc0v.d.ts → environment.d.2fYMoz3o.d.ts} +26 -4
- package/dist/chunks/{git.BVQ8w_Sw.js → git.BFNcloKD.js} +1 -2
- package/dist/chunks/{global.d.DAhT2emn.d.ts → global.d.K6uBQHzY.d.ts} +1 -1
- package/dist/chunks/{globals.Dgo-vS5G.js → globals.lgsmH00r.js} +7 -6
- package/dist/chunks/{index.D3SKT3tv.js → index.7w0eqmYM.js} +14 -24
- package/dist/chunks/{index.D1_MsKEt.js → index.AR8aAkCC.js} +4 -2
- package/dist/chunks/{index.CmSc2RE5.js → index.BG0gqZH-.js} +43 -106
- package/dist/chunks/{index.CtUvr1c8.js → index.CsFXYRkW.js} +27 -46
- package/dist/chunks/{index.Bz6b0Ib7.js → index.VNI-1z5c.js} +276 -604
- package/dist/chunks/{inspector.C914Efll.js → inspector.CvQD-Nie.js} +10 -25
- package/dist/chunks/moduleRunner.d.8kKUsuDg.d.ts +202 -0
- package/dist/chunks/moduleTransport.I-bgQy0S.js +19 -0
- package/dist/chunks/{node.fjCdwEIl.js → node.BOqcT2jW.js} +1 -1
- package/dist/chunks/{plugin.d.CLhMcYdD.d.ts → plugin.d.DuiQJfUL.d.ts} +1 -1
- package/dist/chunks/{reporters.d.DWg40D2B.d.ts → reporters.d.CqR9-CDJ.d.ts} +52 -101
- package/dist/chunks/resolver.Bx6lE0iq.js +119 -0
- package/dist/chunks/{rpc.jnQO9F8a.js → rpc.RpPylpp0.js} +7 -21
- package/dist/chunks/runBaseTests.D6sfuWBM.js +99 -0
- package/dist/chunks/{setup-common.Ebx5x0eP.js → setup-common.hLGRxhC8.js} +15 -27
- package/dist/chunks/startModuleRunner.C8TW8zTN.js +655 -0
- package/dist/chunks/{typechecker.CMNPqJOo.js → typechecker.Cd1wvxUM.js} +97 -209
- package/dist/chunks/{utils.CcGm2cd1.js → utils.C2YI6McM.js} +4 -13
- package/dist/chunks/{utils.XdZDrNZV.js → utils.C7__0Iv5.js} +7 -17
- package/dist/chunks/{vi.CA0EPI9Y.js → vi.BfdOiD4j.js} +116 -269
- package/dist/chunks/{vm.BUnLJt_P.js → vm.BHBje7cC.js} +101 -225
- package/dist/chunks/{worker.d.zjyR34Pb.d.ts → worker.d.D9QWnzAe.d.ts} +16 -13
- package/dist/chunks/{worker.d.C-1AbnVe.d.ts → worker.d.Db-UVmXc.d.ts} +1 -1
- package/dist/cli.js +4 -4
- package/dist/config.cjs +3 -9
- package/dist/config.d.ts +10 -12
- package/dist/config.js +1 -1
- package/dist/coverage.d.ts +10 -11
- package/dist/coverage.js +5 -6
- package/dist/environments.d.ts +2 -2
- package/dist/environments.js +1 -1
- package/dist/index.d.ts +10 -9
- package/dist/index.js +6 -5
- package/dist/module-evaluator.d.ts +12 -0
- package/dist/module-evaluator.js +276 -0
- package/dist/module-runner.js +15 -0
- package/dist/node.d.ts +12 -13
- package/dist/node.js +19 -24
- package/dist/reporters.d.ts +7 -8
- package/dist/reporters.js +3 -3
- package/dist/runners.d.ts +3 -3
- package/dist/runners.js +35 -57
- package/dist/snapshot.js +2 -2
- package/dist/suite.js +2 -2
- package/dist/worker.js +82 -45
- package/dist/workers/forks.js +11 -10
- package/dist/workers/runVmTests.js +27 -46
- package/dist/workers/threads.js +11 -10
- package/dist/workers/vmForks.js +11 -10
- package/dist/workers/vmThreads.js +11 -10
- package/dist/workers.d.ts +5 -4
- package/dist/workers.js +17 -16
- package/package.json +22 -17
- package/dist/chunks/base.BaCDDRPG.js +0 -38
- package/dist/chunks/execute.Dt-pCVcL.js +0 -708
- package/dist/chunks/runBaseTests.DBVVLMSb.js +0 -129
- package/dist/execute.d.ts +0 -148
- package/dist/execute.js +0 -13
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import fs, { statSync, realpathSync, promises as promises$1, mkdirSync, existsSync, readdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import path, { win32, dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { isExternalUrl, unwrapId, nanoid, withTrailingSlash as withTrailingSlash$1, cleanUrl, wrapId, createDefer, slash, shuffle, toArray } from '@vitest/utils';
|
|
3
4
|
import { isAbsolute, join as join$1, dirname as dirname$1, resolve as resolve$1, relative, normalize } from 'pathe';
|
|
4
5
|
import pm from 'picomatch';
|
|
5
6
|
import { glob } from 'tinyglobby';
|
|
6
7
|
import c from 'tinyrainbow';
|
|
7
|
-
import { slash, cleanUrl } from 'vite-node/utils';
|
|
8
8
|
import { c as configDefaults, e as benchmarkConfigDefaults, a as coverageConfigDefaults } from './defaults.CXFFjsi8.js';
|
|
9
9
|
import crypto from 'node:crypto';
|
|
10
|
-
import { createDefer, shuffle, toArray, slash as slash$1 } from '@vitest/utils';
|
|
11
10
|
import { builtinModules, createRequire } from 'node:module';
|
|
12
11
|
import process$1 from 'node:process';
|
|
13
12
|
import fs$1, { writeFile, rename, stat, unlink } from 'node:fs/promises';
|
|
@@ -15,28 +14,26 @@ import { fileURLToPath as fileURLToPath$1, pathToFileURL as pathToFileURL$1, URL
|
|
|
15
14
|
import assert from 'node:assert';
|
|
16
15
|
import v8 from 'node:v8';
|
|
17
16
|
import { format, inspect } from 'node:util';
|
|
18
|
-
import { version, mergeConfig } from 'vite';
|
|
19
|
-
import { c as configFiles,
|
|
17
|
+
import { fetchModule, version, mergeConfig } from 'vite';
|
|
18
|
+
import { c as configFiles, d as defaultBrowserPort, b as defaultInspectPort, a as defaultPort } from './constants.D_Q9UYh-.js';
|
|
20
19
|
import { a as isWindows } from './env.D4Lgay0q.js';
|
|
21
20
|
import * as nodeos from 'node:os';
|
|
22
|
-
import nodeos__default from 'node:os';
|
|
21
|
+
import nodeos__default, { tmpdir } from 'node:os';
|
|
23
22
|
import { isatty } from 'node:tty';
|
|
24
23
|
import EventEmitter from 'node:events';
|
|
25
24
|
import { c as createBirpc } from './index.Bgo3tNWt.js';
|
|
26
25
|
import Tinypool$1, { Tinypool } from 'tinypool';
|
|
27
|
-
import { w as wrapSerializableConfig, a as Typechecker } from './typechecker.
|
|
26
|
+
import { w as wrapSerializableConfig, a as Typechecker } from './typechecker.Cd1wvxUM.js';
|
|
28
27
|
import { MessageChannel } from 'node:worker_threads';
|
|
29
28
|
import { hasFailed } from '@vitest/runner/utils';
|
|
30
29
|
import { rootDir } from '../path.js';
|
|
31
30
|
import { isCI, provider } from 'std-env';
|
|
32
|
-
import { r as resolveCoverageProviderModule } from './coverage.
|
|
31
|
+
import { r as resolveCoverageProviderModule } from './coverage.D_JHT54q.js';
|
|
33
32
|
|
|
34
33
|
function groupBy(collection, iteratee) {
|
|
35
34
|
return collection.reduce((acc, item) => {
|
|
36
35
|
const key = iteratee(item);
|
|
37
|
-
acc[key] ||= [];
|
|
38
|
-
acc[key].push(item);
|
|
39
|
-
return acc;
|
|
36
|
+
return acc[key] ||= [], acc[key].push(item), acc;
|
|
40
37
|
}, {});
|
|
41
38
|
}
|
|
42
39
|
function stdout() {
|
|
@@ -2385,8 +2382,7 @@ const isPackageListed = quansync(function* (name, cwd) {
|
|
|
2385
2382
|
isPackageListed.sync;
|
|
2386
2383
|
|
|
2387
2384
|
function getWorkersCountByPercentage(percent) {
|
|
2388
|
-
const maxWorkersCount = nodeos__default.availableParallelism?.() ?? nodeos__default.cpus().length;
|
|
2389
|
-
const workersCountByPercentage = Math.round(Number.parseInt(percent) / 100 * maxWorkersCount);
|
|
2385
|
+
const maxWorkersCount = nodeos__default.availableParallelism?.() ?? nodeos__default.cpus().length, workersCountByPercentage = Math.round(Number.parseInt(percent) / 100 * maxWorkersCount);
|
|
2390
2386
|
return Math.max(1, Math.min(maxWorkersCount, workersCountByPercentage));
|
|
2391
2387
|
}
|
|
2392
2388
|
|
|
@@ -2396,11 +2392,6 @@ const envsOrder = [
|
|
|
2396
2392
|
"happy-dom",
|
|
2397
2393
|
"edge-runtime"
|
|
2398
2394
|
];
|
|
2399
|
-
function getTransformMode(patterns, filename) {
|
|
2400
|
-
if (patterns.web && pm.isMatch(filename, patterns.web)) return "web";
|
|
2401
|
-
if (patterns.ssr && pm.isMatch(filename, patterns.ssr)) return "ssr";
|
|
2402
|
-
return void 0;
|
|
2403
|
-
}
|
|
2404
2395
|
async function groupFilesByEnv(files) {
|
|
2405
2396
|
const filesWithEnv = await Promise.all(files.map(async ({ moduleId: filepath, project, testLines }) => {
|
|
2406
2397
|
const code = await promises$1.readFile(filepath, "utf-8");
|
|
@@ -2408,16 +2399,12 @@ async function groupFilesByEnv(files) {
|
|
|
2408
2399
|
let env = code.match(/@(?:vitest|jest)-environment\s+([\w-]+)\b/)?.[1];
|
|
2409
2400
|
// 2. Fallback to global env
|
|
2410
2401
|
env ||= project.config.environment || "node";
|
|
2411
|
-
const transformMode = getTransformMode(project.config.testTransformMode, filepath);
|
|
2412
2402
|
let envOptionsJson = code.match(/@(?:vitest|jest)-environment-options\s+(.+)/)?.[1];
|
|
2413
2403
|
if (envOptionsJson?.endsWith("*/"))
|
|
2414
2404
|
// Trim closing Docblock characters the above regex might have captured
|
|
2415
2405
|
envOptionsJson = envOptionsJson.slice(0, -2);
|
|
2416
|
-
const envOptions = JSON.parse(envOptionsJson || "null")
|
|
2417
|
-
const envKey = env === "happy-dom" ? "happyDOM" : env;
|
|
2418
|
-
const environment = {
|
|
2406
|
+
const envOptions = JSON.parse(envOptionsJson || "null"), envKey = env === "happy-dom" ? "happyDOM" : env, environment = {
|
|
2419
2407
|
name: env,
|
|
2420
|
-
transformMode,
|
|
2421
2408
|
options: envOptions ? { [envKey]: envOptions } : null
|
|
2422
2409
|
};
|
|
2423
2410
|
return {
|
|
@@ -2432,45 +2419,198 @@ async function groupFilesByEnv(files) {
|
|
|
2432
2419
|
return groupBy(filesWithEnv, ({ environment }) => environment.name);
|
|
2433
2420
|
}
|
|
2434
2421
|
|
|
2435
|
-
const created = /* @__PURE__ */ new Set();
|
|
2436
|
-
|
|
2422
|
+
const created = /* @__PURE__ */ new Set(), promises = /* @__PURE__ */ new Map();
|
|
2423
|
+
function createFetchModuleFunction(resolver, cacheFs = false, tmpDir = join$1(tmpdir(), nanoid())) {
|
|
2424
|
+
const cachedFsResults = /* @__PURE__ */ new Map();
|
|
2425
|
+
return async (url, importer, environment, options) => {
|
|
2426
|
+
// We are copy pasting Vite's externalization logic from `fetchModule` because
|
|
2427
|
+
// we instead rely on our own `shouldExternalize` method because Vite
|
|
2428
|
+
// doesn't support `resolve.external` in non SSR environments (jsdom/happy-dom)
|
|
2429
|
+
if (url.startsWith("data:")) return {
|
|
2430
|
+
externalize: url,
|
|
2431
|
+
type: "builtin"
|
|
2432
|
+
};
|
|
2433
|
+
if (url === "/@vite/client" || url === "@vite/client")
|
|
2434
|
+
// this will be stubbed
|
|
2435
|
+
return {
|
|
2436
|
+
externalize: "/@vite/client",
|
|
2437
|
+
type: "module"
|
|
2438
|
+
};
|
|
2439
|
+
const isFileUrl = url.startsWith("file://");
|
|
2440
|
+
if (isExternalUrl(url) && !isFileUrl) return {
|
|
2441
|
+
externalize: url,
|
|
2442
|
+
type: "network"
|
|
2443
|
+
};
|
|
2444
|
+
// Vite does the same in `fetchModule`, but we want to externalize modules ourselves,
|
|
2445
|
+
// so we do this first to resolve the module and check its `id`. The next call of
|
|
2446
|
+
// `ensureEntryFromUrl` inside `fetchModule` is cached and should take no time
|
|
2447
|
+
// This also makes it so externalized modules are inside the module graph.
|
|
2448
|
+
const moduleGraphModule = await environment.moduleGraph.ensureEntryFromUrl(unwrapId(url)), cached = !!moduleGraphModule.transformResult;
|
|
2449
|
+
// if url is already cached, we can just confirm it's also cached on the server
|
|
2450
|
+
if (options?.cached && cached) return { cache: true };
|
|
2451
|
+
if (moduleGraphModule.id) {
|
|
2452
|
+
const externalize = await resolver.shouldExternalize(moduleGraphModule.id);
|
|
2453
|
+
if (externalize) return {
|
|
2454
|
+
externalize,
|
|
2455
|
+
type: "module"
|
|
2456
|
+
};
|
|
2457
|
+
}
|
|
2458
|
+
const moduleRunnerModule = await fetchModule(environment, url, importer, {
|
|
2459
|
+
...options,
|
|
2460
|
+
inlineSourceMap: false
|
|
2461
|
+
}).catch(handleRollupError), result = processResultSource(environment, moduleRunnerModule);
|
|
2462
|
+
if (!cacheFs || !("code" in result)) return result;
|
|
2463
|
+
const code = result.code;
|
|
2464
|
+
// to avoid serialising large chunks of code,
|
|
2465
|
+
// we store them in a tmp file and read in the test thread
|
|
2466
|
+
if (cachedFsResults.has(result.id)) return getCachedResult(result, cachedFsResults);
|
|
2467
|
+
const dir = join$1(tmpDir, environment.name), name = hash("sha1", result.id, "hex"), tmp = join$1(dir, name);
|
|
2468
|
+
if (!created.has(dir)) mkdirSync(dir, { recursive: true }), created.add(dir);
|
|
2469
|
+
return promises.has(tmp) ? (await promises.get(tmp), cachedFsResults.set(result.id, tmp), getCachedResult(result, cachedFsResults)) : (promises.set(tmp, atomicWriteFile(tmp, code).catch(() => writeFile(tmp, code, "utf-8")).finally(() => promises.delete(tmp))), await promises.get(tmp), cachedFsResults.set(result.id, tmp), getCachedResult(result, cachedFsResults));
|
|
2470
|
+
};
|
|
2471
|
+
}
|
|
2472
|
+
let SOURCEMAPPING_URL = "sourceMa";
|
|
2473
|
+
SOURCEMAPPING_URL += "ppingURL";
|
|
2474
|
+
const MODULE_RUNNER_SOURCEMAPPING_SOURCE = "//# sourceMappingSource=vite-generated";
|
|
2475
|
+
function processResultSource(environment, result) {
|
|
2476
|
+
if (!("code" in result)) return result;
|
|
2477
|
+
const node = environment.moduleGraph.getModuleById(result.id);
|
|
2478
|
+
if (node?.transformResult)
|
|
2479
|
+
// this also overrides node.transformResult.code which is also what the module
|
|
2480
|
+
// runner does under the hood by default (we disable source maps inlining)
|
|
2481
|
+
inlineSourceMap(node.transformResult);
|
|
2482
|
+
return {
|
|
2483
|
+
...result,
|
|
2484
|
+
code: node?.transformResult?.code || result.code
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2487
|
+
const OTHER_SOURCE_MAP_REGEXP = new RegExp(`//# ${SOURCEMAPPING_URL}=data:application/json[^,]+base64,([A-Za-z0-9+/=]+)$`, "gm");
|
|
2488
|
+
// we have to inline the source map ourselves, because
|
|
2489
|
+
// - we don't need //# sourceURL since we are running code in VM
|
|
2490
|
+
// - important in stack traces and the V8 coverage
|
|
2491
|
+
// - we need to inject an empty line for --inspect-brk
|
|
2492
|
+
function inlineSourceMap(result) {
|
|
2493
|
+
const map = result.map;
|
|
2494
|
+
let code = result.code;
|
|
2495
|
+
if (!map || !("version" in map) || code.includes(MODULE_RUNNER_SOURCEMAPPING_SOURCE)) return result;
|
|
2496
|
+
if (OTHER_SOURCE_MAP_REGEXP.lastIndex = 0, OTHER_SOURCE_MAP_REGEXP.test(code)) code = code.replace(OTHER_SOURCE_MAP_REGEXP, "");
|
|
2497
|
+
const sourceMap = { ...map };
|
|
2498
|
+
// If the first line is not present on source maps, add simple 1:1 mapping ([0,0,0,0], [1,0,0,0])
|
|
2499
|
+
// so that debuggers can be set to break on first line
|
|
2500
|
+
if (sourceMap.mappings.startsWith(";")) sourceMap.mappings = `AAAA,CAAA${sourceMap.mappings}`;
|
|
2501
|
+
return result.code = `${code.trimEnd()}\n${MODULE_RUNNER_SOURCEMAPPING_SOURCE}\n//# ${SOURCEMAPPING_URL}=${genSourceMapUrl(sourceMap)}\n`, result;
|
|
2502
|
+
}
|
|
2503
|
+
function genSourceMapUrl(map) {
|
|
2504
|
+
if (typeof map !== "string") map = JSON.stringify(map);
|
|
2505
|
+
return `data:application/json;base64,${Buffer.from(map).toString("base64")}`;
|
|
2506
|
+
}
|
|
2507
|
+
function getCachedResult(result, cachedFsResults) {
|
|
2508
|
+
const tmp = cachedFsResults.get(result.id);
|
|
2509
|
+
if (!tmp) throw new Error(`The cached result was returned too early for ${result.id}.`);
|
|
2510
|
+
return {
|
|
2511
|
+
cached: true,
|
|
2512
|
+
file: result.file,
|
|
2513
|
+
id: result.id,
|
|
2514
|
+
tmp,
|
|
2515
|
+
url: result.url,
|
|
2516
|
+
invalidate: result.invalidate
|
|
2517
|
+
};
|
|
2518
|
+
}
|
|
2519
|
+
// serialize rollup error on server to preserve details as a test error
|
|
2520
|
+
function handleRollupError(e) {
|
|
2521
|
+
throw e instanceof Error && ("plugin" in e || "frame" in e || "id" in e) ? {
|
|
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
|
+
} : e;
|
|
2533
|
+
}
|
|
2534
|
+
/**
|
|
2535
|
+
* Performs an atomic write operation using the write-then-rename pattern.
|
|
2536
|
+
*
|
|
2537
|
+
* Why we need this:
|
|
2538
|
+
* - Ensures file integrity by never leaving partially written files on disk
|
|
2539
|
+
* - Prevents other processes from reading incomplete data during writes
|
|
2540
|
+
* - Particularly important for test files where incomplete writes could cause test failures
|
|
2541
|
+
*
|
|
2542
|
+
* The implementation writes to a temporary file first, then renames it to the target path.
|
|
2543
|
+
* This rename operation is atomic on most filesystems (including POSIX-compliant ones),
|
|
2544
|
+
* guaranteeing that other processes will only ever see the complete file.
|
|
2545
|
+
*
|
|
2546
|
+
* Added in https://github.com/vitest-dev/vitest/pull/7531
|
|
2547
|
+
*/
|
|
2548
|
+
async function atomicWriteFile(realFilePath, data) {
|
|
2549
|
+
const dir = dirname$1(realFilePath), tmpFilePath = join$1(dir, `.tmp-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
2550
|
+
try {
|
|
2551
|
+
await writeFile(tmpFilePath, data, "utf-8"), await rename(tmpFilePath, realFilePath);
|
|
2552
|
+
} finally {
|
|
2553
|
+
try {
|
|
2554
|
+
if (await stat(tmpFilePath)) await unlink(tmpFilePath);
|
|
2555
|
+
} catch {}
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
// this is copy pasted from vite
|
|
2560
|
+
function normalizeResolvedIdToUrl(environment, resolvedId) {
|
|
2561
|
+
const root = environment.config.root, depsOptimizer = environment.depsOptimizer;
|
|
2562
|
+
let url;
|
|
2563
|
+
// normalize all imports into resolved URLs
|
|
2564
|
+
// e.g. `import 'foo'` -> `import '/@fs/.../node_modules/foo/index.js'`
|
|
2565
|
+
if (resolvedId.startsWith(withTrailingSlash$1(root)))
|
|
2566
|
+
// in root: infer short absolute path from root
|
|
2567
|
+
url = resolvedId.slice(root.length);
|
|
2568
|
+
else if (depsOptimizer?.isOptimizedDepFile(resolvedId) || resolvedId !== "/@react-refresh" && path.isAbsolute(resolvedId) && existsSync(cleanUrl(resolvedId)))
|
|
2569
|
+
// an optimized deps may not yet exists in the filesystem, or
|
|
2570
|
+
// a regular file exists but is out of root: rewrite to absolute /@fs/ paths
|
|
2571
|
+
url = path.posix.join("/@fs/", resolvedId);
|
|
2572
|
+
else url = resolvedId;
|
|
2573
|
+
// if the resolved id is not a valid browser import specifier,
|
|
2574
|
+
// prefix it to make it valid. We will strip this before feeding it
|
|
2575
|
+
// back into the transform pipeline
|
|
2576
|
+
if (url[0] !== "." && url[0] !== "/") url = wrapId(resolvedId);
|
|
2577
|
+
return url;
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2437
2580
|
function createMethodsRPC(project, options = {}) {
|
|
2438
|
-
const ctx = project.vitest;
|
|
2439
|
-
const cacheFs = options.cacheFs ?? false;
|
|
2581
|
+
const ctx = project.vitest, cacheFs = options.cacheFs ?? false, fetch = createFetchModuleFunction(project._resolver, cacheFs, project.tmpDir);
|
|
2440
2582
|
return {
|
|
2583
|
+
async fetch(url, importer, environmentName, options) {
|
|
2584
|
+
const environment = project.vite.environments[environmentName];
|
|
2585
|
+
if (!environment) throw new Error(`The environment ${environmentName} was not defined in the Vite config.`);
|
|
2586
|
+
const start = performance.now();
|
|
2587
|
+
try {
|
|
2588
|
+
return await fetch(url, importer, environment, options);
|
|
2589
|
+
} finally {
|
|
2590
|
+
project.vitest.state.transformTime += performance.now() - start;
|
|
2591
|
+
}
|
|
2592
|
+
},
|
|
2593
|
+
async resolve(id, importer, environmentName) {
|
|
2594
|
+
const environment = project.vite.environments[environmentName];
|
|
2595
|
+
if (!environment) throw new Error(`The environment ${environmentName} was not defined in the Vite config.`);
|
|
2596
|
+
const resolved = await environment.pluginContainer.resolveId(id, importer);
|
|
2597
|
+
return resolved ? {
|
|
2598
|
+
file: cleanUrl(resolved.id),
|
|
2599
|
+
url: normalizeResolvedIdToUrl(environment, resolved.id),
|
|
2600
|
+
id: resolved.id
|
|
2601
|
+
} : null;
|
|
2602
|
+
},
|
|
2441
2603
|
snapshotSaved(snapshot) {
|
|
2442
2604
|
ctx.snapshot.add(snapshot);
|
|
2443
2605
|
},
|
|
2444
2606
|
resolveSnapshotPath(testPath) {
|
|
2445
2607
|
return ctx.snapshot.resolvePath(testPath, { config: project.serializedConfig });
|
|
2446
2608
|
},
|
|
2447
|
-
async
|
|
2448
|
-
const
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
if (code == null) throw new Error(`Failed to fetch module ${id}`);
|
|
2453
|
-
const dir = join$1(project.tmpDir, transformMode);
|
|
2454
|
-
const name = hash("sha1", id, "hex");
|
|
2455
|
-
const tmp = join$1(dir, name);
|
|
2456
|
-
if (!created.has(dir)) {
|
|
2457
|
-
mkdirSync(dir, { recursive: true });
|
|
2458
|
-
created.add(dir);
|
|
2459
|
-
}
|
|
2460
|
-
if (promises.has(tmp)) {
|
|
2461
|
-
await promises.get(tmp);
|
|
2462
|
-
return { id: tmp };
|
|
2463
|
-
}
|
|
2464
|
-
promises.set(tmp, atomicWriteFile(tmp, code).catch(() => writeFile(tmp, code, "utf-8")).finally(() => promises.delete(tmp)));
|
|
2465
|
-
await promises.get(tmp);
|
|
2466
|
-
Object.assign(result, { id: tmp });
|
|
2467
|
-
return { id: tmp };
|
|
2468
|
-
},
|
|
2469
|
-
resolveId(id, importer, transformMode) {
|
|
2470
|
-
return project.vitenode.resolveId(id, importer, transformMode).catch(handleRollupError);
|
|
2471
|
-
},
|
|
2472
|
-
transform(id, environment) {
|
|
2473
|
-
return project.vitenode.transformModule(id, environment).catch(handleRollupError);
|
|
2609
|
+
async transform(id) {
|
|
2610
|
+
const environment = project.vite.environments.__vitest_vm__;
|
|
2611
|
+
if (!environment) throw new Error(`The VM environment was not defined in the Vite config. This is a bug in Vitest. Please, open a new issue with reproduction.`);
|
|
2612
|
+
const url = normalizeResolvedIdToUrl(environment, fileURLToPath$1(id)), result = await environment.transformRequest(url).catch(handleRollupError);
|
|
2613
|
+
return { code: result?.code };
|
|
2474
2614
|
},
|
|
2475
2615
|
async onQueued(file) {
|
|
2476
2616
|
if (options.collect) ctx.state.collectFiles(project, [file]);
|
|
@@ -2505,58 +2645,12 @@ function createMethodsRPC(project, options = {}) {
|
|
|
2505
2645
|
}
|
|
2506
2646
|
};
|
|
2507
2647
|
}
|
|
2508
|
-
// serialize rollup error on server to preserve details as a test error
|
|
2509
|
-
function handleRollupError(e) {
|
|
2510
|
-
if (e instanceof Error && ("plugin" in e || "frame" in e || "id" in e))
|
|
2511
|
-
// eslint-disable-next-line no-throw-literal
|
|
2512
|
-
throw {
|
|
2513
|
-
name: e.name,
|
|
2514
|
-
message: e.message,
|
|
2515
|
-
stack: e.stack,
|
|
2516
|
-
cause: e.cause,
|
|
2517
|
-
__vitest_rollup_error__: {
|
|
2518
|
-
plugin: e.plugin,
|
|
2519
|
-
id: e.id,
|
|
2520
|
-
loc: e.loc,
|
|
2521
|
-
frame: e.frame
|
|
2522
|
-
}
|
|
2523
|
-
};
|
|
2524
|
-
throw e;
|
|
2525
|
-
}
|
|
2526
|
-
/**
|
|
2527
|
-
* Performs an atomic write operation using the write-then-rename pattern.
|
|
2528
|
-
*
|
|
2529
|
-
* Why we need this:
|
|
2530
|
-
* - Ensures file integrity by never leaving partially written files on disk
|
|
2531
|
-
* - Prevents other processes from reading incomplete data during writes
|
|
2532
|
-
* - Particularly important for test files where incomplete writes could cause test failures
|
|
2533
|
-
*
|
|
2534
|
-
* The implementation writes to a temporary file first, then renames it to the target path.
|
|
2535
|
-
* This rename operation is atomic on most filesystems (including POSIX-compliant ones),
|
|
2536
|
-
* guaranteeing that other processes will only ever see the complete file.
|
|
2537
|
-
*
|
|
2538
|
-
* Added in https://github.com/vitest-dev/vitest/pull/7531
|
|
2539
|
-
*/
|
|
2540
|
-
async function atomicWriteFile(realFilePath, data) {
|
|
2541
|
-
const dir = dirname$1(realFilePath);
|
|
2542
|
-
const tmpFilePath = join$1(dir, `.tmp-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
2543
|
-
try {
|
|
2544
|
-
await writeFile(tmpFilePath, data, "utf-8");
|
|
2545
|
-
await rename(tmpFilePath, realFilePath);
|
|
2546
|
-
} finally {
|
|
2547
|
-
try {
|
|
2548
|
-
if (await stat(tmpFilePath)) await unlink(tmpFilePath);
|
|
2549
|
-
} catch {}
|
|
2550
|
-
}
|
|
2551
|
-
}
|
|
2552
2648
|
|
|
2553
2649
|
function createChildProcessChannel$1(project, collect = false) {
|
|
2554
|
-
const emitter = new EventEmitter()
|
|
2555
|
-
const events = {
|
|
2650
|
+
const emitter = new EventEmitter(), events = {
|
|
2556
2651
|
message: "message",
|
|
2557
2652
|
response: "response"
|
|
2558
|
-
}
|
|
2559
|
-
const rpc = createBirpc(createMethodsRPC(project, {
|
|
2653
|
+
}, rpc = createBirpc(createMethodsRPC(project, {
|
|
2560
2654
|
cacheFs: true,
|
|
2561
2655
|
collect
|
|
2562
2656
|
}), {
|
|
@@ -2586,20 +2680,13 @@ function createChildProcessChannel$1(project, collect = false) {
|
|
|
2586
2680
|
onMessage: (callback) => emitter.on(events.message, callback),
|
|
2587
2681
|
postMessage: (message) => emitter.emit(events.response, message),
|
|
2588
2682
|
onClose: () => {
|
|
2589
|
-
emitter.removeAllListeners();
|
|
2590
|
-
rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
|
|
2683
|
+
emitter.removeAllListeners(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
|
|
2591
2684
|
}
|
|
2592
2685
|
};
|
|
2593
2686
|
return channel;
|
|
2594
2687
|
}
|
|
2595
2688
|
function createForksPool(vitest, { execArgv, env }) {
|
|
2596
|
-
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length
|
|
2597
|
-
const threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
|
|
2598
|
-
const poolOptions = vitest.config.poolOptions?.forks ?? {};
|
|
2599
|
-
const maxThreads = poolOptions.maxForks ?? vitest.config.maxWorkers ?? threadsCount;
|
|
2600
|
-
const minThreads = poolOptions.minForks ?? vitest.config.minWorkers ?? Math.min(threadsCount, maxThreads);
|
|
2601
|
-
const worker = resolve(vitest.distPath, "workers/forks.js");
|
|
2602
|
-
const options = {
|
|
2689
|
+
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length, threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1), poolOptions = vitest.config.poolOptions?.forks ?? {}, maxThreads = poolOptions.maxForks ?? vitest.config.maxWorkers ?? threadsCount, minThreads = poolOptions.minForks ?? vitest.config.minWorkers ?? Math.min(threadsCount, maxThreads), worker = resolve(vitest.distPath, "workers/forks.js"), options = {
|
|
2603
2690
|
runtime: "child_process",
|
|
2604
2691
|
filename: resolve(vitest.distPath, "worker.js"),
|
|
2605
2692
|
teardown: "teardown",
|
|
@@ -2609,22 +2696,15 @@ function createForksPool(vitest, { execArgv, env }) {
|
|
|
2609
2696
|
execArgv: [...poolOptions.execArgv ?? [], ...execArgv],
|
|
2610
2697
|
terminateTimeout: vitest.config.teardownTimeout,
|
|
2611
2698
|
concurrentTasksPerWorker: 1
|
|
2612
|
-
};
|
|
2613
|
-
const isolated = poolOptions.isolate ?? true;
|
|
2699
|
+
}, isolated = poolOptions.isolate ?? true;
|
|
2614
2700
|
if (isolated) options.isolateWorkers = true;
|
|
2615
|
-
if (poolOptions.singleFork || !vitest.config.fileParallelism)
|
|
2616
|
-
|
|
2617
|
-
options.minThreads = 1;
|
|
2618
|
-
}
|
|
2619
|
-
const pool = new Tinypool(options);
|
|
2620
|
-
const runWithFiles = (name) => {
|
|
2701
|
+
if (poolOptions.singleFork || !vitest.config.fileParallelism) options.maxThreads = 1, options.minThreads = 1;
|
|
2702
|
+
const pool = new Tinypool(options), runWithFiles = (name) => {
|
|
2621
2703
|
let id = 0;
|
|
2622
2704
|
async function runFiles(project, config, files, environment, invalidates = []) {
|
|
2623
2705
|
const paths = files.map((f) => f.filepath);
|
|
2624
2706
|
vitest.state.clearFiles(project, paths);
|
|
2625
|
-
const channel = createChildProcessChannel$1(project, name === "collect")
|
|
2626
|
-
const workerId = ++id;
|
|
2627
|
-
const data = {
|
|
2707
|
+
const channel = createChildProcessChannel$1(project, name === "collect"), workerId = ++id, data = {
|
|
2628
2708
|
pool: "forks",
|
|
2629
2709
|
worker,
|
|
2630
2710
|
config,
|
|
@@ -2650,40 +2730,25 @@ function createForksPool(vitest, { execArgv, env }) {
|
|
|
2650
2730
|
return async (specs, invalidates) => {
|
|
2651
2731
|
// Cancel pending tasks from pool when possible
|
|
2652
2732
|
vitest.onCancel(() => pool.cancelPendingTasks());
|
|
2653
|
-
const configs = /* @__PURE__ */ new WeakMap()
|
|
2654
|
-
const getConfig = (project) => {
|
|
2733
|
+
const configs = /* @__PURE__ */ new WeakMap(), getConfig = (project) => {
|
|
2655
2734
|
if (configs.has(project)) return configs.get(project);
|
|
2656
|
-
const _config = project.getSerializableConfig();
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
return config;
|
|
2660
|
-
};
|
|
2661
|
-
const singleFork = specs.filter((spec) => spec.project.config.poolOptions?.forks?.singleFork);
|
|
2662
|
-
const multipleForks = specs.filter((spec) => !spec.project.config.poolOptions?.forks?.singleFork);
|
|
2735
|
+
const _config = project.getSerializableConfig(), config = wrapSerializableConfig(_config);
|
|
2736
|
+
return configs.set(project, config), config;
|
|
2737
|
+
}, singleFork = specs.filter((spec) => spec.project.config.poolOptions?.forks?.singleFork), multipleForks = specs.filter((spec) => !spec.project.config.poolOptions?.forks?.singleFork);
|
|
2663
2738
|
if (multipleForks.length) {
|
|
2664
|
-
const filesByEnv = await groupFilesByEnv(multipleForks);
|
|
2665
|
-
const files = Object.values(filesByEnv).flat();
|
|
2666
|
-
const results = [];
|
|
2739
|
+
const filesByEnv = await groupFilesByEnv(multipleForks), files = Object.values(filesByEnv).flat(), results = [];
|
|
2667
2740
|
if (isolated) results.push(...await Promise.allSettled(files.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))));
|
|
2668
2741
|
else {
|
|
2669
2742
|
// When isolation is disabled, we still need to isolate environments and workspace projects from each other.
|
|
2670
2743
|
// Tasks are still running parallel but environments are isolated between tasks.
|
|
2671
2744
|
const grouped = groupBy(files, ({ project, environment }) => project.name + environment.name + JSON.stringify(environment.options));
|
|
2672
|
-
for (const group of Object.values(grouped)) {
|
|
2673
|
-
// Push all files to pool's queue
|
|
2674
|
-
results.push(...await Promise.allSettled(group.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))));
|
|
2675
|
-
// Once all tasks are running or finished, recycle worker for isolation.
|
|
2676
|
-
// On-going workers will run in the previous environment.
|
|
2677
|
-
await new Promise((resolve) => pool.queueSize === 0 ? resolve() : pool.once("drain", resolve));
|
|
2678
|
-
await pool.recycleWorkers();
|
|
2679
|
-
}
|
|
2745
|
+
for (const group of Object.values(grouped)) results.push(...await Promise.allSettled(group.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)))), await new Promise((resolve) => pool.queueSize === 0 ? resolve() : pool.once("drain", resolve)), await pool.recycleWorkers();
|
|
2680
2746
|
}
|
|
2681
2747
|
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2682
2748
|
if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
2683
2749
|
}
|
|
2684
2750
|
if (singleFork.length) {
|
|
2685
|
-
const filesByEnv = await groupFilesByEnv(singleFork);
|
|
2686
|
-
const envs = envsOrder.concat(Object.keys(filesByEnv).filter((env) => !envsOrder.includes(env)));
|
|
2751
|
+
const filesByEnv = await groupFilesByEnv(singleFork), envs = envsOrder.concat(Object.keys(filesByEnv).filter((env) => !envsOrder.includes(env)));
|
|
2687
2752
|
for (const env of envs) {
|
|
2688
2753
|
const files = filesByEnv[env];
|
|
2689
2754
|
if (!files?.length) continue;
|
|
@@ -2707,10 +2772,7 @@ function createForksPool(vitest, { execArgv, env }) {
|
|
|
2707
2772
|
}
|
|
2708
2773
|
|
|
2709
2774
|
function createWorkerChannel$1(project, collect) {
|
|
2710
|
-
const channel = new MessageChannel()
|
|
2711
|
-
const port = channel.port2;
|
|
2712
|
-
const workerPort = channel.port1;
|
|
2713
|
-
const rpc = createBirpc(createMethodsRPC(project, { collect }), {
|
|
2775
|
+
const channel = new MessageChannel(), port = channel.port2, workerPort = channel.port1, rpc = createBirpc(createMethodsRPC(project, { collect }), {
|
|
2714
2776
|
eventNames: ["onCancel"],
|
|
2715
2777
|
post(v) {
|
|
2716
2778
|
port.postMessage(v);
|
|
@@ -2722,9 +2784,7 @@ function createWorkerChannel$1(project, collect) {
|
|
|
2722
2784
|
});
|
|
2723
2785
|
project.vitest.onCancel((reason) => rpc.onCancel(reason));
|
|
2724
2786
|
const onClose = () => {
|
|
2725
|
-
port.close();
|
|
2726
|
-
workerPort.close();
|
|
2727
|
-
rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
|
|
2787
|
+
port.close(), workerPort.close(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
|
|
2728
2788
|
};
|
|
2729
2789
|
return {
|
|
2730
2790
|
workerPort,
|
|
@@ -2733,13 +2793,7 @@ function createWorkerChannel$1(project, collect) {
|
|
|
2733
2793
|
};
|
|
2734
2794
|
}
|
|
2735
2795
|
function createThreadsPool(vitest, { execArgv, env }) {
|
|
2736
|
-
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length
|
|
2737
|
-
const threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
|
|
2738
|
-
const poolOptions = vitest.config.poolOptions?.threads ?? {};
|
|
2739
|
-
const maxThreads = poolOptions.maxThreads ?? vitest.config.maxWorkers ?? threadsCount;
|
|
2740
|
-
const minThreads = poolOptions.minThreads ?? vitest.config.minWorkers ?? Math.min(threadsCount, maxThreads);
|
|
2741
|
-
const worker = resolve(vitest.distPath, "workers/threads.js");
|
|
2742
|
-
const options = {
|
|
2796
|
+
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length, threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1), poolOptions = vitest.config.poolOptions?.threads ?? {}, maxThreads = poolOptions.maxThreads ?? vitest.config.maxWorkers ?? threadsCount, minThreads = poolOptions.minThreads ?? vitest.config.minWorkers ?? Math.min(threadsCount, maxThreads), worker = resolve(vitest.distPath, "workers/threads.js"), options = {
|
|
2743
2797
|
filename: resolve(vitest.distPath, "worker.js"),
|
|
2744
2798
|
teardown: "teardown",
|
|
2745
2799
|
useAtomics: poolOptions.useAtomics ?? false,
|
|
@@ -2749,22 +2803,15 @@ function createThreadsPool(vitest, { execArgv, env }) {
|
|
|
2749
2803
|
execArgv: [...poolOptions.execArgv ?? [], ...execArgv],
|
|
2750
2804
|
terminateTimeout: vitest.config.teardownTimeout,
|
|
2751
2805
|
concurrentTasksPerWorker: 1
|
|
2752
|
-
};
|
|
2753
|
-
const isolated = poolOptions.isolate ?? true;
|
|
2806
|
+
}, isolated = poolOptions.isolate ?? true;
|
|
2754
2807
|
if (isolated) options.isolateWorkers = true;
|
|
2755
|
-
if (poolOptions.singleThread || !vitest.config.fileParallelism)
|
|
2756
|
-
|
|
2757
|
-
options.minThreads = 1;
|
|
2758
|
-
}
|
|
2759
|
-
const pool = new Tinypool$1(options);
|
|
2760
|
-
const runWithFiles = (name) => {
|
|
2808
|
+
if (poolOptions.singleThread || !vitest.config.fileParallelism) options.maxThreads = 1, options.minThreads = 1;
|
|
2809
|
+
const pool = new Tinypool$1(options), runWithFiles = (name) => {
|
|
2761
2810
|
let id = 0;
|
|
2762
2811
|
async function runFiles(project, config, files, environment, invalidates = []) {
|
|
2763
2812
|
const paths = files.map((f) => f.filepath);
|
|
2764
2813
|
vitest.state.clearFiles(project, paths);
|
|
2765
|
-
const { workerPort, onClose } = createWorkerChannel$1(project, name === "collect")
|
|
2766
|
-
const workerId = ++id;
|
|
2767
|
-
const data = {
|
|
2814
|
+
const { workerPort, onClose } = createWorkerChannel$1(project, name === "collect"), workerId = ++id, data = {
|
|
2768
2815
|
pool: "threads",
|
|
2769
2816
|
worker,
|
|
2770
2817
|
port: workerPort,
|
|
@@ -2792,39 +2839,25 @@ function createThreadsPool(vitest, { execArgv, env }) {
|
|
|
2792
2839
|
return async (specs, invalidates) => {
|
|
2793
2840
|
// Cancel pending tasks from pool when possible
|
|
2794
2841
|
vitest.onCancel(() => pool.cancelPendingTasks());
|
|
2795
|
-
const configs = /* @__PURE__ */ new WeakMap()
|
|
2796
|
-
const getConfig = (project) => {
|
|
2842
|
+
const configs = /* @__PURE__ */ new WeakMap(), getConfig = (project) => {
|
|
2797
2843
|
if (configs.has(project)) return configs.get(project);
|
|
2798
2844
|
const config = project.serializedConfig;
|
|
2799
|
-
configs.set(project, config);
|
|
2800
|
-
|
|
2801
|
-
};
|
|
2802
|
-
const singleThreads = specs.filter((spec) => spec.project.config.poolOptions?.threads?.singleThread);
|
|
2803
|
-
const multipleThreads = specs.filter((spec) => !spec.project.config.poolOptions?.threads?.singleThread);
|
|
2845
|
+
return configs.set(project, config), config;
|
|
2846
|
+
}, singleThreads = specs.filter((spec) => spec.project.config.poolOptions?.threads?.singleThread), multipleThreads = specs.filter((spec) => !spec.project.config.poolOptions?.threads?.singleThread);
|
|
2804
2847
|
if (multipleThreads.length) {
|
|
2805
|
-
const filesByEnv = await groupFilesByEnv(multipleThreads);
|
|
2806
|
-
const files = Object.values(filesByEnv).flat();
|
|
2807
|
-
const results = [];
|
|
2848
|
+
const filesByEnv = await groupFilesByEnv(multipleThreads), files = Object.values(filesByEnv).flat(), results = [];
|
|
2808
2849
|
if (isolated) results.push(...await Promise.allSettled(files.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))));
|
|
2809
2850
|
else {
|
|
2810
2851
|
// When isolation is disabled, we still need to isolate environments and workspace projects from each other.
|
|
2811
2852
|
// Tasks are still running parallel but environments are isolated between tasks.
|
|
2812
2853
|
const grouped = groupBy(files, ({ project, environment }) => project.name + environment.name + JSON.stringify(environment.options));
|
|
2813
|
-
for (const group of Object.values(grouped)) {
|
|
2814
|
-
// Push all files to pool's queue
|
|
2815
|
-
results.push(...await Promise.allSettled(group.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))));
|
|
2816
|
-
// Once all tasks are running or finished, recycle worker for isolation.
|
|
2817
|
-
// On-going workers will run in the previous environment.
|
|
2818
|
-
await new Promise((resolve) => pool.queueSize === 0 ? resolve() : pool.once("drain", resolve));
|
|
2819
|
-
await pool.recycleWorkers();
|
|
2820
|
-
}
|
|
2854
|
+
for (const group of Object.values(grouped)) results.push(...await Promise.allSettled(group.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)))), await new Promise((resolve) => pool.queueSize === 0 ? resolve() : pool.once("drain", resolve)), await pool.recycleWorkers();
|
|
2821
2855
|
}
|
|
2822
2856
|
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2823
2857
|
if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
2824
2858
|
}
|
|
2825
2859
|
if (singleThreads.length) {
|
|
2826
|
-
const filesByEnv = await groupFilesByEnv(singleThreads);
|
|
2827
|
-
const envs = envsOrder.concat(Object.keys(filesByEnv).filter((env) => !envsOrder.includes(env)));
|
|
2860
|
+
const filesByEnv = await groupFilesByEnv(singleThreads), envs = envsOrder.concat(Object.keys(filesByEnv).filter((env) => !envsOrder.includes(env)));
|
|
2828
2861
|
for (const env of envs) {
|
|
2829
2862
|
const files = filesByEnv[env];
|
|
2830
2863
|
if (!files?.length) continue;
|
|
@@ -2848,102 +2881,69 @@ function createThreadsPool(vitest, { execArgv, env }) {
|
|
|
2848
2881
|
}
|
|
2849
2882
|
|
|
2850
2883
|
function createTypecheckPool(vitest) {
|
|
2851
|
-
const promisesMap = /* @__PURE__ */ new WeakMap();
|
|
2852
|
-
const rerunTriggered = /* @__PURE__ */ new WeakSet();
|
|
2884
|
+
const promisesMap = /* @__PURE__ */ new WeakMap(), rerunTriggered = /* @__PURE__ */ new WeakSet();
|
|
2853
2885
|
async function onParseEnd(project, { files, sourceErrors }) {
|
|
2854
|
-
const checker = project.typechecker;
|
|
2855
|
-
|
|
2856
|
-
await vitest._testRun.updated(packs, events);
|
|
2857
|
-
if (!project.config.typecheck.ignoreSourceErrors) sourceErrors.forEach((error) => vitest.state.catchError(error, "Unhandled Source Error"));
|
|
2886
|
+
const checker = project.typechecker, { packs, events } = checker.getTestPacksAndEvents();
|
|
2887
|
+
if (await vitest._testRun.updated(packs, events), !project.config.typecheck.ignoreSourceErrors) sourceErrors.forEach((error) => vitest.state.catchError(error, "Unhandled Source Error"));
|
|
2858
2888
|
const processError = !hasFailed(files) && !sourceErrors.length && checker.getExitCode();
|
|
2859
2889
|
if (processError) {
|
|
2860
2890
|
const error = new Error(checker.getOutput());
|
|
2861
|
-
error.stack = "";
|
|
2862
|
-
vitest.state.catchError(error, "Typecheck Error");
|
|
2891
|
+
error.stack = "", vitest.state.catchError(error, "Typecheck Error");
|
|
2863
2892
|
}
|
|
2864
|
-
promisesMap.get(project)?.resolve();
|
|
2865
|
-
rerunTriggered.delete(project);
|
|
2866
2893
|
// triggered by TSC watcher, not Vitest watcher, so we need to emulate what Vitest does in this case
|
|
2867
|
-
if (vitest.config.watch && !vitest.runningPromise) {
|
|
2868
|
-
|
|
2869
|
-
await vitest.report("onWatcherStart", files, [...project.config.typecheck.ignoreSourceErrors ? [] : sourceErrors, ...vitest.state.getUnhandledErrors()]);
|
|
2894
|
+
if (promisesMap.get(project)?.resolve(), rerunTriggered.delete(project), vitest.config.watch && !vitest.runningPromise) {
|
|
2895
|
+
const modules = files.map((file) => vitest.state.getReportedEntity(file)).filter((e) => e?.type === "module"), state = vitest.isCancelling ? "interrupted" : modules.some((m) => !m.ok()) ? "failed" : "passed";
|
|
2896
|
+
await vitest.report("onTestRunEnd", modules, [], state), await vitest.report("onWatcherStart", files, [...project.config.typecheck.ignoreSourceErrors ? [] : sourceErrors, ...vitest.state.getUnhandledErrors()]);
|
|
2870
2897
|
}
|
|
2871
2898
|
}
|
|
2872
2899
|
async function createWorkspaceTypechecker(project, files) {
|
|
2873
2900
|
const checker = project.typechecker ?? new Typechecker(project);
|
|
2874
|
-
|
|
2875
|
-
project.typechecker = checker;
|
|
2876
|
-
checker.setFiles(files);
|
|
2877
|
-
checker.onParseStart(async () => {
|
|
2901
|
+
return project.typechecker ? checker : (project.typechecker = checker, checker.setFiles(files), checker.onParseStart(async () => {
|
|
2878
2902
|
const files = checker.getTestFiles();
|
|
2879
2903
|
for (const file of files) await vitest._testRun.enqueued(project, file);
|
|
2880
2904
|
await vitest._testRun.collected(project, files);
|
|
2881
|
-
})
|
|
2882
|
-
|
|
2883
|
-
checker.onWatcherRerun(async () => {
|
|
2884
|
-
rerunTriggered.add(project);
|
|
2885
|
-
if (!vitest.runningPromise) {
|
|
2886
|
-
vitest.state.clearErrors();
|
|
2887
|
-
await vitest.report("onWatcherRerun", files, "File change detected. Triggering rerun.");
|
|
2888
|
-
}
|
|
2905
|
+
}), checker.onParseEnd((result) => onParseEnd(project, result)), checker.onWatcherRerun(async () => {
|
|
2906
|
+
if (rerunTriggered.add(project), !vitest.runningPromise) vitest.state.clearErrors(), await vitest.report("onWatcherRerun", files, "File change detected. Triggering rerun.");
|
|
2889
2907
|
await checker.collectTests();
|
|
2890
2908
|
const testFiles = checker.getTestFiles();
|
|
2891
2909
|
for (const file of testFiles) await vitest._testRun.enqueued(project, file);
|
|
2892
2910
|
await vitest._testRun.collected(project, testFiles);
|
|
2893
2911
|
const { packs, events } = checker.getTestPacksAndEvents();
|
|
2894
2912
|
await vitest._testRun.updated(packs, events);
|
|
2895
|
-
});
|
|
2896
|
-
return checker;
|
|
2913
|
+
}), checker);
|
|
2897
2914
|
}
|
|
2898
2915
|
async function startTypechecker(project, files) {
|
|
2899
2916
|
if (project.typechecker) return;
|
|
2900
2917
|
const checker = await createWorkspaceTypechecker(project, files);
|
|
2901
|
-
await checker.collectTests();
|
|
2902
|
-
await checker.start();
|
|
2918
|
+
await checker.collectTests(), await checker.start();
|
|
2903
2919
|
}
|
|
2904
2920
|
async function collectTests(specs) {
|
|
2905
2921
|
const specsByProject = groupBy(specs, (spec) => spec.project.name);
|
|
2906
2922
|
for (const name in specsByProject) {
|
|
2907
|
-
const project = specsByProject[name][0].project;
|
|
2908
|
-
|
|
2909
|
-
const checker = await createWorkspaceTypechecker(project, files);
|
|
2910
|
-
checker.setFiles(files);
|
|
2911
|
-
await checker.collectTests();
|
|
2923
|
+
const project = specsByProject[name][0].project, files = specsByProject[name].map((spec) => spec.moduleId), checker = await createWorkspaceTypechecker(project, files);
|
|
2924
|
+
checker.setFiles(files), await checker.collectTests();
|
|
2912
2925
|
const testFiles = checker.getTestFiles();
|
|
2913
2926
|
vitest.state.collectFiles(project, testFiles);
|
|
2914
2927
|
}
|
|
2915
2928
|
}
|
|
2916
2929
|
async function runTests(specs) {
|
|
2917
|
-
const specsByProject = groupBy(specs, (spec) => spec.project.name);
|
|
2918
|
-
const promises = [];
|
|
2930
|
+
const specsByProject = groupBy(specs, (spec) => spec.project.name), promises = [];
|
|
2919
2931
|
for (const name in specsByProject) {
|
|
2920
|
-
const project = specsByProject[name][0].project
|
|
2921
|
-
const files = specsByProject[name].map((spec) => spec.moduleId);
|
|
2922
|
-
const promise = createDefer();
|
|
2923
|
-
// check that watcher actually triggered rerun
|
|
2924
|
-
const _p = new Promise((resolve) => {
|
|
2932
|
+
const project = specsByProject[name][0].project, files = specsByProject[name].map((spec) => spec.moduleId), promise = createDefer(), _p = new Promise((resolve) => {
|
|
2925
2933
|
const _i = setInterval(() => {
|
|
2926
|
-
if (!project.typechecker || rerunTriggered.has(project))
|
|
2927
|
-
resolve(true);
|
|
2928
|
-
clearInterval(_i);
|
|
2929
|
-
}
|
|
2934
|
+
if (!project.typechecker || rerunTriggered.has(project)) resolve(true), clearInterval(_i);
|
|
2930
2935
|
});
|
|
2931
2936
|
setTimeout(() => {
|
|
2932
|
-
resolve(false);
|
|
2933
|
-
clearInterval(_i);
|
|
2937
|
+
resolve(false), clearInterval(_i);
|
|
2934
2938
|
}, 500).unref();
|
|
2935
|
-
});
|
|
2936
|
-
const triggered = await _p;
|
|
2939
|
+
}), triggered = await _p;
|
|
2937
2940
|
if (project.typechecker && !triggered) {
|
|
2938
2941
|
const testFiles = project.typechecker.getTestFiles();
|
|
2939
2942
|
for (const file of testFiles) await vitest._testRun.enqueued(project, file);
|
|
2940
|
-
await vitest._testRun.collected(project, testFiles);
|
|
2941
|
-
await onParseEnd(project, project.typechecker.getResult());
|
|
2943
|
+
await vitest._testRun.collected(project, testFiles), await onParseEnd(project, project.typechecker.getResult());
|
|
2942
2944
|
continue;
|
|
2943
2945
|
}
|
|
2944
|
-
promises.push(promise);
|
|
2945
|
-
promisesMap.set(project, promise);
|
|
2946
|
-
promises.push(startTypechecker(project, files));
|
|
2946
|
+
promises.push(promise), promisesMap.set(project, promise), promises.push(startTypechecker(project, files));
|
|
2947
2947
|
}
|
|
2948
2948
|
await Promise.all(promises);
|
|
2949
2949
|
}
|
|
@@ -2987,8 +2987,7 @@ function stringToBytes(input, percentageReference) {
|
|
|
2987
2987
|
let [, numericString, trailingChars] = input.match(/(.*?)([^0-9.-]+)$/) || [];
|
|
2988
2988
|
if (trailingChars && numericString) {
|
|
2989
2989
|
const numericValue = Number.parseFloat(numericString);
|
|
2990
|
-
trailingChars = trailingChars.toLowerCase()
|
|
2991
|
-
switch (trailingChars) {
|
|
2990
|
+
switch (trailingChars = trailingChars.toLowerCase(), trailingChars) {
|
|
2992
2991
|
case "%":
|
|
2993
2992
|
input = numericValue / 100;
|
|
2994
2993
|
break;
|
|
@@ -3004,21 +3003,20 @@ function stringToBytes(input, percentageReference) {
|
|
|
3004
3003
|
}
|
|
3005
3004
|
}
|
|
3006
3005
|
} else input = Number.parseFloat(input);
|
|
3007
|
-
if (typeof input === "number") if (input <= 1 && input > 0)
|
|
3008
|
-
|
|
3009
|
-
|
|
3006
|
+
if (typeof input === "number") if (input <= 1 && input > 0) {
|
|
3007
|
+
if (percentageReference) return Math.floor(input * percentageReference);
|
|
3008
|
+
throw new Error("For a percentage based memory limit a percentageReference must be supplied");
|
|
3009
|
+
} else if (input > 1) return Math.floor(input);
|
|
3010
3010
|
else throw new Error("Unexpected numerical input for \"memoryLimit\"");
|
|
3011
3011
|
return null;
|
|
3012
3012
|
}
|
|
3013
3013
|
|
|
3014
3014
|
const suppressWarningsPath$1 = resolve(rootDir, "./suppress-warnings.cjs");
|
|
3015
3015
|
function createChildProcessChannel(project, collect) {
|
|
3016
|
-
const emitter = new EventEmitter()
|
|
3017
|
-
const events = {
|
|
3016
|
+
const emitter = new EventEmitter(), events = {
|
|
3018
3017
|
message: "message",
|
|
3019
3018
|
response: "response"
|
|
3020
|
-
}
|
|
3021
|
-
const rpc = createBirpc(createMethodsRPC(project, {
|
|
3019
|
+
}, rpc = createBirpc(createMethodsRPC(project, {
|
|
3022
3020
|
cacheFs: true,
|
|
3023
3021
|
collect
|
|
3024
3022
|
}), {
|
|
@@ -3048,20 +3046,13 @@ function createChildProcessChannel(project, collect) {
|
|
|
3048
3046
|
onMessage: (callback) => emitter.on(events.message, callback),
|
|
3049
3047
|
postMessage: (message) => emitter.emit(events.response, message),
|
|
3050
3048
|
onClose: () => {
|
|
3051
|
-
emitter.removeAllListeners();
|
|
3052
|
-
rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
|
|
3049
|
+
emitter.removeAllListeners(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
|
|
3053
3050
|
}
|
|
3054
3051
|
};
|
|
3055
3052
|
return { channel };
|
|
3056
3053
|
}
|
|
3057
3054
|
function createVmForksPool(vitest, { execArgv, env }) {
|
|
3058
|
-
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length
|
|
3059
|
-
const threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
|
|
3060
|
-
const poolOptions = vitest.config.poolOptions?.vmForks ?? {};
|
|
3061
|
-
const maxThreads = poolOptions.maxForks ?? vitest.config.maxWorkers ?? threadsCount;
|
|
3062
|
-
const minThreads = poolOptions.maxForks ?? vitest.config.minWorkers ?? Math.min(threadsCount, maxThreads);
|
|
3063
|
-
const worker = resolve(vitest.distPath, "workers/vmForks.js");
|
|
3064
|
-
const options = {
|
|
3055
|
+
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length, threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1), poolOptions = vitest.config.poolOptions?.vmForks ?? {}, maxThreads = poolOptions.maxForks ?? vitest.config.maxWorkers ?? threadsCount, minThreads = poolOptions.maxForks ?? vitest.config.minWorkers ?? Math.min(threadsCount, maxThreads), worker = resolve(vitest.distPath, "workers/vmForks.js"), options = {
|
|
3065
3056
|
runtime: "child_process",
|
|
3066
3057
|
filename: resolve(vitest.distPath, "worker.js"),
|
|
3067
3058
|
maxThreads,
|
|
@@ -3079,19 +3070,13 @@ function createVmForksPool(vitest, { execArgv, env }) {
|
|
|
3079
3070
|
concurrentTasksPerWorker: 1,
|
|
3080
3071
|
maxMemoryLimitBeforeRecycle: getMemoryLimit$1(vitest.config) || void 0
|
|
3081
3072
|
};
|
|
3082
|
-
if (poolOptions.singleFork || !vitest.config.fileParallelism)
|
|
3083
|
-
|
|
3084
|
-
options.minThreads = 1;
|
|
3085
|
-
}
|
|
3086
|
-
const pool = new Tinypool$1(options);
|
|
3087
|
-
const runWithFiles = (name) => {
|
|
3073
|
+
if (poolOptions.singleFork || !vitest.config.fileParallelism) options.maxThreads = 1, options.minThreads = 1;
|
|
3074
|
+
const pool = new Tinypool$1(options), runWithFiles = (name) => {
|
|
3088
3075
|
let id = 0;
|
|
3089
3076
|
async function runFiles(project, config, files, environment, invalidates = []) {
|
|
3090
3077
|
const paths = files.map((f) => f.filepath);
|
|
3091
3078
|
vitest.state.clearFiles(project, paths);
|
|
3092
|
-
const { channel } = createChildProcessChannel(project, name === "collect")
|
|
3093
|
-
const workerId = ++id;
|
|
3094
|
-
const data = {
|
|
3079
|
+
const { channel } = createChildProcessChannel(project, name === "collect"), workerId = ++id, data = {
|
|
3095
3080
|
pool: "forks",
|
|
3096
3081
|
worker,
|
|
3097
3082
|
config,
|
|
@@ -3119,18 +3104,11 @@ function createVmForksPool(vitest, { execArgv, env }) {
|
|
|
3119
3104
|
return async (specs, invalidates) => {
|
|
3120
3105
|
// Cancel pending tasks from pool when possible
|
|
3121
3106
|
vitest.onCancel(() => pool.cancelPendingTasks());
|
|
3122
|
-
const configs = /* @__PURE__ */ new Map()
|
|
3123
|
-
const getConfig = (project) => {
|
|
3107
|
+
const configs = /* @__PURE__ */ new Map(), getConfig = (project) => {
|
|
3124
3108
|
if (configs.has(project)) return configs.get(project);
|
|
3125
|
-
const _config = project.serializedConfig;
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
return config;
|
|
3129
|
-
};
|
|
3130
|
-
const filesByEnv = await groupFilesByEnv(specs);
|
|
3131
|
-
const promises = Object.values(filesByEnv).flat();
|
|
3132
|
-
const results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)));
|
|
3133
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3109
|
+
const _config = project.serializedConfig, config = wrapSerializableConfig(_config);
|
|
3110
|
+
return configs.set(project, config), config;
|
|
3111
|
+
}, filesByEnv = await groupFilesByEnv(specs), promises = Object.values(filesByEnv).flat(), results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))), errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3134
3112
|
if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
3135
3113
|
};
|
|
3136
3114
|
};
|
|
@@ -3142,21 +3120,14 @@ function createVmForksPool(vitest, { execArgv, env }) {
|
|
|
3142
3120
|
};
|
|
3143
3121
|
}
|
|
3144
3122
|
function getMemoryLimit$1(config) {
|
|
3145
|
-
const memory = nodeos.totalmem();
|
|
3146
|
-
const limit = getWorkerMemoryLimit(config, "vmForks");
|
|
3147
|
-
if (typeof memory === "number") return stringToBytes(limit, config.watch ? memory / 2 : memory);
|
|
3148
|
-
// If totalmem is not supported we cannot resolve percentage based values like 0.5, "50%"
|
|
3149
|
-
if (typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%") return stringToBytes(limit);
|
|
3123
|
+
const memory = nodeos.totalmem(), limit = getWorkerMemoryLimit(config, "vmForks");
|
|
3150
3124
|
// just ignore "memoryLimit" value because we cannot detect memory limit
|
|
3151
|
-
return null;
|
|
3125
|
+
return typeof memory === "number" ? stringToBytes(limit, config.watch ? memory / 2 : memory) : typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%" ? stringToBytes(limit) : null;
|
|
3152
3126
|
}
|
|
3153
3127
|
|
|
3154
3128
|
const suppressWarningsPath = resolve(rootDir, "./suppress-warnings.cjs");
|
|
3155
3129
|
function createWorkerChannel(project, collect) {
|
|
3156
|
-
const channel = new MessageChannel()
|
|
3157
|
-
const port = channel.port2;
|
|
3158
|
-
const workerPort = channel.port1;
|
|
3159
|
-
const rpc = createBirpc(createMethodsRPC(project, { collect }), {
|
|
3130
|
+
const channel = new MessageChannel(), port = channel.port2, workerPort = channel.port1, rpc = createBirpc(createMethodsRPC(project, { collect }), {
|
|
3160
3131
|
eventNames: ["onCancel"],
|
|
3161
3132
|
post(v) {
|
|
3162
3133
|
port.postMessage(v);
|
|
@@ -3168,9 +3139,7 @@ function createWorkerChannel(project, collect) {
|
|
|
3168
3139
|
});
|
|
3169
3140
|
project.vitest.onCancel((reason) => rpc.onCancel(reason));
|
|
3170
3141
|
function onClose() {
|
|
3171
|
-
workerPort.close();
|
|
3172
|
-
port.close();
|
|
3173
|
-
rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
|
|
3142
|
+
workerPort.close(), port.close(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
|
|
3174
3143
|
}
|
|
3175
3144
|
return {
|
|
3176
3145
|
workerPort,
|
|
@@ -3178,13 +3147,7 @@ function createWorkerChannel(project, collect) {
|
|
|
3178
3147
|
};
|
|
3179
3148
|
}
|
|
3180
3149
|
function createVmThreadsPool(vitest, { execArgv, env }) {
|
|
3181
|
-
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length
|
|
3182
|
-
const threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
|
|
3183
|
-
const poolOptions = vitest.config.poolOptions?.vmThreads ?? {};
|
|
3184
|
-
const maxThreads = poolOptions.maxThreads ?? vitest.config.maxWorkers ?? threadsCount;
|
|
3185
|
-
const minThreads = poolOptions.minThreads ?? vitest.config.minWorkers ?? Math.min(threadsCount, maxThreads);
|
|
3186
|
-
const worker = resolve(vitest.distPath, "workers/vmThreads.js");
|
|
3187
|
-
const options = {
|
|
3150
|
+
const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length, threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1), poolOptions = vitest.config.poolOptions?.vmThreads ?? {}, maxThreads = poolOptions.maxThreads ?? vitest.config.maxWorkers ?? threadsCount, minThreads = poolOptions.minThreads ?? vitest.config.minWorkers ?? Math.min(threadsCount, maxThreads), worker = resolve(vitest.distPath, "workers/vmThreads.js"), options = {
|
|
3188
3151
|
filename: resolve(vitest.distPath, "worker.js"),
|
|
3189
3152
|
useAtomics: poolOptions.useAtomics ?? false,
|
|
3190
3153
|
maxThreads,
|
|
@@ -3202,19 +3165,13 @@ function createVmThreadsPool(vitest, { execArgv, env }) {
|
|
|
3202
3165
|
concurrentTasksPerWorker: 1,
|
|
3203
3166
|
maxMemoryLimitBeforeRecycle: getMemoryLimit(vitest.config) || void 0
|
|
3204
3167
|
};
|
|
3205
|
-
if (poolOptions.singleThread || !vitest.config.fileParallelism)
|
|
3206
|
-
|
|
3207
|
-
options.minThreads = 1;
|
|
3208
|
-
}
|
|
3209
|
-
const pool = new Tinypool$1(options);
|
|
3210
|
-
const runWithFiles = (name) => {
|
|
3168
|
+
if (poolOptions.singleThread || !vitest.config.fileParallelism) options.maxThreads = 1, options.minThreads = 1;
|
|
3169
|
+
const pool = new Tinypool$1(options), runWithFiles = (name) => {
|
|
3211
3170
|
let id = 0;
|
|
3212
3171
|
async function runFiles(project, config, files, environment, invalidates = []) {
|
|
3213
3172
|
const paths = files.map((f) => f.filepath);
|
|
3214
3173
|
vitest.state.clearFiles(project, paths);
|
|
3215
|
-
const { workerPort, onClose } = createWorkerChannel(project, name === "collect")
|
|
3216
|
-
const workerId = ++id;
|
|
3217
|
-
const data = {
|
|
3174
|
+
const { workerPort, onClose } = createWorkerChannel(project, name === "collect"), workerId = ++id, data = {
|
|
3218
3175
|
pool: "vmThreads",
|
|
3219
3176
|
worker,
|
|
3220
3177
|
port: workerPort,
|
|
@@ -3243,17 +3200,11 @@ function createVmThreadsPool(vitest, { execArgv, env }) {
|
|
|
3243
3200
|
return async (specs, invalidates) => {
|
|
3244
3201
|
// Cancel pending tasks from pool when possible
|
|
3245
3202
|
vitest.onCancel(() => pool.cancelPendingTasks());
|
|
3246
|
-
const configs = /* @__PURE__ */ new Map()
|
|
3247
|
-
const getConfig = (project) => {
|
|
3203
|
+
const configs = /* @__PURE__ */ new Map(), getConfig = (project) => {
|
|
3248
3204
|
if (configs.has(project)) return configs.get(project);
|
|
3249
3205
|
const config = project.serializedConfig;
|
|
3250
|
-
configs.set(project, config);
|
|
3251
|
-
|
|
3252
|
-
};
|
|
3253
|
-
const filesByEnv = await groupFilesByEnv(specs);
|
|
3254
|
-
const promises = Object.values(filesByEnv).flat();
|
|
3255
|
-
const results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)));
|
|
3256
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3206
|
+
return configs.set(project, config), config;
|
|
3207
|
+
}, filesByEnv = await groupFilesByEnv(specs), promises = Object.values(filesByEnv).flat(), results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))), errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3257
3208
|
if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
|
|
3258
3209
|
};
|
|
3259
3210
|
};
|
|
@@ -3265,13 +3216,9 @@ function createVmThreadsPool(vitest, { execArgv, env }) {
|
|
|
3265
3216
|
};
|
|
3266
3217
|
}
|
|
3267
3218
|
function getMemoryLimit(config) {
|
|
3268
|
-
const memory = nodeos.totalmem();
|
|
3269
|
-
const limit = getWorkerMemoryLimit(config, "vmThreads");
|
|
3270
|
-
if (typeof memory === "number") return stringToBytes(limit, config.watch ? memory / 2 : memory);
|
|
3271
|
-
// If totalmem is not supported we cannot resolve percentage based values like 0.5, "50%"
|
|
3272
|
-
if (typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%") return stringToBytes(limit);
|
|
3219
|
+
const memory = nodeos.totalmem(), limit = getWorkerMemoryLimit(config, "vmThreads");
|
|
3273
3220
|
// just ignore "memoryLimit" value because we cannot detect memory limit
|
|
3274
|
-
return null;
|
|
3221
|
+
return typeof memory === "number" ? stringToBytes(limit, config.watch ? memory / 2 : memory) : typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%" ? stringToBytes(limit) : null;
|
|
3275
3222
|
}
|
|
3276
3223
|
|
|
3277
3224
|
const builtinPools = [
|
|
@@ -3283,8 +3230,7 @@ const builtinPools = [
|
|
|
3283
3230
|
"typescript"
|
|
3284
3231
|
];
|
|
3285
3232
|
function getDefaultPoolName(project) {
|
|
3286
|
-
|
|
3287
|
-
return project.config.pool;
|
|
3233
|
+
return project.config.browser.enabled ? "browser" : project.config.pool;
|
|
3288
3234
|
}
|
|
3289
3235
|
function getFilePoolName(project) {
|
|
3290
3236
|
return getDefaultPoolName(project);
|
|
@@ -3297,26 +3243,15 @@ function createPool(ctx) {
|
|
|
3297
3243
|
vmThreads: null,
|
|
3298
3244
|
vmForks: null,
|
|
3299
3245
|
typescript: null
|
|
3300
|
-
}
|
|
3301
|
-
// in addition to resolve.conditions Vite also adds production/development,
|
|
3302
|
-
// see: https://github.com/vitejs/vite/blob/af2aa09575229462635b7cbb6d248ca853057ba2/packages/vite/src/node/plugins/resolve.ts#L1056-L1080
|
|
3303
|
-
const viteMajor = Number(version.split(".")[0]);
|
|
3304
|
-
const potentialConditions = new Set(viteMajor >= 6 ? ctx.vite.config.ssr.resolve?.conditions ?? [] : [
|
|
3246
|
+
}, viteMajor = Number(version.split(".")[0]), potentialConditions = new Set(viteMajor >= 6 ? ctx.vite.config.ssr.resolve?.conditions ?? [] : [
|
|
3305
3247
|
"production",
|
|
3306
3248
|
"development",
|
|
3307
3249
|
...ctx.vite.config.resolve.conditions
|
|
3308
|
-
])
|
|
3309
|
-
|
|
3310
|
-
if (condition === "production") return ctx.vite.config.isProduction;
|
|
3311
|
-
if (condition === "development") return !ctx.vite.config.isProduction;
|
|
3312
|
-
return true;
|
|
3250
|
+
]), conditions = [...potentialConditions].filter((condition) => {
|
|
3251
|
+
return condition === "production" ? ctx.vite.config.isProduction : condition === "development" ? !ctx.vite.config.isProduction : true;
|
|
3313
3252
|
}).map((condition) => {
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
}).flatMap((c) => ["--conditions", c]);
|
|
3317
|
-
// Instead of passing whole process.execArgv to the workers, pick allowed options.
|
|
3318
|
-
// Some options may crash worker, e.g. --prof, --title. nodejs/node#41103
|
|
3319
|
-
const execArgv = process.execArgv.filter((execArg) => execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"));
|
|
3253
|
+
return viteMajor >= 6 && condition === "development|production" ? ctx.vite.config.isProduction ? "production" : "development" : condition;
|
|
3254
|
+
}).flatMap((c) => ["--conditions", c]), execArgv = process.execArgv.filter((execArg) => execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"));
|
|
3320
3255
|
async function executeTests(method, files, invalidate) {
|
|
3321
3256
|
const options = {
|
|
3322
3257
|
execArgv: [...execArgv, ...conditions],
|
|
@@ -3332,25 +3267,22 @@ function createPool(ctx) {
|
|
|
3332
3267
|
};
|
|
3333
3268
|
// env are case-insensitive on Windows, but spawned processes don't support it
|
|
3334
3269
|
if (isWindows) for (const name in options.env) options.env[name.toUpperCase()] = options.env[name];
|
|
3335
|
-
const poolConcurrentPromises = /* @__PURE__ */ new Map();
|
|
3336
|
-
const customPools = /* @__PURE__ */ new Map();
|
|
3270
|
+
const poolConcurrentPromises = /* @__PURE__ */ new Map(), customPools = /* @__PURE__ */ new Map();
|
|
3337
3271
|
async function resolveCustomPool(filepath) {
|
|
3338
3272
|
if (customPools.has(filepath)) return customPools.get(filepath);
|
|
3339
|
-
const pool = await ctx.runner.
|
|
3273
|
+
const pool = await ctx.runner.import(filepath);
|
|
3340
3274
|
if (typeof pool.default !== "function") throw new TypeError(`Custom pool "${filepath}" must export a function as default export`);
|
|
3341
3275
|
const poolInstance = await pool.default(ctx, options);
|
|
3342
3276
|
if (typeof poolInstance?.name !== "string") throw new TypeError(`Custom pool "${filepath}" should return an object with "name" property`);
|
|
3343
3277
|
if (typeof poolInstance?.[method] !== "function") throw new TypeError(`Custom pool "${filepath}" should return an object with "${method}" method`);
|
|
3344
|
-
customPools.set(filepath, poolInstance);
|
|
3345
|
-
return poolInstance;
|
|
3278
|
+
return customPools.set(filepath, poolInstance), poolInstance;
|
|
3346
3279
|
}
|
|
3347
3280
|
function getConcurrentPool(pool, fn) {
|
|
3348
3281
|
if (poolConcurrentPromises.has(pool)) return poolConcurrentPromises.get(pool);
|
|
3349
3282
|
const promise = fn().finally(() => {
|
|
3350
3283
|
poolConcurrentPromises.delete(pool);
|
|
3351
3284
|
});
|
|
3352
|
-
poolConcurrentPromises.set(pool, promise);
|
|
3353
|
-
return promise;
|
|
3285
|
+
return poolConcurrentPromises.set(pool, promise), promise;
|
|
3354
3286
|
}
|
|
3355
3287
|
function getCustomPool(pool) {
|
|
3356
3288
|
return getConcurrentPool(pool, () => resolveCustomPool(pool));
|
|
@@ -3361,9 +3293,7 @@ function createPool(ctx) {
|
|
|
3361
3293
|
return createBrowserPool(ctx);
|
|
3362
3294
|
});
|
|
3363
3295
|
}
|
|
3364
|
-
const groupedSpecifications = {}
|
|
3365
|
-
const groups = /* @__PURE__ */ new Set();
|
|
3366
|
-
const factories = {
|
|
3296
|
+
const groupedSpecifications = {}, groups = /* @__PURE__ */ new Set(), factories = {
|
|
3367
3297
|
vmThreads: () => createVmThreadsPool(ctx, options),
|
|
3368
3298
|
vmForks: () => createVmForksPool(ctx, options),
|
|
3369
3299
|
threads: () => createThreadsPool(ctx, options),
|
|
@@ -3372,12 +3302,9 @@ function createPool(ctx) {
|
|
|
3372
3302
|
};
|
|
3373
3303
|
for (const spec of files) {
|
|
3374
3304
|
const group = spec[0].config.sequence.groupOrder ?? 0;
|
|
3375
|
-
groups.add(group);
|
|
3376
|
-
groupedSpecifications[group] ??= [];
|
|
3377
|
-
groupedSpecifications[group].push(spec);
|
|
3305
|
+
groups.add(group), groupedSpecifications[group] ??= [], groupedSpecifications[group].push(spec);
|
|
3378
3306
|
}
|
|
3379
|
-
const Sequencer = ctx.config.sequence.sequencer;
|
|
3380
|
-
const sequencer = new Sequencer(ctx);
|
|
3307
|
+
const Sequencer = ctx.config.sequence.sequencer, sequencer = new Sequencer(ctx);
|
|
3381
3308
|
async function sortSpecs(specs) {
|
|
3382
3309
|
if (ctx.config.shard) {
|
|
3383
3310
|
if (!ctx.config.passWithNoTests && ctx.config.shard.count > specs.length) throw new Error(`--shard <count> must be a smaller than count of test files. Resolved ${specs.length} test files for --shard=${ctx.config.shard.index}/${ctx.config.shard.count}.`);
|
|
@@ -3398,25 +3325,18 @@ function createPool(ctx) {
|
|
|
3398
3325
|
};
|
|
3399
3326
|
specifications.forEach((specification) => {
|
|
3400
3327
|
const pool = specification[2].pool;
|
|
3401
|
-
filesByPool[pool] ??= [];
|
|
3402
|
-
|
|
3403
|
-
});
|
|
3404
|
-
await Promise.all(Object.entries(filesByPool).map(async (entry) => {
|
|
3328
|
+
filesByPool[pool] ??= [], filesByPool[pool].push(specification);
|
|
3329
|
+
}), await Promise.all(Object.entries(filesByPool).map(async (entry) => {
|
|
3405
3330
|
const [pool, files] = entry;
|
|
3406
3331
|
if (!files.length) return null;
|
|
3407
3332
|
const specs = await sortSpecs(files);
|
|
3408
3333
|
if (pool in factories) {
|
|
3409
3334
|
const factory = factories[pool];
|
|
3410
|
-
pools[pool] ??= factory();
|
|
3411
|
-
return pools[pool][method](specs, invalidate);
|
|
3412
|
-
}
|
|
3413
|
-
if (pool === "browser") {
|
|
3414
|
-
pools.browser ??= await getBrowserPool();
|
|
3415
|
-
return pools.browser[method](specs, invalidate);
|
|
3335
|
+
return pools[pool] ??= factory(), pools[pool][method](specs, invalidate);
|
|
3416
3336
|
}
|
|
3337
|
+
if (pool === "browser") return pools.browser ??= await getBrowserPool(), pools.browser[method](specs, invalidate);
|
|
3417
3338
|
const poolHandler = await getCustomPool(pool);
|
|
3418
|
-
pools[poolHandler.name] ??= poolHandler;
|
|
3419
|
-
return poolHandler[method](specs, invalidate);
|
|
3339
|
+
return pools[poolHandler.name] ??= poolHandler, poolHandler[method](specs, invalidate);
|
|
3420
3340
|
}));
|
|
3421
3341
|
}
|
|
3422
3342
|
}
|
|
@@ -3437,12 +3357,9 @@ class BaseSequencer {
|
|
|
3437
3357
|
}
|
|
3438
3358
|
// async so it can be extended by other sequelizers
|
|
3439
3359
|
async shard(files) {
|
|
3440
|
-
const { config } = this.ctx;
|
|
3441
|
-
const { index, count } = config.shard;
|
|
3442
|
-
const [shardStart, shardEnd] = this.calculateShardRange(files.length, index, count);
|
|
3360
|
+
const { config } = this.ctx, { index, count } = config.shard, [shardStart, shardEnd] = this.calculateShardRange(files.length, index, count);
|
|
3443
3361
|
return [...files].map((spec) => {
|
|
3444
|
-
const fullPath = resolve$1(slash(config.root), slash(spec.moduleId));
|
|
3445
|
-
const specPath = fullPath?.slice(config.root.length);
|
|
3362
|
+
const fullPath = resolve$1(slash(config.root), slash(spec.moduleId)), specPath = fullPath?.slice(config.root.length);
|
|
3446
3363
|
return {
|
|
3447
3364
|
spec,
|
|
3448
3365
|
hash: hash("sha1", specPath, "hex")
|
|
@@ -3453,37 +3370,24 @@ class BaseSequencer {
|
|
|
3453
3370
|
async sort(files) {
|
|
3454
3371
|
const cache = this.ctx.cache;
|
|
3455
3372
|
return [...files].sort((a, b) => {
|
|
3456
|
-
const keyA = `${a.project.name}:${relative(this.ctx.config.root, a.moduleId)}
|
|
3457
|
-
const keyB = `${b.project.name}:${relative(this.ctx.config.root, b.moduleId)}`;
|
|
3458
|
-
const aState = cache.getFileTestResults(keyA);
|
|
3459
|
-
const bState = cache.getFileTestResults(keyB);
|
|
3373
|
+
const keyA = `${a.project.name}:${relative(this.ctx.config.root, a.moduleId)}`, keyB = `${b.project.name}:${relative(this.ctx.config.root, b.moduleId)}`, aState = cache.getFileTestResults(keyA), bState = cache.getFileTestResults(keyB);
|
|
3460
3374
|
if (!aState || !bState) {
|
|
3461
|
-
const statsA = cache.getFileStats(keyA);
|
|
3462
|
-
const statsB = cache.getFileStats(keyB);
|
|
3463
|
-
// run unknown first
|
|
3464
|
-
if (!statsA || !statsB) return !statsA && statsB ? -1 : !statsB && statsA ? 1 : 0;
|
|
3375
|
+
const statsA = cache.getFileStats(keyA), statsB = cache.getFileStats(keyB);
|
|
3465
3376
|
// run larger files first
|
|
3466
|
-
return statsB.size - statsA.size;
|
|
3377
|
+
return !statsA || !statsB ? !statsA && statsB ? -1 : !statsB && statsA ? 1 : 0 : statsB.size - statsA.size;
|
|
3467
3378
|
}
|
|
3468
|
-
// run failed first
|
|
3469
|
-
if (aState.failed && !bState.failed) return -1;
|
|
3470
|
-
if (!aState.failed && bState.failed) return 1;
|
|
3471
3379
|
// run longer first
|
|
3472
|
-
return bState.duration - aState.duration;
|
|
3380
|
+
return aState.failed && !bState.failed ? -1 : !aState.failed && bState.failed ? 1 : bState.duration - aState.duration;
|
|
3473
3381
|
});
|
|
3474
3382
|
}
|
|
3475
3383
|
// Calculate distributed shard range [start, end] distributed equally
|
|
3476
3384
|
calculateShardRange(filesCount, index, count) {
|
|
3477
|
-
const baseShardSize = Math.floor(filesCount / count);
|
|
3478
|
-
const remainderTestFilesCount = filesCount % count;
|
|
3385
|
+
const baseShardSize = Math.floor(filesCount / count), remainderTestFilesCount = filesCount % count;
|
|
3479
3386
|
if (remainderTestFilesCount >= index) {
|
|
3480
|
-
const shardSize = baseShardSize + 1;
|
|
3481
|
-
const shardStart = shardSize * (index - 1);
|
|
3482
|
-
const shardEnd = shardSize * index;
|
|
3387
|
+
const shardSize = baseShardSize + 1, shardStart = shardSize * (index - 1), shardEnd = shardSize * index;
|
|
3483
3388
|
return [shardStart, shardEnd];
|
|
3484
3389
|
}
|
|
3485
|
-
const shardStart = remainderTestFilesCount * (baseShardSize + 1) + (index - remainderTestFilesCount - 1) * baseShardSize;
|
|
3486
|
-
const shardEnd = shardStart + baseShardSize;
|
|
3390
|
+
const shardStart = remainderTestFilesCount * (baseShardSize + 1) + (index - remainderTestFilesCount - 1) * baseShardSize, shardEnd = shardStart + baseShardSize;
|
|
3487
3391
|
return [shardStart, shardEnd];
|
|
3488
3392
|
}
|
|
3489
3393
|
}
|
|
@@ -3503,11 +3407,10 @@ function parseInspector(inspect) {
|
|
|
3503
3407
|
if (typeof inspect === "number") return { port: inspect };
|
|
3504
3408
|
if (inspect.match(/https?:\//)) throw new Error(`Inspector host cannot be a URL. Use "host:port" instead of "${inspect}"`);
|
|
3505
3409
|
const [host, port] = inspect.split(":");
|
|
3506
|
-
|
|
3507
|
-
return {
|
|
3410
|
+
return port ? {
|
|
3508
3411
|
host,
|
|
3509
3412
|
port: Number(port) || defaultInspectPort
|
|
3510
|
-
};
|
|
3413
|
+
} : { host };
|
|
3511
3414
|
}
|
|
3512
3415
|
function resolveApiServerConfig(options, defaultPort) {
|
|
3513
3416
|
let api;
|
|
@@ -3525,12 +3428,10 @@ function resolveApiServerConfig(options, defaultPort) {
|
|
|
3525
3428
|
return api;
|
|
3526
3429
|
}
|
|
3527
3430
|
function resolveInlineWorkerOption(value) {
|
|
3528
|
-
|
|
3529
|
-
else return Number(value);
|
|
3431
|
+
return typeof value === "string" && value.trim().endsWith("%") ? getWorkersCountByPercentage(value) : Number(value);
|
|
3530
3432
|
}
|
|
3531
3433
|
function resolveConfig$1(vitest, options, viteConfig) {
|
|
3532
|
-
const mode = vitest.mode;
|
|
3533
|
-
const logger = vitest.logger;
|
|
3434
|
+
const mode = vitest.mode, logger = vitest.logger;
|
|
3534
3435
|
if (options.dom) {
|
|
3535
3436
|
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}"`));
|
|
3536
3437
|
options.environment = "happy-dom";
|
|
@@ -3541,25 +3442,17 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
3541
3442
|
root: viteConfig.root,
|
|
3542
3443
|
mode
|
|
3543
3444
|
};
|
|
3544
|
-
resolved.project = toArray(resolved.project);
|
|
3545
|
-
resolved.provide ??= {};
|
|
3546
|
-
resolved.name = typeof options.name === "string" ? options.name : options.name?.label || "";
|
|
3547
|
-
resolved.color = typeof options.name !== "string" ? options.name?.color : void 0;
|
|
3548
|
-
if (resolved.environment === "browser") throw new Error(`Looks like you set "test.environment" to "browser". To enabled Browser Mode, use "test.browser.enabled" instead.`);
|
|
3445
|
+
if (resolved.project = toArray(resolved.project), resolved.provide ??= {}, resolved.name = typeof options.name === "string" ? options.name : options.name?.label || "", resolved.color = typeof options.name !== "string" ? options.name?.color : void 0, resolved.environment === "browser") throw new Error(`Looks like you set "test.environment" to "browser". To enabled Browser Mode, use "test.browser.enabled" instead.`);
|
|
3549
3446
|
const inspector = resolved.inspect || resolved.inspectBrk;
|
|
3550
|
-
resolved.inspector = {
|
|
3447
|
+
if (resolved.inspector = {
|
|
3551
3448
|
...resolved.inspector,
|
|
3552
3449
|
...parseInspector(inspector),
|
|
3553
3450
|
enabled: !!inspector,
|
|
3554
3451
|
waitForDebugger: options.inspector?.waitForDebugger ?? !!resolved.inspectBrk
|
|
3555
|
-
};
|
|
3556
|
-
if (
|
|
3557
|
-
resolved.clearScreen = resolved.clearScreen ?? viteConfig.clearScreen ?? true;
|
|
3558
|
-
if (options.shard) {
|
|
3452
|
+
}, viteConfig.base !== "/") resolved.base = viteConfig.base;
|
|
3453
|
+
if (resolved.clearScreen = resolved.clearScreen ?? viteConfig.clearScreen ?? true, options.shard) {
|
|
3559
3454
|
if (resolved.watch) throw new Error("You cannot use --shard option with enabled watch");
|
|
3560
|
-
const [indexString, countString] = options.shard.split("/");
|
|
3561
|
-
const index = Math.abs(Number.parseInt(indexString, 10));
|
|
3562
|
-
const count = Math.abs(Number.parseInt(countString, 10));
|
|
3455
|
+
const [indexString, countString] = options.shard.split("/"), index = Math.abs(Number.parseInt(indexString, 10)), count = Math.abs(Number.parseInt(countString, 10));
|
|
3563
3456
|
if (Number.isNaN(count) || count <= 0) throw new Error("--shard <count> must be a positive number");
|
|
3564
3457
|
if (Number.isNaN(index) || index <= 0 || index > count) throw new Error("--shard <index> must be a positive number less then <count>");
|
|
3565
3458
|
resolved.shard = {
|
|
@@ -3571,20 +3464,10 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
3571
3464
|
if (resolved.mergeReports && resolved.watch) throw new Error(`Cannot merge reports with --watch enabled`);
|
|
3572
3465
|
if (resolved.maxWorkers) resolved.maxWorkers = resolveInlineWorkerOption(resolved.maxWorkers);
|
|
3573
3466
|
if (resolved.minWorkers) resolved.minWorkers = resolveInlineWorkerOption(resolved.minWorkers);
|
|
3574
|
-
|
|
3575
|
-
resolved.
|
|
3576
|
-
if (!resolved.fileParallelism) {
|
|
3577
|
-
// ignore user config, parallelism cannot be implemented without limiting workers
|
|
3578
|
-
resolved.maxWorkers = 1;
|
|
3579
|
-
resolved.minWorkers = 1;
|
|
3580
|
-
}
|
|
3581
|
-
if (resolved.maxConcurrency === 0) {
|
|
3582
|
-
logger.console.warn(c.yellow(`The option "maxConcurrency" cannot be set to 0. Using default value ${configDefaults.maxConcurrency} instead.`));
|
|
3583
|
-
resolved.maxConcurrency = configDefaults.maxConcurrency;
|
|
3584
|
-
}
|
|
3467
|
+
if (resolved.fileParallelism ??= mode !== "benchmark", !resolved.fileParallelism) resolved.maxWorkers = 1, resolved.minWorkers = 1;
|
|
3468
|
+
if (resolved.maxConcurrency === 0) logger.console.warn(c.yellow(`The option "maxConcurrency" cannot be set to 0. Using default value ${configDefaults.maxConcurrency} instead.`)), resolved.maxConcurrency = configDefaults.maxConcurrency;
|
|
3585
3469
|
if (resolved.inspect || resolved.inspectBrk) {
|
|
3586
|
-
const isSingleThread = resolved.pool === "threads" && resolved.poolOptions?.threads?.singleThread;
|
|
3587
|
-
const isSingleFork = resolved.pool === "forks" && resolved.poolOptions?.forks?.singleFork;
|
|
3470
|
+
const isSingleThread = resolved.pool === "threads" && resolved.poolOptions?.threads?.singleThread, isSingleFork = resolved.pool === "forks" && resolved.poolOptions?.forks?.singleFork;
|
|
3588
3471
|
if (resolved.fileParallelism && !isSingleThread && !isSingleFork) {
|
|
3589
3472
|
const inspectOption = `--inspect${resolved.inspectBrk ? "-brk" : ""}`;
|
|
3590
3473
|
throw new Error(`You cannot use ${inspectOption} without "--no-file-parallelism", "poolOptions.threads.singleThread" or "poolOptions.forks.singleFork"`);
|
|
@@ -3622,99 +3505,44 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
3622
3505
|
} }, null, 2)}\n\n...or disable ${inspectOption}\n`);
|
|
3623
3506
|
}
|
|
3624
3507
|
}
|
|
3625
|
-
resolved.coverage.reporter = resolveCoverageReporters(resolved.coverage.reporter)
|
|
3626
|
-
if (resolved.coverage.enabled && resolved.coverage.reportsDirectory) {
|
|
3508
|
+
if (resolved.coverage.reporter = resolveCoverageReporters(resolved.coverage.reporter), resolved.coverage.enabled && resolved.coverage.reportsDirectory) {
|
|
3627
3509
|
const reportsDirectory = resolve$1(resolved.root, resolved.coverage.reportsDirectory);
|
|
3628
3510
|
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`);
|
|
3629
3511
|
}
|
|
3630
3512
|
if (resolved.coverage.enabled && resolved.coverage.provider === "custom" && resolved.coverage.customProviderModule) resolved.coverage.customProviderModule = resolvePath(resolved.coverage.customProviderModule, resolved.root);
|
|
3631
|
-
resolved.expect ??= {};
|
|
3632
|
-
|
|
3633
|
-
resolved.deps.moduleDirectories
|
|
3634
|
-
resolved.deps.moduleDirectories = resolved.deps.moduleDirectories.map((dir) => {
|
|
3513
|
+
resolved.expect ??= {}, resolved.deps ??= {}, resolved.deps.moduleDirectories ??= [];
|
|
3514
|
+
const envModuleDirectories = process.env.VITEST_MODULE_DIRECTORIES || process.env.npm_config_VITEST_MODULE_DIRECTORIES;
|
|
3515
|
+
if (envModuleDirectories) resolved.deps.moduleDirectories.push(...envModuleDirectories.split(","));
|
|
3516
|
+
if (resolved.deps.moduleDirectories = resolved.deps.moduleDirectories.map((dir) => {
|
|
3635
3517
|
if (!dir.startsWith("/")) dir = `/${dir}`;
|
|
3636
3518
|
if (!dir.endsWith("/")) dir += "/";
|
|
3637
3519
|
return normalize(dir);
|
|
3638
|
-
});
|
|
3639
|
-
if (
|
|
3640
|
-
resolved.deps.optimizer ??= {};
|
|
3641
|
-
resolved.deps.optimizer.ssr ??= {};
|
|
3642
|
-
resolved.deps.optimizer.ssr.enabled ??= true;
|
|
3643
|
-
resolved.deps.optimizer.web ??= {};
|
|
3644
|
-
resolved.deps.optimizer.web.enabled ??= true;
|
|
3645
|
-
resolved.deps.web ??= {};
|
|
3646
|
-
resolved.deps.web.transformAssets ??= true;
|
|
3647
|
-
resolved.deps.web.transformCss ??= true;
|
|
3648
|
-
resolved.deps.web.transformGlobPattern ??= [];
|
|
3649
|
-
resolved.setupFiles = toArray(resolved.setupFiles || []).map((file) => resolvePath(file, resolved.root));
|
|
3650
|
-
resolved.globalSetup = toArray(resolved.globalSetup || []).map((file) => resolvePath(file, resolved.root));
|
|
3651
|
-
// Add hard-coded default coverage exclusions. These cannot be overidden by user config.
|
|
3652
|
-
// Override original exclude array for cases where user re-uses same object in test.exclude.
|
|
3653
|
-
resolved.coverage.exclude = [
|
|
3520
|
+
}), !resolved.deps.moduleDirectories.includes("/node_modules/")) resolved.deps.moduleDirectories.push("/node_modules/");
|
|
3521
|
+
if (resolved.deps.optimizer ??= {}, resolved.deps.optimizer.ssr ??= {}, resolved.deps.optimizer.ssr.enabled ??= false, resolved.deps.optimizer.client ??= {}, resolved.deps.optimizer.client.enabled ??= false, resolved.deps.web ??= {}, resolved.deps.web.transformAssets ??= true, resolved.deps.web.transformCss ??= true, resolved.deps.web.transformGlobPattern ??= [], resolved.setupFiles = toArray(resolved.setupFiles || []).map((file) => resolvePath(file, resolved.root)), resolved.globalSetup = toArray(resolved.globalSetup || []).map((file) => resolvePath(file, resolved.root)), resolved.coverage.exclude = [
|
|
3654
3522
|
...resolved.coverage.exclude,
|
|
3655
3523
|
...resolved.setupFiles.map((file) => `${resolved.coverage.allowExternal ? "**/" : ""}${relative(resolved.root, file)}`),
|
|
3656
3524
|
...resolved.include,
|
|
3657
|
-
resolved.config && slash
|
|
3525
|
+
resolved.config && slash(resolved.config),
|
|
3658
3526
|
...configFiles,
|
|
3659
3527
|
"**/virtual:*",
|
|
3660
3528
|
"**/__x00__*",
|
|
3661
3529
|
"**/node_modules/**"
|
|
3662
|
-
].filter((pattern) => pattern != null);
|
|
3663
|
-
resolved.forceRerunTriggers = [...resolved.forceRerunTriggers, ...resolved.setupFiles];
|
|
3664
|
-
resolved.server ??= {};
|
|
3665
|
-
resolved.server.deps ??= {};
|
|
3666
|
-
const deprecatedDepsOptions = [
|
|
3667
|
-
"inline",
|
|
3668
|
-
"external",
|
|
3669
|
-
"fallbackCJS"
|
|
3670
|
-
];
|
|
3671
|
-
deprecatedDepsOptions.forEach((option) => {
|
|
3672
|
-
if (resolved.deps[option] === void 0) return;
|
|
3673
|
-
if (option === "fallbackCJS") logger.console.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} "deps.${option}" is deprecated. Use "server.deps.${option}" instead`));
|
|
3674
|
-
else {
|
|
3675
|
-
const transformMode = resolved.environment === "happy-dom" || resolved.environment === "jsdom" ? "web" : "ssr";
|
|
3676
|
-
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"}"`));
|
|
3677
|
-
}
|
|
3678
|
-
if (resolved.server.deps[option] === void 0) resolved.server.deps[option] = resolved.deps[option];
|
|
3679
|
-
});
|
|
3680
|
-
if (resolved.cliExclude) resolved.exclude.push(...resolved.cliExclude);
|
|
3681
|
-
// vitenode will try to import such file with native node,
|
|
3682
|
-
// but then our mocker will not work properly
|
|
3683
|
-
if (resolved.server.deps.inline !== true) {
|
|
3684
|
-
const ssrOptions = viteConfig.ssr;
|
|
3685
|
-
if (ssrOptions?.noExternal === true && resolved.server.deps.inline == null) resolved.server.deps.inline = true;
|
|
3686
|
-
else {
|
|
3687
|
-
resolved.server.deps.inline ??= [];
|
|
3688
|
-
resolved.server.deps.inline.push(...extraInlineDeps);
|
|
3689
|
-
}
|
|
3690
|
-
}
|
|
3691
|
-
resolved.server.deps.inlineFiles ??= [];
|
|
3692
|
-
resolved.server.deps.inlineFiles.push(...resolved.setupFiles);
|
|
3693
|
-
resolved.server.deps.moduleDirectories ??= [];
|
|
3694
|
-
resolved.server.deps.moduleDirectories.push(...resolved.deps.moduleDirectories);
|
|
3530
|
+
].filter((pattern) => pattern != null), resolved.forceRerunTriggers = [...resolved.forceRerunTriggers, ...resolved.setupFiles], resolved.cliExclude) resolved.exclude.push(...resolved.cliExclude);
|
|
3695
3531
|
if (resolved.runner) resolved.runner = resolvePath(resolved.runner, resolved.root);
|
|
3696
|
-
resolved.attachmentsDir = resolve$1(resolved.root, resolved.attachmentsDir ?? ".vitest-attachments");
|
|
3697
|
-
if (resolved.
|
|
3698
|
-
resolved.testNamePattern = resolved.testNamePattern ? resolved.testNamePattern instanceof RegExp ? resolved.testNamePattern : new RegExp(resolved.testNamePattern) : void 0;
|
|
3699
|
-
if (resolved.snapshotFormat && "plugins" in resolved.snapshotFormat) {
|
|
3700
|
-
resolved.snapshotFormat.plugins = [];
|
|
3532
|
+
if (resolved.attachmentsDir = resolve$1(resolved.root, resolved.attachmentsDir ?? ".vitest-attachments"), resolved.snapshotEnvironment) resolved.snapshotEnvironment = resolvePath(resolved.snapshotEnvironment, resolved.root);
|
|
3533
|
+
if (resolved.testNamePattern = resolved.testNamePattern ? resolved.testNamePattern instanceof RegExp ? resolved.testNamePattern : new RegExp(resolved.testNamePattern) : void 0, resolved.snapshotFormat && "plugins" in resolved.snapshotFormat) {
|
|
3701
3534
|
// TODO: support it via separate config (like DiffOptions) or via `Function.toString()`
|
|
3702
|
-
if (typeof resolved.snapshotFormat.compareKeys === "function") throw new TypeError(`"snapshotFormat.compareKeys" function is not supported.`);
|
|
3535
|
+
if (resolved.snapshotFormat.plugins = [], typeof resolved.snapshotFormat.compareKeys === "function") throw new TypeError(`"snapshotFormat.compareKeys" function is not supported.`);
|
|
3703
3536
|
}
|
|
3704
3537
|
const UPDATE_SNAPSHOT = resolved.update || process.env.UPDATE_SNAPSHOT;
|
|
3705
|
-
resolved.snapshotOptions = {
|
|
3538
|
+
if (resolved.snapshotOptions = {
|
|
3706
3539
|
expand: resolved.expandSnapshotDiff ?? false,
|
|
3707
3540
|
snapshotFormat: resolved.snapshotFormat || {},
|
|
3708
3541
|
updateSnapshot: isCI && !UPDATE_SNAPSHOT ? "none" : UPDATE_SNAPSHOT ? "all" : "new",
|
|
3709
3542
|
resolveSnapshotPath: options.resolveSnapshotPath,
|
|
3710
3543
|
snapshotEnvironment: null
|
|
3711
|
-
};
|
|
3712
|
-
resolved.
|
|
3713
|
-
resolved.snapshotSerializers = resolved.snapshotSerializers.map((file) => resolvePath(file, resolved.root));
|
|
3714
|
-
resolved.forceRerunTriggers.push(...resolved.snapshotSerializers);
|
|
3715
|
-
if (options.resolveSnapshotPath) delete resolved.resolveSnapshotPath;
|
|
3716
|
-
resolved.pool ??= "threads";
|
|
3717
|
-
if (process.env.VITEST_MAX_THREADS) resolved.poolOptions = {
|
|
3544
|
+
}, resolved.snapshotSerializers ??= [], resolved.snapshotSerializers = resolved.snapshotSerializers.map((file) => resolvePath(file, resolved.root)), resolved.forceRerunTriggers.push(...resolved.snapshotSerializers), options.resolveSnapshotPath) delete resolved.resolveSnapshotPath;
|
|
3545
|
+
if (resolved.pool ??= "threads", process.env.VITEST_MAX_THREADS) resolved.poolOptions = {
|
|
3718
3546
|
...resolved.poolOptions,
|
|
3719
3547
|
threads: {
|
|
3720
3548
|
...resolved.poolOptions?.threads,
|
|
@@ -3777,13 +3605,7 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
3777
3605
|
resolved.benchmark = {
|
|
3778
3606
|
...benchmarkConfigDefaults,
|
|
3779
3607
|
...resolved.benchmark
|
|
3780
|
-
};
|
|
3781
|
-
// override test config
|
|
3782
|
-
resolved.coverage.enabled = false;
|
|
3783
|
-
resolved.typecheck.enabled = false;
|
|
3784
|
-
resolved.include = resolved.benchmark.include;
|
|
3785
|
-
resolved.exclude = resolved.benchmark.exclude;
|
|
3786
|
-
resolved.includeSource = resolved.benchmark.includeSource;
|
|
3608
|
+
}, resolved.coverage.enabled = false, resolved.typecheck.enabled = false, resolved.include = resolved.benchmark.include, resolved.exclude = resolved.benchmark.exclude, resolved.includeSource = resolved.benchmark.includeSource;
|
|
3787
3609
|
const reporters = Array.from(new Set([...toArray(resolved.benchmark.reporters), ...toArray(options.reporter)])).filter(Boolean);
|
|
3788
3610
|
if (reporters.length) resolved.benchmark.reporters = reporters;
|
|
3789
3611
|
else resolved.benchmark.reporters = ["default"];
|
|
@@ -3792,17 +3614,13 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
3792
3614
|
if (options.compare) resolved.benchmark.compare = options.compare;
|
|
3793
3615
|
if (options.outputJson) resolved.benchmark.outputJson = options.outputJson;
|
|
3794
3616
|
}
|
|
3795
|
-
if (typeof resolved.diff === "string")
|
|
3796
|
-
resolved.diff = resolvePath(resolved.diff, resolved.root);
|
|
3797
|
-
resolved.forceRerunTriggers.push(resolved.diff);
|
|
3798
|
-
}
|
|
3617
|
+
if (typeof resolved.diff === "string") resolved.diff = resolvePath(resolved.diff, resolved.root), resolved.forceRerunTriggers.push(resolved.diff);
|
|
3799
3618
|
// the server has been created, we don't need to override vite.server options
|
|
3800
3619
|
const api = resolveApiServerConfig(options, defaultPort);
|
|
3801
|
-
resolved.api = {
|
|
3620
|
+
if (resolved.api = {
|
|
3802
3621
|
...api,
|
|
3803
3622
|
token: crypto.randomUUID()
|
|
3804
|
-
};
|
|
3805
|
-
if (options.related) resolved.related = toArray(options.related).map((file) => resolve$1(resolved.root, file));
|
|
3623
|
+
}, options.related) resolved.related = toArray(options.related).map((file) => resolve$1(resolved.root, file));
|
|
3806
3624
|
/*
|
|
3807
3625
|
* Reporters can be defined in many different ways:
|
|
3808
3626
|
* { reporter: 'json' }
|
|
@@ -3831,84 +3649,51 @@ function resolveConfig$1(vitest, options, viteConfig) {
|
|
|
3831
3649
|
if (mode !== "benchmark") {
|
|
3832
3650
|
// @ts-expect-error "reporter" is from CLI, should be absolute to the running directory
|
|
3833
3651
|
// it is passed down as "vitest --reporter ../reporter.js"
|
|
3834
|
-
const reportersFromCLI = resolved.reporter
|
|
3835
|
-
|
|
3836
|
-
// ./reporter.js || ../reporter.js, but not .reporters/reporter.js
|
|
3837
|
-
if (/^\.\.?\//.test(reporter)) return resolve$1(process.cwd(), reporter);
|
|
3838
|
-
return reporter;
|
|
3652
|
+
const reportersFromCLI = resolved.reporter, cliReporters = toArray(reportersFromCLI || []).map((reporter) => {
|
|
3653
|
+
return /^\.\.?\//.test(reporter) ? resolve$1(process.cwd(), reporter) : reporter;
|
|
3839
3654
|
});
|
|
3840
3655
|
if (cliReporters.length) resolved.reporters = Array.from(new Set(toArray(cliReporters))).filter(Boolean).map((reporter) => [reporter, {}]);
|
|
3841
3656
|
}
|
|
3842
3657
|
if (!resolved.reporters.length) {
|
|
3843
|
-
resolved.reporters.push(["default", {}]);
|
|
3844
3658
|
// also enable github-actions reporter as a default
|
|
3845
|
-
if (process.env.GITHUB_ACTIONS === "true") resolved.reporters.push(["github-actions", {}]);
|
|
3659
|
+
if (resolved.reporters.push(["default", {}]), process.env.GITHUB_ACTIONS === "true") resolved.reporters.push(["github-actions", {}]);
|
|
3846
3660
|
}
|
|
3847
3661
|
if (resolved.changed) resolved.passWithNoTests ??= true;
|
|
3848
|
-
resolved.css ??= {};
|
|
3849
|
-
if (typeof resolved.css === "object") {
|
|
3850
|
-
resolved.css.modules ??= {};
|
|
3851
|
-
resolved.css.modules.classNameStrategy ??= "stable";
|
|
3852
|
-
}
|
|
3662
|
+
if (resolved.css ??= {}, typeof resolved.css === "object") resolved.css.modules ??= {}, resolved.css.modules.classNameStrategy ??= "stable";
|
|
3853
3663
|
if (resolved.cache !== false) {
|
|
3854
3664
|
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"`);
|
|
3855
3665
|
resolved.cache = { dir: viteConfig.cacheDir };
|
|
3856
3666
|
}
|
|
3857
|
-
resolved.sequence ??= {}
|
|
3858
|
-
if (resolved.sequence.shuffle && typeof resolved.sequence.shuffle === "object") {
|
|
3667
|
+
if (resolved.sequence ??= {}, resolved.sequence.shuffle && typeof resolved.sequence.shuffle === "object") {
|
|
3859
3668
|
const { files, tests } = resolved.sequence.shuffle;
|
|
3860
|
-
resolved.sequence.sequencer ??= files ? RandomSequencer : BaseSequencer;
|
|
3861
|
-
resolved.sequence.shuffle = tests;
|
|
3669
|
+
resolved.sequence.sequencer ??= files ? RandomSequencer : BaseSequencer, resolved.sequence.shuffle = tests;
|
|
3862
3670
|
}
|
|
3863
3671
|
if (!resolved.sequence?.sequencer)
|
|
3864
3672
|
// CLI flag has higher priority
|
|
3865
3673
|
resolved.sequence.sequencer = resolved.sequence.shuffle ? RandomSequencer : BaseSequencer;
|
|
3866
|
-
resolved.sequence.groupOrder ??= 0;
|
|
3867
|
-
resolved.
|
|
3868
|
-
if (resolved.sequence.sequencer === RandomSequencer) resolved.sequence.seed ??= Date.now();
|
|
3869
|
-
resolved.typecheck = {
|
|
3674
|
+
if (resolved.sequence.groupOrder ??= 0, resolved.sequence.hooks ??= "stack", resolved.sequence.sequencer === RandomSequencer) resolved.sequence.seed ??= Date.now();
|
|
3675
|
+
if (resolved.typecheck = {
|
|
3870
3676
|
...configDefaults.typecheck,
|
|
3871
3677
|
...resolved.typecheck
|
|
3872
|
-
};
|
|
3873
|
-
resolved.
|
|
3874
|
-
resolved.typecheck.enabled ??= false;
|
|
3875
|
-
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."));
|
|
3876
|
-
resolved.browser.enabled ??= false;
|
|
3877
|
-
resolved.browser.headless ??= isCI;
|
|
3878
|
-
resolved.browser.isolate ??= true;
|
|
3879
|
-
resolved.browser.fileParallelism ??= options.fileParallelism ?? mode !== "benchmark";
|
|
3880
|
-
// disable in headless mode by default, and if CI is detected
|
|
3881
|
-
resolved.browser.ui ??= resolved.browser.headless === true ? false : !isCI;
|
|
3882
|
-
if (resolved.browser.screenshotDirectory) resolved.browser.screenshotDirectory = resolve$1(resolved.root, resolved.browser.screenshotDirectory);
|
|
3678
|
+
}, resolved.typecheck ??= {}, resolved.typecheck.enabled ??= false, 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."));
|
|
3679
|
+
if (resolved.browser.enabled ??= false, resolved.browser.headless ??= isCI, resolved.browser.isolate ??= true, resolved.browser.fileParallelism ??= options.fileParallelism ?? mode !== "benchmark", resolved.browser.ui ??= resolved.browser.headless === true ? false : !isCI, resolved.browser.screenshotDirectory) resolved.browser.screenshotDirectory = resolve$1(resolved.root, resolved.browser.screenshotDirectory);
|
|
3883
3680
|
const isPreview = resolved.browser.provider === "preview";
|
|
3884
|
-
if (isPreview && resolved.browser.screenshotFailures === true)
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
} else resolved.browser.screenshotFailures ??= !isPreview && !resolved.browser.ui;
|
|
3892
|
-
resolved.browser.viewport ??= {};
|
|
3893
|
-
resolved.browser.viewport.width ??= 414;
|
|
3894
|
-
resolved.browser.viewport.height ??= 896;
|
|
3895
|
-
resolved.browser.locators ??= {};
|
|
3896
|
-
resolved.browser.locators.testIdAttribute ??= "data-testid";
|
|
3897
|
-
if (resolved.browser.enabled && provider === "stackblitz") resolved.browser.provider = "preview";
|
|
3898
|
-
resolved.browser.api = resolveApiServerConfig(resolved.browser, defaultBrowserPort) || { port: defaultBrowserPort };
|
|
3681
|
+
if (isPreview && resolved.browser.screenshotFailures === true) console.warn(c.yellow([
|
|
3682
|
+
`Browser provider "preview" doesn't support screenshots, `,
|
|
3683
|
+
`so "browser.screenshotFailures" option is forcefully disabled. `,
|
|
3684
|
+
`Set "browser.screenshotFailures" to false or remove it from the config to suppress this warning.`
|
|
3685
|
+
].join(""))), resolved.browser.screenshotFailures = false;
|
|
3686
|
+
else resolved.browser.screenshotFailures ??= !isPreview && !resolved.browser.ui;
|
|
3687
|
+
if (resolved.browser.viewport ??= {}, resolved.browser.viewport.width ??= 414, resolved.browser.viewport.height ??= 896, resolved.browser.locators ??= {}, resolved.browser.locators.testIdAttribute ??= "data-testid", resolved.browser.enabled && provider === "stackblitz") resolved.browser.provider = "preview";
|
|
3899
3688
|
// enable includeTaskLocation by default in UI mode
|
|
3900
|
-
if (resolved.browser.enabled) {
|
|
3689
|
+
if (resolved.browser.api = resolveApiServerConfig(resolved.browser, defaultBrowserPort) || { port: defaultBrowserPort }, resolved.browser.enabled) {
|
|
3901
3690
|
if (resolved.browser.ui) resolved.includeTaskLocation ??= true;
|
|
3902
3691
|
} else if (resolved.ui) resolved.includeTaskLocation ??= true;
|
|
3903
3692
|
const htmlReporter = toArray(resolved.reporters).some((reporter) => {
|
|
3904
|
-
|
|
3905
|
-
return false;
|
|
3693
|
+
return Array.isArray(reporter) ? reporter[0] === "html" : false;
|
|
3906
3694
|
});
|
|
3907
3695
|
if (htmlReporter) resolved.includeTaskLocation ??= true;
|
|
3908
|
-
resolved.
|
|
3909
|
-
resolved.testTimeout ??= resolved.browser.enabled ? 15e3 : 5e3;
|
|
3910
|
-
resolved.hookTimeout ??= resolved.browser.enabled ? 3e4 : 1e4;
|
|
3911
|
-
return resolved;
|
|
3696
|
+
return resolved.server ??= {}, resolved.server.deps ??= {}, resolved.testTimeout ??= resolved.browser.enabled ? 15e3 : 5e3, resolved.hookTimeout ??= resolved.browser.enabled ? 3e4 : 1e4, resolved;
|
|
3912
3697
|
}
|
|
3913
3698
|
function isBrowserEnabled(config) {
|
|
3914
3699
|
return Boolean(config.browser?.enabled);
|
|
@@ -3944,14 +3729,11 @@ const THRESHOLD_KEYS = [
|
|
|
3944
3729
|
"functions",
|
|
3945
3730
|
"statements",
|
|
3946
3731
|
"branches"
|
|
3947
|
-
];
|
|
3948
|
-
const GLOBAL_THRESHOLDS_KEY = "global";
|
|
3949
|
-
const DEFAULT_PROJECT = Symbol.for("default-project");
|
|
3732
|
+
], GLOBAL_THRESHOLDS_KEY = "global", DEFAULT_PROJECT = Symbol.for("default-project");
|
|
3950
3733
|
let uniqueId = 0;
|
|
3951
3734
|
async function getCoverageProvider(options, loader) {
|
|
3952
3735
|
const coverageModule = await resolveCoverageProviderModule(options, loader);
|
|
3953
|
-
|
|
3954
|
-
return null;
|
|
3736
|
+
return coverageModule ? coverageModule.getProvider() : null;
|
|
3955
3737
|
}
|
|
3956
3738
|
class BaseCoverageProvider {
|
|
3957
3739
|
ctx;
|
|
@@ -3964,8 +3746,7 @@ class BaseCoverageProvider {
|
|
|
3964
3746
|
coverageFilesDirectory;
|
|
3965
3747
|
roots = [];
|
|
3966
3748
|
_initialize(ctx) {
|
|
3967
|
-
this.ctx = ctx
|
|
3968
|
-
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} `))}.
|
|
3749
|
+
if (this.ctx = ctx, 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} `))}.
|
|
3969
3750
|
Running mixed versions is not supported and may lead into bugs
|
|
3970
3751
|
Update your dependencies and make sure the versions match.`));
|
|
3971
3752
|
const config = ctx.config.coverage;
|
|
@@ -3983,25 +3764,18 @@ Update your dependencies and make sure the versions match.`));
|
|
|
3983
3764
|
statements: config.thresholds["100"] ? 100 : config.thresholds.statements
|
|
3984
3765
|
}
|
|
3985
3766
|
};
|
|
3986
|
-
const shard = this.ctx.config.shard
|
|
3987
|
-
const tempDirectory = `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`;
|
|
3988
|
-
this.coverageFilesDirectory = resolve$1(this.options.reportsDirectory, tempDirectory);
|
|
3767
|
+
const shard = this.ctx.config.shard, tempDirectory = `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`;
|
|
3989
3768
|
// If --project filter is set pick only roots of resolved projects
|
|
3990
|
-
this.roots = ctx.config.project?.length ? [...new Set(ctx.projects.map((project) => project.config.root))] : [ctx.config.root];
|
|
3769
|
+
this.coverageFilesDirectory = resolve$1(this.options.reportsDirectory, tempDirectory), this.roots = ctx.config.project?.length ? [...new Set(ctx.projects.map((project) => project.config.root))] : [ctx.config.root];
|
|
3991
3770
|
}
|
|
3992
3771
|
/**
|
|
3993
3772
|
* Check if file matches `coverage.include` but not `coverage.exclude`
|
|
3994
3773
|
*/
|
|
3995
3774
|
isIncluded(_filename, root) {
|
|
3996
|
-
const roots = root ? [root] : this.roots;
|
|
3997
|
-
const filename = slash(_filename);
|
|
3998
|
-
const cacheHit = this.globCache.get(filename);
|
|
3775
|
+
const roots = root ? [root] : this.roots, filename = slash(_filename), cacheHit = this.globCache.get(filename);
|
|
3999
3776
|
if (cacheHit !== void 0) return cacheHit;
|
|
4000
3777
|
// File outside project root with default allowExternal
|
|
4001
|
-
if (this.options.allowExternal === false && roots.every((root) => !filename.startsWith(root)))
|
|
4002
|
-
this.globCache.set(filename, false);
|
|
4003
|
-
return false;
|
|
4004
|
-
}
|
|
3778
|
+
if (this.options.allowExternal === false && roots.every((root) => !filename.startsWith(root))) return this.globCache.set(filename, false), false;
|
|
4005
3779
|
// By default `coverage.include` matches all files, except "coverage.exclude"
|
|
4006
3780
|
const glob = this.options.include || "**";
|
|
4007
3781
|
let included = roots.some((root) => {
|
|
@@ -4013,9 +3787,7 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4013
3787
|
};
|
|
4014
3788
|
return pm.isMatch(filename, glob, options);
|
|
4015
3789
|
});
|
|
4016
|
-
included &&= existsSync(cleanUrl(filename));
|
|
4017
|
-
this.globCache.set(filename, included);
|
|
4018
|
-
return included;
|
|
3790
|
+
return included &&= existsSync(cleanUrl(filename)), this.globCache.set(filename, included), included;
|
|
4019
3791
|
}
|
|
4020
3792
|
async getUntestedFilesByRoot(testedFiles, include, root) {
|
|
4021
3793
|
let includedFiles = await glob(include, {
|
|
@@ -4025,15 +3797,12 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4025
3797
|
dot: true,
|
|
4026
3798
|
onlyFiles: true
|
|
4027
3799
|
});
|
|
4028
|
-
|
|
4029
|
-
includedFiles = includedFiles.filter((file) => this.isIncluded(file, root));
|
|
4030
|
-
if (this.ctx.config.changed) includedFiles = (this.ctx.config.related || []).filter((file) => includedFiles.includes(file));
|
|
3800
|
+
if (includedFiles = includedFiles.filter((file) => this.isIncluded(file, root)), this.ctx.config.changed) includedFiles = (this.ctx.config.related || []).filter((file) => includedFiles.includes(file));
|
|
4031
3801
|
return includedFiles.map((file) => slash(path.resolve(root, file)));
|
|
4032
3802
|
}
|
|
4033
3803
|
async getUntestedFiles(testedFiles) {
|
|
4034
3804
|
if (this.options.include == null) return [];
|
|
4035
|
-
const rootMapper = this.getUntestedFilesByRoot.bind(this, testedFiles, this.options.include);
|
|
4036
|
-
const matrix = await Promise.all(this.roots.map(rootMapper));
|
|
3805
|
+
const rootMapper = this.getUntestedFilesByRoot.bind(this, testedFiles, this.options.include), matrix = await Promise.all(this.roots.map(rootMapper));
|
|
4037
3806
|
return matrix.flatMap((files) => files);
|
|
4038
3807
|
}
|
|
4039
3808
|
createCoverageMap() {
|
|
@@ -4059,56 +3828,37 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4059
3828
|
force: true,
|
|
4060
3829
|
maxRetries: 10
|
|
4061
3830
|
});
|
|
4062
|
-
await promises$1.mkdir(this.coverageFilesDirectory, { recursive: true });
|
|
4063
|
-
this.coverageFiles = /* @__PURE__ */ new Map();
|
|
4064
|
-
this.pendingPromises = [];
|
|
3831
|
+
await promises$1.mkdir(this.coverageFilesDirectory, { recursive: true }), this.coverageFiles = /* @__PURE__ */ new Map(), this.pendingPromises = [];
|
|
4065
3832
|
}
|
|
4066
|
-
onAfterSuiteRun({ coverage,
|
|
3833
|
+
onAfterSuiteRun({ coverage, environment, projectName, testFiles }) {
|
|
4067
3834
|
if (!coverage) return;
|
|
4068
|
-
if (transformMode !== "web" && transformMode !== "ssr" && transformMode !== "browser") throw new Error(`Invalid transform mode: ${transformMode}`);
|
|
4069
3835
|
let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT);
|
|
4070
|
-
if (!entry) {
|
|
4071
|
-
|
|
4072
|
-
web: {},
|
|
4073
|
-
ssr: {},
|
|
4074
|
-
browser: {}
|
|
4075
|
-
};
|
|
4076
|
-
this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
|
|
4077
|
-
}
|
|
4078
|
-
const testFilenames = testFiles.join();
|
|
4079
|
-
const filename = resolve$1(this.coverageFilesDirectory, `coverage-${uniqueId++}.json`);
|
|
3836
|
+
if (!entry) entry = {}, this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
|
|
3837
|
+
const testFilenames = testFiles.join(), filename = resolve$1(this.coverageFilesDirectory, `coverage-${uniqueId++}.json`);
|
|
4080
3838
|
// If there's a result from previous run, overwrite it
|
|
4081
|
-
entry[
|
|
3839
|
+
entry[environment] ??= {}, entry[environment][testFilenames] = filename;
|
|
4082
3840
|
const promise = promises$1.writeFile(filename, JSON.stringify(coverage), "utf-8");
|
|
4083
3841
|
this.pendingPromises.push(promise);
|
|
4084
3842
|
}
|
|
4085
3843
|
async readCoverageFiles({ onFileRead, onFinished, onDebug }) {
|
|
4086
3844
|
let index = 0;
|
|
4087
3845
|
const total = this.pendingPromises.length;
|
|
4088
|
-
await Promise.all(this.pendingPromises);
|
|
4089
|
-
this.
|
|
4090
|
-
|
|
4091
|
-
const filenames = Object.values(coverageByTestfiles);
|
|
4092
|
-
const project = this.ctx.getProjectByName(projectName);
|
|
3846
|
+
await Promise.all(this.pendingPromises), this.pendingPromises = [];
|
|
3847
|
+
for (const [projectName, coveragePerProject] of this.coverageFiles.entries()) for (const [environment, coverageByTestfiles] of Object.entries(coveragePerProject)) {
|
|
3848
|
+
const filenames = Object.values(coverageByTestfiles), project = this.ctx.getProjectByName(projectName);
|
|
4093
3849
|
for (const chunk of this.toSlices(filenames, this.options.processingConcurrency)) {
|
|
4094
|
-
if (onDebug.enabled) {
|
|
4095
|
-
index += chunk.length;
|
|
4096
|
-
onDebug(`Reading coverage results ${index}/${total}`);
|
|
4097
|
-
}
|
|
3850
|
+
if (onDebug.enabled) index += chunk.length, onDebug(`Reading coverage results ${index}/${total}`);
|
|
4098
3851
|
await Promise.all(chunk.map(async (filename) => {
|
|
4099
|
-
const contents = await promises$1.readFile(filename, "utf-8");
|
|
4100
|
-
const coverage = JSON.parse(contents);
|
|
3852
|
+
const contents = await promises$1.readFile(filename, "utf-8"), coverage = JSON.parse(contents);
|
|
4101
3853
|
onFileRead(coverage);
|
|
4102
3854
|
}));
|
|
4103
3855
|
}
|
|
4104
|
-
await onFinished(project,
|
|
3856
|
+
await onFinished(project, environment);
|
|
4105
3857
|
}
|
|
4106
3858
|
}
|
|
4107
3859
|
async cleanAfterRun() {
|
|
4108
|
-
this.coverageFiles = /* @__PURE__ */ new Map();
|
|
4109
|
-
await promises$1.rm(this.coverageFilesDirectory, { recursive: true });
|
|
4110
3860
|
// Remove empty reports directory, e.g. when only text-reporter is used
|
|
4111
|
-
if (readdirSync(this.options.reportsDirectory).length === 0) await promises$1.rm(this.options.reportsDirectory, { recursive: true });
|
|
3861
|
+
if (this.coverageFiles = /* @__PURE__ */ new Map(), await promises$1.rm(this.coverageFilesDirectory, { recursive: true }), readdirSync(this.options.reportsDirectory).length === 0) await promises$1.rm(this.options.reportsDirectory, { recursive: true });
|
|
4112
3862
|
}
|
|
4113
3863
|
async onTestFailure() {
|
|
4114
3864
|
if (!this.options.reportOnFailure) await this.cleanAfterRun();
|
|
@@ -4121,11 +3871,9 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4121
3871
|
}
|
|
4122
3872
|
async reportThresholds(coverageMap, allTestsRun) {
|
|
4123
3873
|
const resolvedThresholds = this.resolveThresholds(coverageMap);
|
|
4124
|
-
this.checkThresholds(resolvedThresholds)
|
|
4125
|
-
if (this.options.thresholds?.autoUpdate && allTestsRun) {
|
|
3874
|
+
if (this.checkThresholds(resolvedThresholds), this.options.thresholds?.autoUpdate && allTestsRun) {
|
|
4126
3875
|
if (!this.ctx.server.config.configFile) throw new Error("Missing configurationFile. The \"coverage.thresholds.autoUpdate\" can only be enabled when configuration file is used.");
|
|
4127
|
-
const configFilePath = this.ctx.server.config.configFile;
|
|
4128
|
-
const configModule = await this.parseConfigModule(configFilePath);
|
|
3876
|
+
const configFilePath = this.ctx.server.config.configFile, configModule = await this.parseConfigModule(configFilePath);
|
|
4129
3877
|
await this.updateThresholds({
|
|
4130
3878
|
thresholds: resolvedThresholds,
|
|
4131
3879
|
configurationFile: configModule,
|
|
@@ -4139,16 +3887,10 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4139
3887
|
* for specific files defined by glob pattern or global for all other files.
|
|
4140
3888
|
*/
|
|
4141
3889
|
resolveThresholds(coverageMap) {
|
|
4142
|
-
const resolvedThresholds = [];
|
|
4143
|
-
const files = coverageMap.files();
|
|
4144
|
-
const globalCoverageMap = this.createCoverageMap();
|
|
3890
|
+
const resolvedThresholds = [], files = coverageMap.files(), globalCoverageMap = this.createCoverageMap();
|
|
4145
3891
|
for (const key of Object.keys(this.options.thresholds)) {
|
|
4146
3892
|
if (key === "perFile" || key === "autoUpdate" || key === "100" || THRESHOLD_KEYS.includes(key)) continue;
|
|
4147
|
-
const glob = key;
|
|
4148
|
-
const globThresholds = resolveGlobThresholds(this.options.thresholds[glob]);
|
|
4149
|
-
const globCoverageMap = this.createCoverageMap();
|
|
4150
|
-
const matcher = pm(glob);
|
|
4151
|
-
const matchingFiles = files.filter((file) => matcher(relative(this.ctx.config.root, file)));
|
|
3893
|
+
const glob = key, globThresholds = resolveGlobThresholds(this.options.thresholds[glob]), globCoverageMap = this.createCoverageMap(), matcher = pm(glob), matchingFiles = files.filter((file) => matcher(relative(this.ctx.config.root, file)));
|
|
4152
3894
|
for (const file of matchingFiles) {
|
|
4153
3895
|
const fileCoverage = coverageMap.fileCoverageFor(file);
|
|
4154
3896
|
globCoverageMap.addFileCoverage(fileCoverage);
|
|
@@ -4164,7 +3906,7 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4164
3906
|
const fileCoverage = coverageMap.fileCoverageFor(file);
|
|
4165
3907
|
globalCoverageMap.addFileCoverage(fileCoverage);
|
|
4166
3908
|
}
|
|
4167
|
-
resolvedThresholds.unshift({
|
|
3909
|
+
return resolvedThresholds.unshift({
|
|
4168
3910
|
name: GLOBAL_THRESHOLDS_KEY,
|
|
4169
3911
|
coverageMap: globalCoverageMap,
|
|
4170
3912
|
thresholds: {
|
|
@@ -4173,8 +3915,7 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4173
3915
|
lines: this.options.thresholds?.lines,
|
|
4174
3916
|
statements: this.options.thresholds?.statements
|
|
4175
3917
|
}
|
|
4176
|
-
});
|
|
4177
|
-
return resolvedThresholds;
|
|
3918
|
+
}), resolvedThresholds;
|
|
4178
3919
|
}
|
|
4179
3920
|
/**
|
|
4180
3921
|
* Check collected coverage against configured thresholds. Sets exit code to 1 when thresholds not reached.
|
|
@@ -4212,8 +3953,7 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4212
3953
|
this.ctx.logger.error(errorMessage);
|
|
4213
3954
|
}
|
|
4214
3955
|
} else {
|
|
4215
|
-
const uncovered = summary.data[thresholdKey].total - summary.data[thresholdKey].covered;
|
|
4216
|
-
const absoluteThreshold = threshold * -1;
|
|
3956
|
+
const uncovered = summary.data[thresholdKey].total - summary.data[thresholdKey].covered, absoluteThreshold = threshold * -1;
|
|
4217
3957
|
if (uncovered > absoluteThreshold) {
|
|
4218
3958
|
process.exitCode = 1;
|
|
4219
3959
|
/**
|
|
@@ -4237,8 +3977,7 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4237
3977
|
const config = resolveConfig(configurationFile);
|
|
4238
3978
|
assertConfigurationModule(config);
|
|
4239
3979
|
for (const { coverageMap, thresholds, name } of allThresholds) {
|
|
4240
|
-
const summaries = this.options.thresholds?.perFile ? coverageMap.files().map((file) => coverageMap.fileCoverageFor(file).toSummary()) : [coverageMap.getCoverageSummary()];
|
|
4241
|
-
const thresholdsToUpdate = [];
|
|
3980
|
+
const summaries = this.options.thresholds?.perFile ? coverageMap.files().map((file) => coverageMap.fileCoverageFor(file).toSummary()) : [coverageMap.getCoverageSummary()], thresholdsToUpdate = [];
|
|
4242
3981
|
for (const key of THRESHOLD_KEYS) {
|
|
4243
3982
|
const threshold = thresholds[key] ?? 100;
|
|
4244
3983
|
/**
|
|
@@ -4249,8 +3988,7 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4249
3988
|
const actual = Math.min(...summaries.map((summary) => summary[key].pct));
|
|
4250
3989
|
if (actual > threshold) thresholdsToUpdate.push([key, actual]);
|
|
4251
3990
|
} else {
|
|
4252
|
-
const absoluteThreshold = threshold * -1;
|
|
4253
|
-
const actual = Math.max(...summaries.map((summary) => summary[key].total - summary[key].covered));
|
|
3991
|
+
const absoluteThreshold = threshold * -1, actual = Math.max(...summaries.map((summary) => summary[key].total - summary[key].covered));
|
|
4254
3992
|
if (actual < absoluteThreshold) {
|
|
4255
3993
|
// If everything was covered, set new threshold to 100% (since a threshold of 0 would be considered as 0%)
|
|
4256
3994
|
const updatedThreshold = actual === 0 ? 100 : actual * -1;
|
|
@@ -4266,10 +4004,7 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4266
4004
|
glob[threshold] = newValue;
|
|
4267
4005
|
}
|
|
4268
4006
|
}
|
|
4269
|
-
if (updatedThresholds)
|
|
4270
|
-
this.ctx.logger.log("Updating thresholds to configuration file. You may want to push with updated coverage thresholds.");
|
|
4271
|
-
onUpdate();
|
|
4272
|
-
}
|
|
4007
|
+
if (updatedThresholds) this.ctx.logger.log("Updating thresholds to configuration file. You may want to push with updated coverage thresholds."), onUpdate();
|
|
4273
4008
|
}
|
|
4274
4009
|
async mergeReports(coverageMaps) {
|
|
4275
4010
|
const coverageMap = this.createCoverageMap();
|
|
@@ -4281,10 +4016,8 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4281
4016
|
}
|
|
4282
4017
|
toSlices(array, size) {
|
|
4283
4018
|
return array.reduce((chunks, item) => {
|
|
4284
|
-
const index = Math.max(0, chunks.length - 1);
|
|
4285
|
-
|
|
4286
|
-
chunks[index] = lastChunk;
|
|
4287
|
-
if (lastChunk.length >= size) chunks.push([item]);
|
|
4019
|
+
const index = Math.max(0, chunks.length - 1), lastChunk = chunks[index] || [];
|
|
4020
|
+
if (chunks[index] = lastChunk, lastChunk.length >= size) chunks.push([item]);
|
|
4288
4021
|
else lastChunk.push(item);
|
|
4289
4022
|
return chunks;
|
|
4290
4023
|
}, []);
|
|
@@ -4293,25 +4026,25 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4293
4026
|
const servers = [...ctx.projects.map((project) => ({
|
|
4294
4027
|
root: project.config.root,
|
|
4295
4028
|
isBrowserEnabled: project.isBrowserEnabled(),
|
|
4296
|
-
|
|
4297
|
-
})),
|
|
4029
|
+
vite: project.vite
|
|
4030
|
+
})), (
|
|
4298
4031
|
// Check core last as it will match all files anyway
|
|
4299
|
-
{
|
|
4032
|
+
{
|
|
4300
4033
|
root: ctx.config.root,
|
|
4301
|
-
|
|
4034
|
+
vite: ctx.vite,
|
|
4302
4035
|
isBrowserEnabled: ctx.getRootProject().isBrowserEnabled()
|
|
4303
|
-
}];
|
|
4036
|
+
})];
|
|
4304
4037
|
return async function transformFile(filename) {
|
|
4305
4038
|
let lastError;
|
|
4306
|
-
for (const { root,
|
|
4039
|
+
for (const { root, vite, isBrowserEnabled } of servers) {
|
|
4307
4040
|
// On Windows root doesn't start with "/" while filenames do
|
|
4308
4041
|
if (!filename.startsWith(root) && !filename.startsWith(`/${root}`)) continue;
|
|
4309
4042
|
if (isBrowserEnabled) {
|
|
4310
|
-
const result = await
|
|
4043
|
+
const result = await vite.environments.client.transformRequest(filename).catch(() => null);
|
|
4311
4044
|
if (result) return result;
|
|
4312
4045
|
}
|
|
4313
4046
|
try {
|
|
4314
|
-
return await
|
|
4047
|
+
return await vite.environments.ssr.transformRequest(filename);
|
|
4315
4048
|
} catch (error) {
|
|
4316
4049
|
lastError = error;
|
|
4317
4050
|
}
|
|
@@ -4325,14 +4058,12 @@ Update your dependencies and make sure the versions match.`));
|
|
|
4325
4058
|
* Narrow down `unknown` glob thresholds to resolved ones
|
|
4326
4059
|
*/
|
|
4327
4060
|
function resolveGlobThresholds(thresholds) {
|
|
4328
|
-
|
|
4329
|
-
if (100 in thresholds && thresholds[100] === true) return {
|
|
4061
|
+
return !thresholds || typeof thresholds !== "object" ? {} : 100 in thresholds && thresholds[100] === true ? {
|
|
4330
4062
|
lines: 100,
|
|
4331
4063
|
branches: 100,
|
|
4332
4064
|
functions: 100,
|
|
4333
4065
|
statements: 100
|
|
4334
|
-
}
|
|
4335
|
-
return {
|
|
4066
|
+
} : {
|
|
4336
4067
|
lines: "lines" in thresholds && typeof thresholds.lines === "number" ? thresholds.lines : void 0,
|
|
4337
4068
|
branches: "branches" in thresholds && typeof thresholds.branches === "number" ? thresholds.branches : void 0,
|
|
4338
4069
|
functions: "functions" in thresholds && typeof thresholds.functions === "number" ? thresholds.functions : void 0,
|
|
@@ -4358,8 +4089,7 @@ function resolveConfig(configModule) {
|
|
|
4358
4089
|
if (config) return config;
|
|
4359
4090
|
// "export default mergeConfig(..., defineConfig(...))"
|
|
4360
4091
|
if (mod.$type === "function-call" && mod.$callee === "mergeConfig") {
|
|
4361
|
-
config = resolveMergeConfig(mod);
|
|
4362
|
-
if (config) return config;
|
|
4092
|
+
if (config = resolveMergeConfig(mod), config) return config;
|
|
4363
4093
|
}
|
|
4364
4094
|
} catch (error) {
|
|
4365
4095
|
// Reduce magicast's verbose errors to readable ones
|
|
@@ -4388,4 +4118,4 @@ function resolveMergeConfig(mod) {
|
|
|
4388
4118
|
}
|
|
4389
4119
|
}
|
|
4390
4120
|
|
|
4391
|
-
export { BaseCoverageProvider as B, RandomSequencer as R, resolveApiServerConfig as a, BaseSequencer as b, createMethodsRPC as c,
|
|
4121
|
+
export { BaseCoverageProvider as B, RandomSequencer as R, resolveApiServerConfig as a, BaseSequencer as b, createMethodsRPC as c, createFetchModuleFunction as d, isBrowserEnabled as e, groupBy as f, getFilePoolName as g, hash as h, isPackageExists as i, getCoverageProvider as j, createPool as k, normalizeResolvedIdToUrl as n, resolveConfig$1 as r, stdout as s, wildcardPatternToRegExp as w };
|