New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

vitest

Package Overview
Dependencies
Maintainers
5
Versions
459
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

vitest - npm Package Compare versions

Comparing version
4.1.0-beta.3
to
4.1.0-beta.4
+203
dist/chunks/base.C_KzYoIG.js
import { runInThisContext } from 'node:vm';
import * as spyModule from '@vitest/spy';
import { r as resolveTestRunner, a as resolveSnapshotEnvironment, d as detectAsyncLeaks, s as setupChaiConfig } from './index.DmJHrI1k.js';
import { l as loadEnvironment, e as emitModuleRunner, a as listenForErrors } from './init.B95Mm0Iz.js';
import { N as NativeModuleRunner } from './nativeModuleRunner.BIakptoF.js';
import { T as Traces } from './traces.CCmnQaNT.js';
import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js';
import { s as startVitestModuleRunner, c as createNodeImportMeta } from './startVitestModuleRunner.BK-u7y4N.js';
import { performance as performance$1 } from 'node:perf_hooks';
import { startTests, collectTests } from '@vitest/runner';
import { s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker } from './setup-common.Bafp3r-q.js';
import { g as globalExpect, v as vi } from './test.EDIwt4Yp.js';
import { c as closeInspector } from './inspector.CvyFGlXm.js';
import { createRequire } from 'node:module';
import timers from 'node:timers';
import timersPromises from 'node:timers/promises';
import util from 'node:util';
import { KNOWN_ASSET_TYPES } from '@vitest/utils/constants';
import { i as index } from './index.C39wbgWx.js';
import { g as getWorkerState, r as resetModules, p as provideWorkerState, a as getSafeWorkerState } from './utils.DT4VyRyl.js';
// this should only be used in Node
let globalSetup = false;
async function setupGlobalEnv(config, environment) {
await setupCommonEnv(config);
Object.defineProperty(globalThis, "__vitest_index__", {
value: index,
enumerable: false
});
globalExpect.setState({ environment: environment.name });
if (globalSetup) return;
globalSetup = true;
if ((environment.viteEnvironment || environment.name) === "client") {
const _require = createRequire(import.meta.url);
// always mock "required" `css` files, because we cannot process them
_require.extensions[".css"] = resolveCss;
_require.extensions[".scss"] = resolveCss;
_require.extensions[".sass"] = resolveCss;
_require.extensions[".less"] = resolveCss;
// since we are using Vite, we can assume how these will be resolved
KNOWN_ASSET_TYPES.forEach((type) => {
_require.extensions[`.${type}`] = resolveAsset;
});
process.env.SSR = "";
} else process.env.SSR = "1";
// @ts-expect-error not typed global for patched timers
globalThis.__vitest_required__ = {
util,
timers,
timersPromises
};
if (!config.disableConsoleIntercept) await setupConsoleLogSpy();
}
function resolveCss(mod) {
mod.exports = "";
}
function resolveAsset(mod, url) {
mod.exports = url;
}
async function setupConsoleLogSpy() {
const { createCustomConsole } = await import('./console.CNlG1KsP.js');
globalThis.console = createCustomConsole();
}
// browser shouldn't call this!
async function run(method, files, config, moduleRunner, environment, traces) {
const workerState = getWorkerState();
const [testRunner] = await Promise.all([
traces.$("vitest.runtime.runner", () => resolveTestRunner(config, moduleRunner, traces)),
traces.$("vitest.runtime.global_env", () => setupGlobalEnv(config, environment)),
traces.$("vitest.runtime.coverage.start", () => startCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.isolate })),
traces.$("vitest.runtime.snapshot.environment", async () => {
if (!workerState.config.snapshotOptions.snapshotEnvironment) workerState.config.snapshotOptions.snapshotEnvironment = await resolveSnapshotEnvironment(config, moduleRunner);
})
]);
workerState.onCancel((reason) => {
closeInspector(config);
testRunner.cancel?.(reason);
});
workerState.durations.prepare = performance$1.now() - workerState.durations.prepare;
await traces.$(`vitest.test.runner.${method}`, async () => {
for (const file of files) {
if (config.isolate) {
moduleRunner.mocker?.reset();
resetModules(workerState.evaluatedModules, true);
}
workerState.filepath = file.filepath;
if (method === "run") {
const collectAsyncLeaks = config.detectAsyncLeaks ? detectAsyncLeaks(file.filepath, workerState.ctx.projectName) : void 0;
await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => startTests([file], testRunner));
const leaks = await collectAsyncLeaks?.();
if (leaks?.length) workerState.rpc.onAsyncLeaks(leaks);
} else await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => collectTests([file], testRunner));
// reset after tests, because user might call `vi.setConfig` in setupFile
vi.resetConfig();
// mocks should not affect different files
vi.restoreAllMocks();
}
});
await traces.$("vitest.runtime.coverage.stop", () => stopCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.isolate }));
}
let _moduleRunner;
const evaluatedModules = new VitestEvaluatedModules();
const moduleExecutionInfo = /* @__PURE__ */ new Map();
async function startModuleRunner(options) {
if (_moduleRunner) return _moduleRunner;
process.exit = (code = process.exitCode || 0) => {
throw new Error(`process.exit unexpectedly called with "${code}"`);
};
const state = () => getSafeWorkerState() || options.state;
listenForErrors(state);
if (options.state.config.experimental.viteModuleRunner === false) {
const root = options.state.config.root;
let mocker;
if (options.state.config.experimental.nodeLoader !== false) {
// this additionally imports acorn/magic-string
const { NativeModuleMocker } = await import('./nativeModuleMocker.D_q5sFv6.js');
mocker = new NativeModuleMocker({
async resolveId(id, importer) {
// TODO: use import.meta.resolve instead
return state().rpc.resolve(id, importer, "__vitest__");
},
root,
moduleDirectories: state().config.deps.moduleDirectories || ["/node_modules/"],
traces: options.traces || new Traces({ enabled: false }),
getCurrentTestFilepath() {
return state().filepath;
},
spyModule
});
}
_moduleRunner = new NativeModuleRunner(root, mocker);
return _moduleRunner;
}
_moduleRunner = startVitestModuleRunner(options);
return _moduleRunner;
}
let _currentEnvironment;
let _environmentTime;
/** @experimental */
async function setupBaseEnvironment(context) {
if (context.config.experimental.viteModuleRunner === false) {
const { setupNodeLoaderHooks } = await import('./native.mV0-490A.js');
await setupNodeLoaderHooks(context);
}
const startTime = performance.now();
const { environment: { name: environmentName, options: environmentOptions }, rpc, config } = context;
// we could load @vite/env, but it would take ~8ms, while this takes ~0,02ms
if (context.config.serializedDefines) try {
runInThisContext(`(() =>{\n${context.config.serializedDefines}})()`, {
lineOffset: 1,
filename: "virtual:load-defines.js"
});
} catch (error) {
throw new Error(`Failed to load custom "defines": ${error.message}`);
}
const otel = context.traces;
const { environment, loader } = await loadEnvironment(environmentName, config.root, rpc, otel, context.config.experimental.viteModuleRunner);
_currentEnvironment = environment;
const env = await otel.$("vitest.runtime.environment.setup", { attributes: {
"vitest.environment": environment.name,
"vitest.environment.vite_environment": environment.viteEnvironment || environment.name
} }, () => environment.setup(globalThis, environmentOptions || config.environmentOptions || {}));
_environmentTime = performance.now() - startTime;
if (config.chaiConfig) setupChaiConfig(config.chaiConfig);
return async () => {
await otel.$("vitest.runtime.environment.teardown", () => env.teardown(globalThis));
await loader?.close();
};
}
/** @experimental */
async function runBaseTests(method, state, traces) {
const { ctx } = state;
state.environment = _currentEnvironment;
state.durations.environment = _environmentTime;
// state has new context, but we want to reuse existing ones
state.evaluatedModules = evaluatedModules;
state.moduleExecutionInfo = moduleExecutionInfo;
provideWorkerState(globalThis, state);
if (ctx.invalidates) ctx.invalidates.forEach((filepath) => {
(state.evaluatedModules.fileToModulesMap.get(filepath) || []).forEach((module) => {
state.evaluatedModules.invalidateModule(module);
});
});
ctx.files.forEach((i) => {
const filepath = i.filepath;
(state.evaluatedModules.fileToModulesMap.get(filepath) || []).forEach((module) => {
state.evaluatedModules.invalidateModule(module);
});
});
const moduleRunner = await startModuleRunner({
state,
evaluatedModules: state.evaluatedModules,
spyModule,
createImportMeta: createNodeImportMeta,
traces
});
emitModuleRunner(moduleRunner);
await run(method, ctx.files, ctx.config, moduleRunner, _currentEnvironment, traces);
}
export { runBaseTests as r, setupBaseEnvironment as s };
import { FileSpecification } from '@vitest/runner';
import { O as OTELCarrier } from './traces.d.402V_yFI.js';
import { T as TestExecutionMethod } from './worker.d.KWMdtGFQ.js';
type SerializedTestSpecification = [project: {
name: string | undefined;
root: string;
}, file: string, options: {
pool: string;
testLines?: number[] | undefined;
testIds?: string[] | undefined;
testNamePattern?: RegExp | undefined;
testTagsFilter?: string[] | undefined;
}];
interface ModuleDefinitionLocation {
line: number;
column: number;
}
interface SourceModuleLocations {
modules: ModuleDefinitionDiagnostic[];
untracked: ModuleDefinitionDiagnostic[];
}
interface ModuleDefinitionDiagnostic {
start: ModuleDefinitionLocation;
end: ModuleDefinitionLocation;
startIndex: number;
endIndex: number;
rawUrl: string;
resolvedUrl: string;
resolvedId: string;
}
interface ModuleDefinitionDurationsDiagnostic extends ModuleDefinitionDiagnostic {
selfTime: number;
totalTime: number;
transformTime?: number;
external?: boolean;
importer?: string;
}
interface UntrackedModuleDefinitionDiagnostic {
url: string;
resolvedId: string;
resolvedUrl: string;
selfTime: number;
totalTime: number;
transformTime?: number;
external?: boolean;
importer?: string;
}
interface SourceModuleDiagnostic {
modules: ModuleDefinitionDurationsDiagnostic[];
untrackedModules: UntrackedModuleDefinitionDiagnostic[];
}
interface BrowserTesterOptions {
method: TestExecutionMethod;
files: FileSpecification[];
providedContext: string;
otelCarrier?: OTELCarrier;
}
export type { BrowserTesterOptions as B, ModuleDefinitionDurationsDiagnostic as M, SerializedTestSpecification as S, UntrackedModuleDefinitionDiagnostic as U, ModuleDefinitionDiagnostic as a, ModuleDefinitionLocation as b, SourceModuleDiagnostic as c, SourceModuleLocations as d };

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

import { PrettyFormatOptions } from '@vitest/pretty-format';
import { SequenceHooks, SequenceSetupFiles, SerializableRetry, TestTagDefinition } from '@vitest/runner';
import { SnapshotUpdateState, SnapshotEnvironment } from '@vitest/snapshot';
import { SerializedDiffOptions } from '@vitest/utils/diff';
/**
* Names of clock methods that may be faked by install.
*/
type FakeMethod =
| "setTimeout"
| "clearTimeout"
| "setImmediate"
| "clearImmediate"
| "setInterval"
| "clearInterval"
| "Date"
| "nextTick"
| "hrtime"
| "requestAnimationFrame"
| "cancelAnimationFrame"
| "requestIdleCallback"
| "cancelIdleCallback"
| "performance"
| "queueMicrotask";
interface FakeTimerInstallOpts {
/**
* Installs fake timers with the specified unix epoch (default: 0)
*/
now?: number | Date | undefined;
/**
* An array with names of global methods and APIs to fake. By default, `@sinonjs/fake-timers` does not replace `nextTick()` and `queueMicrotask()`.
* For instance, `FakeTimers.install({ toFake: ['setTimeout', 'nextTick'] })` will fake only `setTimeout()` and `nextTick()`
*/
toFake?: FakeMethod[] | undefined;
/**
* The maximum number of timers that will be run when calling runAll() (default: 1000)
*/
loopLimit?: number | undefined;
/**
* Tells @sinonjs/fake-timers to increment mocked time automatically based on the real system time shift (e.g. the mocked time will be incremented by
* 20ms for every 20ms change in the real system time) (default: false)
*/
shouldAdvanceTime?: boolean | undefined;
/**
* Relevant only when using with shouldAdvanceTime: true. increment mocked time by advanceTimeDelta ms every advanceTimeDelta ms change
* in the real system time (default: 20)
*/
advanceTimeDelta?: number | undefined;
/**
* Tells FakeTimers to clear 'native' (i.e. not fake) timers by delegating to their respective handlers. These are not cleared by
* default, leading to potentially unexpected behavior if timers existed prior to installing FakeTimers. (default: false)
*/
shouldClearNativeTimers?: boolean | undefined;
/**
* Tells FakeTimers to not throw an error when faking a timer that does not exist in the global object. (default: false)
*/
ignoreMissingTimers?: boolean | undefined;
}
/**
* Config that tests have access to.
*/
interface SerializedConfig {
name: string | undefined;
globals: boolean;
base: string | undefined;
snapshotEnvironment?: string;
disableConsoleIntercept: boolean | undefined;
runner: string | undefined;
isolate: boolean;
maxWorkers: number;
mode: "test" | "benchmark";
bail: number | undefined;
environmentOptions?: Record<string, any>;
root: string;
setupFiles: string[];
passWithNoTests: boolean;
testNamePattern: RegExp | undefined;
allowOnly: boolean;
testTimeout: number;
hookTimeout: number;
clearMocks: boolean;
mockReset: boolean;
restoreMocks: boolean;
unstubGlobals: boolean;
unstubEnvs: boolean;
fakeTimers: FakeTimerInstallOpts;
maxConcurrency: number;
defines: Record<string, any>;
expect: {
requireAssertions?: boolean;
poll?: {
timeout?: number;
interval?: number;
};
};
printConsoleTrace: boolean | undefined;
sequence: {
shuffle?: boolean;
concurrent?: boolean;
seed: number;
hooks: SequenceHooks;
setupFiles: SequenceSetupFiles;
};
deps: {
web: {
transformAssets?: boolean;
transformCss?: boolean;
transformGlobPattern?: RegExp | RegExp[];
};
optimizer: Record<string, {
enabled: boolean;
}>;
interopDefault: boolean | undefined;
moduleDirectories: string[] | undefined;
};
snapshotOptions: {
updateSnapshot: SnapshotUpdateState;
expand: boolean | undefined;
snapshotFormat: PrettyFormatOptions | undefined;
/**
* only exists for tests, not available in the main process
*/
snapshotEnvironment: SnapshotEnvironment;
};
pool: string;
snapshotSerializers: string[];
chaiConfig: {
includeStack?: boolean;
showDiff?: boolean;
truncateThreshold?: number;
} | undefined;
api: {
allowExec: boolean | undefined;
allowWrite: boolean | undefined;
};
diff: string | SerializedDiffOptions | undefined;
retry: SerializableRetry;
includeTaskLocation: boolean | undefined;
inspect: boolean | string | undefined;
inspectBrk: boolean | string | undefined;
inspector: {
enabled?: boolean;
port?: number;
host?: string;
waitForDebugger?: boolean;
};
watch: boolean;
env: Record<string, any>;
browser: {
name: string;
headless: boolean;
isolate: boolean;
fileParallelism: boolean;
ui: boolean;
viewport: {
width: number;
height: number;
};
locators: {
testIdAttribute: string;
};
screenshotFailures: boolean;
providerOptions: {
actionTimeout?: number;
};
trace: BrowserTraceViewMode;
trackUnhandledErrors: boolean;
detailsPanelPosition: "right" | "bottom";
};
standalone: boolean;
logHeapUsage: boolean | undefined;
detectAsyncLeaks: boolean;
coverage: SerializedCoverageConfig;
benchmark: {
includeSamples: boolean;
} | undefined;
serializedDefines: string;
experimental: {
fsModuleCache: boolean;
importDurations: {
print: boolean | "on-warn";
limit: number;
failOnDanger: boolean;
thresholds: {
warn: number;
danger: number;
};
};
viteModuleRunner: boolean;
nodeLoader: boolean;
openTelemetry: {
enabled: boolean;
sdkPath?: string;
browserSdkPath?: string;
} | undefined;
};
tags: TestTagDefinition[];
tagsFilter: string[] | undefined;
strictTags: boolean;
}
interface SerializedCoverageConfig {
provider: "istanbul" | "v8" | "custom" | undefined;
reportsDirectory: string;
htmlDir: string | undefined;
enabled: boolean;
customProviderModule: string | undefined;
}
type RuntimeConfig = Pick<SerializedConfig, "allowOnly" | "testTimeout" | "hookTimeout" | "clearMocks" | "mockReset" | "restoreMocks" | "fakeTimers" | "maxConcurrency" | "expect" | "printConsoleTrace"> & {
sequence?: {
hooks?: SequenceHooks;
};
};
type RuntimeOptions = Partial<RuntimeConfig>;
type BrowserTraceViewMode = "on" | "off" | "on-first-retry" | "on-all-retries" | "retain-on-failure";
export type { BrowserTraceViewMode as B, FakeTimerInstallOpts as F, RuntimeOptions as R, SerializedConfig as S, SerializedCoverageConfig as a, RuntimeConfig as b };
import { existsSync, promises, readdirSync, writeFileSync } from 'node:fs';
import module$1 from 'node:module';
import path from 'node:path';
import { pathToFileURL, fileURLToPath } from 'node:url';
import { slash, shuffle, toArray } from '@vitest/utils/helpers';
import { resolve, relative, normalize } from 'pathe';
import pm from 'picomatch';
import { glob } from 'tinyglobby';
import c from 'tinyrainbow';
import { c as configDefaults, e as benchmarkConfigDefaults, a as coverageConfigDefaults } from './defaults.BlJmGxXD.js';
import crypto from 'node:crypto';
import { r as resolveModule } from './index.BCY_7LL2.js';
import { mergeConfig } from 'vite';
import { c as configFiles, d as defaultBrowserPort, a as defaultInspectPort, b as defaultPort } from './constants.CPYnjOGj.js';
import './env.D4Lgay0q.js';
import nodeos__default from 'node:os';
import { isCI, provider } from 'std-env';
import { r as resolveCoverageProviderModule } from './coverage.D_JHT54q.js';
const hash = crypto.hash ?? ((algorithm, data, outputEncoding) => crypto.createHash(algorithm).update(data).digest(outputEncoding));
function getWorkersCountByPercentage(percent) {
const maxWorkersCount = nodeos__default.availableParallelism?.() ?? nodeos__default.cpus().length;
const workersCountByPercentage = Math.round(Number.parseInt(percent) / 100 * maxWorkersCount);
return Math.max(1, Math.min(maxWorkersCount, workersCountByPercentage));
}
class BaseSequencer {
ctx;
constructor(ctx) {
this.ctx = ctx;
}
// async so it can be extended by other sequelizers
async shard(files) {
const { config } = this.ctx;
const { index, count } = config.shard;
const [shardStart, shardEnd] = this.calculateShardRange(files.length, index, count);
return [...files].map((spec) => {
const specPath = resolve(slash(config.root), slash(spec.moduleId))?.slice(config.root.length);
return {
spec,
hash: hash("sha1", specPath, "hex")
};
}).sort((a, b) => a.hash < b.hash ? -1 : a.hash > b.hash ? 1 : 0).slice(shardStart, shardEnd).map(({ spec }) => spec);
}
// async so it can be extended by other sequelizers
async sort(files) {
const cache = this.ctx.cache;
return [...files].sort((a, b) => {
// "sequence.groupOrder" is higher priority
const groupOrderDiff = a.project.config.sequence.groupOrder - b.project.config.sequence.groupOrder;
if (groupOrderDiff !== 0) return groupOrderDiff;
// Projects run sequential
if (a.project.name !== b.project.name) return a.project.name < b.project.name ? -1 : 1;
// Isolated run first
if (a.project.config.isolate && !b.project.config.isolate) return -1;
if (!a.project.config.isolate && b.project.config.isolate) return 1;
const keyA = `${a.project.name}:${relative(this.ctx.config.root, a.moduleId)}`;
const keyB = `${b.project.name}:${relative(this.ctx.config.root, b.moduleId)}`;
const aState = cache.getFileTestResults(keyA);
const bState = cache.getFileTestResults(keyB);
if (!aState || !bState) {
const statsA = cache.getFileStats(keyA);
const statsB = cache.getFileStats(keyB);
// run unknown first
if (!statsA || !statsB) return !statsA && statsB ? -1 : !statsB && statsA ? 1 : 0;
// run larger files first
return statsB.size - statsA.size;
}
// run failed first
if (aState.failed && !bState.failed) return -1;
if (!aState.failed && bState.failed) return 1;
// run longer first
return bState.duration - aState.duration;
});
}
// Calculate distributed shard range [start, end] distributed equally
calculateShardRange(filesCount, index, count) {
const baseShardSize = Math.floor(filesCount / count);
const remainderTestFilesCount = filesCount % count;
if (remainderTestFilesCount >= index) {
const shardSize = baseShardSize + 1;
return [shardSize * (index - 1), shardSize * index];
}
const shardStart = remainderTestFilesCount * (baseShardSize + 1) + (index - remainderTestFilesCount - 1) * baseShardSize;
return [shardStart, shardStart + baseShardSize];
}
}
class RandomSequencer extends BaseSequencer {
async sort(files) {
const { sequence } = this.ctx.config;
return shuffle(files, sequence.seed);
}
}
function resolvePath(path, root) {
return normalize(/* @__PURE__ */ resolveModule(path, { paths: [root] }) ?? resolve(root, path));
}
function parseInspector(inspect) {
if (typeof inspect === "boolean" || inspect === void 0) return {};
if (typeof inspect === "number") return { port: inspect };
if (inspect.match(/https?:\//)) throw new Error(`Inspector host cannot be a URL. Use "host:port" instead of "${inspect}"`);
const [host, port] = inspect.split(":");
if (!port) return { host };
return {
host,
port: Number(port) || defaultInspectPort
};
}
/**
* @deprecated Internal function
*/
function resolveApiServerConfig(options, defaultPort, parentApi, logger) {
let api;
if (options.ui && !options.api) api = { port: defaultPort };
else if (options.api === true) api = { port: defaultPort };
else if (typeof options.api === "number") api = { port: options.api };
if (typeof options.api === "object") if (api) {
if (options.api.port) api.port = options.api.port;
if (options.api.strictPort) api.strictPort = options.api.strictPort;
if (options.api.host) api.host = options.api.host;
} else api = { ...options.api };
if (api) {
if (!api.port && !api.middlewareMode) api.port = defaultPort;
} else api = { middlewareMode: true };
// if the API server is exposed to network, disable write operations by default
if (!api.middlewareMode && api.host && api.host !== "localhost" && api.host !== "127.0.0.1") {
// assigned to browser
if (parentApi) {
if (api.allowWrite == null && api.allowExec == null) logger?.error(c.yellow(`${c.yellowBright(" WARNING ")} API server is exposed to network, disabling write and exec operations by default for security reasons. This can cause some APIs to not work as expected. Set \`browser.api.allowExec\` manually to hide this warning. See https://vitest.dev/config/browser/api for more details.`));
}
api.allowWrite ??= parentApi?.allowWrite ?? false;
api.allowExec ??= parentApi?.allowExec ?? false;
} else {
api.allowWrite ??= parentApi?.allowWrite ?? true;
api.allowExec ??= parentApi?.allowExec ?? true;
}
return api;
}
function resolveInlineWorkerOption(value) {
if (typeof value === "string" && value.trim().endsWith("%")) return getWorkersCountByPercentage(value);
else return Number(value);
}
function resolveConfig$1(vitest, options, viteConfig) {
const mode = vitest.mode;
const logger = vitest.logger;
if (options.dom) {
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}"`));
options.environment = "happy-dom";
}
const resolved = {
...configDefaults,
...options,
root: viteConfig.root,
mode
};
if (resolved.retry && typeof resolved.retry === "object" && typeof resolved.retry.condition === "function") {
logger.console.warn(c.yellow("Warning: retry.condition function cannot be used inside a config file. Use a RegExp pattern instead, or define the function in your test file."));
resolved.retry = {
...resolved.retry,
condition: void 0
};
}
if (options.pool && typeof options.pool !== "string") {
resolved.pool = options.pool.name;
resolved.poolRunner = options.pool;
}
if ("poolOptions" in resolved) logger.deprecate("`test.poolOptions` was removed in Vitest 4. All previous `poolOptions` are now top-level options. Please, refer to the migration guide: https://vitest.dev/guide/migration#pool-rework");
resolved.pool ??= "forks";
resolved.project = toArray(resolved.project);
resolved.provide ??= {};
// shallow copy tags array to avoid mutating user config
resolved.tags = [...resolved.tags || []];
const definedTags = /* @__PURE__ */ new Set();
resolved.tags.forEach((tag) => {
if (!tag.name || typeof tag.name !== "string") throw new Error(`Each tag defined in "test.tags" must have a "name" property, received: ${JSON.stringify(tag)}`);
if (definedTags.has(tag.name)) throw new Error(`Tag name "${tag.name}" is already defined in "test.tags". Tag names must be unique.`);
if (tag.name.match(/\s/)) throw new Error(`Tag name "${tag.name}" is invalid. Tag names cannot contain spaces.`);
if (tag.name.match(/([!()*|&])/)) throw new Error(`Tag name "${tag.name}" is invalid. Tag names cannot contain "!", "*", "&", "|", "(", or ")".`);
if (tag.name.match(/^\s*(and|or|not)\s*$/i)) throw new Error(`Tag name "${tag.name}" is invalid. Tag names cannot be a logical operator like "and", "or", "not".`);
if (typeof tag.retry === "object" && typeof tag.retry.condition === "function") throw new TypeError(`Tag "${tag.name}": retry.condition function cannot be used inside a config file. Use a RegExp pattern instead, or define the function in your test file.`);
if (tag.priority != null && (typeof tag.priority !== "number" || tag.priority < 0)) throw new TypeError(`Tag "${tag.name}": priority must be a non-negative number.`);
definedTags.add(tag.name);
});
resolved.name = typeof options.name === "string" ? options.name : options.name?.label || "";
resolved.color = typeof options.name !== "string" ? options.name?.color : void 0;
if (resolved.environment === "browser") throw new Error(`Looks like you set "test.environment" to "browser". To enable Browser Mode, use "test.browser.enabled" instead.`);
const inspector = resolved.inspect || resolved.inspectBrk;
resolved.inspector = {
...resolved.inspector,
...parseInspector(inspector),
enabled: !!inspector,
waitForDebugger: options.inspector?.waitForDebugger ?? !!resolved.inspectBrk
};
if (viteConfig.base !== "/") resolved.base = viteConfig.base;
resolved.clearScreen = resolved.clearScreen ?? viteConfig.clearScreen ?? true;
if (options.shard) {
if (resolved.watch) throw new Error("You cannot use --shard option with enabled watch");
const [indexString, countString] = options.shard.split("/");
const index = Math.abs(Number.parseInt(indexString, 10));
const count = Math.abs(Number.parseInt(countString, 10));
if (Number.isNaN(count) || count <= 0) throw new Error("--shard <count> must be a positive number");
if (Number.isNaN(index) || index <= 0 || index > count) throw new Error("--shard <index> must be a positive number less then <count>");
resolved.shard = {
index,
count
};
}
if (resolved.standalone && !resolved.watch) throw new Error(`Vitest standalone mode requires --watch`);
if (resolved.mergeReports && resolved.watch) throw new Error(`Cannot merge reports with --watch enabled`);
if (resolved.maxWorkers) resolved.maxWorkers = resolveInlineWorkerOption(resolved.maxWorkers);
if (!(options.fileParallelism ?? mode !== "benchmark"))
// ignore user config, parallelism cannot be implemented without limiting workers
resolved.maxWorkers = 1;
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;
}
if (resolved.inspect || resolved.inspectBrk) {
if (resolved.maxWorkers !== 1) {
const inspectOption = `--inspect${resolved.inspectBrk ? "-brk" : ""}`;
throw new Error(`You cannot use ${inspectOption} without "--no-file-parallelism"`);
}
}
// apply browser CLI options only if the config already has the browser config and not disabled manually
if (vitest._cliOptions.browser && resolved.browser && (resolved.browser.enabled !== false || vitest._cliOptions.browser.enabled)) resolved.browser = mergeConfig(resolved.browser, vitest._cliOptions.browser);
resolved.browser ??= {};
const browser = resolved.browser;
if (browser.enabled) {
const instances = browser.instances;
if (!browser.instances) browser.instances = [];
// use `chromium` by default when the preview provider is specified
// for a smoother experience. if chromium is not available, it will
// open the default browser anyway
if (!browser.instances.length && browser.provider?.name === "preview") browser.instances = [{ browser: "chromium" }];
if (browser.name && instances?.length) {
// --browser=chromium filters configs to a single one
browser.instances = browser.instances.filter((instance) => instance.browser === browser.name);
// if `instances` were defined, but now they are empty,
// let's throw an error because the filter is invalid
if (!browser.instances.length) throw new Error([`"browser.instances" was set in the config, but the array is empty. Define at least one browser config.`, ` The "browser.name" was set to "${browser.name}" which filtered all configs (${instances.map((c) => c.browser).join(", ")}). Did you mean to use another name?`].join(""));
}
}
if (resolved.coverage.enabled && resolved.coverage.provider === "istanbul" && resolved.experimental?.viteModuleRunner === false) throw new Error(`"Istanbul" coverage provider is not compatible with "experimental.viteModuleRunner: false". Please, enable "viteModuleRunner" or switch to "v8" coverage provider.`);
if (browser.enabled && resolved.detectAsyncLeaks) logger.console.warn(c.yellow("The option \"detectAsyncLeaks\" is not supported in browser mode and will be ignored."));
const containsChromium = hasBrowserChromium(vitest, resolved);
const hasOnlyChromium = hasOnlyBrowserChromium(vitest, resolved);
// Browser-mode "Chromium" only features:
if (browser.enabled && (!containsChromium || !hasOnlyChromium)) {
const browserConfig = `
{
browser: {
provider: ${browser.provider?.name || "preview"}(),
instances: [
${(browser.instances || []).map((i) => `{ browser: '${i.browser}' }`).join(",\n ")}
],
},
}
`.trim();
const preferredProvider = !browser.provider?.name || browser.provider.name === "preview" ? "playwright" : browser.provider.name;
const correctExample = `
{
browser: {
provider: ${preferredProvider}(),
instances: [
{ browser: '${preferredProvider === "playwright" ? "chromium" : "chrome"}' }
],
},
}
`.trim();
// requires all projects to be chromium
if (!hasOnlyChromium && resolved.coverage.enabled && resolved.coverage.provider === "v8") {
const coverageExample = `
{
coverage: {
provider: 'istanbul',
},
}
`.trim();
throw new Error(`@vitest/coverage-v8 does not work with\n${browserConfig}\n\nUse either:\n${correctExample}\n\n...or change your coverage provider to:\n${coverageExample}\n`);
}
// ignores non-chromium browsers when there is at least one chromium project
if (!containsChromium && (resolved.inspect || resolved.inspectBrk)) {
const inspectOption = `--inspect${resolved.inspectBrk ? "-brk" : ""}`;
throw new Error(`${inspectOption} does not work with\n${browserConfig}\n\nUse either:\n${correctExample}\n\n...or disable ${inspectOption}\n`);
}
}
resolved.coverage.reporter = resolveCoverageReporters(resolved.coverage.reporter);
if (resolved.coverage.enabled && resolved.coverage.reportsDirectory) {
const reportsDirectory = resolve(resolved.root, resolved.coverage.reportsDirectory);
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`);
if (resolved.coverage.htmlDir) resolved.coverage.htmlDir = resolve(resolved.root, resolved.coverage.htmlDir);
// infer default htmlDir based on builtin reporter's html output location
if (!resolved.coverage.htmlDir) {
const htmlReporter = resolved.coverage.reporter.find(([name]) => name === "html" || name === "html-spa");
if (htmlReporter) {
const [, options] = htmlReporter;
const subdir = options && typeof options === "object" && "subdir" in options && typeof options.subdir === "string" ? options.subdir : void 0;
resolved.coverage.htmlDir = resolve(reportsDirectory, subdir || ".");
} else if (resolved.coverage.reporter.find(([name]) => name === "lcov")) resolved.coverage.htmlDir = resolve(reportsDirectory, "lcov-report");
}
}
if (resolved.coverage.enabled && resolved.coverage.provider === "custom" && resolved.coverage.customProviderModule) resolved.coverage.customProviderModule = resolvePath(resolved.coverage.customProviderModule, resolved.root);
resolved.expect ??= {};
resolved.deps ??= {};
resolved.deps.moduleDirectories ??= [];
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));
// Add hard-coded default coverage exclusions. These cannot be overidden by user config.
// Override original exclude array for cases where user re-uses same object in test.exclude.
resolved.coverage.exclude = [
...resolved.coverage.exclude,
...resolved.setupFiles.map((file) => `${resolved.coverage.allowExternal ? "**/" : ""}${relative(resolved.root, file)}`),
...resolved.include,
resolved.config && slash(resolved.config),
...configFiles,
"**/virtual:*",
"**/__x00__*",
"**/node_modules/**"
].filter((pattern) => typeof pattern === "string");
resolved.forceRerunTriggers = [...resolved.forceRerunTriggers, ...resolved.setupFiles];
if (resolved.cliExclude) resolved.exclude.push(...resolved.cliExclude);
if (resolved.runner) resolved.runner = resolvePath(resolved.runner, resolved.root);
resolved.attachmentsDir = resolve(resolved.root, resolved.attachmentsDir ?? ".vitest-attachments");
if (resolved.snapshotEnvironment) resolved.snapshotEnvironment = resolvePath(resolved.snapshotEnvironment, resolved.root);
resolved.testNamePattern = resolved.testNamePattern ? resolved.testNamePattern instanceof RegExp ? resolved.testNamePattern : new RegExp(resolved.testNamePattern) : void 0;
if (resolved.snapshotFormat && "plugins" in resolved.snapshotFormat) {
resolved.snapshotFormat.plugins = [];
// TODO: support it via separate config (like DiffOptions) or via `Function.toString()`
if (typeof resolved.snapshotFormat.compareKeys === "function") throw new TypeError(`"snapshotFormat.compareKeys" function is not supported.`);
}
const UPDATE_SNAPSHOT = resolved.update || process.env.UPDATE_SNAPSHOT;
resolved.snapshotOptions = {
expand: resolved.expandSnapshotDiff ?? false,
snapshotFormat: resolved.snapshotFormat || {},
updateSnapshot: UPDATE_SNAPSHOT === "all" || UPDATE_SNAPSHOT === "new" ? UPDATE_SNAPSHOT : isCI && !UPDATE_SNAPSHOT ? "none" : UPDATE_SNAPSHOT ? "all" : "new",
resolveSnapshotPath: options.resolveSnapshotPath,
snapshotEnvironment: null
};
resolved.snapshotSerializers ??= [];
resolved.snapshotSerializers = resolved.snapshotSerializers.map((file) => resolvePath(file, resolved.root));
resolved.forceRerunTriggers.push(...resolved.snapshotSerializers);
if (options.resolveSnapshotPath) delete resolved.resolveSnapshotPath;
resolved.execArgv ??= [];
resolved.pool ??= "threads";
if (resolved.pool === "vmForks" || resolved.pool === "vmThreads" || resolved.pool === "typescript") resolved.isolate = false;
if (process.env.VITEST_MAX_WORKERS) resolved.maxWorkers = Number.parseInt(process.env.VITEST_MAX_WORKERS);
if (mode === "benchmark") {
resolved.benchmark = {
...benchmarkConfigDefaults,
...resolved.benchmark
};
// override test config
resolved.coverage.enabled = false;
resolved.typecheck.enabled = false;
resolved.include = resolved.benchmark.include;
resolved.exclude = resolved.benchmark.exclude;
resolved.includeSource = resolved.benchmark.includeSource;
const reporters = Array.from(new Set([...toArray(resolved.benchmark.reporters), ...toArray(options.reporter)])).filter(Boolean);
if (reporters.length) resolved.benchmark.reporters = reporters;
else resolved.benchmark.reporters = ["default"];
if (options.outputFile) resolved.benchmark.outputFile = options.outputFile;
// --compare from cli
if (options.compare) resolved.benchmark.compare = options.compare;
if (options.outputJson) resolved.benchmark.outputJson = options.outputJson;
}
if (typeof resolved.diff === "string") {
resolved.diff = resolvePath(resolved.diff, resolved.root);
resolved.forceRerunTriggers.push(resolved.diff);
}
resolved.api = {
...resolveApiServerConfig(options, defaultPort),
token: crypto.randomUUID()
};
if (options.related) resolved.related = toArray(options.related).map((file) => resolve(resolved.root, file));
/*
* Reporters can be defined in many different ways:
* { reporter: 'json' }
* { reporter: { onFinish() { method() } } }
* { reporter: ['json', { onFinish() { method() } }] }
* { reporter: [[ 'json' ]] }
* { reporter: [[ 'json' ], 'html'] }
* { reporter: [[ 'json', { outputFile: 'test.json' } ], 'html'] }
*/
if (options.reporters) if (!Array.isArray(options.reporters))
// Reporter name, e.g. { reporters: 'json' }
if (typeof options.reporters === "string") resolved.reporters = [[options.reporters, {}]];
else resolved.reporters = [options.reporters];
else {
resolved.reporters = [];
for (const reporter of options.reporters) if (Array.isArray(reporter))
// Reporter with options, e.g. { reporters: [ [ 'json', { outputFile: 'test.json' } ] ] }
resolved.reporters.push([reporter[0], reporter[1] || {}]);
else if (typeof reporter === "string")
// Reporter name in array, e.g. { reporters: ["html", "json"]}
resolved.reporters.push([reporter, {}]);
else
// Inline reporter, e.g. { reporter: [{ onFinish() { method() } }] }
resolved.reporters.push(reporter);
}
if (mode !== "benchmark") {
// @ts-expect-error "reporter" is from CLI, should be absolute to the running directory
// it is passed down as "vitest --reporter ../reporter.js"
const reportersFromCLI = resolved.reporter;
const cliReporters = toArray(reportersFromCLI || []).map((reporter) => {
// ./reporter.js || ../reporter.js, but not .reporters/reporter.js
if (/^\.\.?\//.test(reporter)) return resolve(process.cwd(), reporter);
return reporter;
});
if (cliReporters.length) {
// When CLI reporters are specified, preserve options from config file
const configReportersMap = /* @__PURE__ */ new Map();
// Build a map of reporter names to their options from the config
for (const reporter of resolved.reporters) if (Array.isArray(reporter)) {
const [reporterName, reporterOptions] = reporter;
if (typeof reporterName === "string") configReportersMap.set(reporterName, reporterOptions);
}
resolved.reporters = Array.from(new Set(toArray(cliReporters))).filter(Boolean).map((reporter) => [reporter, configReportersMap.get(reporter) || {}]);
}
}
if (!resolved.reporters.length) {
resolved.reporters.push(["default", {}]);
// also enable github-actions reporter as a default
if (process.env.GITHUB_ACTIONS === "true") resolved.reporters.push(["github-actions", {}]);
}
if (resolved.changed) resolved.passWithNoTests ??= true;
resolved.css ??= {};
if (typeof resolved.css === "object") {
resolved.css.modules ??= {};
resolved.css.modules.classNameStrategy ??= "stable";
}
if (resolved.cache !== false) {
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"`);
resolved.cache = { dir: viteConfig.cacheDir };
}
resolved.sequence ??= {};
if (resolved.sequence.shuffle && typeof resolved.sequence.shuffle === "object") {
const { files, tests } = resolved.sequence.shuffle;
resolved.sequence.sequencer ??= files ? RandomSequencer : BaseSequencer;
resolved.sequence.shuffle = tests;
}
if (!resolved.sequence?.sequencer)
// CLI flag has higher priority
resolved.sequence.sequencer = resolved.sequence.shuffle ? RandomSequencer : BaseSequencer;
resolved.sequence.groupOrder ??= 0;
resolved.sequence.hooks ??= "stack";
// Set seed if either files or tests are shuffled
if (resolved.sequence.sequencer === RandomSequencer || resolved.sequence.shuffle) resolved.sequence.seed ??= Date.now();
resolved.typecheck = {
...configDefaults.typecheck,
...resolved.typecheck
};
resolved.typecheck ??= {};
resolved.typecheck.enabled ??= false;
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."));
resolved.browser.enabled ??= false;
resolved.browser.headless ??= isCI;
if (resolved.browser.isolate) logger.console.warn(c.yellow("`browser.isolate` is deprecated. Use top-level `isolate` instead."));
resolved.browser.isolate ??= resolved.isolate ?? true;
resolved.browser.fileParallelism ??= options.fileParallelism ?? mode !== "benchmark";
// disable in headless mode by default, and if CI is detected
resolved.browser.ui ??= resolved.browser.headless === true ? false : !isCI;
resolved.browser.commands ??= {};
resolved.browser.detailsPanelPosition ??= "right";
if (resolved.browser.screenshotDirectory) resolved.browser.screenshotDirectory = resolve(resolved.root, resolved.browser.screenshotDirectory);
if (resolved.inspector.enabled) resolved.browser.trackUnhandledErrors ??= false;
resolved.browser.viewport ??= {};
resolved.browser.viewport.width ??= 414;
resolved.browser.viewport.height ??= 896;
resolved.browser.locators ??= {};
resolved.browser.locators.testIdAttribute ??= "data-testid";
if (typeof resolved.browser.provider === "string") {
const source = `@vitest/browser-${resolved.browser.provider}`;
throw new TypeError(`The \`browser.provider\` configuration was changed to accept a factory instead of a string. Add an import of "${resolved.browser.provider}" from "${source}" instead. See: https://vitest.dev/config/browser/provider`);
}
const isPreview = resolved.browser.provider?.name === "preview";
if (!isPreview && resolved.browser.enabled && provider === "stackblitz") throw new Error(`stackblitz environment does not support the ${resolved.browser.provider?.name} provider. Please, use "@vitest/browser-preview" instead.`);
if (isPreview && resolved.browser.screenshotFailures === true) {
console.warn(c.yellow([
`Browser provider "preview" doesn't support screenshots, `,
`so "browser.screenshotFailures" option is forcefully disabled. `,
`Set "browser.screenshotFailures" to false or remove it from the config to suppress this warning.`
].join("")));
resolved.browser.screenshotFailures = false;
} else resolved.browser.screenshotFailures ??= !isPreview && !resolved.browser.ui;
if (resolved.browser.provider && resolved.browser.provider.options == null) resolved.browser.provider.options = {};
resolved.browser.api = resolveApiServerConfig(resolved.browser, defaultBrowserPort, resolved.api, logger) || { port: defaultBrowserPort };
// enable includeTaskLocation by default in UI mode
if (resolved.browser.enabled) {
if (resolved.browser.ui) resolved.includeTaskLocation ??= true;
} else if (resolved.ui) resolved.includeTaskLocation ??= true;
if (typeof resolved.browser.trace === "string" || !resolved.browser.trace) resolved.browser.trace = { mode: resolved.browser.trace || "off" };
if (resolved.browser.trace.tracesDir != null) resolved.browser.trace.tracesDir = resolvePath(resolved.browser.trace.tracesDir, resolved.root);
if (toArray(resolved.reporters).some((reporter) => {
if (Array.isArray(reporter)) return reporter[0] === "html";
return false;
})) resolved.includeTaskLocation ??= true;
resolved.server ??= {};
resolved.server.deps ??= {};
if (resolved.server.debug?.dump || process.env.VITEST_DEBUG_DUMP) {
const userFolder = resolved.server.debug?.dump || process.env.VITEST_DEBUG_DUMP;
resolved.dumpDir = resolve(resolved.root, typeof userFolder === "string" && userFolder !== "true" ? userFolder : ".vitest-dump", resolved.name || "root");
}
resolved.testTimeout ??= resolved.browser.enabled ? 15e3 : 5e3;
resolved.hookTimeout ??= resolved.browser.enabled ? 3e4 : 1e4;
resolved.experimental ??= {};
if (resolved.experimental.openTelemetry?.sdkPath) {
const sdkPath = resolve(resolved.root, resolved.experimental.openTelemetry.sdkPath);
resolved.experimental.openTelemetry.sdkPath = pathToFileURL(sdkPath).toString();
}
if (resolved.experimental.openTelemetry?.browserSdkPath) {
const browserSdkPath = resolve(resolved.root, resolved.experimental.openTelemetry.browserSdkPath);
resolved.experimental.openTelemetry.browserSdkPath = browserSdkPath;
}
if (resolved.experimental.fsModuleCachePath) resolved.experimental.fsModuleCachePath = resolve(resolved.root, resolved.experimental.fsModuleCachePath);
resolved.experimental.importDurations ??= {};
resolved.experimental.importDurations.print ??= false;
resolved.experimental.importDurations.failOnDanger ??= false;
if (resolved.experimental.importDurations.limit == null) {
const shouldCollect = resolved.experimental.importDurations.print || resolved.experimental.importDurations.failOnDanger || resolved.ui;
resolved.experimental.importDurations.limit = shouldCollect ? 10 : 0;
}
resolved.experimental.importDurations.thresholds ??= {};
resolved.experimental.importDurations.thresholds.warn ??= 100;
resolved.experimental.importDurations.thresholds.danger ??= 500;
return resolved;
}
function isBrowserEnabled(config) {
return Boolean(config.browser?.enabled);
}
function resolveCoverageReporters(configReporters) {
// E.g. { reporter: "html" }
if (!Array.isArray(configReporters)) return [[configReporters, {}]];
const resolvedReporters = [];
for (const reporter of configReporters) if (Array.isArray(reporter))
// E.g. { reporter: [ ["html", { skipEmpty: true }], ["lcov"], ["json", { file: "map.json" }] ]}
resolvedReporters.push([reporter[0], reporter[1] || {}]);
else
// E.g. { reporter: ["html", "json"]}
resolvedReporters.push([reporter, {}]);
return resolvedReporters;
}
function isChromiumName(provider, name) {
if (provider === "playwright") return name === "chromium";
return name === "chrome" || name === "edge";
}
function hasBrowserChromium(vitest, config) {
const browser = config.browser;
if (!browser || !browser.provider || browser.provider.name === "preview" || !browser.enabled) return false;
if (browser.name) return isChromiumName(browser.provider.name, browser.name);
if (!browser.instances) return false;
return browser.instances.some((instance) => {
const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser);
// browser config is filtered out
if (!vitest.matchesProjectFilter(name)) return false;
return isChromiumName(browser.provider.name, instance.browser);
});
}
function hasOnlyBrowserChromium(vitest, config) {
const browser = config.browser;
if (!browser || !browser.provider || browser.provider.name === "preview" || !browser.enabled) return false;
if (browser.name) return isChromiumName(browser.provider.name, browser.name);
if (!browser.instances) return false;
return browser.instances.every((instance) => {
const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser);
// browser config is filtered out
if (!vitest.matchesProjectFilter(name)) return true;
return isChromiumName(browser.provider.name, instance.browser);
});
}
const THRESHOLD_KEYS = [
"lines",
"functions",
"statements",
"branches"
];
const GLOBAL_THRESHOLDS_KEY = "global";
const DEFAULT_PROJECT = Symbol.for("default-project");
let uniqueId = 0;
async function getCoverageProvider(options, loader) {
const coverageModule = await resolveCoverageProviderModule(options, loader);
if (coverageModule) return coverageModule.getProvider();
return null;
}
class BaseCoverageProvider {
ctx;
name;
version;
options;
globCache = /* @__PURE__ */ new Map();
autoUpdateMarker = "\n// __VITEST_COVERAGE_MARKER__";
coverageFiles = /* @__PURE__ */ new Map();
pendingPromises = [];
coverageFilesDirectory;
roots = [];
_initialize(ctx) {
this.ctx = ctx;
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} `))}.
Running mixed versions is not supported and may lead into bugs
Update your dependencies and make sure the versions match.`));
const config = ctx._coverageOptions;
this.options = {
...coverageConfigDefaults,
...config,
provider: this.name,
reportsDirectory: resolve(ctx.config.root, config.reportsDirectory || coverageConfigDefaults.reportsDirectory),
reporter: resolveCoverageReporters(config.reporter || coverageConfigDefaults.reporter),
thresholds: config.thresholds && {
...config.thresholds,
lines: config.thresholds["100"] ? 100 : config.thresholds.lines,
branches: config.thresholds["100"] ? 100 : config.thresholds.branches,
functions: config.thresholds["100"] ? 100 : config.thresholds.functions,
statements: config.thresholds["100"] ? 100 : config.thresholds.statements
}
};
const shard = this.ctx.config.shard;
const tempDirectory = `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`;
this.coverageFilesDirectory = resolve(this.options.reportsDirectory, tempDirectory);
// If --project filter is set pick only roots of resolved projects
this.roots = ctx.config.project?.length ? [...new Set(ctx.projects.map((project) => project.config.root))] : [ctx.config.root];
}
/**
* Check if file matches `coverage.include` but not `coverage.exclude`
*/
isIncluded(_filename, root) {
const roots = root ? [root] : this.roots;
const filename = slash(_filename);
const cacheHit = this.globCache.get(filename);
if (cacheHit !== void 0) return cacheHit;
// File outside project root with default allowExternal
if (this.options.allowExternal === false && roots.every((root) => !filename.startsWith(root))) {
this.globCache.set(filename, false);
return false;
}
// By default `coverage.include` matches all files, except "coverage.exclude"
const glob = this.options.include || "**";
const included = pm.isMatch(filename, glob, {
contains: true,
dot: true,
ignore: this.options.exclude
});
this.globCache.set(filename, included);
return included;
}
async getUntestedFilesByRoot(testedFiles, include, root) {
let includedFiles = await glob(include, {
cwd: root,
ignore: [...this.options.exclude, ...testedFiles.map((file) => slash(file))],
absolute: true,
dot: true,
onlyFiles: true
});
// Run again through picomatch as tinyglobby's exclude pattern is different ({ "exclude": ["math"] } should ignore "src/math.ts")
includedFiles = includedFiles.filter((file) => this.isIncluded(file, root));
if (this.ctx.config.changed) includedFiles = (this.ctx.config.related || []).filter((file) => includedFiles.includes(file));
return includedFiles.map((file) => slash(path.resolve(root, file)));
}
async getUntestedFiles(testedFiles) {
if (this.options.include == null) return [];
const rootMapper = this.getUntestedFilesByRoot.bind(this, testedFiles, this.options.include);
return (await Promise.all(this.roots.map(rootMapper))).flatMap((files) => files);
}
createCoverageMap() {
throw new Error("BaseReporter's createCoverageMap was not overwritten");
}
async generateReports(_, __) {
throw new Error("BaseReporter's generateReports was not overwritten");
}
async parseConfigModule(_) {
throw new Error("BaseReporter's parseConfigModule was not overwritten");
}
resolveOptions() {
return this.options;
}
async clean(clean = true) {
if (clean && existsSync(this.options.reportsDirectory)) await promises.rm(this.options.reportsDirectory, {
recursive: true,
force: true,
maxRetries: 10
});
if (existsSync(this.coverageFilesDirectory)) await promises.rm(this.coverageFilesDirectory, {
recursive: true,
force: true,
maxRetries: 10
});
await promises.mkdir(this.coverageFilesDirectory, { recursive: true });
this.coverageFiles = /* @__PURE__ */ new Map();
this.pendingPromises = [];
}
onAfterSuiteRun({ coverage, environment, projectName, testFiles }) {
if (!coverage) return;
let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT);
if (!entry) {
entry = {};
this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
}
const testFilenames = testFiles.join();
const filename = resolve(this.coverageFilesDirectory, `coverage-${uniqueId++}.json`);
entry[environment] ??= {};
// If there's a result from previous run, overwrite it
entry[environment][testFilenames] = filename;
const promise = promises.writeFile(filename, JSON.stringify(coverage), "utf-8");
this.pendingPromises.push(promise);
}
async readCoverageFiles({ onFileRead, onFinished, onDebug }) {
let index = 0;
const total = this.pendingPromises.length;
await Promise.all(this.pendingPromises);
this.pendingPromises = [];
for (const [projectName, coveragePerProject] of this.coverageFiles.entries()) for (const [environment, coverageByTestfiles] of Object.entries(coveragePerProject)) {
const filenames = Object.values(coverageByTestfiles);
const project = this.ctx.getProjectByName(projectName);
for (const chunk of this.toSlices(filenames, this.options.processingConcurrency)) {
if (onDebug.enabled) {
index += chunk.length;
onDebug(`Reading coverage results ${index}/${total}`);
}
await Promise.all(chunk.map(async (filename) => {
const contents = await promises.readFile(filename, "utf-8");
onFileRead(JSON.parse(contents));
}));
}
await onFinished(project, environment);
}
}
async cleanAfterRun() {
this.coverageFiles = /* @__PURE__ */ new Map();
await promises.rm(this.coverageFilesDirectory, { recursive: true });
// Remove empty reports directory, e.g. when only text-reporter is used
if (readdirSync(this.options.reportsDirectory).length === 0) await promises.rm(this.options.reportsDirectory, { recursive: true });
}
async onTestFailure() {
if (!this.options.reportOnFailure) await this.cleanAfterRun();
}
async reportCoverage(coverageMap, { allTestsRun }) {
await this.generateReports(coverageMap || this.createCoverageMap(), allTestsRun);
if (!(!this.options.cleanOnRerun && this.ctx.config.watch)) await this.cleanAfterRun();
}
async reportThresholds(coverageMap, allTestsRun) {
const resolvedThresholds = this.resolveThresholds(coverageMap);
this.checkThresholds(resolvedThresholds);
if (this.options.thresholds?.autoUpdate && allTestsRun) {
if (!this.ctx.vite.config.configFile) throw new Error("Missing configurationFile. The \"coverage.thresholds.autoUpdate\" can only be enabled when configuration file is used.");
const configFilePath = this.ctx.vite.config.configFile;
const configModule = await this.parseConfigModule(configFilePath);
await this.updateThresholds({
thresholds: resolvedThresholds,
configurationFile: configModule,
onUpdate: () => writeFileSync(configFilePath, configModule.generate().code.replace(this.autoUpdateMarker, ""), "utf-8")
});
}
}
/**
* Constructs collected coverage and users' threshold options into separate sets
* where each threshold set holds their own coverage maps. Threshold set is either
* for specific files defined by glob pattern or global for all other files.
*/
resolveThresholds(coverageMap) {
const resolvedThresholds = [];
const files = coverageMap.files();
const globalCoverageMap = this.createCoverageMap();
for (const key of Object.keys(this.options.thresholds)) {
if (key === "perFile" || key === "autoUpdate" || key === "100" || THRESHOLD_KEYS.includes(key)) continue;
const glob = key;
const globThresholds = resolveGlobThresholds(this.options.thresholds[glob]);
const globCoverageMap = this.createCoverageMap();
const matcher = pm(glob);
const matchingFiles = files.filter((file) => matcher(relative(this.ctx.config.root, file)));
for (const file of matchingFiles) {
const fileCoverage = coverageMap.fileCoverageFor(file);
globCoverageMap.addFileCoverage(fileCoverage);
}
resolvedThresholds.push({
name: glob,
coverageMap: globCoverageMap,
thresholds: globThresholds
});
}
// Global threshold is for all files, even if they are included by glob patterns
for (const file of files) {
const fileCoverage = coverageMap.fileCoverageFor(file);
globalCoverageMap.addFileCoverage(fileCoverage);
}
resolvedThresholds.unshift({
name: GLOBAL_THRESHOLDS_KEY,
coverageMap: globalCoverageMap,
thresholds: {
branches: this.options.thresholds?.branches,
functions: this.options.thresholds?.functions,
lines: this.options.thresholds?.lines,
statements: this.options.thresholds?.statements
}
});
return resolvedThresholds;
}
/**
* Check collected coverage against configured thresholds. Sets exit code to 1 when thresholds not reached.
*/
checkThresholds(allThresholds) {
for (const { coverageMap, thresholds, name } of allThresholds) {
if (thresholds.branches === void 0 && thresholds.functions === void 0 && thresholds.lines === void 0 && thresholds.statements === void 0) continue;
// Construct list of coverage summaries where thresholds are compared against
const summaries = this.options.thresholds?.perFile ? coverageMap.files().map((file) => ({
file,
summary: coverageMap.fileCoverageFor(file).toSummary()
})) : [{
file: null,
summary: coverageMap.getCoverageSummary()
}];
// Check thresholds of each summary
for (const { summary, file } of summaries) for (const thresholdKey of THRESHOLD_KEYS) {
const threshold = thresholds[thresholdKey];
if (threshold === void 0) continue;
/**
* Positive thresholds are treated as minimum coverage percentages (X means: X% of lines must be covered),
* while negative thresholds are treated as maximum uncovered counts (-X means: X lines may be uncovered).
*/
if (threshold >= 0) {
const coverage = summary.data[thresholdKey].pct;
if (coverage < threshold) {
process.exitCode = 1;
/**
* Generate error message based on perFile flag:
* - ERROR: Coverage for statements (33.33%) does not meet threshold (85%) for src/math.ts
* - ERROR: Coverage for statements (50%) does not meet global threshold (85%)
*/
let errorMessage = `ERROR: Coverage for ${thresholdKey} (${coverage}%) does not meet ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${threshold}%)`;
if (this.options.thresholds?.perFile && file) errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
this.ctx.logger.error(errorMessage);
}
} else {
const uncovered = summary.data[thresholdKey].total - summary.data[thresholdKey].covered;
const absoluteThreshold = threshold * -1;
if (uncovered > absoluteThreshold) {
process.exitCode = 1;
/**
* Generate error message based on perFile flag:
* - ERROR: Uncovered statements (33) exceed threshold (30) for src/math.ts
* - ERROR: Uncovered statements (33) exceed global threshold (30)
*/
let errorMessage = `ERROR: Uncovered ${thresholdKey} (${uncovered}) exceed ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${absoluteThreshold})`;
if (this.options.thresholds?.perFile && file) errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
this.ctx.logger.error(errorMessage);
}
}
}
}
}
/**
* Check if current coverage is above configured thresholds and bump the thresholds if needed
*/
async updateThresholds({ thresholds: allThresholds, onUpdate, configurationFile }) {
let updatedThresholds = false;
const config = resolveConfig(configurationFile);
assertConfigurationModule(config);
for (const { coverageMap, thresholds, name } of allThresholds) {
const summaries = this.options.thresholds?.perFile ? coverageMap.files().map((file) => coverageMap.fileCoverageFor(file).toSummary()) : [coverageMap.getCoverageSummary()];
const thresholdsToUpdate = [];
for (const key of THRESHOLD_KEYS) {
const threshold = thresholds[key] ?? 100;
/**
* Positive thresholds are treated as minimum coverage percentages (X means: X% of lines must be covered),
* while negative thresholds are treated as maximum uncovered counts (-X means: X lines may be uncovered).
*/
if (threshold >= 0) {
const actual = Math.min(...summaries.map((summary) => summary[key].pct));
if (actual > threshold) thresholdsToUpdate.push([key, actual]);
} else {
const absoluteThreshold = threshold * -1;
const actual = Math.max(...summaries.map((summary) => summary[key].total - summary[key].covered));
if (actual < absoluteThreshold) {
// If everything was covered, set new threshold to 100% (since a threshold of 0 would be considered as 0%)
const updatedThreshold = actual === 0 ? 100 : actual * -1;
thresholdsToUpdate.push([key, updatedThreshold]);
}
}
}
if (thresholdsToUpdate.length === 0) continue;
updatedThresholds = true;
const thresholdFormatter = typeof this.options.thresholds?.autoUpdate === "function" ? this.options.thresholds?.autoUpdate : (value) => value;
for (const [threshold, newValue] of thresholdsToUpdate) {
const formattedValue = thresholdFormatter(newValue);
if (name === GLOBAL_THRESHOLDS_KEY) config.test.coverage.thresholds[threshold] = formattedValue;
else {
const glob = config.test.coverage.thresholds[name];
glob[threshold] = formattedValue;
}
}
}
if (updatedThresholds) {
this.ctx.logger.log("Updating thresholds to configuration file. You may want to push with updated coverage thresholds.");
onUpdate();
}
}
async mergeReports(coverageMaps) {
const coverageMap = this.createCoverageMap();
for (const coverage of coverageMaps) coverageMap.merge(coverage);
await this.generateReports(coverageMap, true);
}
hasTerminalReporter(reporters) {
return reporters.some(([reporter]) => reporter === "text" || reporter === "text-summary" || reporter === "text-lcov" || reporter === "teamcity");
}
toSlices(array, size) {
return array.reduce((chunks, item) => {
const index = Math.max(0, chunks.length - 1);
const lastChunk = chunks[index] || [];
chunks[index] = lastChunk;
if (lastChunk.length >= size) chunks.push([item]);
else lastChunk.push(item);
return chunks;
}, []);
}
// TODO: should this be abstracted in `project`/`vitest` instead?
// if we decide to keep `viteModuleRunner: false`, we will need to abstract transformation in both main thread and tests
// custom --import=module.registerHooks need to be transformed as well somehow
async transformFile(url, project, viteEnvironment) {
const config = project.config;
// vite is disabled, should transform manually if possible
if (config.experimental.viteModuleRunner === false) {
const pathname = url.split("?")[0];
const filename = pathname.startsWith("file://") ? fileURLToPath(pathname) : pathname;
const extension = path.extname(filename);
if (!(extension === ".ts" || extension === ".mts" || extension === ".cts")) return {
code: await promises.readFile(filename, "utf-8"),
map: null
};
if (!module$1.stripTypeScriptTypes) throw new Error(`Cannot parse '${url}' because "module.stripTypeScriptTypes" is not supported. TypeScript coverage requires Node.js 22.15 or higher. This is NOT a bug of Vitest.`);
const isTransform = process.execArgv.includes("--experimental-transform-types") || config.execArgv.includes("--experimental-transform-types") || process.env.NODE_OPTIONS?.includes("--experimental-transform-types") || config.env?.NODE_OPTIONS?.includes("--experimental-transform-types");
const code = await promises.readFile(filename, "utf-8");
return {
code: module$1.stripTypeScriptTypes(code, { mode: isTransform ? "transform" : "strip" }),
map: null
};
}
if (project.isBrowserEnabled() || viteEnvironment === "__browser__") {
const result = await (project.browser?.vite.environments.client || project.vite.environments.client).transformRequest(url);
if (result) return result;
}
return project.vite.environments[viteEnvironment].transformRequest(url);
}
createUncoveredFileTransformer(ctx) {
const projects = new Set([...ctx.projects, ctx.getRootProject()]);
return async (filename) => {
let lastError;
for (const project of projects) {
const root = project.config.root;
// On Windows root doesn't start with "/" while filenames do
if (!filename.startsWith(root) && !filename.startsWith(`/${root}`)) continue;
try {
const environment = project.config.environment;
const viteEnvironment = environment === "jsdom" || environment === "happy-dom" ? "client" : "ssr";
return await this.transformFile(filename, project, viteEnvironment);
} catch (err) {
lastError = err;
}
}
// All vite servers failed to transform the file
throw lastError;
};
}
}
/**
* Narrow down `unknown` glob thresholds to resolved ones
*/
function resolveGlobThresholds(thresholds) {
if (!thresholds || typeof thresholds !== "object") return {};
if (100 in thresholds && thresholds[100] === true) return {
lines: 100,
branches: 100,
functions: 100,
statements: 100
};
return {
lines: "lines" in thresholds && typeof thresholds.lines === "number" ? thresholds.lines : void 0,
branches: "branches" in thresholds && typeof thresholds.branches === "number" ? thresholds.branches : void 0,
functions: "functions" in thresholds && typeof thresholds.functions === "number" ? thresholds.functions : void 0,
statements: "statements" in thresholds && typeof thresholds.statements === "number" ? thresholds.statements : void 0
};
}
function assertConfigurationModule(config) {
try {
// @ts-expect-error -- Intentional unsafe null pointer check as wrapped in try-catch
if (typeof config.test.coverage.thresholds !== "object") throw new TypeError("Expected config.test.coverage.thresholds to be an object");
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Unable to parse thresholds from configuration file: ${message}`);
}
}
function resolveConfig(configModule) {
const mod = configModule.exports.default;
try {
// Check for "export default { test: {...} }"
if (mod.$type === "object") return mod;
// "export default defineConfig(...)"
let config = resolveDefineConfig(mod);
if (config) return config;
// "export default mergeConfig(..., defineConfig(...))"
if (mod.$type === "function-call" && mod.$callee === "mergeConfig") {
config = resolveMergeConfig(mod);
if (config) return config;
}
} catch (error) {
// Reduce magicast's verbose errors to readable ones
throw new Error(error instanceof Error ? error.message : String(error));
}
throw new Error("Failed to update coverage thresholds. Configuration file is too complex.");
}
function resolveDefineConfig(mod) {
if (mod.$type === "function-call" && mod.$callee === "defineConfig") {
// "export default defineConfig({ test: {...} })"
if (mod.$args[0].$type === "object") return mod.$args[0];
if (mod.$args[0].$type === "arrow-function-expression") {
if (mod.$args[0].$body.$type === "object")
// "export default defineConfig(() => ({ test: {...} }))"
return mod.$args[0].$body;
// "export default defineConfig(() => mergeConfig({...}, ...))"
const config = resolveMergeConfig(mod.$args[0].$body);
if (config) return config;
}
}
}
function resolveMergeConfig(mod) {
if (mod.$type === "function-call" && mod.$callee === "mergeConfig") for (const arg of mod.$args) {
const config = resolveDefineConfig(arg);
if (config) return config;
}
}
export { BaseCoverageProvider as B, RandomSequencer as R, BaseSequencer as a, resolveApiServerConfig as b, getCoverageProvider as g, hash as h, isBrowserEnabled as i, resolveConfig$1 as r };
import nodeos__default from 'node:os';
import './env.D4Lgay0q.js';
import { isCI } from 'std-env';
const defaultInclude = ["**/*.{test,spec}.?(c|m)[jt]s?(x)"];
const defaultExclude = ["**/node_modules/**", "**/.git/**"];
const benchmarkConfigDefaults = {
include: ["**/*.{bench,benchmark}.?(c|m)[jt]s?(x)"],
exclude: defaultExclude,
includeSource: [],
reporters: ["default"],
includeSamples: false
};
// These are the generic defaults for coverage. Providers may also set some provider specific defaults.
const coverageConfigDefaults = {
provider: "v8",
enabled: false,
clean: true,
cleanOnRerun: true,
reportsDirectory: "./coverage",
exclude: [],
reportOnFailure: false,
reporter: [
["text", {}],
["html", {}],
["clover", {}],
["json", {}]
],
allowExternal: false,
excludeAfterRemap: false,
processingConcurrency: Math.min(20, nodeos__default.availableParallelism?.() ?? nodeos__default.cpus().length)
};
const fakeTimersDefaults = {
loopLimit: 1e4,
shouldClearNativeTimers: true
};
const configDefaults = Object.freeze({
allowOnly: !isCI,
isolate: true,
watch: !isCI && process.stdin.isTTY,
globals: false,
environment: "node",
clearMocks: false,
restoreMocks: false,
mockReset: false,
unstubGlobals: false,
unstubEnvs: false,
include: defaultInclude,
exclude: defaultExclude,
teardownTimeout: 1e4,
forceRerunTriggers: ["**/package.json/**", "**/{vitest,vite}.config.*/**"],
update: false,
reporters: [],
silent: false,
hideSkippedTests: false,
api: false,
ui: false,
uiBase: "/__vitest__/",
open: !isCI,
css: { include: [] },
coverage: coverageConfigDefaults,
fakeTimers: fakeTimersDefaults,
maxConcurrency: 5,
dangerouslyIgnoreUnhandledErrors: false,
typecheck: {
checker: "tsc",
include: ["**/*.{test,spec}-d.?(c|m)[jt]s?(x)"],
exclude: defaultExclude
},
slowTestThreshold: 300,
disableConsoleIntercept: false,
detectAsyncLeaks: false
});
export { coverageConfigDefaults as a, defaultInclude as b, configDefaults as c, defaultExclude as d, benchmarkConfigDefaults as e };
import { PromisifyAssertion, Tester, ExpectStatic } from '@vitest/expect';
import { Plugin } from '@vitest/pretty-format';
import { SnapshotState } from '@vitest/snapshot';
import { B as BenchmarkResult } from './benchmark.d.DAaHLpsq.js';
import { U as UserConsoleLog } from './rpc.d.BFMWpdph.js';
interface SnapshotMatcher<T> {
<U extends { [P in keyof T] : any }>(snapshot: Partial<U>, hint?: string): void;
(hint?: string): void;
}
interface InlineSnapshotMatcher<T> {
<U extends { [P in keyof T] : any }>(properties: Partial<U>, snapshot?: string, hint?: string): void;
(hint?: string): void;
}
declare module "@vitest/expect" {
interface MatcherState {
environment: string;
snapshotState: SnapshotState;
}
interface ExpectPollOptions {
interval?: number;
timeout?: number;
message?: string;
}
interface ExpectStatic {
assert: Chai.AssertStatic;
unreachable: (message?: string) => never;
soft: <T>(actual: T, message?: string) => Assertion<T>;
poll: <T>(actual: () => T, options?: ExpectPollOptions) => PromisifyAssertion<Awaited<T>>;
addEqualityTesters: (testers: Array<Tester>) => void;
assertions: (expected: number) => void;
hasAssertions: () => void;
addSnapshotSerializer: (plugin: Plugin) => void;
}
interface Assertion<T> {
matchSnapshot: SnapshotMatcher<T>;
toMatchSnapshot: SnapshotMatcher<T>;
toMatchInlineSnapshot: InlineSnapshotMatcher<T>;
/**
* Checks that an error thrown by a function matches a previously recorded snapshot.
*
* @param hint - Optional custom error message.
*
* @example
* expect(functionWithError).toThrowErrorMatchingSnapshot();
*/
toThrowErrorMatchingSnapshot: (hint?: string) => void;
/**
* Checks that an error thrown by a function matches an inline snapshot within the test file.
* Useful for keeping snapshots close to the test code.
*
* @param snapshot - Optional inline snapshot string to match.
* @param hint - Optional custom error message.
*
* @example
* const throwError = () => { throw new Error('Error occurred') };
* expect(throwError).toThrowErrorMatchingInlineSnapshot(`"Error occurred"`);
*/
toThrowErrorMatchingInlineSnapshot: (snapshot?: string, hint?: string) => void;
/**
* Compares the received value to a snapshot saved in a specified file.
* Useful for cases where snapshot content is large or needs to be shared across tests.
*
* @param filepath - Path to the snapshot file.
* @param hint - Optional custom error message.
*
* @example
* await expect(largeData).toMatchFileSnapshot('path/to/snapshot.json');
*/
toMatchFileSnapshot: (filepath: string, hint?: string) => Promise<void>;
}
}
declare module "@vitest/runner" {
interface TestContext {
/**
* `expect` instance bound to the current test.
*
* This API is useful for running snapshot tests concurrently because global expect cannot track them.
*/
readonly expect: ExpectStatic;
/** @internal */
_local: boolean;
}
interface TaskMeta {
typecheck?: boolean;
benchmark?: boolean;
}
interface File {
prepareDuration?: number;
environmentLoad?: number;
}
interface TaskBase {
logs?: UserConsoleLog[];
}
interface TaskResult {
benchmark?: BenchmarkResult;
}
}
import { g as globalApis } from './constants.CPYnjOGj.js';
import { i as index } from './index.C39wbgWx.js';
import './test.EDIwt4Yp.js';
import '@vitest/runner';
import '@vitest/utils/helpers';
import '@vitest/utils/timers';
import './benchmark.BoqSLF53.js';
import '@vitest/runner/utils';
import './utils.DT4VyRyl.js';
import '@vitest/expect';
import '@vitest/utils/error';
import 'pathe';
import '@vitest/snapshot';
import '@vitest/spy';
import '@vitest/utils/offset';
import '@vitest/utils/source-map';
import './_commonjsHelpers.D26ty3Ew.js';
import './rpc.DcRWTy5G.js';
import './index.Chj8NDwU.js';
import './evaluatedModules.Dg1zASAC.js';
import 'vite/module-runner';
import 'expect-type';
function registerApiGlobally() {
globalApis.forEach((api) => {
// @ts-expect-error I know what I am doing :P
globalThis[api] = index[api];
});
}
export { registerApiGlobally };
import fs from 'node:fs';
import { getTasks, getFullName, getTests } from '@vitest/runner/utils';
import * as pathe from 'pathe';
import c from 'tinyrainbow';
import { g as getStateSymbol, t as truncateString, F as F_RIGHT, D as DefaultReporter, f as formatProjectName, s as separator } from './index.CoafDRze.js';
import { stripVTControlCharacters } from 'node:util';
import { notNullish } from '@vitest/utils/helpers';
function createBenchmarkJsonReport(files) {
const report = { files: [] };
for (const file of files) {
const groups = [];
for (const task of getTasks(file)) if (task?.type === "suite") {
const benchmarks = [];
for (const t of task.tasks) {
const benchmark = t.meta.benchmark && t.result?.benchmark;
if (benchmark) benchmarks.push({
id: t.id,
...benchmark,
samples: []
});
}
if (benchmarks.length) groups.push({
fullName: getFullName(task, " > "),
benchmarks
});
}
report.files.push({
filepath: file.filepath,
groups
});
}
return report;
}
function flattenFormattedBenchmarkReport(report) {
const flat = {};
for (const file of report.files) for (const group of file.groups) for (const t of group.benchmarks) flat[t.id] = t;
return flat;
}
const outputMap = /* @__PURE__ */ new WeakMap();
function formatNumber(number) {
const res = String(number.toFixed(number < 100 ? 4 : 2)).split(".");
return res[0].replace(/(?=(?:\d{3})+$)\B/g, ",") + (res[1] ? `.${res[1]}` : "");
}
const tableHead = [
"name",
"hz",
"min",
"max",
"mean",
"p75",
"p99",
"p995",
"p999",
"rme",
"samples"
];
function renderBenchmarkItems(result) {
return [
result.name,
formatNumber(result.hz || 0),
formatNumber(result.min || 0),
formatNumber(result.max || 0),
formatNumber(result.mean || 0),
formatNumber(result.p75 || 0),
formatNumber(result.p99 || 0),
formatNumber(result.p995 || 0),
formatNumber(result.p999 || 0),
`±${(result.rme || 0).toFixed(2)}%`,
(result.sampleCount || 0).toString()
];
}
function computeColumnWidths(results) {
const rows = [tableHead, ...results.map((v) => renderBenchmarkItems(v))];
return Array.from(tableHead, (_, i) => Math.max(...rows.map((row) => stripVTControlCharacters(row[i]).length)));
}
function padRow(row, widths) {
return row.map((v, i) => i ? v.padStart(widths[i], " ") : v.padEnd(widths[i], " "));
}
function renderTableHead(widths) {
return " ".repeat(3) + padRow(tableHead, widths).map(c.bold).join(" ");
}
function renderBenchmark(result, widths) {
const padded = padRow(renderBenchmarkItems(result), widths);
return [
padded[0],
c.blue(padded[1]),
c.cyan(padded[2]),
c.cyan(padded[3]),
c.cyan(padded[4]),
c.cyan(padded[5]),
c.cyan(padded[6]),
c.cyan(padded[7]),
c.cyan(padded[8]),
c.dim(padded[9]),
c.dim(padded[10])
].join(" ");
}
function renderTable(options) {
const output = [];
const benchMap = {};
for (const task of options.tasks) if (task.meta.benchmark && task.result?.benchmark) benchMap[task.id] = {
current: task.result.benchmark,
baseline: options.compare?.[task.id]
};
const benchCount = Object.entries(benchMap).length;
const columnWidths = computeColumnWidths(Object.values(benchMap).flatMap((v) => [v.current, v.baseline]).filter(notNullish));
let idx = 0;
const padding = " ".repeat(1 );
for (const task of options.tasks) {
const duration = task.result?.duration;
const bench = benchMap[task.id];
let prefix = "";
if (idx === 0 && task.meta?.benchmark) prefix += `${renderTableHead(columnWidths)}\n${padding}`;
prefix += ` ${getStateSymbol(task)} `;
let suffix = "";
if (task.type === "suite") suffix += c.dim(` (${getTests(task).length})`);
if (task.mode === "skip" || task.mode === "todo") suffix += c.dim(c.gray(" [skipped]"));
if (duration != null) {
const color = duration > options.slowTestThreshold ? c.yellow : c.green;
suffix += color(` ${Math.round(duration)}${c.dim("ms")}`);
}
if (options.showHeap && task.result?.heap != null) suffix += c.magenta(` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`);
if (bench) {
let body = renderBenchmark(bench.current, columnWidths);
if (options.compare && bench.baseline) {
if (bench.current.hz) {
const diff = bench.current.hz / bench.baseline.hz;
const diffFixed = diff.toFixed(2);
if (diffFixed === "1.0.0") body += c.gray(` [${diffFixed}x]`);
if (diff > 1) body += c.blue(` [${diffFixed}x] ⇑`);
else body += c.red(` [${diffFixed}x] ⇓`);
}
output.push(padding + prefix + body + suffix);
const bodyBaseline = renderBenchmark(bench.baseline, columnWidths);
output.push(`${padding} ${bodyBaseline} ${c.dim("(baseline)")}`);
} else {
if (bench.current.rank === 1 && benchCount > 1) body += c.bold(c.green(" fastest"));
if (bench.current.rank === benchCount && benchCount > 2) body += c.bold(c.gray(" slowest"));
output.push(padding + prefix + body + suffix);
}
} else output.push(padding + prefix + task.name + suffix);
if (task.result?.state !== "pass" && outputMap.get(task) != null) {
let data = outputMap.get(task);
if (typeof data === "string") {
data = stripVTControlCharacters(data.trim().split("\n").filter(Boolean).pop());
if (data === "") data = void 0;
}
if (data != null) {
const out = ` ${" ".repeat(options.level)}${F_RIGHT} ${data}`;
output.push(c.gray(truncateString(out, options.columns)));
}
}
idx++;
}
return output.filter(Boolean).join("\n");
}
class BenchmarkReporter extends DefaultReporter {
compare;
async onInit(ctx) {
super.onInit(ctx);
if (this.ctx.config.benchmark?.compare) {
const compareFile = pathe.resolve(this.ctx.config.root, this.ctx.config.benchmark?.compare);
try {
this.compare = flattenFormattedBenchmarkReport(JSON.parse(await fs.promises.readFile(compareFile, "utf-8")));
} catch (e) {
this.error(`Failed to read '${compareFile}'`, e);
}
}
}
onTaskUpdate(packs) {
for (const pack of packs) {
const task = this.ctx.state.idMap.get(pack[0]);
if (task?.type === "suite" && task.result?.state !== "run") task.tasks.filter((task) => task.result?.benchmark).sort((benchA, benchB) => benchA.result.benchmark.mean - benchB.result.benchmark.mean).forEach((bench, idx) => {
bench.result.benchmark.rank = Number(idx) + 1;
});
}
}
onTestSuiteResult(testSuite) {
super.onTestSuiteResult(testSuite);
this.printSuiteTable(testSuite);
}
printTestModule(testModule) {
this.printSuiteTable(testModule);
}
printSuiteTable(testTask) {
const state = testTask.state();
if (state === "pending" || state === "queued") return;
const benches = testTask.task.tasks.filter((t) => t.meta.benchmark);
const duration = testTask.task.result?.duration || 0;
if (benches.length > 0 && benches.every((t) => t.result?.state !== "run" && t.result?.state !== "queued")) {
let title = `\n ${getStateSymbol(testTask.task)} ${formatProjectName(testTask.project)}${getFullName(testTask.task, separator)}`;
if (duration != null && duration > this.ctx.config.slowTestThreshold) title += c.yellow(` ${Math.round(duration)}${c.dim("ms")}`);
this.log(title);
this.log(renderTable({
tasks: benches,
level: 1,
columns: this.ctx.logger.getColumns(),
compare: this.compare,
showHeap: this.ctx.config.logHeapUsage,
slowTestThreshold: this.ctx.config.slowTestThreshold
}));
}
}
async onTestRunEnd(testModules, unhandledErrors, reason) {
super.onTestRunEnd(testModules, unhandledErrors, reason);
// write output for future comparison
let outputFile = this.ctx.config.benchmark?.outputJson;
if (outputFile) {
outputFile = pathe.resolve(this.ctx.config.root, outputFile);
const outputDirectory = pathe.dirname(outputFile);
if (!fs.existsSync(outputDirectory)) await fs.promises.mkdir(outputDirectory, { recursive: true });
const output = createBenchmarkJsonReport(testModules.map((t) => t.task.file));
await fs.promises.writeFile(outputFile, JSON.stringify(output, null, 2));
this.log(`Benchmark report written to ${outputFile}`);
}
}
}
class VerboseBenchmarkReporter extends BenchmarkReporter {
verbose = true;
}
const BenchmarkReportsMap = {
default: BenchmarkReporter,
verbose: VerboseBenchmarkReporter
};
export { BenchmarkReporter as B, VerboseBenchmarkReporter as V, BenchmarkReportsMap as a };
import { v as vi, N as NodeBenchmarkRunner, T as TestRunner, a as assert, c as createExpect, g as globalExpect, i as inject, s as should, b as vitest } from './test.EDIwt4Yp.js';
import { b as bench } from './benchmark.BoqSLF53.js';
import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js';
import { expectTypeOf } from 'expect-type';
import { afterAll, afterEach, aroundAll, aroundEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, recordArtifact, suite, test } from '@vitest/runner';
import { chai } from '@vitest/expect';
const assertType = function assertType() {};
var index = /*#__PURE__*/Object.freeze({
__proto__: null,
BenchmarkRunner: NodeBenchmarkRunner,
EvaluatedModules: VitestEvaluatedModules,
TestRunner: TestRunner,
afterAll: afterAll,
afterEach: afterEach,
aroundAll: aroundAll,
aroundEach: aroundEach,
assert: assert,
assertType: assertType,
beforeAll: beforeAll,
beforeEach: beforeEach,
bench: bench,
chai: chai,
createExpect: createExpect,
describe: describe,
expect: globalExpect,
expectTypeOf: expectTypeOf,
inject: inject,
it: it,
onTestFailed: onTestFailed,
onTestFinished: onTestFinished,
recordArtifact: recordArtifact,
should: should,
suite: suite,
test: test,
vi: vi,
vitest: vitest
});
export { assertType as a, index as i };

Sorry, the diff of this file is too big to display

import { chai } from '@vitest/expect';
import { createHook } from 'node:async_hooks';
import { l as loadDiffConfig, a as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.Bafp3r-q.js';
import { r as rpc } from './rpc.DcRWTy5G.js';
import { g as getWorkerState } from './utils.DT4VyRyl.js';
import { T as TestRunner, N as NodeBenchmarkRunner } from './test.EDIwt4Yp.js';
function setupChaiConfig(config) {
Object.assign(chai.config, config);
}
async function resolveSnapshotEnvironment(config, moduleRunner) {
if (!config.snapshotEnvironment) {
const { VitestNodeSnapshotEnvironment } = await import('./node.CrSEwhm4.js');
return new VitestNodeSnapshotEnvironment();
}
const mod = await moduleRunner.import(config.snapshotEnvironment);
if (typeof mod.default !== "object" || !mod.default) throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`");
return mod.default;
}
const IGNORED_TYPES = new Set([
"DNSCHANNEL",
"ELDHISTOGRAM",
"PerformanceObserver",
"RANDOMBYTESREQUEST",
"SIGNREQUEST",
"STREAM_END_OF_STREAM",
"TCPWRAP",
"TIMERWRAP",
"TLSWRAP",
"ZLIB"
]);
function detectAsyncLeaks(testFile, projectName) {
const resources = /* @__PURE__ */ new Map();
const hook = createHook({
init(asyncId, type, triggerAsyncId, resource) {
if (IGNORED_TYPES.has(type)) return;
let stack = "";
const limit = Error.stackTraceLimit;
// VitestModuleEvaluator's async wrapper of node:vm causes out-of-bound stack traces, simply skip it.
// Crash fixed in https://github.com/vitejs/vite/pull/21585
try {
Error.stackTraceLimit = 100;
stack = (/* @__PURE__ */ new Error("VITEST_DETECT_ASYNC_LEAKS")).stack || "";
} catch {
return;
} finally {
Error.stackTraceLimit = limit;
}
if (!stack.includes(testFile)) {
const trigger = resources.get(triggerAsyncId);
if (!trigger) return;
stack = trigger.stack;
}
let isActive = isActiveDefault;
if ("hasRef" in resource) {
const ref = new WeakRef(resource);
isActive = () => ref.deref()?.hasRef() ?? false;
}
resources.set(asyncId, {
type,
stack,
projectName,
filename: testFile,
isActive
});
},
destroy(asyncId) {
if (resources.get(asyncId)?.type !== "PROMISE") resources.delete(asyncId);
},
promiseResolve(asyncId) {
resources.delete(asyncId);
}
});
hook.enable();
return async function collect() {
await Promise.resolve(setImmediate);
hook.disable();
const leaks = [];
for (const resource of resources.values()) if (resource.isActive()) leaks.push({
stack: resource.stack,
type: resource.type,
filename: resource.filename,
projectName: resource.projectName
});
resources.clear();
return leaks;
};
}
function isActiveDefault() {
return true;
}
async function getTestRunnerConstructor(config, moduleRunner) {
if (!config.runner) return config.mode === "test" ? TestRunner : NodeBenchmarkRunner;
const mod = await moduleRunner.import(config.runner);
if (!mod.default && typeof mod.default !== "function") throw new Error(`Runner must export a default function, but got ${typeof mod.default} imported from ${config.runner}`);
return mod.default;
}
async function resolveTestRunner(config, moduleRunner, traces) {
const testRunner = new (await (getTestRunnerConstructor(config, moduleRunner)))(config);
// inject private executor to every runner
Object.defineProperty(testRunner, "moduleRunner", {
value: moduleRunner,
enumerable: false,
configurable: false
});
if (!testRunner.config) testRunner.config = config;
if (!testRunner.importFile) throw new Error("Runner must implement \"importFile\" method.");
if ("__setTraces" in testRunner) testRunner.__setTraces(traces);
const [diffOptions] = await Promise.all([loadDiffConfig(config, moduleRunner), loadSnapshotSerializers(config, moduleRunner)]);
testRunner.config.diffOptions = diffOptions;
// patch some methods, so custom runners don't need to call RPC
const originalOnTaskUpdate = testRunner.onTaskUpdate;
testRunner.onTaskUpdate = async (task, events) => {
const p = rpc().onTaskUpdate(task, events);
await originalOnTaskUpdate?.call(testRunner, task, events);
return p;
};
// patch some methods, so custom runners don't need to call RPC
const originalOnTestAnnotate = testRunner.onTestAnnotate;
testRunner.onTestAnnotate = async (test, annotation) => {
const p = rpc().onTaskArtifactRecord(test.id, {
type: "internal:annotation",
location: annotation.location,
annotation
});
const overriddenResult = await originalOnTestAnnotate?.call(testRunner, test, annotation);
const vitestResult = await p;
return overriddenResult || vitestResult.annotation;
};
const originalOnTestArtifactRecord = testRunner.onTestArtifactRecord;
testRunner.onTestArtifactRecord = async (test, artifact) => {
const p = rpc().onTaskArtifactRecord(test.id, artifact);
const overriddenResult = await originalOnTestArtifactRecord?.call(testRunner, test, artifact);
const vitestResult = await p;
return overriddenResult || vitestResult;
};
const originalOnCollectStart = testRunner.onCollectStart;
testRunner.onCollectStart = async (file) => {
await rpc().onQueued(file);
await originalOnCollectStart?.call(testRunner, file);
};
const originalOnCollected = testRunner.onCollected;
testRunner.onCollected = async (files) => {
const state = getWorkerState();
files.forEach((file) => {
file.prepareDuration = state.durations.prepare;
file.environmentLoad = state.durations.environment;
// should be collected only for a single test file in a batch
state.durations.prepare = 0;
state.durations.environment = 0;
});
// Strip function conditions from retry config before sending via RPC
// Functions cannot be cloned by structured clone algorithm
const sanitizeRetryConditions = (task) => {
if (task.retry && typeof task.retry === "object" && typeof task.retry.condition === "function")
// Remove function condition - it can't be serialized
task.retry = {
...task.retry,
condition: void 0
};
if (task.tasks) task.tasks.forEach(sanitizeRetryConditions);
};
files.forEach(sanitizeRetryConditions);
rpc().onCollected(files);
await originalOnCollected?.call(testRunner, files);
};
const originalOnAfterRun = testRunner.onAfterRunFiles;
testRunner.onAfterRunFiles = async (files) => {
const state = getWorkerState();
const coverage = await takeCoverageInsideWorker(config.coverage, moduleRunner);
if (coverage) rpc().onAfterSuiteRun({
coverage,
testFiles: files.map((file) => file.name).sort(),
environment: state.environment.viteEnvironment || state.environment.name,
projectName: state.ctx.projectName
});
await originalOnAfterRun?.call(testRunner, files);
};
const originalOnAfterRunTask = testRunner.onAfterRunTask;
testRunner.onAfterRunTask = async (test) => {
if (config.bail && test.result?.state === "fail") {
if (1 + await rpc().getCountOfFailedTests() >= config.bail) {
rpc().onCancel("test-failure");
testRunner.cancel?.("test-failure");
}
}
await originalOnAfterRunTask?.call(testRunner, test);
};
return testRunner;
}
export { resolveSnapshotEnvironment as a, detectAsyncLeaks as d, resolveTestRunner as r, setupChaiConfig as s };
import { DevEnvironment } from 'vite';
import { V as Vitest, T as TestProject, a as TestProjectConfiguration } from './reporters.d.DFKgJkZE.js';
/**
* Generate a unique cache identifier.
*
* Return `false` to disable caching of the file.
* @experimental
*/
interface CacheKeyIdGenerator {
(context: CacheKeyIdGeneratorContext): string | undefined | null | false;
}
/**
* @experimental
*/
interface CacheKeyIdGeneratorContext {
environment: DevEnvironment;
id: string;
sourceCode: string;
}
interface VitestPluginContext {
vitest: Vitest;
project: TestProject;
injectTestProjects: (config: TestProjectConfiguration | TestProjectConfiguration[]) => Promise<TestProject[]>;
/**
* Define a generator that will be applied before hashing the cache key.
*
* Use this to make sure Vitest generates correct hash. It is a good idea
* to define this function if your plugin can be registered with different options.
*
* This is called only if `experimental.fsModuleCache` is defined.
* @experimental
*/
experimental_defineCacheKeyGenerator: (callback: CacheKeyIdGenerator) => void;
}
export type { CacheKeyIdGenerator as C, VitestPluginContext as V, CacheKeyIdGeneratorContext as a };

Sorry, the diff of this file is too big to display

import { File, TestArtifact, TaskResultPack, TaskEventPack, CancelReason } from '@vitest/runner';
import { SnapshotResult } from '@vitest/snapshot';
import { FetchFunctionOptions, FetchResult } from 'vite/module-runner';
import { O as OTELCarrier } from './traces.d.402V_yFI.js';
interface AfterSuiteRunMeta {
coverage?: unknown;
testFiles: string[];
environment: string;
projectName?: string;
}
interface UserConsoleLog {
content: string;
origin?: string;
browser?: boolean;
type: "stdout" | "stderr";
taskId?: string;
time: number;
size: number;
}
interface ModuleGraphData {
graph: Record<string, string[]>;
externalized: string[];
inlined: string[];
}
interface ProvidedContext {}
interface ResolveFunctionResult {
id: string;
file: string;
url: string;
}
interface FetchCachedFileSystemResult {
cached: true;
tmp: string;
id: string;
file: string | null;
url: string;
invalidate: boolean;
}
type LabelColor = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white";
interface AsyncLeak {
filename: string;
projectName: string;
stack: string;
type: string;
}
interface RuntimeRPC {
fetch: (id: string, importer: string | undefined, environment: string, options?: FetchFunctionOptions, otelCarrier?: OTELCarrier) => Promise<FetchResult | FetchCachedFileSystemResult>;
resolve: (id: string, importer: string | undefined, environment: string) => Promise<ResolveFunctionResult | null>;
transform: (id: string) => Promise<{
code?: string;
}>;
onUserConsoleLog: (log: UserConsoleLog) => void;
onUnhandledError: (err: unknown, type: string) => void;
onAsyncLeaks: (leak: AsyncLeak[]) => void;
onQueued: (file: File) => void;
onCollected: (files: File[]) => Promise<void>;
onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void;
onTaskArtifactRecord: <Artifact extends TestArtifact>(testId: string, artifact: Artifact) => Promise<Artifact>;
onTaskUpdate: (pack: TaskResultPack[], events: TaskEventPack[]) => Promise<void>;
onCancel: (reason: CancelReason) => void;
getCountOfFailedTests: () => number;
snapshotSaved: (snapshot: SnapshotResult) => void;
resolveSnapshotPath: (testPath: string) => string;
ensureModuleGraphEntry: (id: string, importer: string) => void;
}
interface RunnerRPC {
onCancel: (reason: CancelReason) => void;
}
export type { AfterSuiteRunMeta as A, LabelColor as L, ModuleGraphData as M, ProvidedContext as P, RuntimeRPC as R, UserConsoleLog as U, RunnerRPC as a, AsyncLeak as b };
import { r as resolveCoverageProviderModule } from './coverage.D_JHT54q.js';
import { addSerializer } from '@vitest/snapshot';
import { setSafeTimers } from '@vitest/utils/timers';
import { g as getWorkerState } from './utils.DT4VyRyl.js';
async function startCoverageInsideWorker(options, loader, runtimeOptions) {
const coverageModule = await resolveCoverageProviderModule(options, loader);
if (coverageModule) return coverageModule.startCoverage?.(runtimeOptions);
return null;
}
async function takeCoverageInsideWorker(options, loader) {
const coverageModule = await resolveCoverageProviderModule(options, loader);
if (coverageModule) return coverageModule.takeCoverage?.({ moduleExecutionInfo: loader.moduleExecutionInfo });
return null;
}
async function stopCoverageInsideWorker(options, loader, runtimeOptions) {
const coverageModule = await resolveCoverageProviderModule(options, loader);
if (coverageModule) return coverageModule.stopCoverage?.(runtimeOptions);
return null;
}
let globalSetup = false;
async function setupCommonEnv(config) {
setupDefines(config);
setupEnv(config.env);
if (globalSetup) return;
globalSetup = true;
setSafeTimers();
if (config.globals) (await import('./globals.BSO_gjS1.js')).registerApiGlobally();
}
function setupDefines(config) {
for (const key in config.defines) globalThis[key] = config.defines[key];
}
function setupEnv(env) {
const state = getWorkerState();
// same boolean-to-string assignment as VitestPlugin.configResolved
const { PROD, DEV, ...restEnvs } = env;
state.metaEnv.PROD = PROD;
state.metaEnv.DEV = DEV;
for (const key in restEnvs) state.metaEnv[key] = env[key];
}
async function loadDiffConfig(config, moduleRunner) {
if (typeof config.diff === "object") return config.diff;
if (typeof config.diff !== "string") return;
const diffModule = await moduleRunner.import(config.diff);
if (diffModule && typeof diffModule.default === "object" && diffModule.default != null) return diffModule.default;
else throw new Error(`invalid diff config file ${config.diff}. Must have a default export with config object`);
}
async function loadSnapshotSerializers(config, moduleRunner) {
const files = config.snapshotSerializers;
(await Promise.all(files.map(async (file) => {
const mo = await moduleRunner.import(file);
if (!mo || typeof mo.default !== "object" || mo.default === null) throw new Error(`invalid snapshot serializer file ${file}. Must export a default object`);
const config = mo.default;
if (typeof config.test !== "function" || typeof config.serialize !== "function" && typeof config.print !== "function") throw new TypeError(`invalid snapshot serializer in ${file}. Must have a 'test' method along with either a 'serialize' or 'print' method.`);
return config;
}))).forEach((serializer) => addSerializer(serializer));
}
export { loadSnapshotSerializers as a, startCoverageInsideWorker as b, stopCoverageInsideWorker as c, loadDiffConfig as l, setupCommonEnv as s, takeCoverageInsideWorker as t };

Sorry, the diff of this file is too big to display

import { FileSpecification, Task, CancelReason } from '@vitest/runner';
import { EvaluatedModules } from 'vite/module-runner';
import { S as SerializedConfig } from './config.d.BAKb_cTu.js';
import { E as Environment } from './environment.d.CrsxCzP1.js';
import { R as RuntimeRPC, a as RunnerRPC } from './rpc.d.BFMWpdph.js';
//#region src/messages.d.ts
declare const TYPE_REQUEST: "q";
interface RpcRequest {
/**
* Type
*/
t: typeof TYPE_REQUEST;
/**
* ID
*/
i?: string;
/**
* Method
*/
m: string;
/**
* Arguments
*/
a: any[];
/**
* Optional
*/
o?: boolean;
}
//#endregion
//#region src/utils.d.ts
type ArgumentsType<T> = T extends ((...args: infer A) => any) ? A : never;
type ReturnType<T> = T extends ((...args: any) => infer R) ? R : never;
type Thenable<T> = T | PromiseLike<T>;
//#endregion
//#region src/main.d.ts
type PromisifyFn<T> = ReturnType<T> extends Promise<any> ? T : (...args: ArgumentsType<T>) => Promise<Awaited<ReturnType<T>>>;
type BirpcResolver<This> = (this: This, name: string, resolved: (...args: unknown[]) => unknown) => Thenable<((...args: any[]) => any) | undefined>;
interface ChannelOptions {
/**
* Function to post raw message
*/
post: (data: any, ...extras: any[]) => Thenable<any>;
/**
* Listener to receive raw message
*/
on: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>;
/**
* Clear the listener when `$close` is called
*/
off?: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>;
/**
* Custom function to serialize data
*
* by default it passes the data as-is
*/
serialize?: (data: any) => any;
/**
* Custom function to deserialize data
*
* by default it passes the data as-is
*/
deserialize?: (data: any) => any;
/**
* Call the methods with the RPC context or the original functions object
*/
bind?: 'rpc' | 'functions';
/**
* Custom meta data to attached to the RPC instance's `$meta` property
*/
meta?: any;
}
interface EventOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> {
/**
* Names of remote functions that do not need response.
*/
eventNames?: (keyof RemoteFunctions)[];
/**
* Maximum timeout for waiting for response, in milliseconds.
*
* @default 60_000
*/
timeout?: number;
/**
* Whether to proxy the remote functions.
*
* When `proxify` is false, calling the remote function
* with `rpc.$call('method', ...args)` instead of `rpc.method(...args)`
* explicitly is required.
*
* @default true
*/
proxify?: Proxify;
/**
* Custom resolver to resolve function to be called
*
* For advanced use cases only
*/
resolver?: BirpcResolver<BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>>;
/**
* Hook triggered before an event is sent to the remote
*
* @param req - Request parameters
* @param next - Function to continue the request
* @param resolve - Function to resolve the response directly
*/
onRequest?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, req: RpcRequest, next: (req?: RpcRequest) => Promise<any>, resolve: (res: any) => void) => void | Promise<void>;
/**
* Custom error handler for errors occurred in local functions being called
*
* @returns `true` to prevent the error from being thrown
*/
onFunctionError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName: string, args: any[]) => boolean | void;
/**
* Custom error handler for errors occurred during serialization or messsaging
*
* @returns `true` to prevent the error from being thrown
*/
onGeneralError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName?: string, args?: any[]) => boolean | void;
/**
* Custom error handler for timeouts
*
* @returns `true` to prevent the error from being thrown
*/
onTimeoutError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, functionName: string, args: any[]) => boolean | void;
}
type BirpcOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = EventOptions<RemoteFunctions, LocalFunctions, Proxify> & ChannelOptions;
type BirpcFn<T> = PromisifyFn<T> & {
/**
* Send event without asking for response
*/
asEvent: (...args: ArgumentsType<T>) => Promise<void>;
};
interface BirpcReturnBuiltin<RemoteFunctions, LocalFunctions = Record<string, unknown>> {
/**
* Raw functions object
*/
$functions: LocalFunctions;
/**
* Whether the RPC is closed
*/
readonly $closed: boolean;
/**
* Custom meta data attached to the RPC instance
*/
readonly $meta: any;
/**
* Close the RPC connection
*/
$close: (error?: Error) => void;
/**
* Reject pending calls
*/
$rejectPendingCalls: (handler?: PendingCallHandler) => Promise<void>[];
/**
* Call the remote function and wait for the result.
* An alternative to directly calling the function
*/
$call: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]>>>;
/**
* Same as `$call`, but returns `undefined` if the function is not defined on the remote side.
*/
$callOptional: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]> | undefined>>;
/**
* Send event without asking for response
*/
$callEvent: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<void>;
/**
* Call the remote function with the raw options.
*/
$callRaw: (options: {
method: string;
args: unknown[];
event?: boolean;
optional?: boolean;
}) => Promise<Awaited<ReturnType<any>>[]>;
}
type ProxifiedRemoteFunctions<RemoteFunctions extends object = Record<string, unknown>> = { [K in keyof RemoteFunctions]: BirpcFn<RemoteFunctions[K]> };
type BirpcReturn<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = Proxify extends true ? ProxifiedRemoteFunctions<RemoteFunctions> & BirpcReturnBuiltin<RemoteFunctions, LocalFunctions> : BirpcReturnBuiltin<RemoteFunctions, LocalFunctions>;
type PendingCallHandler = (options: Pick<PromiseEntry, 'method' | 'reject'>) => void | Promise<void>;
interface PromiseEntry {
resolve: (arg: any) => void;
reject: (error: any) => void;
method: string;
timeoutId?: ReturnType<typeof setTimeout>;
}
declare const setTimeout: typeof globalThis.setTimeout;
type WorkerRPC = BirpcReturn<RuntimeRPC, RunnerRPC>;
interface ContextTestEnvironment {
name: string;
options: Record<string, any> | null;
}
interface WorkerTestEnvironment {
name: string;
options: Record<string, any> | null;
}
type TestExecutionMethod = "run" | "collect";
interface WorkerExecuteContext {
files: FileSpecification[];
providedContext: Record<string, any>;
invalidates?: string[];
environment: ContextTestEnvironment;
/** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */
workerId: number;
}
interface ContextRPC {
pool: string;
config: SerializedConfig;
projectName: string;
environment: WorkerTestEnvironment;
rpc: WorkerRPC;
files: FileSpecification[];
providedContext: Record<string, any>;
invalidates?: string[];
/** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */
workerId: number;
}
interface WorkerSetupContext {
environment: WorkerTestEnvironment;
pool: string;
config: SerializedConfig;
projectName: string;
rpc: WorkerRPC;
}
interface WorkerGlobalState {
ctx: ContextRPC;
config: SerializedConfig;
rpc: WorkerRPC;
current?: Task;
filepath?: string;
metaEnv: {
[key: string]: any;
BASE_URL: string;
MODE: string;
DEV: boolean;
PROD: boolean;
SSR: boolean;
};
environment: Environment;
evaluatedModules: EvaluatedModules;
resolvingModules: Set<string>;
moduleExecutionInfo: Map<string, any>;
onCancel: (listener: (reason: CancelReason) => unknown) => void;
onCleanup: (listener: () => unknown) => void;
providedContext: Record<string, any>;
durations: {
environment: number;
prepare: number;
};
onFilterStackTrace?: (trace: string) => string;
}
export type { BirpcOptions as B, ContextRPC as C, TestExecutionMethod as T, WorkerGlobalState as W, WorkerSetupContext as a, BirpcReturn as b, ContextTestEnvironment as c, WorkerExecuteContext as d, WorkerTestEnvironment as e };
+1
-1

@@ -1,2 +0,2 @@

import { a as SerializedCoverageConfig, S as SerializedConfig } from './chunks/config.d.pC9164XK.js';
import { a as SerializedCoverageConfig, S as SerializedConfig } from './chunks/config.d.BAKb_cTu.js';
import { R as RuntimeCoverageModuleLoader } from './chunks/coverage.d.BZtK59WP.js';

@@ -3,0 +3,0 @@ import { SerializedDiffOptions } from '@vitest/utils/diff';

@@ -1,2 +0,2 @@

export { l as loadDiffConfig, a as loadSnapshotSerializers, s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker, t as takeCoverageInsideWorker } from './chunks/setup-common.BoY7R7rC.js';
export { l as loadDiffConfig, a as loadSnapshotSerializers, s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker, t as takeCoverageInsideWorker } from './chunks/setup-common.Bafp3r-q.js';
export { T as Traces } from './chunks/traces.CCmnQaNT.js';

@@ -3,0 +3,0 @@ export { collectTests, startTests } from '@vitest/runner';

@@ -1,2 +0,2 @@

import { c as createCLI } from './chunks/cac.Bmb60yM3.js';
import { c as createCLI } from './chunks/cac.B3UKR5lX.js';
import '@vitest/utils/helpers';

@@ -7,3 +7,3 @@ import 'events';

import './chunks/constants.CPYnjOGj.js';
import './chunks/index.De5aIHUc.js';
import './chunks/index.CoafDRze.js';
import 'node:fs';

@@ -16,5 +16,5 @@ import 'node:fs/promises';

import 'std-env';
import 'node:util';
import 'node:console';
import 'node:stream';
import 'node:util';
import '@vitest/utils/display';

@@ -21,0 +21,0 @@ import 'node:os';

@@ -74,3 +74,4 @@ 'use strict';

slowTestThreshold: 300,
disableConsoleIntercept: false
disableConsoleIntercept: false,
detectAsyncLeaks: false
});

@@ -77,0 +78,0 @@

import { HookHandler, UserConfig, ConfigEnv } from 'vite';
export { ConfigEnv, Plugin, UserConfig as ViteUserConfig, mergeConfig } from 'vite';
import { I as InlineConfig, C as CoverageV8Options, R as ResolvedCoverageOptions, U as UserWorkspaceConfig, b as UserProjectConfigFn, c as UserProjectConfigExport } from './chunks/reporters.d.DPe11uSn.js';
export { a as TestProjectConfiguration, d as TestProjectInlineConfiguration, e as TestUserConfig, W as WatcherTriggerPattern } from './chunks/reporters.d.DPe11uSn.js';
import { V as VitestPluginContext } from './chunks/plugin.d.CTohQCcC.js';
import { F as FakeTimerInstallOpts } from './chunks/config.d.pC9164XK.js';
import { I as InlineConfig, C as CoverageV8Options, R as ResolvedCoverageOptions, U as UserWorkspaceConfig, b as UserProjectConfigFn, c as UserProjectConfigExport } from './chunks/reporters.d.DFKgJkZE.js';
export { a as TestProjectConfiguration, d as TestProjectInlineConfiguration, e as TestUserConfig, W as WatcherTriggerPattern } from './chunks/reporters.d.DFKgJkZE.js';
import { V as VitestPluginContext } from './chunks/plugin.d.D1im4ulu.js';
import { F as FakeTimerInstallOpts } from './chunks/config.d.BAKb_cTu.js';
export { TestTagDefinition } from '@vitest/runner';
import '@vitest/utils';
import './chunks/rpc.d.CUhiUEld.js';
import './chunks/rpc.d.BFMWpdph.js';
import '@vitest/snapshot';

@@ -14,4 +14,4 @@ import 'vite/module-runner';

import 'node:stream';
import './chunks/browser.d.CweQ2M9y.js';
import './chunks/worker.d.CiaQ1oon.js';
import './chunks/browser.d.B8ZWo0aT.js';
import './chunks/worker.d.KWMdtGFQ.js';
import './chunks/environment.d.CrsxCzP1.js';

@@ -88,2 +88,3 @@ import '@vitest/pretty-format';

disableConsoleIntercept: boolean;
detectAsyncLeaks: boolean;
}>;

@@ -90,0 +91,0 @@

@@ -1,2 +0,2 @@

export { c as configDefaults, a as coverageConfigDefaults, d as defaultExclude, b as defaultInclude } from './chunks/defaults.BOqNVLsY.js';
export { c as configDefaults, a as coverageConfigDefaults, d as defaultExclude, b as defaultInclude } from './chunks/defaults.BlJmGxXD.js';
export { mergeConfig } from 'vite';

@@ -3,0 +3,0 @@ export { d as defaultBrowserPort } from './chunks/constants.CPYnjOGj.js';

@@ -1,12 +0,12 @@

import { R as ResolvedCoverageOptions, V as Vitest, aY as CoverageMap, am as ReportContext, T as TestProject } from './chunks/reporters.d.DPe11uSn.js';
import { R as ResolvedCoverageOptions, V as Vitest, aY as CoverageMap, am as ReportContext, T as TestProject } from './chunks/reporters.d.DFKgJkZE.js';
import { TransformResult } from 'vite';
import { A as AfterSuiteRunMeta } from './chunks/rpc.d.CUhiUEld.js';
import { A as AfterSuiteRunMeta } from './chunks/rpc.d.BFMWpdph.js';
import '@vitest/runner';
import '@vitest/utils';
import 'node:stream';
import './chunks/browser.d.CweQ2M9y.js';
import './chunks/browser.d.B8ZWo0aT.js';
import './chunks/traces.d.402V_yFI.js';
import './chunks/worker.d.CiaQ1oon.js';
import './chunks/worker.d.KWMdtGFQ.js';
import 'vite/module-runner';
import './chunks/config.d.pC9164XK.js';
import './chunks/config.d.BAKb_cTu.js';
import '@vitest/pretty-format';

@@ -13,0 +13,0 @@ import '@vitest/snapshot';

@@ -1,2 +0,2 @@

export { B as BaseCoverageProvider } from './chunks/coverage.DAUQBfjL.js';
export { B as BaseCoverageProvider } from './chunks/coverage.B8UAoQGx.js';
import 'node:fs';

@@ -11,3 +11,3 @@ import 'node:module';

import 'tinyrainbow';
import './chunks/defaults.BOqNVLsY.js';
import './chunks/defaults.BlJmGxXD.js';
import 'node:os';

@@ -14,0 +14,0 @@ import './chunks/env.D4Lgay0q.js';

@@ -1,4 +0,4 @@

import { M as ModuleDefinitionDurationsDiagnostic, U as UntrackedModuleDefinitionDiagnostic, S as SerializedTestSpecification, a as ModuleDefinitionDiagnostic, b as ModuleDefinitionLocation, c as SourceModuleDiagnostic, d as SourceModuleLocations } from './chunks/browser.d.CweQ2M9y.js';
export { B as BrowserTesterOptions } from './chunks/browser.d.CweQ2M9y.js';
import './chunks/global.d.DYf8kr_l.js';
import { M as ModuleDefinitionDurationsDiagnostic, U as UntrackedModuleDefinitionDiagnostic, S as SerializedTestSpecification, a as ModuleDefinitionDiagnostic, b as ModuleDefinitionLocation, c as SourceModuleDiagnostic, d as SourceModuleLocations } from './chunks/browser.d.B8ZWo0aT.js';
export { B as BrowserTesterOptions } from './chunks/browser.d.B8ZWo0aT.js';
import './chunks/global.d.x-ILCfAE.js';
import { File, TestAnnotation, TestArtifact, TaskResultPack, TaskEventPack, Test, TaskPopulated } from '@vitest/runner';

@@ -8,8 +8,8 @@ export { CancelReason, ImportDuration, OnTestFailedHandler, OnTestFinishedHandler, RunMode, Task as RunnerTask, TaskBase as RunnerTaskBase, TaskEventPack as RunnerTaskEventPack, TaskResult as RunnerTaskResult, TaskResultPack as RunnerTaskResultPack, Test as RunnerTestCase, File as RunnerTestFile, Suite as RunnerTestSuite, SuiteAPI, SuiteCollector, SuiteFactory, SuiteOptions, TaskCustomOptions, TaskMeta, TaskState, TestAPI, TestAnnotation, TestAnnotationArtifact, TestArtifact, TestArtifactBase, TestArtifactLocation, TestArtifactRegistry, TestAttachment, TestContext, TestFunction, TestOptions, VitestRunnerConfig as TestRunnerConfig, TestTags, VitestRunner as VitestTestRunner, afterAll, afterEach, aroundAll, aroundEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, recordArtifact, suite, test } from '@vitest/runner';

export { ParsedStack, SerializedError, TestError } from '@vitest/utils';
import { b as BirpcReturn } from './chunks/worker.d.CiaQ1oon.js';
export { C as ContextRPC, c as ContextTestEnvironment, T as TestExecutionMethod, W as WorkerGlobalState } from './chunks/worker.d.CiaQ1oon.js';
import { S as SerializedConfig, F as FakeTimerInstallOpts, R as RuntimeOptions } from './chunks/config.d.pC9164XK.js';
export { b as RuntimeConfig, a as SerializedCoverageConfig } from './chunks/config.d.pC9164XK.js';
import { U as UserConsoleLog, L as LabelColor, M as ModuleGraphData, P as ProvidedContext } from './chunks/rpc.d.CUhiUEld.js';
export { A as AfterSuiteRunMeta, a as RunnerRPC, R as RuntimeRPC } from './chunks/rpc.d.CUhiUEld.js';
import { b as BirpcReturn } from './chunks/worker.d.KWMdtGFQ.js';
export { C as ContextRPC, c as ContextTestEnvironment, T as TestExecutionMethod, W as WorkerGlobalState } from './chunks/worker.d.KWMdtGFQ.js';
import { S as SerializedConfig, F as FakeTimerInstallOpts, R as RuntimeOptions } from './chunks/config.d.BAKb_cTu.js';
export { b as RuntimeConfig, a as SerializedCoverageConfig } from './chunks/config.d.BAKb_cTu.js';
import { U as UserConsoleLog, L as LabelColor, M as ModuleGraphData, P as ProvidedContext } from './chunks/rpc.d.BFMWpdph.js';
export { A as AfterSuiteRunMeta, a as RunnerRPC, R as RuntimeRPC } from './chunks/rpc.d.BFMWpdph.js';
import { ExpectStatic } from '@vitest/expect';

@@ -148,3 +148,3 @@ export { Assertion, AsymmetricMatchersContaining, DeeplyAllowMatchers, ExpectPollOptions, ExpectStatic, JestAssertion, RawMatcherFn as Matcher, ExpectationResult as MatcherResult, MatcherState, Matchers, chai } from '@vitest/expect';

* This method will invoke every initiated timer until the timer queue is empty. It means that every timer called during `runAllTimers` will be fired.
* If you have an infinite interval, it will throw after 10,000 tries (can be configured with [`fakeTimers.loopLimit`](https://vitest.dev/config/#faketimers-looplimit)).
* If you have an infinite interval, it will throw after 10,000 tries (can be configured with [`fakeTimers.loopLimit`](https://vitest.dev/config/faketimers#faketimers-looplimit)).
*/

@@ -154,3 +154,3 @@ runAllTimers: () => VitestUtils;

* This method will asynchronously invoke every initiated timer until the timer queue is empty. It means that every timer called during `runAllTimersAsync` will be fired even asynchronous timers.
* If you have an infinite interval, it will throw after 10 000 tries (can be configured with [`fakeTimers.loopLimit`](https://vitest.dev/config/#faketimers-looplimit)).
* If you have an infinite interval, it will throw after 10 000 tries (can be configured with [`fakeTimers.loopLimit`](https://vitest.dev/config/faketimers#faketimers-looplimit)).
*/

@@ -271,2 +271,35 @@ runAllTimersAsync: () => Promise<VitestUtils>;

/**
* Wraps a function to create an assertion helper. When an assertion fails inside the helper,
* the error stack trace will point to where the helper was called, not inside the helper itself.
* Works with both synchronous and asynchronous functions, and supports `expect.soft()`.
*
* @example
* ```ts
* const myEqual = vi.defineHelper((x, y) => {
* expect(x).toEqual(y)
* })
*
* test('example', () => {
* myEqual('left', 'right') // Error points to this line
* })
* ```
* Example output:
* ```
* FAIL example.test.ts > example
* AssertionError: expected 'left' to deeply equal 'right'
*
* Expected: "right"
* Received: "left"
*
* ❯ example.test.ts:6:3
* 4| test('example', () => {
* 5| myEqual('left', 'right')
* | ^
* 6| })
* ```
* @param fn The assertion function to wrap
* @returns A wrapped function with the same signature
*/
defineHelper: <F extends (...args: any) => any>(fn: F) => F;
/**
* This is similar to [`vi.waitFor`](https://vitest.dev/api/vi#vi-waitfor), but if the callback throws any errors, execution is immediately interrupted and an error message is received.

@@ -273,0 +306,0 @@ *

@@ -1,5 +0,5 @@

export { N as BenchmarkRunner, T as TestRunner, a as assert, c as createExpect, g as expect, i as inject, s as should, v as vi, b as vitest } from './chunks/test.CnO2BIt2.js';
export { N as BenchmarkRunner, T as TestRunner, a as assert, c as createExpect, g as expect, i as inject, s as should, v as vi, b as vitest } from './chunks/test.EDIwt4Yp.js';
export { b as bench } from './chunks/benchmark.BoqSLF53.js';
export { V as EvaluatedModules } from './chunks/evaluatedModules.Dg1zASAC.js';
export { a as assertType } from './chunks/index.D3wDRGBz.js';
export { a as assertType } from './chunks/index.C39wbgWx.js';
export { expectTypeOf } from 'expect-type';

@@ -6,0 +6,0 @@ export { afterAll, afterEach, aroundAll, aroundEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, recordArtifact, suite, test } from '@vitest/runner';

import { ModuleEvaluator, ModuleRunnerImportMeta, ModuleRunnerContext, EvaluatedModuleNode } from 'vite/module-runner';
import { V as VitestEvaluatedModules } from './chunks/evaluatedModules.d.BxJ5omdx.js';
import vm from 'node:vm';
import { R as RuntimeRPC } from './chunks/rpc.d.CUhiUEld.js';
import { R as RuntimeRPC } from './chunks/rpc.d.BFMWpdph.js';
import '@vitest/runner';

@@ -6,0 +6,0 @@ import '@vitest/snapshot';

@@ -6,18 +6,18 @@ import * as vite from 'vite';

import { IncomingMessage } from 'node:http';
import { f as ResolvedConfig, e as UserConfig, g as VitestRunMode, h as VitestOptions, V as Vitest, A as ApiConfig, L as Logger, i as TestSpecification, T as TestProject, P as PoolWorker, j as PoolOptions, k as WorkerRequest, l as TestSequencer } from './chunks/reporters.d.DPe11uSn.js';
export { B as BaseCoverageOptions, m as BaseReporter, n as BenchmarkBuiltinReporters, o as BenchmarkReporter, p as BenchmarkReportsMap, q as BenchmarkUserOptions, r as BrowserBuiltinProvider, s as BrowserCommand, t as BrowserCommandContext, u as BrowserConfigOptions, v as BrowserInstanceOption, w as BrowserModuleMocker, x as BrowserOrchestrator, y as BrowserProvider, z as BrowserProviderOption, D as BrowserScript, E as BrowserServerFactory, F as BrowserServerOptions, G as BrowserServerState, H as BrowserServerStateSession, J as BuiltinEnvironment, K as BuiltinReporterOptions, M as BuiltinReporters, N as CDPSession, O as CSSModuleScopeStrategy, Q as CoverageIstanbulOptions, S as CoverageOptions, X as CoverageProvider, Y as CoverageProviderModule, Z as CoverageReporter, C as CoverageV8Options, _ as CustomProviderOptions, $ as DefaultReporter, a0 as DepsOptimizationOptions, a1 as DotReporter, a2 as EnvironmentOptions, a3 as GithubActionsReporter, a4 as HTMLOptions, a5 as HangingProcessReporter, I as InlineConfig, a6 as JUnitOptions, a7 as JUnitReporter, a8 as JsonAssertionResult, a9 as JsonOptions, aa as JsonReporter, ab as JsonTestResult, ac as JsonTestResults, ad as ModuleDiagnostic, ae as OnServerRestartHandler, af as OnTestsRerunHandler, ag as ParentProjectBrowser, ah as Pool, ai as PoolRunnerInitializer, aj as PoolTask, ak as ProjectBrowser, al as ProjectConfig, am as ReportContext, an as ReportedHookContext, ao as Reporter, ap as ReportersMap, aq as ResolveSnapshotPathHandler, ar as ResolveSnapshotPathHandlerContext, as as ResolvedBrowserOptions, R as ResolvedCoverageOptions, at as ResolvedProjectConfig, au as SerializedTestProject, av as TapFlatReporter, aw as TapReporter, ax as TaskOptions, ay as TestCase, az as TestCollection, aA as TestDiagnostic, aB as TestModule, aC as TestModuleState, aD as TestResult, aE as TestResultFailed, aF as TestResultPassed, aG as TestResultSkipped, aH as TestRunEndReason, aI as TestRunResult, aJ as TestSequencerConstructor, aK as TestSpecificationOptions, aL as TestState, aM as TestSuite, aN as TestSuiteState, aO as ToMatchScreenshotComparators, aP as ToMatchScreenshotOptions, aQ as TypecheckConfig, U as UserWorkspaceConfig, aR as VerboseBenchmarkReporter, aS as VerboseReporter, aT as VitestEnvironment, aU as VitestPackageInstaller, W as WatcherTriggerPattern, aV as WorkerResponse, aW as _BrowserNames, aX as experimental_getRunnerTask } from './chunks/reporters.d.DPe11uSn.js';
export { C as CacheKeyIdGenerator, a as CacheKeyIdGeneratorContext, V as VitestPluginContext } from './chunks/plugin.d.CTohQCcC.js';
import { f as ResolvedConfig, e as UserConfig, g as VitestRunMode, h as VitestOptions, V as Vitest, A as ApiConfig, L as Logger, i as TestSpecification, T as TestProject, P as PoolWorker, j as PoolOptions, k as WorkerRequest, l as TestSequencer } from './chunks/reporters.d.DFKgJkZE.js';
export { B as BaseCoverageOptions, m as BaseReporter, n as BenchmarkBuiltinReporters, o as BenchmarkReporter, p as BenchmarkReportsMap, q as BenchmarkUserOptions, r as BrowserBuiltinProvider, s as BrowserCommand, t as BrowserCommandContext, u as BrowserConfigOptions, v as BrowserInstanceOption, w as BrowserModuleMocker, x as BrowserOrchestrator, y as BrowserProvider, z as BrowserProviderOption, D as BrowserScript, E as BrowserServerFactory, F as BrowserServerOptions, G as BrowserServerState, H as BrowserServerStateSession, J as BuiltinEnvironment, K as BuiltinReporterOptions, M as BuiltinReporters, N as CDPSession, O as CSSModuleScopeStrategy, Q as CoverageIstanbulOptions, S as CoverageOptions, X as CoverageProvider, Y as CoverageProviderModule, Z as CoverageReporter, C as CoverageV8Options, _ as CustomProviderOptions, $ as DefaultReporter, a0 as DepsOptimizationOptions, a1 as DotReporter, a2 as EnvironmentOptions, a3 as GithubActionsReporter, a4 as HTMLOptions, a5 as HangingProcessReporter, I as InlineConfig, a6 as JUnitOptions, a7 as JUnitReporter, a8 as JsonAssertionResult, a9 as JsonOptions, aa as JsonReporter, ab as JsonTestResult, ac as JsonTestResults, ad as ModuleDiagnostic, ae as OnServerRestartHandler, af as OnTestsRerunHandler, ag as ParentProjectBrowser, ah as Pool, ai as PoolRunnerInitializer, aj as PoolTask, ak as ProjectBrowser, al as ProjectConfig, am as ReportContext, an as ReportedHookContext, ao as Reporter, ap as ReportersMap, aq as ResolveSnapshotPathHandler, ar as ResolveSnapshotPathHandlerContext, as as ResolvedBrowserOptions, R as ResolvedCoverageOptions, at as ResolvedProjectConfig, au as SerializedTestProject, av as TapFlatReporter, aw as TapReporter, ax as TaskOptions, ay as TestCase, az as TestCollection, aA as TestDiagnostic, aB as TestModule, aC as TestModuleState, aD as TestResult, aE as TestResultFailed, aF as TestResultPassed, aG as TestResultSkipped, aH as TestRunEndReason, aI as TestRunResult, aJ as TestSequencerConstructor, aK as TestSpecificationOptions, aL as TestState, aM as TestSuite, aN as TestSuiteState, aO as ToMatchScreenshotComparators, aP as ToMatchScreenshotOptions, aQ as TypecheckConfig, U as UserWorkspaceConfig, aR as VerboseBenchmarkReporter, aS as VerboseReporter, aT as VitestEnvironment, aU as VitestPackageInstaller, W as WatcherTriggerPattern, aV as WorkerResponse, aW as _BrowserNames, aX as experimental_getRunnerTask } from './chunks/reporters.d.DFKgJkZE.js';
export { C as CacheKeyIdGenerator, a as CacheKeyIdGeneratorContext, V as VitestPluginContext } from './chunks/plugin.d.D1im4ulu.js';
export { BaseCoverageProvider } from './coverage.js';
import { Awaitable } from '@vitest/utils';
export { SerializedError } from '@vitest/utils';
import { R as RuntimeRPC } from './chunks/rpc.d.CUhiUEld.js';
import { R as RuntimeRPC } from './chunks/rpc.d.BFMWpdph.js';
import { Writable } from 'node:stream';
import { C as ContextRPC } from './chunks/worker.d.CiaQ1oon.js';
export { T as TestExecutionType } from './chunks/worker.d.CiaQ1oon.js';
import { C as ContextRPC } from './chunks/worker.d.KWMdtGFQ.js';
export { T as TestExecutionType } from './chunks/worker.d.KWMdtGFQ.js';
import { Debugger } from 'obug';
import './chunks/global.d.DYf8kr_l.js';
import './chunks/global.d.x-ILCfAE.js';
export { Task as RunnerTask, TaskResult as RunnerTaskResult, TaskResultPack as RunnerTaskResultPack, Test as RunnerTestCase, File as RunnerTestFile, Suite as RunnerTestSuite, SequenceHooks, SequenceSetupFiles } from '@vitest/runner';
export { b as RuntimeConfig } from './chunks/config.d.pC9164XK.js';
export { b as RuntimeConfig } from './chunks/config.d.BAKb_cTu.js';
export { generateFileHash } from '@vitest/runner/utils';
import './chunks/browser.d.CweQ2M9y.js';
import './chunks/browser.d.B8ZWo0aT.js';
import './chunks/traces.d.402V_yFI.js';

@@ -87,3 +87,13 @@ import '@vitest/pretty-format';

/**
* Override vite config's configLoader from cli.
* Parse files statically instead of running them to collect tests
* @experimental
*/
staticParse?: boolean;
/**
* How many tests to process at the same time
* @experimental
*/
staticParseConcurrency?: number;
/**
* Override vite config's configLoader from CLI.
* Use `bundle` to bundle the config with esbuild or `runner` (experimental) to process it on the fly (default: `bundle`).

@@ -90,0 +100,0 @@ * This is only available with **vite version 6.1.0** and above.

import * as vite from 'vite';
import { resolveConfig as resolveConfig$1, mergeConfig } from 'vite';
export { esbuildVersion, isCSSRequest, isFileLoadingAllowed, parseAst, parseAstAsync, rollupVersion, version as viteVersion } from 'vite';
import { V as Vitest, a as VitestPlugin } from './chunks/cli-api.DwoCIT8I.js';
export { F as ForksPoolWorker, G as GitNotFoundError, b as TestsNotFoundError, T as ThreadsPoolWorker, c as TypecheckPoolWorker, d as VitestPackageInstaller, e as VmForksPoolWorker, f as VmThreadsPoolWorker, g as createDebugger, h as createMethodsRPC, i as createViteLogger, j as createVitest, k as escapeTestName, l as experimental_getRunnerTask, m as getFilePoolName, n as isFileServingAllowed, o as isValidApiRequest, r as registerConsoleShortcuts, p as resolveFsAllow, s as startVitest } from './chunks/cli-api.DwoCIT8I.js';
export { p as parseCLI } from './chunks/cac.Bmb60yM3.js';
import { r as resolveConfig$2 } from './chunks/coverage.DAUQBfjL.js';
export { B as BaseCoverageProvider, a as BaseSequencer, b as resolveApiServerConfig } from './chunks/coverage.DAUQBfjL.js';
import { V as Vitest, a as VitestPlugin } from './chunks/cli-api.BFaocysU.js';
export { F as ForksPoolWorker, G as GitNotFoundError, b as TestsNotFoundError, T as ThreadsPoolWorker, c as TypecheckPoolWorker, d as VitestPackageInstaller, e as VmForksPoolWorker, f as VmThreadsPoolWorker, g as createDebugger, h as createMethodsRPC, i as createViteLogger, j as createVitest, k as escapeTestName, l as experimental_getRunnerTask, m as getFilePoolName, n as isFileServingAllowed, o as isValidApiRequest, r as registerConsoleShortcuts, p as resolveFsAllow, s as startVitest } from './chunks/cli-api.BFaocysU.js';
export { p as parseCLI } from './chunks/cac.B3UKR5lX.js';
import { r as resolveConfig$2 } from './chunks/coverage.B8UAoQGx.js';
export { B as BaseCoverageProvider, a as BaseSequencer, b as resolveApiServerConfig } from './chunks/coverage.B8UAoQGx.js';
import { slash, deepClone } from '@vitest/utils/helpers';

@@ -13,6 +13,6 @@ import { a as any } from './chunks/index.og1WyBLx.js';

import { c as configFiles } from './chunks/constants.CPYnjOGj.js';
export { D as DefaultReporter, a as DotReporter, G as GithubActionsReporter, H as HangingProcessReporter, J as JUnitReporter, b as JsonReporter, R as ReportersMap, T as TapFlatReporter, c as TapReporter, V as VerboseReporter } from './chunks/index.De5aIHUc.js';
export { D as DefaultReporter, a as DotReporter, G as GithubActionsReporter, H as HangingProcessReporter, J as JUnitReporter, b as JsonReporter, R as ReportersMap, T as TapFlatReporter, c as TapReporter, V as VerboseReporter } from './chunks/index.CoafDRze.js';
export { distDir, rootDir } from './path.js';
export { generateFileHash } from '@vitest/runner/utils';
export { B as BenchmarkReporter, a as BenchmarkReportsMap, V as VerboseBenchmarkReporter } from './chunks/index.qcTcl_eM.js';
export { B as BenchmarkReporter, a as BenchmarkReportsMap, V as VerboseBenchmarkReporter } from './chunks/index._gmCCuHk.js';
import 'node:fs';

@@ -31,16 +31,2 @@ import './chunks/coverage.D_JHT54q.js';

import '@vitest/snapshot/manager';
import 'node:perf_hooks';
import './chunks/index.Chj8NDwU.js';
import 'events';
import 'https';
import 'http';
import 'net';
import 'tls';
import 'crypto';
import 'stream';
import 'url';
import 'zlib';
import 'buffer';
import './chunks/_commonjsHelpers.D26ty3Ew.js';
import 'node:crypto';
import './chunks/nativeModuleRunner.BIakptoF.js';

@@ -53,7 +39,9 @@ import 'vite/module-runner';

import 'node:console';
import '@vitest/utils/highlight';
import './chunks/_commonjsHelpers.D26ty3Ew.js';
import './chunks/env.D4Lgay0q.js';
import 'std-env';
import 'node:tty';
import 'node:crypto';
import 'node:events';
import './chunks/index.Chj8NDwU.js';
import './chunks/modules.BJuCwlRJ.js';

@@ -64,5 +52,16 @@ import 'node:child_process';

import 'tinyglobby';
import 'node:perf_hooks';
import 'events';
import 'https';
import 'http';
import 'net';
import 'tls';
import 'crypto';
import 'stream';
import 'url';
import 'zlib';
import 'buffer';
import 'magic-string';
import '@vitest/mocker/node';
import './chunks/defaults.BOqNVLsY.js';
import './chunks/defaults.BlJmGxXD.js';
import '@vitest/utils/constants';

@@ -69,0 +68,0 @@ import '@vitest/utils/resolver';

@@ -1,5 +0,5 @@

export { m as BaseReporter, n as BenchmarkBuiltinReporters, o as BenchmarkReporter, p as BenchmarkReportsMap, K as BuiltinReporterOptions, M as BuiltinReporters, $ as DefaultReporter, a1 as DotReporter, a3 as GithubActionsReporter, a5 as HangingProcessReporter, a7 as JUnitReporter, a8 as JsonAssertionResult, aa as JsonReporter, ab as JsonTestResult, ac as JsonTestResults, an as ReportedHookContext, ao as Reporter, ap as ReportersMap, av as TapFlatReporter, aw as TapReporter, aH as TestRunEndReason, aR as VerboseBenchmarkReporter, aS as VerboseReporter } from './chunks/reporters.d.DPe11uSn.js';
export { m as BaseReporter, n as BenchmarkBuiltinReporters, o as BenchmarkReporter, p as BenchmarkReportsMap, K as BuiltinReporterOptions, M as BuiltinReporters, $ as DefaultReporter, a1 as DotReporter, a3 as GithubActionsReporter, a5 as HangingProcessReporter, a7 as JUnitReporter, a8 as JsonAssertionResult, aa as JsonReporter, ab as JsonTestResult, ac as JsonTestResults, an as ReportedHookContext, ao as Reporter, ap as ReportersMap, av as TapFlatReporter, aw as TapReporter, aH as TestRunEndReason, aR as VerboseBenchmarkReporter, aS as VerboseReporter } from './chunks/reporters.d.DFKgJkZE.js';
import '@vitest/runner';
import '@vitest/utils';
import './chunks/rpc.d.CUhiUEld.js';
import './chunks/rpc.d.BFMWpdph.js';
import '@vitest/snapshot';

@@ -10,5 +10,5 @@ import 'vite/module-runner';

import 'vite';
import './chunks/browser.d.CweQ2M9y.js';
import './chunks/worker.d.CiaQ1oon.js';
import './chunks/config.d.pC9164XK.js';
import './chunks/browser.d.B8ZWo0aT.js';
import './chunks/worker.d.KWMdtGFQ.js';
import './chunks/config.d.BAKb_cTu.js';
import '@vitest/pretty-format';

@@ -15,0 +15,0 @@ import '@vitest/utils/diff';

@@ -1,3 +0,3 @@

export { D as DefaultReporter, a as DotReporter, G as GithubActionsReporter, H as HangingProcessReporter, J as JUnitReporter, b as JsonReporter, R as ReportersMap, T as TapFlatReporter, c as TapReporter, V as VerboseReporter } from './chunks/index.De5aIHUc.js';
export { B as BenchmarkReporter, a as BenchmarkReportsMap, V as VerboseBenchmarkReporter } from './chunks/index.qcTcl_eM.js';
export { D as DefaultReporter, a as DotReporter, G as GithubActionsReporter, H as HangingProcessReporter, J as JUnitReporter, b as JsonReporter, R as ReportersMap, T as TapFlatReporter, c as TapReporter, V as VerboseReporter } from './chunks/index.CoafDRze.js';
export { B as BenchmarkReporter, a as BenchmarkReportsMap, V as VerboseBenchmarkReporter } from './chunks/index._gmCCuHk.js';
import 'node:fs';

@@ -13,5 +13,5 @@ import 'node:fs/promises';

import 'std-env';
import 'node:util';
import 'node:console';
import 'node:stream';
import 'node:util';
import '@vitest/utils/display';

@@ -18,0 +18,0 @@ import 'node:os';

import * as tinybench from 'tinybench';
import { VitestRunner, VitestRunnerImportSource, Suite, File, Task, CancelReason, Test, TestContext, ImportDuration, createTaskCollector, getCurrentSuite, getCurrentTest, getHooks, getFn } from '@vitest/runner';
export { VitestRunner } from '@vitest/runner';
import { S as SerializedConfig } from './chunks/config.d.pC9164XK.js';
import { S as SerializedConfig } from './chunks/config.d.BAKb_cTu.js';
import { T as Traces } from './chunks/traces.d.402V_yFI.js';

@@ -39,3 +39,2 @@ import { createChainable } from '@vitest/runner/utils';

onAfterRunFiles(): void;
getWorkerContext(): Record<string, unknown>;
onAfterRunSuite(suite: Suite): Promise<void>;

@@ -42,0 +41,0 @@ onAfterRunTask(test: Task): void;

@@ -1,2 +0,2 @@

export { N as NodeBenchmarkRunner, T as VitestTestRunner } from './chunks/test.CnO2BIt2.js';
export { N as NodeBenchmarkRunner, T as VitestTestRunner } from './chunks/test.EDIwt4Yp.js';
import '@vitest/runner';

@@ -3,0 +3,0 @@ import '@vitest/utils/helpers';

@@ -1,8 +0,8 @@

import { W as WorkerGlobalState, a as WorkerSetupContext, B as BirpcOptions } from './chunks/worker.d.CiaQ1oon.js';
import { W as WorkerGlobalState, a as WorkerSetupContext, B as BirpcOptions } from './chunks/worker.d.KWMdtGFQ.js';
import { T as Traces } from './chunks/traces.d.402V_yFI.js';
import { Awaitable } from '@vitest/utils';
import { ModuleRunner } from 'vite/module-runner';
import { R as RuntimeRPC } from './chunks/rpc.d.CUhiUEld.js';
import { R as RuntimeRPC } from './chunks/rpc.d.BFMWpdph.js';
import '@vitest/runner';
import './chunks/config.d.pC9164XK.js';
import './chunks/config.d.BAKb_cTu.js';
import '@vitest/pretty-format';

@@ -9,0 +9,0 @@ import '@vitest/snapshot';

@@ -1,8 +0,9 @@

export { r as runBaseTests, s as setupEnvironment } from './chunks/base.BawQY8vy.js';
export { r as runBaseTests, s as setupEnvironment } from './chunks/base.C_KzYoIG.js';
export { i as init } from './chunks/init.B95Mm0Iz.js';
import 'node:vm';
import '@vitest/spy';
import './chunks/index.CEU66SQN.js';
import './chunks/index.DmJHrI1k.js';
import '@vitest/expect';
import './chunks/setup-common.BoY7R7rC.js';
import 'node:async_hooks';
import './chunks/setup-common.Bafp3r-q.js';
import './chunks/coverage.D_JHT54q.js';

@@ -14,3 +15,3 @@ import '@vitest/snapshot';

import './chunks/index.Chj8NDwU.js';
import './chunks/test.CnO2BIt2.js';
import './chunks/test.EDIwt4Yp.js';
import '@vitest/runner';

@@ -50,3 +51,3 @@ import '@vitest/utils/helpers';

import '@vitest/utils/constants';
import './chunks/index.D3wDRGBz.js';
import './chunks/index.C39wbgWx.js';
import 'expect-type';

@@ -53,0 +54,0 @@ import './chunks/index.CyBMJtT7.js';

@@ -1,8 +0,9 @@

import { r as runBaseTests, s as setupBaseEnvironment } from '../chunks/base.BawQY8vy.js';
import { r as runBaseTests, s as setupBaseEnvironment } from '../chunks/base.C_KzYoIG.js';
import { w as workerInit } from '../chunks/init-forks.BnCXPazU.js';
import 'node:vm';
import '@vitest/spy';
import '../chunks/index.CEU66SQN.js';
import '../chunks/index.DmJHrI1k.js';
import '@vitest/expect';
import '../chunks/setup-common.BoY7R7rC.js';
import 'node:async_hooks';
import '../chunks/setup-common.Bafp3r-q.js';
import '../chunks/coverage.D_JHT54q.js';

@@ -14,3 +15,3 @@ import '@vitest/snapshot';

import '../chunks/index.Chj8NDwU.js';
import '../chunks/test.CnO2BIt2.js';
import '../chunks/test.EDIwt4Yp.js';
import '@vitest/runner';

@@ -54,3 +55,3 @@ import '@vitest/utils/helpers';

import '@vitest/utils/constants';
import '../chunks/index.D3wDRGBz.js';
import '../chunks/index.C39wbgWx.js';
import 'expect-type';

@@ -57,0 +58,0 @@

@@ -8,9 +8,10 @@ import { createRequire } from 'node:module';

import { KNOWN_ASSET_TYPES } from '@vitest/utils/constants';
import { s as setupChaiConfig, r as resolveTestRunner, a as resolveSnapshotEnvironment } from '../chunks/index.CEU66SQN.js';
import { s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker } from '../chunks/setup-common.BoY7R7rC.js';
import { i as index } from '../chunks/index.D3wDRGBz.js';
import { s as setupChaiConfig, r as resolveTestRunner, a as resolveSnapshotEnvironment, d as detectAsyncLeaks } from '../chunks/index.DmJHrI1k.js';
import { s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker } from '../chunks/setup-common.Bafp3r-q.js';
import { i as index } from '../chunks/index.C39wbgWx.js';
import { c as closeInspector } from '../chunks/inspector.CvyFGlXm.js';
import { g as getWorkerState } from '../chunks/utils.DT4VyRyl.js';
import { g as globalExpect } from '../chunks/test.CnO2BIt2.js';
import { g as globalExpect } from '../chunks/test.EDIwt4Yp.js';
import '@vitest/expect';
import 'node:async_hooks';
import '../chunks/rpc.DcRWTy5G.js';

@@ -67,3 +68,2 @@ import '@vitest/utils/timers';

config.snapshotOptions.snapshotEnvironment = snapshotEnvironment;
testRunner.getWorkerContext = void 0;
workerState.onCancel((reason) => {

@@ -78,4 +78,8 @@ closeInspector(config);

workerState.filepath = file.filepath;
if (method === "run") await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => startTests([file], testRunner));
else await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => collectTests([file], testRunner));
if (method === "run") {
const collectAsyncLeaks = config.detectAsyncLeaks ? detectAsyncLeaks(file.filepath, workerState.ctx.projectName) : void 0;
await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => startTests([file], testRunner));
const leaks = await collectAsyncLeaks?.();
if (leaks?.length) workerState.rpc.onAsyncLeaks(leaks);
} else await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => collectTests([file], testRunner));
// reset after tests, because user might call `vi.setConfig` in setupFile

@@ -82,0 +86,0 @@ vi.resetConfig();

@@ -1,8 +0,9 @@

import { s as setupBaseEnvironment, r as runBaseTests } from '../chunks/base.BawQY8vy.js';
import { s as setupBaseEnvironment, r as runBaseTests } from '../chunks/base.C_KzYoIG.js';
import { w as workerInit } from '../chunks/init-threads.Cyh2PqXi.js';
import 'node:vm';
import '@vitest/spy';
import '../chunks/index.CEU66SQN.js';
import '../chunks/index.DmJHrI1k.js';
import '@vitest/expect';
import '../chunks/setup-common.BoY7R7rC.js';
import 'node:async_hooks';
import '../chunks/setup-common.Bafp3r-q.js';
import '../chunks/coverage.D_JHT54q.js';

@@ -14,3 +15,3 @@ import '@vitest/snapshot';

import '../chunks/index.Chj8NDwU.js';
import '../chunks/test.CnO2BIt2.js';
import '../chunks/test.EDIwt4Yp.js';
import '@vitest/runner';

@@ -54,3 +55,3 @@ import '@vitest/utils/helpers';

import '@vitest/utils/constants';
import '../chunks/index.D3wDRGBz.js';
import '../chunks/index.C39wbgWx.js';
import 'expect-type';

@@ -57,0 +58,0 @@ import 'node:worker_threads';

@@ -319,2 +319,33 @@ # Vitest core license

## convert-source-map
License: MIT
By: Thorsten Lorenz
Repository: git://github.com/thlorenz/convert-source-map.git
> Copyright 2013 Thorsten Lorenz.
> All rights reserved.
>
> Permission is hereby granted, free of charge, to any person
> obtaining a copy of this software and associated documentation
> files (the "Software"), to deal in the Software without
> restriction, including without limitation the rights to use,
> copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the
> Software is furnished to do so, subject to the following
> conditions:
>
> The above copyright notice and this permission notice shall be
> included in all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER DEALINGS IN THE SOFTWARE.
---------------------------------------
## empathic

@@ -367,3 +398,3 @@ License: MIT

>
> Copyright (c) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 Simon Lydell
> Copyright (c) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Simon Lydell
>

@@ -650,2 +681,86 @@ > Permission is hereby granted, free of charge, to any person obtaining a copy

## tinyhighlight
License: MIT
Repository: git+https://github.com/tinylibs/tinyhighlight.git
> # Tinyhighlight core license
>
> MIT License
>
> Copyright (c) 2023 Tinylibs
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in all
> copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> SOFTWARE.
>
> # Additionaly Tinyhighlight modifies code with the following licenses:
>
> MIT
>
> ## @babel/highlight
>
> MIT License
>
> Copyright (c) 2014-present Sebastian McKenzie and other contributors
>
> Permission is hereby granted, free of charge, to any person obtaining
> a copy of this software and associated documentation files (the
> "Software"), to deal in the Software without restriction, including
> without limitation the rights to use, copy, modify, merge, publish,
> distribute, sublicense, and/or sell copies of the Software, and to
> permit persons to whom the Software is furnished to do so, subject to
> the following conditions:
>
> The above copyright notice and this permission notice shall be
> included in all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
>
> ## @babel/helper-validator-identifier
>
> MIT License
>
> Copyright (c) 2014-present Sebastian McKenzie and other contributors
>
> Permission is hereby granted, free of charge, to any person obtaining
> a copy of this software and associated documentation files (the
> "Software"), to deal in the Software without restriction, including
> without limitation the rights to use, copy, modify, merge, publish,
> distribute, sublicense, and/or sell copies of the Software, and to
> permit persons to whom the Software is furnished to do so, subject to
> the following conditions:
>
> The above copyright notice and this permission notice shall be
> included in all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---------------------------------------
## type-detect

@@ -652,0 +767,0 @@ License: MIT

{
"name": "vitest",
"type": "module",
"version": "4.1.0-beta.3",
"version": "4.1.0-beta.4",
"description": "Next generation testing framework powered by Vite",

@@ -134,6 +134,7 @@ "author": "Anthony Fu <anthonyfu117@hotmail.com>",

"jsdom": "*",
"@vitest/browser-playwright": "4.1.0-beta.3",
"@vitest/browser-preview": "4.1.0-beta.3",
"@vitest/ui": "4.1.0-beta.3",
"@vitest/browser-webdriverio": "4.1.0-beta.3"
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0",
"@vitest/browser-playwright": "4.1.0-beta.4",
"@vitest/browser-preview": "4.1.0-beta.4",
"@vitest/ui": "4.1.0-beta.4",
"@vitest/browser-webdriverio": "4.1.0-beta.4"
},

@@ -167,2 +168,5 @@ "peerDependenciesMeta": {

"optional": true
},
"vite": {
"optional": false
}

@@ -182,11 +186,11 @@ },

"tinyrainbow": "^3.0.3",
"vite": "^6.0.0 || ^7.0.0",
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0",
"why-is-node-running": "^2.3.0",
"@vitest/expect": "4.1.0-beta.3",
"@vitest/mocker": "4.1.0-beta.3",
"@vitest/snapshot": "4.1.0-beta.3",
"@vitest/runner": "4.1.0-beta.3",
"@vitest/pretty-format": "4.1.0-beta.3",
"@vitest/spy": "4.1.0-beta.3",
"@vitest/utils": "4.1.0-beta.3"
"@vitest/expect": "4.1.0-beta.4",
"@vitest/pretty-format": "4.1.0-beta.4",
"@vitest/runner": "4.1.0-beta.4",
"@vitest/mocker": "4.1.0-beta.4",
"@vitest/snapshot": "4.1.0-beta.4",
"@vitest/spy": "4.1.0-beta.4",
"@vitest/utils": "4.1.0-beta.4"
},

@@ -200,2 +204,3 @@ "devDependencies": {

"@sinonjs/fake-timers": "15.0.0",
"@types/convert-source-map": "^2.0.3",
"@types/estree": "^1.0.8",

@@ -213,2 +218,3 @@ "@types/istanbul-lib-coverage": "^2.0.6",

"cac": "^6.7.14",
"convert-source-map": "^2.0.0",
"empathic": "^2.0.0",

@@ -222,2 +228,3 @@ "flatted": "3.3.3",

"strip-literal": "^3.1.0",
"tinyhighlight": "^0.3.2",
"ws": "^8.19.0"

@@ -224,0 +231,0 @@ },

import { runInThisContext } from 'node:vm';
import * as spyModule from '@vitest/spy';
import { r as resolveTestRunner, a as resolveSnapshotEnvironment, s as setupChaiConfig } from './index.CEU66SQN.js';
import { l as loadEnvironment, e as emitModuleRunner, a as listenForErrors } from './init.B95Mm0Iz.js';
import { N as NativeModuleRunner } from './nativeModuleRunner.BIakptoF.js';
import { T as Traces } from './traces.CCmnQaNT.js';
import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js';
import { s as startVitestModuleRunner, c as createNodeImportMeta } from './startVitestModuleRunner.BK-u7y4N.js';
import { performance as performance$1 } from 'node:perf_hooks';
import { startTests, collectTests } from '@vitest/runner';
import { s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker } from './setup-common.BoY7R7rC.js';
import { g as globalExpect, v as vi } from './test.CnO2BIt2.js';
import { c as closeInspector } from './inspector.CvyFGlXm.js';
import { createRequire } from 'node:module';
import timers from 'node:timers';
import timersPromises from 'node:timers/promises';
import util from 'node:util';
import { KNOWN_ASSET_TYPES } from '@vitest/utils/constants';
import { i as index } from './index.D3wDRGBz.js';
import { g as getWorkerState, r as resetModules, p as provideWorkerState, a as getSafeWorkerState } from './utils.DT4VyRyl.js';
// this should only be used in Node
let globalSetup = false;
async function setupGlobalEnv(config, environment) {
await setupCommonEnv(config);
Object.defineProperty(globalThis, "__vitest_index__", {
value: index,
enumerable: false
});
globalExpect.setState({ environment: environment.name });
if (globalSetup) return;
globalSetup = true;
if ((environment.viteEnvironment || environment.name) === "client") {
const _require = createRequire(import.meta.url);
// always mock "required" `css` files, because we cannot process them
_require.extensions[".css"] = resolveCss;
_require.extensions[".scss"] = resolveCss;
_require.extensions[".sass"] = resolveCss;
_require.extensions[".less"] = resolveCss;
// since we are using Vite, we can assume how these will be resolved
KNOWN_ASSET_TYPES.forEach((type) => {
_require.extensions[`.${type}`] = resolveAsset;
});
process.env.SSR = "";
} else process.env.SSR = "1";
// @ts-expect-error not typed global for patched timers
globalThis.__vitest_required__ = {
util,
timers,
timersPromises
};
if (!config.disableConsoleIntercept) await setupConsoleLogSpy();
}
function resolveCss(mod) {
mod.exports = "";
}
function resolveAsset(mod, url) {
mod.exports = url;
}
async function setupConsoleLogSpy() {
const { createCustomConsole } = await import('./console.CNlG1KsP.js');
globalThis.console = createCustomConsole();
}
// browser shouldn't call this!
async function run(method, files, config, moduleRunner, environment, traces) {
const workerState = getWorkerState();
const [testRunner] = await Promise.all([
traces.$("vitest.runtime.runner", () => resolveTestRunner(config, moduleRunner, traces)),
traces.$("vitest.runtime.global_env", () => setupGlobalEnv(config, environment)),
traces.$("vitest.runtime.coverage.start", () => startCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.isolate })),
traces.$("vitest.runtime.snapshot.environment", async () => {
if (!workerState.config.snapshotOptions.snapshotEnvironment) workerState.config.snapshotOptions.snapshotEnvironment = await resolveSnapshotEnvironment(config, moduleRunner);
})
]);
workerState.onCancel((reason) => {
closeInspector(config);
testRunner.cancel?.(reason);
});
workerState.durations.prepare = performance$1.now() - workerState.durations.prepare;
await traces.$(`vitest.test.runner.${method}`, async () => {
for (const file of files) {
if (config.isolate) {
moduleRunner.mocker?.reset();
resetModules(workerState.evaluatedModules, true);
}
workerState.filepath = file.filepath;
if (method === "run") await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => startTests([file], testRunner));
else await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => collectTests([file], testRunner));
// reset after tests, because user might call `vi.setConfig` in setupFile
vi.resetConfig();
// mocks should not affect different files
vi.restoreAllMocks();
}
});
await traces.$("vitest.runtime.coverage.stop", () => stopCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.isolate }));
}
let _moduleRunner;
const evaluatedModules = new VitestEvaluatedModules();
const moduleExecutionInfo = /* @__PURE__ */ new Map();
async function startModuleRunner(options) {
if (_moduleRunner) return _moduleRunner;
process.exit = (code = process.exitCode || 0) => {
throw new Error(`process.exit unexpectedly called with "${code}"`);
};
const state = () => getSafeWorkerState() || options.state;
listenForErrors(state);
if (options.state.config.experimental.viteModuleRunner === false) {
const root = options.state.config.root;
let mocker;
if (options.state.config.experimental.nodeLoader !== false) {
// this additionally imports acorn/magic-string
const { NativeModuleMocker } = await import('./nativeModuleMocker.D_q5sFv6.js');
mocker = new NativeModuleMocker({
async resolveId(id, importer) {
// TODO: use import.meta.resolve instead
return state().rpc.resolve(id, importer, "__vitest__");
},
root,
moduleDirectories: state().config.deps.moduleDirectories || ["/node_modules/"],
traces: options.traces || new Traces({ enabled: false }),
getCurrentTestFilepath() {
return state().filepath;
},
spyModule
});
}
_moduleRunner = new NativeModuleRunner(root, mocker);
return _moduleRunner;
}
_moduleRunner = startVitestModuleRunner(options);
return _moduleRunner;
}
let _currentEnvironment;
let _environmentTime;
/** @experimental */
async function setupBaseEnvironment(context) {
if (context.config.experimental.viteModuleRunner === false) {
const { setupNodeLoaderHooks } = await import('./native.mV0-490A.js');
await setupNodeLoaderHooks(context);
}
const startTime = performance.now();
const { environment: { name: environmentName, options: environmentOptions }, rpc, config } = context;
// we could load @vite/env, but it would take ~8ms, while this takes ~0,02ms
if (context.config.serializedDefines) try {
runInThisContext(`(() =>{\n${context.config.serializedDefines}})()`, {
lineOffset: 1,
filename: "virtual:load-defines.js"
});
} catch (error) {
throw new Error(`Failed to load custom "defines": ${error.message}`);
}
const otel = context.traces;
const { environment, loader } = await loadEnvironment(environmentName, config.root, rpc, otel, context.config.experimental.viteModuleRunner);
_currentEnvironment = environment;
const env = await otel.$("vitest.runtime.environment.setup", { attributes: {
"vitest.environment": environment.name,
"vitest.environment.vite_environment": environment.viteEnvironment || environment.name
} }, () => environment.setup(globalThis, environmentOptions || config.environmentOptions || {}));
_environmentTime = performance.now() - startTime;
if (config.chaiConfig) setupChaiConfig(config.chaiConfig);
return async () => {
await otel.$("vitest.runtime.environment.teardown", () => env.teardown(globalThis));
await loader?.close();
};
}
/** @experimental */
async function runBaseTests(method, state, traces) {
const { ctx } = state;
state.environment = _currentEnvironment;
state.durations.environment = _environmentTime;
// state has new context, but we want to reuse existing ones
state.evaluatedModules = evaluatedModules;
state.moduleExecutionInfo = moduleExecutionInfo;
provideWorkerState(globalThis, state);
if (ctx.invalidates) ctx.invalidates.forEach((filepath) => {
(state.evaluatedModules.fileToModulesMap.get(filepath) || []).forEach((module) => {
state.evaluatedModules.invalidateModule(module);
});
});
ctx.files.forEach((i) => {
const filepath = i.filepath;
(state.evaluatedModules.fileToModulesMap.get(filepath) || []).forEach((module) => {
state.evaluatedModules.invalidateModule(module);
});
});
const moduleRunner = await startModuleRunner({
state,
evaluatedModules: state.evaluatedModules,
spyModule,
createImportMeta: createNodeImportMeta,
traces
});
emitModuleRunner(moduleRunner);
await run(method, ctx.files, ctx.config, moduleRunner, _currentEnvironment, traces);
}
export { runBaseTests as r, setupBaseEnvironment as s };
import { FileSpecification } from '@vitest/runner';
import { O as OTELCarrier } from './traces.d.402V_yFI.js';
import { T as TestExecutionMethod } from './worker.d.CiaQ1oon.js';
type SerializedTestSpecification = [project: {
name: string | undefined;
root: string;
}, file: string, options: {
pool: string;
testLines?: number[] | undefined;
testIds?: string[] | undefined;
testNamePattern?: RegExp | undefined;
testTagsFilter?: string[] | undefined;
}];
interface ModuleDefinitionLocation {
line: number;
column: number;
}
interface SourceModuleLocations {
modules: ModuleDefinitionDiagnostic[];
untracked: ModuleDefinitionDiagnostic[];
}
interface ModuleDefinitionDiagnostic {
start: ModuleDefinitionLocation;
end: ModuleDefinitionLocation;
startIndex: number;
endIndex: number;
rawUrl: string;
resolvedUrl: string;
resolvedId: string;
}
interface ModuleDefinitionDurationsDiagnostic extends ModuleDefinitionDiagnostic {
selfTime: number;
totalTime: number;
transformTime?: number;
external?: boolean;
importer?: string;
}
interface UntrackedModuleDefinitionDiagnostic {
url: string;
resolvedId: string;
resolvedUrl: string;
selfTime: number;
totalTime: number;
transformTime?: number;
external?: boolean;
importer?: string;
}
interface SourceModuleDiagnostic {
modules: ModuleDefinitionDurationsDiagnostic[];
untrackedModules: UntrackedModuleDefinitionDiagnostic[];
}
interface BrowserTesterOptions {
method: TestExecutionMethod;
files: FileSpecification[];
providedContext: string;
otelCarrier?: OTELCarrier;
}
export type { BrowserTesterOptions as B, ModuleDefinitionDurationsDiagnostic as M, SerializedTestSpecification as S, UntrackedModuleDefinitionDiagnostic as U, ModuleDefinitionDiagnostic as a, ModuleDefinitionLocation as b, SourceModuleDiagnostic as c, SourceModuleLocations as d };

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

import { PrettyFormatOptions } from '@vitest/pretty-format';
import { SequenceHooks, SequenceSetupFiles, SerializableRetry, TestTagDefinition } from '@vitest/runner';
import { SnapshotUpdateState, SnapshotEnvironment } from '@vitest/snapshot';
import { SerializedDiffOptions } from '@vitest/utils/diff';
/**
* Names of clock methods that may be faked by install.
*/
type FakeMethod =
| "setTimeout"
| "clearTimeout"
| "setImmediate"
| "clearImmediate"
| "setInterval"
| "clearInterval"
| "Date"
| "nextTick"
| "hrtime"
| "requestAnimationFrame"
| "cancelAnimationFrame"
| "requestIdleCallback"
| "cancelIdleCallback"
| "performance"
| "queueMicrotask";
interface FakeTimerInstallOpts {
/**
* Installs fake timers with the specified unix epoch (default: 0)
*/
now?: number | Date | undefined;
/**
* An array with names of global methods and APIs to fake. By default, `@sinonjs/fake-timers` does not replace `nextTick()` and `queueMicrotask()`.
* For instance, `FakeTimers.install({ toFake: ['setTimeout', 'nextTick'] })` will fake only `setTimeout()` and `nextTick()`
*/
toFake?: FakeMethod[] | undefined;
/**
* The maximum number of timers that will be run when calling runAll() (default: 1000)
*/
loopLimit?: number | undefined;
/**
* Tells @sinonjs/fake-timers to increment mocked time automatically based on the real system time shift (e.g. the mocked time will be incremented by
* 20ms for every 20ms change in the real system time) (default: false)
*/
shouldAdvanceTime?: boolean | undefined;
/**
* Relevant only when using with shouldAdvanceTime: true. increment mocked time by advanceTimeDelta ms every advanceTimeDelta ms change
* in the real system time (default: 20)
*/
advanceTimeDelta?: number | undefined;
/**
* Tells FakeTimers to clear 'native' (i.e. not fake) timers by delegating to their respective handlers. These are not cleared by
* default, leading to potentially unexpected behavior if timers existed prior to installing FakeTimers. (default: false)
*/
shouldClearNativeTimers?: boolean | undefined;
/**
* Tells FakeTimers to not throw an error when faking a timer that does not exist in the global object. (default: false)
*/
ignoreMissingTimers?: boolean | undefined;
}
/**
* Config that tests have access to.
*/
interface SerializedConfig {
name: string | undefined;
globals: boolean;
base: string | undefined;
snapshotEnvironment?: string;
disableConsoleIntercept: boolean | undefined;
runner: string | undefined;
isolate: boolean;
maxWorkers: number;
mode: "test" | "benchmark";
bail: number | undefined;
environmentOptions?: Record<string, any>;
root: string;
setupFiles: string[];
passWithNoTests: boolean;
testNamePattern: RegExp | undefined;
allowOnly: boolean;
testTimeout: number;
hookTimeout: number;
clearMocks: boolean;
mockReset: boolean;
restoreMocks: boolean;
unstubGlobals: boolean;
unstubEnvs: boolean;
fakeTimers: FakeTimerInstallOpts;
maxConcurrency: number;
defines: Record<string, any>;
expect: {
requireAssertions?: boolean;
poll?: {
timeout?: number;
interval?: number;
};
};
printConsoleTrace: boolean | undefined;
sequence: {
shuffle?: boolean;
concurrent?: boolean;
seed: number;
hooks: SequenceHooks;
setupFiles: SequenceSetupFiles;
};
deps: {
web: {
transformAssets?: boolean;
transformCss?: boolean;
transformGlobPattern?: RegExp | RegExp[];
};
optimizer: Record<string, {
enabled: boolean;
}>;
interopDefault: boolean | undefined;
moduleDirectories: string[] | undefined;
};
snapshotOptions: {
updateSnapshot: SnapshotUpdateState;
expand: boolean | undefined;
snapshotFormat: PrettyFormatOptions | undefined;
/**
* only exists for tests, not available in the main process
*/
snapshotEnvironment: SnapshotEnvironment;
};
pool: string;
snapshotSerializers: string[];
chaiConfig: {
includeStack?: boolean;
showDiff?: boolean;
truncateThreshold?: number;
} | undefined;
api: {
allowExec: boolean | undefined;
allowWrite: boolean | undefined;
};
diff: string | SerializedDiffOptions | undefined;
retry: SerializableRetry;
includeTaskLocation: boolean | undefined;
inspect: boolean | string | undefined;
inspectBrk: boolean | string | undefined;
inspector: {
enabled?: boolean;
port?: number;
host?: string;
waitForDebugger?: boolean;
};
watch: boolean;
env: Record<string, any>;
browser: {
name: string;
headless: boolean;
isolate: boolean;
fileParallelism: boolean;
ui: boolean;
viewport: {
width: number;
height: number;
};
locators: {
testIdAttribute: string;
};
screenshotFailures: boolean;
providerOptions: {
actionTimeout?: number;
};
trace: BrowserTraceViewMode;
trackUnhandledErrors: boolean;
detailsPanelPosition: "right" | "bottom";
};
standalone: boolean;
logHeapUsage: boolean | undefined;
coverage: SerializedCoverageConfig;
benchmark: {
includeSamples: boolean;
} | undefined;
serializedDefines: string;
experimental: {
fsModuleCache: boolean;
importDurations: {
print: boolean | "on-warn";
limit: number;
failOnDanger: boolean;
thresholds: {
warn: number;
danger: number;
};
};
viteModuleRunner: boolean;
nodeLoader: boolean;
openTelemetry: {
enabled: boolean;
sdkPath?: string;
browserSdkPath?: string;
} | undefined;
};
tags: TestTagDefinition[];
tagsFilter: string[] | undefined;
strictTags: boolean;
}
interface SerializedCoverageConfig {
provider: "istanbul" | "v8" | "custom" | undefined;
reportsDirectory: string;
htmlReporter: {
subdir: string | undefined;
} | undefined;
enabled: boolean;
customProviderModule: string | undefined;
}
type RuntimeConfig = Pick<SerializedConfig, "allowOnly" | "testTimeout" | "hookTimeout" | "clearMocks" | "mockReset" | "restoreMocks" | "fakeTimers" | "maxConcurrency" | "expect" | "printConsoleTrace"> & {
sequence?: {
hooks?: SequenceHooks;
};
};
type RuntimeOptions = Partial<RuntimeConfig>;
type BrowserTraceViewMode = "on" | "off" | "on-first-retry" | "on-all-retries" | "retain-on-failure";
export type { BrowserTraceViewMode as B, FakeTimerInstallOpts as F, RuntimeOptions as R, SerializedConfig as S, SerializedCoverageConfig as a, RuntimeConfig as b };
import { existsSync, promises, readdirSync, writeFileSync } from 'node:fs';
import module$1 from 'node:module';
import path from 'node:path';
import { pathToFileURL, fileURLToPath } from 'node:url';
import { slash, shuffle, toArray } from '@vitest/utils/helpers';
import { resolve, relative, normalize } from 'pathe';
import pm from 'picomatch';
import { glob } from 'tinyglobby';
import c from 'tinyrainbow';
import { c as configDefaults, e as benchmarkConfigDefaults, a as coverageConfigDefaults } from './defaults.BOqNVLsY.js';
import crypto from 'node:crypto';
import { r as resolveModule } from './index.BCY_7LL2.js';
import { mergeConfig } from 'vite';
import { c as configFiles, d as defaultBrowserPort, a as defaultInspectPort, b as defaultPort } from './constants.CPYnjOGj.js';
import './env.D4Lgay0q.js';
import nodeos__default from 'node:os';
import { isCI, provider } from 'std-env';
import { r as resolveCoverageProviderModule } from './coverage.D_JHT54q.js';
const hash = crypto.hash ?? ((algorithm, data, outputEncoding) => crypto.createHash(algorithm).update(data).digest(outputEncoding));
function getWorkersCountByPercentage(percent) {
const maxWorkersCount = nodeos__default.availableParallelism?.() ?? nodeos__default.cpus().length;
const workersCountByPercentage = Math.round(Number.parseInt(percent) / 100 * maxWorkersCount);
return Math.max(1, Math.min(maxWorkersCount, workersCountByPercentage));
}
class BaseSequencer {
ctx;
constructor(ctx) {
this.ctx = ctx;
}
// async so it can be extended by other sequelizers
async shard(files) {
const { config } = this.ctx;
const { index, count } = config.shard;
const [shardStart, shardEnd] = this.calculateShardRange(files.length, index, count);
return [...files].map((spec) => {
const specPath = resolve(slash(config.root), slash(spec.moduleId))?.slice(config.root.length);
return {
spec,
hash: hash("sha1", specPath, "hex")
};
}).sort((a, b) => a.hash < b.hash ? -1 : a.hash > b.hash ? 1 : 0).slice(shardStart, shardEnd).map(({ spec }) => spec);
}
// async so it can be extended by other sequelizers
async sort(files) {
const cache = this.ctx.cache;
return [...files].sort((a, b) => {
// "sequence.groupOrder" is higher priority
const groupOrderDiff = a.project.config.sequence.groupOrder - b.project.config.sequence.groupOrder;
if (groupOrderDiff !== 0) return groupOrderDiff;
// Projects run sequential
if (a.project.name !== b.project.name) return a.project.name < b.project.name ? -1 : 1;
// Isolated run first
if (a.project.config.isolate && !b.project.config.isolate) return -1;
if (!a.project.config.isolate && b.project.config.isolate) return 1;
const keyA = `${a.project.name}:${relative(this.ctx.config.root, a.moduleId)}`;
const keyB = `${b.project.name}:${relative(this.ctx.config.root, b.moduleId)}`;
const aState = cache.getFileTestResults(keyA);
const bState = cache.getFileTestResults(keyB);
if (!aState || !bState) {
const statsA = cache.getFileStats(keyA);
const statsB = cache.getFileStats(keyB);
// run unknown first
if (!statsA || !statsB) return !statsA && statsB ? -1 : !statsB && statsA ? 1 : 0;
// run larger files first
return statsB.size - statsA.size;
}
// run failed first
if (aState.failed && !bState.failed) return -1;
if (!aState.failed && bState.failed) return 1;
// run longer first
return bState.duration - aState.duration;
});
}
// Calculate distributed shard range [start, end] distributed equally
calculateShardRange(filesCount, index, count) {
const baseShardSize = Math.floor(filesCount / count);
const remainderTestFilesCount = filesCount % count;
if (remainderTestFilesCount >= index) {
const shardSize = baseShardSize + 1;
return [shardSize * (index - 1), shardSize * index];
}
const shardStart = remainderTestFilesCount * (baseShardSize + 1) + (index - remainderTestFilesCount - 1) * baseShardSize;
return [shardStart, shardStart + baseShardSize];
}
}
class RandomSequencer extends BaseSequencer {
async sort(files) {
const { sequence } = this.ctx.config;
return shuffle(files, sequence.seed);
}
}
function resolvePath(path, root) {
return normalize(/* @__PURE__ */ resolveModule(path, { paths: [root] }) ?? resolve(root, path));
}
function parseInspector(inspect) {
if (typeof inspect === "boolean" || inspect === void 0) return {};
if (typeof inspect === "number") return { port: inspect };
if (inspect.match(/https?:\//)) throw new Error(`Inspector host cannot be a URL. Use "host:port" instead of "${inspect}"`);
const [host, port] = inspect.split(":");
if (!port) return { host };
return {
host,
port: Number(port) || defaultInspectPort
};
}
/**
* @deprecated Internal function
*/
function resolveApiServerConfig(options, defaultPort, parentApi, logger) {
let api;
if (options.ui && !options.api) api = { port: defaultPort };
else if (options.api === true) api = { port: defaultPort };
else if (typeof options.api === "number") api = { port: options.api };
if (typeof options.api === "object") if (api) {
if (options.api.port) api.port = options.api.port;
if (options.api.strictPort) api.strictPort = options.api.strictPort;
if (options.api.host) api.host = options.api.host;
} else api = { ...options.api };
if (api) {
if (!api.port && !api.middlewareMode) api.port = defaultPort;
} else api = { middlewareMode: true };
// if the API server is exposed to network, disable write operations by default
if (!api.middlewareMode && api.host && api.host !== "localhost" && api.host !== "127.0.0.1") {
// assigned to browser
if (parentApi) {
if (api.allowWrite == null && api.allowExec == null) logger?.error(c.yellow(`${c.yellowBright(" WARNING ")} API server is exposed to network, disabling write and exec operations by default for security reasons. This can cause some APIs to not work as expected. Set \`browser.api.allowExec\` manually to hide this warning. See https://vitest.dev/config/browser/api for more details.`));
}
api.allowWrite ??= parentApi?.allowWrite ?? false;
api.allowExec ??= parentApi?.allowExec ?? false;
} else {
api.allowWrite ??= parentApi?.allowWrite ?? true;
api.allowExec ??= parentApi?.allowExec ?? true;
}
return api;
}
function resolveInlineWorkerOption(value) {
if (typeof value === "string" && value.trim().endsWith("%")) return getWorkersCountByPercentage(value);
else return Number(value);
}
function resolveConfig$1(vitest, options, viteConfig) {
const mode = vitest.mode;
const logger = vitest.logger;
if (options.dom) {
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}"`));
options.environment = "happy-dom";
}
const resolved = {
...configDefaults,
...options,
root: viteConfig.root,
mode
};
if (resolved.retry && typeof resolved.retry === "object" && typeof resolved.retry.condition === "function") {
logger.console.warn(c.yellow("Warning: retry.condition function cannot be used inside a config file. Use a RegExp pattern instead, or define the function in your test file."));
resolved.retry = {
...resolved.retry,
condition: void 0
};
}
if (options.pool && typeof options.pool !== "string") {
resolved.pool = options.pool.name;
resolved.poolRunner = options.pool;
}
if ("poolOptions" in resolved) logger.deprecate("`test.poolOptions` was removed in Vitest 4. All previous `poolOptions` are now top-level options. Please, refer to the migration guide: https://vitest.dev/guide/migration#pool-rework");
resolved.pool ??= "forks";
resolved.project = toArray(resolved.project);
resolved.provide ??= {};
// shallow copy tags array to avoid mutating user config
resolved.tags = [...resolved.tags || []];
const definedTags = /* @__PURE__ */ new Set();
resolved.tags.forEach((tag) => {
if (!tag.name || typeof tag.name !== "string") throw new Error(`Each tag defined in "test.tags" must have a "name" property, received: ${JSON.stringify(tag)}`);
if (definedTags.has(tag.name)) throw new Error(`Tag name "${tag.name}" is already defined in "test.tags". Tag names must be unique.`);
if (tag.name.match(/\s/)) throw new Error(`Tag name "${tag.name}" is invalid. Tag names cannot contain spaces.`);
if (tag.name.match(/([!()*|&])/)) throw new Error(`Tag name "${tag.name}" is invalid. Tag names cannot contain "!", "*", "&", "|", "(", or ")".`);
if (tag.name.match(/^\s*(and|or|not)\s*$/i)) throw new Error(`Tag name "${tag.name}" is invalid. Tag names cannot be a logical operator like "and", "or", "not".`);
if (typeof tag.retry === "object" && typeof tag.retry.condition === "function") throw new TypeError(`Tag "${tag.name}": retry.condition function cannot be used inside a config file. Use a RegExp pattern instead, or define the function in your test file.`);
if (tag.priority != null && (typeof tag.priority !== "number" || tag.priority < 0)) throw new TypeError(`Tag "${tag.name}": priority must be a non-negative number.`);
definedTags.add(tag.name);
});
resolved.name = typeof options.name === "string" ? options.name : options.name?.label || "";
resolved.color = typeof options.name !== "string" ? options.name?.color : void 0;
if (resolved.environment === "browser") throw new Error(`Looks like you set "test.environment" to "browser". To enable Browser Mode, use "test.browser.enabled" instead.`);
const inspector = resolved.inspect || resolved.inspectBrk;
resolved.inspector = {
...resolved.inspector,
...parseInspector(inspector),
enabled: !!inspector,
waitForDebugger: options.inspector?.waitForDebugger ?? !!resolved.inspectBrk
};
if (viteConfig.base !== "/") resolved.base = viteConfig.base;
resolved.clearScreen = resolved.clearScreen ?? viteConfig.clearScreen ?? true;
if (options.shard) {
if (resolved.watch) throw new Error("You cannot use --shard option with enabled watch");
const [indexString, countString] = options.shard.split("/");
const index = Math.abs(Number.parseInt(indexString, 10));
const count = Math.abs(Number.parseInt(countString, 10));
if (Number.isNaN(count) || count <= 0) throw new Error("--shard <count> must be a positive number");
if (Number.isNaN(index) || index <= 0 || index > count) throw new Error("--shard <index> must be a positive number less then <count>");
resolved.shard = {
index,
count
};
}
if (resolved.standalone && !resolved.watch) throw new Error(`Vitest standalone mode requires --watch`);
if (resolved.mergeReports && resolved.watch) throw new Error(`Cannot merge reports with --watch enabled`);
if (resolved.maxWorkers) resolved.maxWorkers = resolveInlineWorkerOption(resolved.maxWorkers);
if (!(options.fileParallelism ?? mode !== "benchmark"))
// ignore user config, parallelism cannot be implemented without limiting workers
resolved.maxWorkers = 1;
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;
}
if (resolved.inspect || resolved.inspectBrk) {
if (resolved.maxWorkers !== 1) {
const inspectOption = `--inspect${resolved.inspectBrk ? "-brk" : ""}`;
throw new Error(`You cannot use ${inspectOption} without "--no-file-parallelism"`);
}
}
// apply browser CLI options only if the config already has the browser config and not disabled manually
if (vitest._cliOptions.browser && resolved.browser && (resolved.browser.enabled !== false || vitest._cliOptions.browser.enabled)) resolved.browser = mergeConfig(resolved.browser, vitest._cliOptions.browser);
resolved.browser ??= {};
const browser = resolved.browser;
if (browser.enabled) {
const instances = browser.instances;
if (!browser.instances) browser.instances = [];
// use `chromium` by default when the preview provider is specified
// for a smoother experience. if chromium is not available, it will
// open the default browser anyway
if (!browser.instances.length && browser.provider?.name === "preview") browser.instances = [{ browser: "chromium" }];
if (browser.name && instances?.length) {
// --browser=chromium filters configs to a single one
browser.instances = browser.instances.filter((instance) => instance.browser === browser.name);
// if `instances` were defined, but now they are empty,
// let's throw an error because the filter is invalid
if (!browser.instances.length) throw new Error([`"browser.instances" was set in the config, but the array is empty. Define at least one browser config.`, ` The "browser.name" was set to "${browser.name}" which filtered all configs (${instances.map((c) => c.browser).join(", ")}). Did you mean to use another name?`].join(""));
}
}
if (resolved.coverage.enabled && resolved.coverage.provider === "istanbul" && resolved.experimental?.viteModuleRunner === false) throw new Error(`"Istanbul" coverage provider is not compatible with "experimental.viteModuleRunner: false". Please, enable "viteModuleRunner" or switch to "v8" coverage provider.`);
const containsChromium = hasBrowserChromium(vitest, resolved);
const hasOnlyChromium = hasOnlyBrowserChromium(vitest, resolved);
// Browser-mode "Chromium" only features:
if (browser.enabled && (!containsChromium || !hasOnlyChromium)) {
const browserConfig = `
{
browser: {
provider: ${browser.provider?.name || "preview"}(),
instances: [
${(browser.instances || []).map((i) => `{ browser: '${i.browser}' }`).join(",\n ")}
],
},
}
`.trim();
const preferredProvider = !browser.provider?.name || browser.provider.name === "preview" ? "playwright" : browser.provider.name;
const correctExample = `
{
browser: {
provider: ${preferredProvider}(),
instances: [
{ browser: '${preferredProvider === "playwright" ? "chromium" : "chrome"}' }
],
},
}
`.trim();
// requires all projects to be chromium
if (!hasOnlyChromium && resolved.coverage.enabled && resolved.coverage.provider === "v8") {
const coverageExample = `
{
coverage: {
provider: 'istanbul',
},
}
`.trim();
throw new Error(`@vitest/coverage-v8 does not work with\n${browserConfig}\n\nUse either:\n${correctExample}\n\n...or change your coverage provider to:\n${coverageExample}\n`);
}
// ignores non-chromium browsers when there is at least one chromium project
if (!containsChromium && (resolved.inspect || resolved.inspectBrk)) {
const inspectOption = `--inspect${resolved.inspectBrk ? "-brk" : ""}`;
throw new Error(`${inspectOption} does not work with\n${browserConfig}\n\nUse either:\n${correctExample}\n\n...or disable ${inspectOption}\n`);
}
}
resolved.coverage.reporter = resolveCoverageReporters(resolved.coverage.reporter);
if (resolved.coverage.enabled && resolved.coverage.reportsDirectory) {
const reportsDirectory = resolve(resolved.root, resolved.coverage.reportsDirectory);
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`);
}
if (resolved.coverage.enabled && resolved.coverage.provider === "custom" && resolved.coverage.customProviderModule) resolved.coverage.customProviderModule = resolvePath(resolved.coverage.customProviderModule, resolved.root);
resolved.expect ??= {};
resolved.deps ??= {};
resolved.deps.moduleDirectories ??= [];
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));
// Add hard-coded default coverage exclusions. These cannot be overidden by user config.
// Override original exclude array for cases where user re-uses same object in test.exclude.
resolved.coverage.exclude = [
...resolved.coverage.exclude,
...resolved.setupFiles.map((file) => `${resolved.coverage.allowExternal ? "**/" : ""}${relative(resolved.root, file)}`),
...resolved.include,
resolved.config && slash(resolved.config),
...configFiles,
"**/virtual:*",
"**/__x00__*",
"**/node_modules/**"
].filter((pattern) => typeof pattern === "string");
resolved.forceRerunTriggers = [...resolved.forceRerunTriggers, ...resolved.setupFiles];
if (resolved.cliExclude) resolved.exclude.push(...resolved.cliExclude);
if (resolved.runner) resolved.runner = resolvePath(resolved.runner, resolved.root);
resolved.attachmentsDir = resolve(resolved.root, resolved.attachmentsDir ?? ".vitest-attachments");
if (resolved.snapshotEnvironment) resolved.snapshotEnvironment = resolvePath(resolved.snapshotEnvironment, resolved.root);
resolved.testNamePattern = resolved.testNamePattern ? resolved.testNamePattern instanceof RegExp ? resolved.testNamePattern : new RegExp(resolved.testNamePattern) : void 0;
if (resolved.snapshotFormat && "plugins" in resolved.snapshotFormat) {
resolved.snapshotFormat.plugins = [];
// TODO: support it via separate config (like DiffOptions) or via `Function.toString()`
if (typeof resolved.snapshotFormat.compareKeys === "function") throw new TypeError(`"snapshotFormat.compareKeys" function is not supported.`);
}
const UPDATE_SNAPSHOT = resolved.update || process.env.UPDATE_SNAPSHOT;
resolved.snapshotOptions = {
expand: resolved.expandSnapshotDiff ?? false,
snapshotFormat: resolved.snapshotFormat || {},
updateSnapshot: UPDATE_SNAPSHOT === "all" || UPDATE_SNAPSHOT === "new" ? UPDATE_SNAPSHOT : isCI && !UPDATE_SNAPSHOT ? "none" : UPDATE_SNAPSHOT ? "all" : "new",
resolveSnapshotPath: options.resolveSnapshotPath,
snapshotEnvironment: null
};
resolved.snapshotSerializers ??= [];
resolved.snapshotSerializers = resolved.snapshotSerializers.map((file) => resolvePath(file, resolved.root));
resolved.forceRerunTriggers.push(...resolved.snapshotSerializers);
if (options.resolveSnapshotPath) delete resolved.resolveSnapshotPath;
resolved.execArgv ??= [];
resolved.pool ??= "threads";
if (resolved.pool === "vmForks" || resolved.pool === "vmThreads" || resolved.pool === "typescript") resolved.isolate = false;
if (process.env.VITEST_MAX_WORKERS) resolved.maxWorkers = Number.parseInt(process.env.VITEST_MAX_WORKERS);
if (mode === "benchmark") {
resolved.benchmark = {
...benchmarkConfigDefaults,
...resolved.benchmark
};
// override test config
resolved.coverage.enabled = false;
resolved.typecheck.enabled = false;
resolved.include = resolved.benchmark.include;
resolved.exclude = resolved.benchmark.exclude;
resolved.includeSource = resolved.benchmark.includeSource;
const reporters = Array.from(new Set([...toArray(resolved.benchmark.reporters), ...toArray(options.reporter)])).filter(Boolean);
if (reporters.length) resolved.benchmark.reporters = reporters;
else resolved.benchmark.reporters = ["default"];
if (options.outputFile) resolved.benchmark.outputFile = options.outputFile;
// --compare from cli
if (options.compare) resolved.benchmark.compare = options.compare;
if (options.outputJson) resolved.benchmark.outputJson = options.outputJson;
}
if (typeof resolved.diff === "string") {
resolved.diff = resolvePath(resolved.diff, resolved.root);
resolved.forceRerunTriggers.push(resolved.diff);
}
resolved.api = {
...resolveApiServerConfig(options, defaultPort),
token: crypto.randomUUID()
};
if (options.related) resolved.related = toArray(options.related).map((file) => resolve(resolved.root, file));
/*
* Reporters can be defined in many different ways:
* { reporter: 'json' }
* { reporter: { onFinish() { method() } } }
* { reporter: ['json', { onFinish() { method() } }] }
* { reporter: [[ 'json' ]] }
* { reporter: [[ 'json' ], 'html'] }
* { reporter: [[ 'json', { outputFile: 'test.json' } ], 'html'] }
*/
if (options.reporters) if (!Array.isArray(options.reporters))
// Reporter name, e.g. { reporters: 'json' }
if (typeof options.reporters === "string") resolved.reporters = [[options.reporters, {}]];
else resolved.reporters = [options.reporters];
else {
resolved.reporters = [];
for (const reporter of options.reporters) if (Array.isArray(reporter))
// Reporter with options, e.g. { reporters: [ [ 'json', { outputFile: 'test.json' } ] ] }
resolved.reporters.push([reporter[0], reporter[1] || {}]);
else if (typeof reporter === "string")
// Reporter name in array, e.g. { reporters: ["html", "json"]}
resolved.reporters.push([reporter, {}]);
else
// Inline reporter, e.g. { reporter: [{ onFinish() { method() } }] }
resolved.reporters.push(reporter);
}
if (mode !== "benchmark") {
// @ts-expect-error "reporter" is from CLI, should be absolute to the running directory
// it is passed down as "vitest --reporter ../reporter.js"
const reportersFromCLI = resolved.reporter;
const cliReporters = toArray(reportersFromCLI || []).map((reporter) => {
// ./reporter.js || ../reporter.js, but not .reporters/reporter.js
if (/^\.\.?\//.test(reporter)) return resolve(process.cwd(), reporter);
return reporter;
});
if (cliReporters.length) {
// When CLI reporters are specified, preserve options from config file
const configReportersMap = /* @__PURE__ */ new Map();
// Build a map of reporter names to their options from the config
for (const reporter of resolved.reporters) if (Array.isArray(reporter)) {
const [reporterName, reporterOptions] = reporter;
if (typeof reporterName === "string") configReportersMap.set(reporterName, reporterOptions);
}
resolved.reporters = Array.from(new Set(toArray(cliReporters))).filter(Boolean).map((reporter) => [reporter, configReportersMap.get(reporter) || {}]);
}
}
if (!resolved.reporters.length) {
resolved.reporters.push(["default", {}]);
// also enable github-actions reporter as a default
if (process.env.GITHUB_ACTIONS === "true") resolved.reporters.push(["github-actions", {}]);
}
if (resolved.changed) resolved.passWithNoTests ??= true;
resolved.css ??= {};
if (typeof resolved.css === "object") {
resolved.css.modules ??= {};
resolved.css.modules.classNameStrategy ??= "stable";
}
if (resolved.cache !== false) {
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"`);
resolved.cache = { dir: viteConfig.cacheDir };
}
resolved.sequence ??= {};
if (resolved.sequence.shuffle && typeof resolved.sequence.shuffle === "object") {
const { files, tests } = resolved.sequence.shuffle;
resolved.sequence.sequencer ??= files ? RandomSequencer : BaseSequencer;
resolved.sequence.shuffle = tests;
}
if (!resolved.sequence?.sequencer)
// CLI flag has higher priority
resolved.sequence.sequencer = resolved.sequence.shuffle ? RandomSequencer : BaseSequencer;
resolved.sequence.groupOrder ??= 0;
resolved.sequence.hooks ??= "stack";
if (resolved.sequence.sequencer === RandomSequencer) resolved.sequence.seed ??= Date.now();
resolved.typecheck = {
...configDefaults.typecheck,
...resolved.typecheck
};
resolved.typecheck ??= {};
resolved.typecheck.enabled ??= false;
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."));
resolved.browser.enabled ??= false;
resolved.browser.headless ??= isCI;
if (resolved.browser.isolate) logger.console.warn(c.yellow("`browser.isolate` is deprecated. Use top-level `isolate` instead."));
resolved.browser.isolate ??= resolved.isolate ?? true;
resolved.browser.fileParallelism ??= options.fileParallelism ?? mode !== "benchmark";
// disable in headless mode by default, and if CI is detected
resolved.browser.ui ??= resolved.browser.headless === true ? false : !isCI;
resolved.browser.commands ??= {};
resolved.browser.detailsPanelPosition ??= "right";
if (resolved.browser.screenshotDirectory) resolved.browser.screenshotDirectory = resolve(resolved.root, resolved.browser.screenshotDirectory);
if (resolved.inspector.enabled) resolved.browser.trackUnhandledErrors ??= false;
resolved.browser.viewport ??= {};
resolved.browser.viewport.width ??= 414;
resolved.browser.viewport.height ??= 896;
resolved.browser.locators ??= {};
resolved.browser.locators.testIdAttribute ??= "data-testid";
if (typeof resolved.browser.provider === "string") {
const source = `@vitest/browser-${resolved.browser.provider}`;
throw new TypeError(`The \`browser.provider\` configuration was changed to accept a factory instead of a string. Add an import of "${resolved.browser.provider}" from "${source}" instead. See: https://vitest.dev/config/browser/provider`);
}
const isPreview = resolved.browser.provider?.name === "preview";
if (!isPreview && resolved.browser.enabled && provider === "stackblitz") throw new Error(`stackblitz environment does not support the ${resolved.browser.provider?.name} provider. Please, use "@vitest/browser-preview" instead.`);
if (isPreview && resolved.browser.screenshotFailures === true) {
console.warn(c.yellow([
`Browser provider "preview" doesn't support screenshots, `,
`so "browser.screenshotFailures" option is forcefully disabled. `,
`Set "browser.screenshotFailures" to false or remove it from the config to suppress this warning.`
].join("")));
resolved.browser.screenshotFailures = false;
} else resolved.browser.screenshotFailures ??= !isPreview && !resolved.browser.ui;
if (resolved.browser.provider && resolved.browser.provider.options == null) resolved.browser.provider.options = {};
resolved.browser.api = resolveApiServerConfig(resolved.browser, defaultBrowserPort, resolved.api, logger) || { port: defaultBrowserPort };
// enable includeTaskLocation by default in UI mode
if (resolved.browser.enabled) {
if (resolved.browser.ui) resolved.includeTaskLocation ??= true;
} else if (resolved.ui) resolved.includeTaskLocation ??= true;
if (typeof resolved.browser.trace === "string" || !resolved.browser.trace) resolved.browser.trace = { mode: resolved.browser.trace || "off" };
if (resolved.browser.trace.tracesDir != null) resolved.browser.trace.tracesDir = resolvePath(resolved.browser.trace.tracesDir, resolved.root);
if (toArray(resolved.reporters).some((reporter) => {
if (Array.isArray(reporter)) return reporter[0] === "html";
return false;
})) resolved.includeTaskLocation ??= true;
resolved.server ??= {};
resolved.server.deps ??= {};
if (resolved.server.debug?.dump || process.env.VITEST_DEBUG_DUMP) {
const userFolder = resolved.server.debug?.dump || process.env.VITEST_DEBUG_DUMP;
resolved.dumpDir = resolve(resolved.root, typeof userFolder === "string" && userFolder !== "true" ? userFolder : ".vitest-dump", resolved.name || "root");
}
resolved.testTimeout ??= resolved.browser.enabled ? 15e3 : 5e3;
resolved.hookTimeout ??= resolved.browser.enabled ? 3e4 : 1e4;
resolved.experimental ??= {};
if (resolved.experimental.openTelemetry?.sdkPath) {
const sdkPath = resolve(resolved.root, resolved.experimental.openTelemetry.sdkPath);
resolved.experimental.openTelemetry.sdkPath = pathToFileURL(sdkPath).toString();
}
if (resolved.experimental.openTelemetry?.browserSdkPath) {
const browserSdkPath = resolve(resolved.root, resolved.experimental.openTelemetry.browserSdkPath);
resolved.experimental.openTelemetry.browserSdkPath = browserSdkPath;
}
if (resolved.experimental.fsModuleCachePath) resolved.experimental.fsModuleCachePath = resolve(resolved.root, resolved.experimental.fsModuleCachePath);
resolved.experimental.importDurations ??= {};
resolved.experimental.importDurations.print ??= false;
resolved.experimental.importDurations.failOnDanger ??= false;
if (resolved.experimental.importDurations.limit == null) {
const shouldCollect = resolved.experimental.importDurations.print || resolved.experimental.importDurations.failOnDanger || resolved.ui;
resolved.experimental.importDurations.limit = shouldCollect ? 10 : 0;
}
resolved.experimental.importDurations.thresholds ??= {};
resolved.experimental.importDurations.thresholds.warn ??= 100;
resolved.experimental.importDurations.thresholds.danger ??= 500;
return resolved;
}
function isBrowserEnabled(config) {
return Boolean(config.browser?.enabled);
}
function resolveCoverageReporters(configReporters) {
// E.g. { reporter: "html" }
if (!Array.isArray(configReporters)) return [[configReporters, {}]];
const resolvedReporters = [];
for (const reporter of configReporters) if (Array.isArray(reporter))
// E.g. { reporter: [ ["html", { skipEmpty: true }], ["lcov"], ["json", { file: "map.json" }] ]}
resolvedReporters.push([reporter[0], reporter[1] || {}]);
else
// E.g. { reporter: ["html", "json"]}
resolvedReporters.push([reporter, {}]);
return resolvedReporters;
}
function isChromiumName(provider, name) {
if (provider === "playwright") return name === "chromium";
return name === "chrome" || name === "edge";
}
function hasBrowserChromium(vitest, config) {
const browser = config.browser;
if (!browser || !browser.provider || browser.provider.name === "preview" || !browser.enabled) return false;
if (browser.name) return isChromiumName(browser.provider.name, browser.name);
if (!browser.instances) return false;
return browser.instances.some((instance) => {
const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser);
// browser config is filtered out
if (!vitest.matchesProjectFilter(name)) return false;
return isChromiumName(browser.provider.name, instance.browser);
});
}
function hasOnlyBrowserChromium(vitest, config) {
const browser = config.browser;
if (!browser || !browser.provider || browser.provider.name === "preview" || !browser.enabled) return false;
if (browser.name) return isChromiumName(browser.provider.name, browser.name);
if (!browser.instances) return false;
return browser.instances.every((instance) => {
const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser);
// browser config is filtered out
if (!vitest.matchesProjectFilter(name)) return true;
return isChromiumName(browser.provider.name, instance.browser);
});
}
const THRESHOLD_KEYS = [
"lines",
"functions",
"statements",
"branches"
];
const GLOBAL_THRESHOLDS_KEY = "global";
const DEFAULT_PROJECT = Symbol.for("default-project");
let uniqueId = 0;
async function getCoverageProvider(options, loader) {
const coverageModule = await resolveCoverageProviderModule(options, loader);
if (coverageModule) return coverageModule.getProvider();
return null;
}
class BaseCoverageProvider {
ctx;
name;
version;
options;
globCache = /* @__PURE__ */ new Map();
autoUpdateMarker = "\n// __VITEST_COVERAGE_MARKER__";
coverageFiles = /* @__PURE__ */ new Map();
pendingPromises = [];
coverageFilesDirectory;
roots = [];
_initialize(ctx) {
this.ctx = ctx;
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} `))}.
Running mixed versions is not supported and may lead into bugs
Update your dependencies and make sure the versions match.`));
const config = ctx._coverageOptions;
this.options = {
...coverageConfigDefaults,
...config,
provider: this.name,
reportsDirectory: resolve(ctx.config.root, config.reportsDirectory || coverageConfigDefaults.reportsDirectory),
reporter: resolveCoverageReporters(config.reporter || coverageConfigDefaults.reporter),
thresholds: config.thresholds && {
...config.thresholds,
lines: config.thresholds["100"] ? 100 : config.thresholds.lines,
branches: config.thresholds["100"] ? 100 : config.thresholds.branches,
functions: config.thresholds["100"] ? 100 : config.thresholds.functions,
statements: config.thresholds["100"] ? 100 : config.thresholds.statements
}
};
const shard = this.ctx.config.shard;
const tempDirectory = `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`;
this.coverageFilesDirectory = resolve(this.options.reportsDirectory, tempDirectory);
// If --project filter is set pick only roots of resolved projects
this.roots = ctx.config.project?.length ? [...new Set(ctx.projects.map((project) => project.config.root))] : [ctx.config.root];
}
/**
* Check if file matches `coverage.include` but not `coverage.exclude`
*/
isIncluded(_filename, root) {
const roots = root ? [root] : this.roots;
const filename = slash(_filename);
const cacheHit = this.globCache.get(filename);
if (cacheHit !== void 0) return cacheHit;
// File outside project root with default allowExternal
if (this.options.allowExternal === false && roots.every((root) => !filename.startsWith(root))) {
this.globCache.set(filename, false);
return false;
}
// By default `coverage.include` matches all files, except "coverage.exclude"
const glob = this.options.include || "**";
const included = pm.isMatch(filename, glob, {
contains: true,
dot: true,
ignore: this.options.exclude
});
this.globCache.set(filename, included);
return included;
}
async getUntestedFilesByRoot(testedFiles, include, root) {
let includedFiles = await glob(include, {
cwd: root,
ignore: [...this.options.exclude, ...testedFiles.map((file) => slash(file))],
absolute: true,
dot: true,
onlyFiles: true
});
// Run again through picomatch as tinyglobby's exclude pattern is different ({ "exclude": ["math"] } should ignore "src/math.ts")
includedFiles = includedFiles.filter((file) => this.isIncluded(file, root));
if (this.ctx.config.changed) includedFiles = (this.ctx.config.related || []).filter((file) => includedFiles.includes(file));
return includedFiles.map((file) => slash(path.resolve(root, file)));
}
async getUntestedFiles(testedFiles) {
if (this.options.include == null) return [];
const rootMapper = this.getUntestedFilesByRoot.bind(this, testedFiles, this.options.include);
return (await Promise.all(this.roots.map(rootMapper))).flatMap((files) => files);
}
createCoverageMap() {
throw new Error("BaseReporter's createCoverageMap was not overwritten");
}
async generateReports(_, __) {
throw new Error("BaseReporter's generateReports was not overwritten");
}
async parseConfigModule(_) {
throw new Error("BaseReporter's parseConfigModule was not overwritten");
}
resolveOptions() {
return this.options;
}
async clean(clean = true) {
if (clean && existsSync(this.options.reportsDirectory)) await promises.rm(this.options.reportsDirectory, {
recursive: true,
force: true,
maxRetries: 10
});
if (existsSync(this.coverageFilesDirectory)) await promises.rm(this.coverageFilesDirectory, {
recursive: true,
force: true,
maxRetries: 10
});
await promises.mkdir(this.coverageFilesDirectory, { recursive: true });
this.coverageFiles = /* @__PURE__ */ new Map();
this.pendingPromises = [];
}
onAfterSuiteRun({ coverage, environment, projectName, testFiles }) {
if (!coverage) return;
let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT);
if (!entry) {
entry = {};
this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
}
const testFilenames = testFiles.join();
const filename = resolve(this.coverageFilesDirectory, `coverage-${uniqueId++}.json`);
entry[environment] ??= {};
// If there's a result from previous run, overwrite it
entry[environment][testFilenames] = filename;
const promise = promises.writeFile(filename, JSON.stringify(coverage), "utf-8");
this.pendingPromises.push(promise);
}
async readCoverageFiles({ onFileRead, onFinished, onDebug }) {
let index = 0;
const total = this.pendingPromises.length;
await Promise.all(this.pendingPromises);
this.pendingPromises = [];
for (const [projectName, coveragePerProject] of this.coverageFiles.entries()) for (const [environment, coverageByTestfiles] of Object.entries(coveragePerProject)) {
const filenames = Object.values(coverageByTestfiles);
const project = this.ctx.getProjectByName(projectName);
for (const chunk of this.toSlices(filenames, this.options.processingConcurrency)) {
if (onDebug.enabled) {
index += chunk.length;
onDebug(`Reading coverage results ${index}/${total}`);
}
await Promise.all(chunk.map(async (filename) => {
const contents = await promises.readFile(filename, "utf-8");
onFileRead(JSON.parse(contents));
}));
}
await onFinished(project, environment);
}
}
async cleanAfterRun() {
this.coverageFiles = /* @__PURE__ */ new Map();
await promises.rm(this.coverageFilesDirectory, { recursive: true });
// Remove empty reports directory, e.g. when only text-reporter is used
if (readdirSync(this.options.reportsDirectory).length === 0) await promises.rm(this.options.reportsDirectory, { recursive: true });
}
async onTestFailure() {
if (!this.options.reportOnFailure) await this.cleanAfterRun();
}
async reportCoverage(coverageMap, { allTestsRun }) {
await this.generateReports(coverageMap || this.createCoverageMap(), allTestsRun);
if (!(!this.options.cleanOnRerun && this.ctx.config.watch)) await this.cleanAfterRun();
}
async reportThresholds(coverageMap, allTestsRun) {
const resolvedThresholds = this.resolveThresholds(coverageMap);
this.checkThresholds(resolvedThresholds);
if (this.options.thresholds?.autoUpdate && allTestsRun) {
if (!this.ctx.vite.config.configFile) throw new Error("Missing configurationFile. The \"coverage.thresholds.autoUpdate\" can only be enabled when configuration file is used.");
const configFilePath = this.ctx.vite.config.configFile;
const configModule = await this.parseConfigModule(configFilePath);
await this.updateThresholds({
thresholds: resolvedThresholds,
configurationFile: configModule,
onUpdate: () => writeFileSync(configFilePath, configModule.generate().code.replace(this.autoUpdateMarker, ""), "utf-8")
});
}
}
/**
* Constructs collected coverage and users' threshold options into separate sets
* where each threshold set holds their own coverage maps. Threshold set is either
* for specific files defined by glob pattern or global for all other files.
*/
resolveThresholds(coverageMap) {
const resolvedThresholds = [];
const files = coverageMap.files();
const globalCoverageMap = this.createCoverageMap();
for (const key of Object.keys(this.options.thresholds)) {
if (key === "perFile" || key === "autoUpdate" || key === "100" || THRESHOLD_KEYS.includes(key)) continue;
const glob = key;
const globThresholds = resolveGlobThresholds(this.options.thresholds[glob]);
const globCoverageMap = this.createCoverageMap();
const matcher = pm(glob);
const matchingFiles = files.filter((file) => matcher(relative(this.ctx.config.root, file)));
for (const file of matchingFiles) {
const fileCoverage = coverageMap.fileCoverageFor(file);
globCoverageMap.addFileCoverage(fileCoverage);
}
resolvedThresholds.push({
name: glob,
coverageMap: globCoverageMap,
thresholds: globThresholds
});
}
// Global threshold is for all files, even if they are included by glob patterns
for (const file of files) {
const fileCoverage = coverageMap.fileCoverageFor(file);
globalCoverageMap.addFileCoverage(fileCoverage);
}
resolvedThresholds.unshift({
name: GLOBAL_THRESHOLDS_KEY,
coverageMap: globalCoverageMap,
thresholds: {
branches: this.options.thresholds?.branches,
functions: this.options.thresholds?.functions,
lines: this.options.thresholds?.lines,
statements: this.options.thresholds?.statements
}
});
return resolvedThresholds;
}
/**
* Check collected coverage against configured thresholds. Sets exit code to 1 when thresholds not reached.
*/
checkThresholds(allThresholds) {
for (const { coverageMap, thresholds, name } of allThresholds) {
if (thresholds.branches === void 0 && thresholds.functions === void 0 && thresholds.lines === void 0 && thresholds.statements === void 0) continue;
// Construct list of coverage summaries where thresholds are compared against
const summaries = this.options.thresholds?.perFile ? coverageMap.files().map((file) => ({
file,
summary: coverageMap.fileCoverageFor(file).toSummary()
})) : [{
file: null,
summary: coverageMap.getCoverageSummary()
}];
// Check thresholds of each summary
for (const { summary, file } of summaries) for (const thresholdKey of THRESHOLD_KEYS) {
const threshold = thresholds[thresholdKey];
if (threshold === void 0) continue;
/**
* Positive thresholds are treated as minimum coverage percentages (X means: X% of lines must be covered),
* while negative thresholds are treated as maximum uncovered counts (-X means: X lines may be uncovered).
*/
if (threshold >= 0) {
const coverage = summary.data[thresholdKey].pct;
if (coverage < threshold) {
process.exitCode = 1;
/**
* Generate error message based on perFile flag:
* - ERROR: Coverage for statements (33.33%) does not meet threshold (85%) for src/math.ts
* - ERROR: Coverage for statements (50%) does not meet global threshold (85%)
*/
let errorMessage = `ERROR: Coverage for ${thresholdKey} (${coverage}%) does not meet ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${threshold}%)`;
if (this.options.thresholds?.perFile && file) errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
this.ctx.logger.error(errorMessage);
}
} else {
const uncovered = summary.data[thresholdKey].total - summary.data[thresholdKey].covered;
const absoluteThreshold = threshold * -1;
if (uncovered > absoluteThreshold) {
process.exitCode = 1;
/**
* Generate error message based on perFile flag:
* - ERROR: Uncovered statements (33) exceed threshold (30) for src/math.ts
* - ERROR: Uncovered statements (33) exceed global threshold (30)
*/
let errorMessage = `ERROR: Uncovered ${thresholdKey} (${uncovered}) exceed ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${absoluteThreshold})`;
if (this.options.thresholds?.perFile && file) errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
this.ctx.logger.error(errorMessage);
}
}
}
}
}
/**
* Check if current coverage is above configured thresholds and bump the thresholds if needed
*/
async updateThresholds({ thresholds: allThresholds, onUpdate, configurationFile }) {
let updatedThresholds = false;
const config = resolveConfig(configurationFile);
assertConfigurationModule(config);
for (const { coverageMap, thresholds, name } of allThresholds) {
const summaries = this.options.thresholds?.perFile ? coverageMap.files().map((file) => coverageMap.fileCoverageFor(file).toSummary()) : [coverageMap.getCoverageSummary()];
const thresholdsToUpdate = [];
for (const key of THRESHOLD_KEYS) {
const threshold = thresholds[key] ?? 100;
/**
* Positive thresholds are treated as minimum coverage percentages (X means: X% of lines must be covered),
* while negative thresholds are treated as maximum uncovered counts (-X means: X lines may be uncovered).
*/
if (threshold >= 0) {
const actual = Math.min(...summaries.map((summary) => summary[key].pct));
if (actual > threshold) thresholdsToUpdate.push([key, actual]);
} else {
const absoluteThreshold = threshold * -1;
const actual = Math.max(...summaries.map((summary) => summary[key].total - summary[key].covered));
if (actual < absoluteThreshold) {
// If everything was covered, set new threshold to 100% (since a threshold of 0 would be considered as 0%)
const updatedThreshold = actual === 0 ? 100 : actual * -1;
thresholdsToUpdate.push([key, updatedThreshold]);
}
}
}
if (thresholdsToUpdate.length === 0) continue;
updatedThresholds = true;
const thresholdFormatter = typeof this.options.thresholds?.autoUpdate === "function" ? this.options.thresholds?.autoUpdate : (value) => value;
for (const [threshold, newValue] of thresholdsToUpdate) {
const formattedValue = thresholdFormatter(newValue);
if (name === GLOBAL_THRESHOLDS_KEY) config.test.coverage.thresholds[threshold] = formattedValue;
else {
const glob = config.test.coverage.thresholds[name];
glob[threshold] = formattedValue;
}
}
}
if (updatedThresholds) {
this.ctx.logger.log("Updating thresholds to configuration file. You may want to push with updated coverage thresholds.");
onUpdate();
}
}
async mergeReports(coverageMaps) {
const coverageMap = this.createCoverageMap();
for (const coverage of coverageMaps) coverageMap.merge(coverage);
await this.generateReports(coverageMap, true);
}
hasTerminalReporter(reporters) {
return reporters.some(([reporter]) => reporter === "text" || reporter === "text-summary" || reporter === "text-lcov" || reporter === "teamcity");
}
toSlices(array, size) {
return array.reduce((chunks, item) => {
const index = Math.max(0, chunks.length - 1);
const lastChunk = chunks[index] || [];
chunks[index] = lastChunk;
if (lastChunk.length >= size) chunks.push([item]);
else lastChunk.push(item);
return chunks;
}, []);
}
// TODO: should this be abstracted in `project`/`vitest` instead?
// if we decide to keep `viteModuleRunner: false`, we will need to abstract transformation in both main thread and tests
// custom --import=module.registerHooks need to be transformed as well somehow
async transformFile(url, project, viteEnvironment) {
const config = project.config;
// vite is disabled, should transform manually if possible
if (config.experimental.viteModuleRunner === false) {
const pathname = url.split("?")[0];
const filename = pathname.startsWith("file://") ? fileURLToPath(pathname) : pathname;
const extension = path.extname(filename);
if (!(extension === ".ts" || extension === ".mts" || extension === ".cts")) return {
code: await promises.readFile(filename, "utf-8"),
map: null
};
if (!module$1.stripTypeScriptTypes) throw new Error(`Cannot parse '${url}' because "module.stripTypeScriptTypes" is not supported. TypeScript coverage requires Node.js 22.15 or higher. This is NOT a bug of Vitest.`);
const isTransform = process.execArgv.includes("--experimental-transform-types") || config.execArgv.includes("--experimental-transform-types") || process.env.NODE_OPTIONS?.includes("--experimental-transform-types") || config.env?.NODE_OPTIONS?.includes("--experimental-transform-types");
const code = await promises.readFile(filename, "utf-8");
return {
code: module$1.stripTypeScriptTypes(code, { mode: isTransform ? "transform" : "strip" }),
map: null
};
}
if (project.isBrowserEnabled() || viteEnvironment === "__browser__") {
const result = await (project.browser?.vite.environments.client || project.vite.environments.client).transformRequest(url);
if (result) return result;
}
return project.vite.environments[viteEnvironment].transformRequest(url);
}
createUncoveredFileTransformer(ctx) {
const projects = new Set([...ctx.projects, ctx.getRootProject()]);
return async (filename) => {
let lastError;
for (const project of projects) {
const root = project.config.root;
// On Windows root doesn't start with "/" while filenames do
if (!filename.startsWith(root) && !filename.startsWith(`/${root}`)) continue;
try {
const environment = project.config.environment;
const viteEnvironment = environment === "jsdom" || environment === "happy-dom" ? "client" : "ssr";
return await this.transformFile(filename, project, viteEnvironment);
} catch (err) {
lastError = err;
}
}
// All vite servers failed to transform the file
throw lastError;
};
}
}
/**
* Narrow down `unknown` glob thresholds to resolved ones
*/
function resolveGlobThresholds(thresholds) {
if (!thresholds || typeof thresholds !== "object") return {};
if (100 in thresholds && thresholds[100] === true) return {
lines: 100,
branches: 100,
functions: 100,
statements: 100
};
return {
lines: "lines" in thresholds && typeof thresholds.lines === "number" ? thresholds.lines : void 0,
branches: "branches" in thresholds && typeof thresholds.branches === "number" ? thresholds.branches : void 0,
functions: "functions" in thresholds && typeof thresholds.functions === "number" ? thresholds.functions : void 0,
statements: "statements" in thresholds && typeof thresholds.statements === "number" ? thresholds.statements : void 0
};
}
function assertConfigurationModule(config) {
try {
// @ts-expect-error -- Intentional unsafe null pointer check as wrapped in try-catch
if (typeof config.test.coverage.thresholds !== "object") throw new TypeError("Expected config.test.coverage.thresholds to be an object");
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Unable to parse thresholds from configuration file: ${message}`);
}
}
function resolveConfig(configModule) {
const mod = configModule.exports.default;
try {
// Check for "export default { test: {...} }"
if (mod.$type === "object") return mod;
// "export default defineConfig(...)"
let config = resolveDefineConfig(mod);
if (config) return config;
// "export default mergeConfig(..., defineConfig(...))"
if (mod.$type === "function-call" && mod.$callee === "mergeConfig") {
config = resolveMergeConfig(mod);
if (config) return config;
}
} catch (error) {
// Reduce magicast's verbose errors to readable ones
throw new Error(error instanceof Error ? error.message : String(error));
}
throw new Error("Failed to update coverage thresholds. Configuration file is too complex.");
}
function resolveDefineConfig(mod) {
if (mod.$type === "function-call" && mod.$callee === "defineConfig") {
// "export default defineConfig({ test: {...} })"
if (mod.$args[0].$type === "object") return mod.$args[0];
if (mod.$args[0].$type === "arrow-function-expression") {
if (mod.$args[0].$body.$type === "object")
// "export default defineConfig(() => ({ test: {...} }))"
return mod.$args[0].$body;
// "export default defineConfig(() => mergeConfig({...}, ...))"
const config = resolveMergeConfig(mod.$args[0].$body);
if (config) return config;
}
}
}
function resolveMergeConfig(mod) {
if (mod.$type === "function-call" && mod.$callee === "mergeConfig") for (const arg of mod.$args) {
const config = resolveDefineConfig(arg);
if (config) return config;
}
}
export { BaseCoverageProvider as B, RandomSequencer as R, BaseSequencer as a, resolveApiServerConfig as b, getCoverageProvider as g, hash as h, isBrowserEnabled as i, resolveConfig$1 as r };
import nodeos__default from 'node:os';
import './env.D4Lgay0q.js';
import { isCI } from 'std-env';
const defaultInclude = ["**/*.{test,spec}.?(c|m)[jt]s?(x)"];
const defaultExclude = ["**/node_modules/**", "**/.git/**"];
const benchmarkConfigDefaults = {
include: ["**/*.{bench,benchmark}.?(c|m)[jt]s?(x)"],
exclude: defaultExclude,
includeSource: [],
reporters: ["default"],
includeSamples: false
};
// These are the generic defaults for coverage. Providers may also set some provider specific defaults.
const coverageConfigDefaults = {
provider: "v8",
enabled: false,
clean: true,
cleanOnRerun: true,
reportsDirectory: "./coverage",
exclude: [],
reportOnFailure: false,
reporter: [
["text", {}],
["html", {}],
["clover", {}],
["json", {}]
],
allowExternal: false,
excludeAfterRemap: false,
processingConcurrency: Math.min(20, nodeos__default.availableParallelism?.() ?? nodeos__default.cpus().length)
};
const fakeTimersDefaults = {
loopLimit: 1e4,
shouldClearNativeTimers: true
};
const configDefaults = Object.freeze({
allowOnly: !isCI,
isolate: true,
watch: !isCI && process.stdin.isTTY,
globals: false,
environment: "node",
clearMocks: false,
restoreMocks: false,
mockReset: false,
unstubGlobals: false,
unstubEnvs: false,
include: defaultInclude,
exclude: defaultExclude,
teardownTimeout: 1e4,
forceRerunTriggers: ["**/package.json/**", "**/{vitest,vite}.config.*/**"],
update: false,
reporters: [],
silent: false,
hideSkippedTests: false,
api: false,
ui: false,
uiBase: "/__vitest__/",
open: !isCI,
css: { include: [] },
coverage: coverageConfigDefaults,
fakeTimers: fakeTimersDefaults,
maxConcurrency: 5,
dangerouslyIgnoreUnhandledErrors: false,
typecheck: {
checker: "tsc",
include: ["**/*.{test,spec}-d.?(c|m)[jt]s?(x)"],
exclude: defaultExclude
},
slowTestThreshold: 300,
disableConsoleIntercept: false
});
export { coverageConfigDefaults as a, defaultInclude as b, configDefaults as c, defaultExclude as d, benchmarkConfigDefaults as e };
import { PromisifyAssertion, Tester, ExpectStatic } from '@vitest/expect';
import { Plugin } from '@vitest/pretty-format';
import { SnapshotState } from '@vitest/snapshot';
import { B as BenchmarkResult } from './benchmark.d.DAaHLpsq.js';
import { U as UserConsoleLog } from './rpc.d.CUhiUEld.js';
interface SnapshotMatcher<T> {
<U extends { [P in keyof T] : any }>(snapshot: Partial<U>, hint?: string): void;
(hint?: string): void;
}
interface InlineSnapshotMatcher<T> {
<U extends { [P in keyof T] : any }>(properties: Partial<U>, snapshot?: string, hint?: string): void;
(hint?: string): void;
}
declare module "@vitest/expect" {
interface MatcherState {
environment: string;
snapshotState: SnapshotState;
}
interface ExpectPollOptions {
interval?: number;
timeout?: number;
message?: string;
}
interface ExpectStatic {
assert: Chai.AssertStatic;
unreachable: (message?: string) => never;
soft: <T>(actual: T, message?: string) => Assertion<T>;
poll: <T>(actual: () => T, options?: ExpectPollOptions) => PromisifyAssertion<Awaited<T>>;
addEqualityTesters: (testers: Array<Tester>) => void;
assertions: (expected: number) => void;
hasAssertions: () => void;
addSnapshotSerializer: (plugin: Plugin) => void;
}
interface Assertion<T> {
matchSnapshot: SnapshotMatcher<T>;
toMatchSnapshot: SnapshotMatcher<T>;
toMatchInlineSnapshot: InlineSnapshotMatcher<T>;
/**
* Checks that an error thrown by a function matches a previously recorded snapshot.
*
* @param hint - Optional custom error message.
*
* @example
* expect(functionWithError).toThrowErrorMatchingSnapshot();
*/
toThrowErrorMatchingSnapshot: (hint?: string) => void;
/**
* Checks that an error thrown by a function matches an inline snapshot within the test file.
* Useful for keeping snapshots close to the test code.
*
* @param snapshot - Optional inline snapshot string to match.
* @param hint - Optional custom error message.
*
* @example
* const throwError = () => { throw new Error('Error occurred') };
* expect(throwError).toThrowErrorMatchingInlineSnapshot(`"Error occurred"`);
*/
toThrowErrorMatchingInlineSnapshot: (snapshot?: string, hint?: string) => void;
/**
* Compares the received value to a snapshot saved in a specified file.
* Useful for cases where snapshot content is large or needs to be shared across tests.
*
* @param filepath - Path to the snapshot file.
* @param hint - Optional custom error message.
*
* @example
* await expect(largeData).toMatchFileSnapshot('path/to/snapshot.json');
*/
toMatchFileSnapshot: (filepath: string, hint?: string) => Promise<void>;
}
}
declare module "@vitest/runner" {
interface TestContext {
/**
* `expect` instance bound to the current test.
*
* This API is useful for running snapshot tests concurrently because global expect cannot track them.
*/
readonly expect: ExpectStatic;
/** @internal */
_local: boolean;
}
interface TaskMeta {
typecheck?: boolean;
benchmark?: boolean;
failScreenshotPath?: string;
}
interface File {
prepareDuration?: number;
environmentLoad?: number;
}
interface TaskBase {
logs?: UserConsoleLog[];
}
interface TaskResult {
benchmark?: BenchmarkResult;
}
}
import { g as globalApis } from './constants.CPYnjOGj.js';
import { i as index } from './index.D3wDRGBz.js';
import './test.CnO2BIt2.js';
import '@vitest/runner';
import '@vitest/utils/helpers';
import '@vitest/utils/timers';
import './benchmark.BoqSLF53.js';
import '@vitest/runner/utils';
import './utils.DT4VyRyl.js';
import '@vitest/expect';
import '@vitest/utils/error';
import 'pathe';
import '@vitest/snapshot';
import '@vitest/spy';
import '@vitest/utils/offset';
import '@vitest/utils/source-map';
import './_commonjsHelpers.D26ty3Ew.js';
import './rpc.DcRWTy5G.js';
import './index.Chj8NDwU.js';
import './evaluatedModules.Dg1zASAC.js';
import 'vite/module-runner';
import 'expect-type';
function registerApiGlobally() {
globalApis.forEach((api) => {
// @ts-expect-error I know what I am doing :P
globalThis[api] = index[api];
});
}
export { registerApiGlobally };
import { chai } from '@vitest/expect';
import { l as loadDiffConfig, a as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.BoY7R7rC.js';
import { r as rpc } from './rpc.DcRWTy5G.js';
import { g as getWorkerState } from './utils.DT4VyRyl.js';
import { T as TestRunner, N as NodeBenchmarkRunner } from './test.CnO2BIt2.js';
function setupChaiConfig(config) {
Object.assign(chai.config, config);
}
async function resolveSnapshotEnvironment(config, moduleRunner) {
if (!config.snapshotEnvironment) {
const { VitestNodeSnapshotEnvironment } = await import('./node.CrSEwhm4.js');
return new VitestNodeSnapshotEnvironment();
}
const mod = await moduleRunner.import(config.snapshotEnvironment);
if (typeof mod.default !== "object" || !mod.default) throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`");
return mod.default;
}
async function getTestRunnerConstructor(config, moduleRunner) {
if (!config.runner) return config.mode === "test" ? TestRunner : NodeBenchmarkRunner;
const mod = await moduleRunner.import(config.runner);
if (!mod.default && typeof mod.default !== "function") throw new Error(`Runner must export a default function, but got ${typeof mod.default} imported from ${config.runner}`);
return mod.default;
}
async function resolveTestRunner(config, moduleRunner, traces) {
const testRunner = new (await (getTestRunnerConstructor(config, moduleRunner)))(config);
// inject private executor to every runner
Object.defineProperty(testRunner, "moduleRunner", {
value: moduleRunner,
enumerable: false,
configurable: false
});
if (!testRunner.config) testRunner.config = config;
if (!testRunner.importFile) throw new Error("Runner must implement \"importFile\" method.");
if ("__setTraces" in testRunner) testRunner.__setTraces(traces);
const [diffOptions] = await Promise.all([loadDiffConfig(config, moduleRunner), loadSnapshotSerializers(config, moduleRunner)]);
testRunner.config.diffOptions = diffOptions;
// patch some methods, so custom runners don't need to call RPC
const originalOnTaskUpdate = testRunner.onTaskUpdate;
testRunner.onTaskUpdate = async (task, events) => {
const p = rpc().onTaskUpdate(task, events);
await originalOnTaskUpdate?.call(testRunner, task, events);
return p;
};
// patch some methods, so custom runners don't need to call RPC
const originalOnTestAnnotate = testRunner.onTestAnnotate;
testRunner.onTestAnnotate = async (test, annotation) => {
const p = rpc().onTaskArtifactRecord(test.id, {
type: "internal:annotation",
location: annotation.location,
annotation
});
const overriddenResult = await originalOnTestAnnotate?.call(testRunner, test, annotation);
const vitestResult = await p;
return overriddenResult || vitestResult.annotation;
};
const originalOnTestArtifactRecord = testRunner.onTestArtifactRecord;
testRunner.onTestArtifactRecord = async (test, artifact) => {
const p = rpc().onTaskArtifactRecord(test.id, artifact);
const overriddenResult = await originalOnTestArtifactRecord?.call(testRunner, test, artifact);
const vitestResult = await p;
return overriddenResult || vitestResult;
};
const originalOnCollectStart = testRunner.onCollectStart;
testRunner.onCollectStart = async (file) => {
await rpc().onQueued(file);
await originalOnCollectStart?.call(testRunner, file);
};
const originalOnCollected = testRunner.onCollected;
testRunner.onCollected = async (files) => {
const state = getWorkerState();
files.forEach((file) => {
file.prepareDuration = state.durations.prepare;
file.environmentLoad = state.durations.environment;
// should be collected only for a single test file in a batch
state.durations.prepare = 0;
state.durations.environment = 0;
});
// Strip function conditions from retry config before sending via RPC
// Functions cannot be cloned by structured clone algorithm
const sanitizeRetryConditions = (task) => {
if (task.retry && typeof task.retry === "object" && typeof task.retry.condition === "function")
// Remove function condition - it can't be serialized
task.retry = {
...task.retry,
condition: void 0
};
if (task.tasks) task.tasks.forEach(sanitizeRetryConditions);
};
files.forEach(sanitizeRetryConditions);
rpc().onCollected(files);
await originalOnCollected?.call(testRunner, files);
};
const originalOnAfterRun = testRunner.onAfterRunFiles;
testRunner.onAfterRunFiles = async (files) => {
const state = getWorkerState();
const coverage = await takeCoverageInsideWorker(config.coverage, moduleRunner);
if (coverage) rpc().onAfterSuiteRun({
coverage,
testFiles: files.map((file) => file.name).sort(),
environment: state.environment.viteEnvironment || state.environment.name,
projectName: state.ctx.projectName
});
await originalOnAfterRun?.call(testRunner, files);
};
const originalOnAfterRunTask = testRunner.onAfterRunTask;
testRunner.onAfterRunTask = async (test) => {
if (config.bail && test.result?.state === "fail") {
if (1 + await rpc().getCountOfFailedTests() >= config.bail) {
rpc().onCancel("test-failure");
testRunner.cancel?.("test-failure");
}
}
await originalOnAfterRunTask?.call(testRunner, test);
};
return testRunner;
}
export { resolveSnapshotEnvironment as a, resolveTestRunner as r, setupChaiConfig as s };
import { v as vi, N as NodeBenchmarkRunner, T as TestRunner, a as assert, c as createExpect, g as globalExpect, i as inject, s as should, b as vitest } from './test.CnO2BIt2.js';
import { b as bench } from './benchmark.BoqSLF53.js';
import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js';
import { expectTypeOf } from 'expect-type';
import { afterAll, afterEach, aroundAll, aroundEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, recordArtifact, suite, test } from '@vitest/runner';
import { chai } from '@vitest/expect';
const assertType = function assertType() {};
var index = /*#__PURE__*/Object.freeze({
__proto__: null,
BenchmarkRunner: NodeBenchmarkRunner,
EvaluatedModules: VitestEvaluatedModules,
TestRunner: TestRunner,
afterAll: afterAll,
afterEach: afterEach,
aroundAll: aroundAll,
aroundEach: aroundEach,
assert: assert,
assertType: assertType,
beforeAll: beforeAll,
beforeEach: beforeEach,
bench: bench,
chai: chai,
createExpect: createExpect,
describe: describe,
expect: globalExpect,
expectTypeOf: expectTypeOf,
inject: inject,
it: it,
onTestFailed: onTestFailed,
onTestFinished: onTestFinished,
recordArtifact: recordArtifact,
should: should,
suite: suite,
test: test,
vi: vi,
vitest: vitest
});
export { assertType as a, index as i };

Sorry, the diff of this file is too big to display

import fs from 'node:fs';
import { getTasks, getFullName, getTests } from '@vitest/runner/utils';
import * as pathe from 'pathe';
import c from 'tinyrainbow';
import { g as getStateSymbol, t as truncateString, F as F_RIGHT, D as DefaultReporter, f as formatProjectName, s as separator } from './index.De5aIHUc.js';
import { stripVTControlCharacters } from 'node:util';
import { notNullish } from '@vitest/utils/helpers';
function createBenchmarkJsonReport(files) {
const report = { files: [] };
for (const file of files) {
const groups = [];
for (const task of getTasks(file)) if (task?.type === "suite") {
const benchmarks = [];
for (const t of task.tasks) {
const benchmark = t.meta.benchmark && t.result?.benchmark;
if (benchmark) benchmarks.push({
id: t.id,
...benchmark,
samples: []
});
}
if (benchmarks.length) groups.push({
fullName: getFullName(task, " > "),
benchmarks
});
}
report.files.push({
filepath: file.filepath,
groups
});
}
return report;
}
function flattenFormattedBenchmarkReport(report) {
const flat = {};
for (const file of report.files) for (const group of file.groups) for (const t of group.benchmarks) flat[t.id] = t;
return flat;
}
const outputMap = /* @__PURE__ */ new WeakMap();
function formatNumber(number) {
const res = String(number.toFixed(number < 100 ? 4 : 2)).split(".");
return res[0].replace(/(?=(?:\d{3})+$)\B/g, ",") + (res[1] ? `.${res[1]}` : "");
}
const tableHead = [
"name",
"hz",
"min",
"max",
"mean",
"p75",
"p99",
"p995",
"p999",
"rme",
"samples"
];
function renderBenchmarkItems(result) {
return [
result.name,
formatNumber(result.hz || 0),
formatNumber(result.min || 0),
formatNumber(result.max || 0),
formatNumber(result.mean || 0),
formatNumber(result.p75 || 0),
formatNumber(result.p99 || 0),
formatNumber(result.p995 || 0),
formatNumber(result.p999 || 0),
`±${(result.rme || 0).toFixed(2)}%`,
(result.sampleCount || 0).toString()
];
}
function computeColumnWidths(results) {
const rows = [tableHead, ...results.map((v) => renderBenchmarkItems(v))];
return Array.from(tableHead, (_, i) => Math.max(...rows.map((row) => stripVTControlCharacters(row[i]).length)));
}
function padRow(row, widths) {
return row.map((v, i) => i ? v.padStart(widths[i], " ") : v.padEnd(widths[i], " "));
}
function renderTableHead(widths) {
return " ".repeat(3) + padRow(tableHead, widths).map(c.bold).join(" ");
}
function renderBenchmark(result, widths) {
const padded = padRow(renderBenchmarkItems(result), widths);
return [
padded[0],
c.blue(padded[1]),
c.cyan(padded[2]),
c.cyan(padded[3]),
c.cyan(padded[4]),
c.cyan(padded[5]),
c.cyan(padded[6]),
c.cyan(padded[7]),
c.cyan(padded[8]),
c.dim(padded[9]),
c.dim(padded[10])
].join(" ");
}
function renderTable(options) {
const output = [];
const benchMap = {};
for (const task of options.tasks) if (task.meta.benchmark && task.result?.benchmark) benchMap[task.id] = {
current: task.result.benchmark,
baseline: options.compare?.[task.id]
};
const benchCount = Object.entries(benchMap).length;
const columnWidths = computeColumnWidths(Object.values(benchMap).flatMap((v) => [v.current, v.baseline]).filter(notNullish));
let idx = 0;
const padding = " ".repeat(1 );
for (const task of options.tasks) {
const duration = task.result?.duration;
const bench = benchMap[task.id];
let prefix = "";
if (idx === 0 && task.meta?.benchmark) prefix += `${renderTableHead(columnWidths)}\n${padding}`;
prefix += ` ${getStateSymbol(task)} `;
let suffix = "";
if (task.type === "suite") suffix += c.dim(` (${getTests(task).length})`);
if (task.mode === "skip" || task.mode === "todo") suffix += c.dim(c.gray(" [skipped]"));
if (duration != null) {
const color = duration > options.slowTestThreshold ? c.yellow : c.green;
suffix += color(` ${Math.round(duration)}${c.dim("ms")}`);
}
if (options.showHeap && task.result?.heap != null) suffix += c.magenta(` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`);
if (bench) {
let body = renderBenchmark(bench.current, columnWidths);
if (options.compare && bench.baseline) {
if (bench.current.hz) {
const diff = bench.current.hz / bench.baseline.hz;
const diffFixed = diff.toFixed(2);
if (diffFixed === "1.0.0") body += c.gray(` [${diffFixed}x]`);
if (diff > 1) body += c.blue(` [${diffFixed}x] ⇑`);
else body += c.red(` [${diffFixed}x] ⇓`);
}
output.push(padding + prefix + body + suffix);
const bodyBaseline = renderBenchmark(bench.baseline, columnWidths);
output.push(`${padding} ${bodyBaseline} ${c.dim("(baseline)")}`);
} else {
if (bench.current.rank === 1 && benchCount > 1) body += c.bold(c.green(" fastest"));
if (bench.current.rank === benchCount && benchCount > 2) body += c.bold(c.gray(" slowest"));
output.push(padding + prefix + body + suffix);
}
} else output.push(padding + prefix + task.name + suffix);
if (task.result?.state !== "pass" && outputMap.get(task) != null) {
let data = outputMap.get(task);
if (typeof data === "string") {
data = stripVTControlCharacters(data.trim().split("\n").filter(Boolean).pop());
if (data === "") data = void 0;
}
if (data != null) {
const out = ` ${" ".repeat(options.level)}${F_RIGHT} ${data}`;
output.push(c.gray(truncateString(out, options.columns)));
}
}
idx++;
}
return output.filter(Boolean).join("\n");
}
class BenchmarkReporter extends DefaultReporter {
compare;
async onInit(ctx) {
super.onInit(ctx);
if (this.ctx.config.benchmark?.compare) {
const compareFile = pathe.resolve(this.ctx.config.root, this.ctx.config.benchmark?.compare);
try {
this.compare = flattenFormattedBenchmarkReport(JSON.parse(await fs.promises.readFile(compareFile, "utf-8")));
} catch (e) {
this.error(`Failed to read '${compareFile}'`, e);
}
}
}
onTaskUpdate(packs) {
for (const pack of packs) {
const task = this.ctx.state.idMap.get(pack[0]);
if (task?.type === "suite" && task.result?.state !== "run") task.tasks.filter((task) => task.result?.benchmark).sort((benchA, benchB) => benchA.result.benchmark.mean - benchB.result.benchmark.mean).forEach((bench, idx) => {
bench.result.benchmark.rank = Number(idx) + 1;
});
}
}
onTestSuiteResult(testSuite) {
super.onTestSuiteResult(testSuite);
this.printSuiteTable(testSuite);
}
printTestModule(testModule) {
this.printSuiteTable(testModule);
}
printSuiteTable(testTask) {
const state = testTask.state();
if (state === "pending" || state === "queued") return;
const benches = testTask.task.tasks.filter((t) => t.meta.benchmark);
const duration = testTask.task.result?.duration || 0;
if (benches.length > 0 && benches.every((t) => t.result?.state !== "run" && t.result?.state !== "queued")) {
let title = `\n ${getStateSymbol(testTask.task)} ${formatProjectName(testTask.project)}${getFullName(testTask.task, separator)}`;
if (duration != null && duration > this.ctx.config.slowTestThreshold) title += c.yellow(` ${Math.round(duration)}${c.dim("ms")}`);
this.log(title);
this.log(renderTable({
tasks: benches,
level: 1,
columns: this.ctx.logger.getColumns(),
compare: this.compare,
showHeap: this.ctx.config.logHeapUsage,
slowTestThreshold: this.ctx.config.slowTestThreshold
}));
}
}
async onTestRunEnd(testModules, unhandledErrors, reason) {
super.onTestRunEnd(testModules, unhandledErrors, reason);
// write output for future comparison
let outputFile = this.ctx.config.benchmark?.outputJson;
if (outputFile) {
outputFile = pathe.resolve(this.ctx.config.root, outputFile);
const outputDirectory = pathe.dirname(outputFile);
if (!fs.existsSync(outputDirectory)) await fs.promises.mkdir(outputDirectory, { recursive: true });
const output = createBenchmarkJsonReport(testModules.map((t) => t.task.file));
await fs.promises.writeFile(outputFile, JSON.stringify(output, null, 2));
this.log(`Benchmark report written to ${outputFile}`);
}
}
}
class VerboseBenchmarkReporter extends BenchmarkReporter {
verbose = true;
}
const BenchmarkReportsMap = {
default: BenchmarkReporter,
verbose: VerboseBenchmarkReporter
};
export { BenchmarkReporter as B, VerboseBenchmarkReporter as V, BenchmarkReportsMap as a };
import { DevEnvironment } from 'vite';
import { V as Vitest, T as TestProject, a as TestProjectConfiguration } from './reporters.d.DPe11uSn.js';
/**
* Generate a unique cache identifier.
*
* Return `false` to disable caching of the file.
* @experimental
*/
interface CacheKeyIdGenerator {
(context: CacheKeyIdGeneratorContext): string | undefined | null | false;
}
/**
* @experimental
*/
interface CacheKeyIdGeneratorContext {
environment: DevEnvironment;
id: string;
sourceCode: string;
}
interface VitestPluginContext {
vitest: Vitest;
project: TestProject;
injectTestProjects: (config: TestProjectConfiguration | TestProjectConfiguration[]) => Promise<TestProject[]>;
/**
* Define a generator that will be applied before hashing the cache key.
*
* Use this to make sure Vitest generates correct hash. It is a good idea
* to define this function if your plugin can be registered with different options.
*
* This is called only if `experimental.fsModuleCache` is defined.
* @experimental
*/
experimental_defineCacheKeyGenerator: (callback: CacheKeyIdGenerator) => void;
}
export type { CacheKeyIdGenerator as C, VitestPluginContext as V, CacheKeyIdGeneratorContext as a };

Sorry, the diff of this file is too big to display

import { File, TestArtifact, TaskResultPack, TaskEventPack, CancelReason } from '@vitest/runner';
import { SnapshotResult } from '@vitest/snapshot';
import { FetchFunctionOptions, FetchResult } from 'vite/module-runner';
import { O as OTELCarrier } from './traces.d.402V_yFI.js';
interface AfterSuiteRunMeta {
coverage?: unknown;
testFiles: string[];
environment: string;
projectName?: string;
}
interface UserConsoleLog {
content: string;
origin?: string;
browser?: boolean;
type: "stdout" | "stderr";
taskId?: string;
time: number;
size: number;
}
interface ModuleGraphData {
graph: Record<string, string[]>;
externalized: string[];
inlined: string[];
}
interface ProvidedContext {}
interface ResolveFunctionResult {
id: string;
file: string;
url: string;
}
interface FetchCachedFileSystemResult {
cached: true;
tmp: string;
id: string;
file: string | null;
url: string;
invalidate: boolean;
}
type LabelColor = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white";
interface RuntimeRPC {
fetch: (id: string, importer: string | undefined, environment: string, options?: FetchFunctionOptions, otelCarrier?: OTELCarrier) => Promise<FetchResult | FetchCachedFileSystemResult>;
resolve: (id: string, importer: string | undefined, environment: string) => Promise<ResolveFunctionResult | null>;
transform: (id: string) => Promise<{
code?: string;
}>;
onUserConsoleLog: (log: UserConsoleLog) => void;
onUnhandledError: (err: unknown, type: string) => void;
onQueued: (file: File) => void;
onCollected: (files: File[]) => Promise<void>;
onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void;
onTaskArtifactRecord: <Artifact extends TestArtifact>(testId: string, artifact: Artifact) => Promise<Artifact>;
onTaskUpdate: (pack: TaskResultPack[], events: TaskEventPack[]) => Promise<void>;
onCancel: (reason: CancelReason) => void;
getCountOfFailedTests: () => number;
snapshotSaved: (snapshot: SnapshotResult) => void;
resolveSnapshotPath: (testPath: string) => string;
ensureModuleGraphEntry: (id: string, importer: string) => void;
}
interface RunnerRPC {
onCancel: (reason: CancelReason) => void;
}
export type { AfterSuiteRunMeta as A, LabelColor as L, ModuleGraphData as M, ProvidedContext as P, RuntimeRPC as R, UserConsoleLog as U, RunnerRPC as a };
import { r as resolveCoverageProviderModule } from './coverage.D_JHT54q.js';
import { addSerializer } from '@vitest/snapshot';
import { setSafeTimers } from '@vitest/utils/timers';
import { g as getWorkerState } from './utils.DT4VyRyl.js';
async function startCoverageInsideWorker(options, loader, runtimeOptions) {
const coverageModule = await resolveCoverageProviderModule(options, loader);
if (coverageModule) return coverageModule.startCoverage?.(runtimeOptions);
return null;
}
async function takeCoverageInsideWorker(options, loader) {
const coverageModule = await resolveCoverageProviderModule(options, loader);
if (coverageModule) return coverageModule.takeCoverage?.({ moduleExecutionInfo: loader.moduleExecutionInfo });
return null;
}
async function stopCoverageInsideWorker(options, loader, runtimeOptions) {
const coverageModule = await resolveCoverageProviderModule(options, loader);
if (coverageModule) return coverageModule.stopCoverage?.(runtimeOptions);
return null;
}
let globalSetup = false;
async function setupCommonEnv(config) {
setupDefines(config);
setupEnv(config.env);
if (globalSetup) return;
globalSetup = true;
setSafeTimers();
if (config.globals) (await import('./globals.AhCakrmA.js')).registerApiGlobally();
}
function setupDefines(config) {
for (const key in config.defines) globalThis[key] = config.defines[key];
}
function setupEnv(env) {
const state = getWorkerState();
// same boolean-to-string assignment as VitestPlugin.configResolved
const { PROD, DEV, ...restEnvs } = env;
state.metaEnv.PROD = PROD;
state.metaEnv.DEV = DEV;
for (const key in restEnvs) state.metaEnv[key] = env[key];
}
async function loadDiffConfig(config, moduleRunner) {
if (typeof config.diff === "object") return config.diff;
if (typeof config.diff !== "string") return;
const diffModule = await moduleRunner.import(config.diff);
if (diffModule && typeof diffModule.default === "object" && diffModule.default != null) return diffModule.default;
else throw new Error(`invalid diff config file ${config.diff}. Must have a default export with config object`);
}
async function loadSnapshotSerializers(config, moduleRunner) {
const files = config.snapshotSerializers;
(await Promise.all(files.map(async (file) => {
const mo = await moduleRunner.import(file);
if (!mo || typeof mo.default !== "object" || mo.default === null) throw new Error(`invalid snapshot serializer file ${file}. Must export a default object`);
const config = mo.default;
if (typeof config.test !== "function" || typeof config.serialize !== "function" && typeof config.print !== "function") throw new TypeError(`invalid snapshot serializer in ${file}. Must have a 'test' method along with either a 'serialize' or 'print' method.`);
return config;
}))).forEach((serializer) => addSerializer(serializer));
}
export { loadSnapshotSerializers as a, startCoverageInsideWorker as b, stopCoverageInsideWorker as c, loadDiffConfig as l, setupCommonEnv as s, takeCoverageInsideWorker as t };

Sorry, the diff of this file is too big to display

import { FileSpecification, Task, CancelReason } from '@vitest/runner';
import { EvaluatedModules } from 'vite/module-runner';
import { S as SerializedConfig } from './config.d.pC9164XK.js';
import { E as Environment } from './environment.d.CrsxCzP1.js';
import { R as RuntimeRPC, a as RunnerRPC } from './rpc.d.CUhiUEld.js';
//#region src/messages.d.ts
declare const TYPE_REQUEST: "q";
interface RpcRequest {
/**
* Type
*/
t: typeof TYPE_REQUEST;
/**
* ID
*/
i?: string;
/**
* Method
*/
m: string;
/**
* Arguments
*/
a: any[];
/**
* Optional
*/
o?: boolean;
}
//#endregion
//#region src/utils.d.ts
type ArgumentsType<T> = T extends ((...args: infer A) => any) ? A : never;
type ReturnType<T> = T extends ((...args: any) => infer R) ? R : never;
type Thenable<T> = T | PromiseLike<T>;
//#endregion
//#region src/main.d.ts
type PromisifyFn<T> = ReturnType<T> extends Promise<any> ? T : (...args: ArgumentsType<T>) => Promise<Awaited<ReturnType<T>>>;
type BirpcResolver<This> = (this: This, name: string, resolved: (...args: unknown[]) => unknown) => Thenable<((...args: any[]) => any) | undefined>;
interface ChannelOptions {
/**
* Function to post raw message
*/
post: (data: any, ...extras: any[]) => Thenable<any>;
/**
* Listener to receive raw message
*/
on: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>;
/**
* Clear the listener when `$close` is called
*/
off?: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>;
/**
* Custom function to serialize data
*
* by default it passes the data as-is
*/
serialize?: (data: any) => any;
/**
* Custom function to deserialize data
*
* by default it passes the data as-is
*/
deserialize?: (data: any) => any;
/**
* Call the methods with the RPC context or the original functions object
*/
bind?: 'rpc' | 'functions';
/**
* Custom meta data to attached to the RPC instance's `$meta` property
*/
meta?: any;
}
interface EventOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> {
/**
* Names of remote functions that do not need response.
*/
eventNames?: (keyof RemoteFunctions)[];
/**
* Maximum timeout for waiting for response, in milliseconds.
*
* @default 60_000
*/
timeout?: number;
/**
* Whether to proxy the remote functions.
*
* When `proxify` is false, calling the remote function
* with `rpc.$call('method', ...args)` instead of `rpc.method(...args)`
* explicitly is required.
*
* @default true
*/
proxify?: Proxify;
/**
* Custom resolver to resolve function to be called
*
* For advanced use cases only
*/
resolver?: BirpcResolver<BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>>;
/**
* Hook triggered before an event is sent to the remote
*
* @param req - Request parameters
* @param next - Function to continue the request
* @param resolve - Function to resolve the response directly
*/
onRequest?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, req: RpcRequest, next: (req?: RpcRequest) => Promise<any>, resolve: (res: any) => void) => void | Promise<void>;
/**
* Custom error handler for errors occurred in local functions being called
*
* @returns `true` to prevent the error from being thrown
*/
onFunctionError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName: string, args: any[]) => boolean | void;
/**
* Custom error handler for errors occurred during serialization or messsaging
*
* @returns `true` to prevent the error from being thrown
*/
onGeneralError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName?: string, args?: any[]) => boolean | void;
/**
* Custom error handler for timeouts
*
* @returns `true` to prevent the error from being thrown
*/
onTimeoutError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, functionName: string, args: any[]) => boolean | void;
}
type BirpcOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = EventOptions<RemoteFunctions, LocalFunctions, Proxify> & ChannelOptions;
type BirpcFn<T> = PromisifyFn<T> & {
/**
* Send event without asking for response
*/
asEvent: (...args: ArgumentsType<T>) => Promise<void>;
};
interface BirpcReturnBuiltin<RemoteFunctions, LocalFunctions = Record<string, unknown>> {
/**
* Raw functions object
*/
$functions: LocalFunctions;
/**
* Whether the RPC is closed
*/
readonly $closed: boolean;
/**
* Custom meta data attached to the RPC instance
*/
readonly $meta: any;
/**
* Close the RPC connection
*/
$close: (error?: Error) => void;
/**
* Reject pending calls
*/
$rejectPendingCalls: (handler?: PendingCallHandler) => Promise<void>[];
/**
* Call the remote function and wait for the result.
* An alternative to directly calling the function
*/
$call: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]>>>;
/**
* Same as `$call`, but returns `undefined` if the function is not defined on the remote side.
*/
$callOptional: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]> | undefined>>;
/**
* Send event without asking for response
*/
$callEvent: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<void>;
/**
* Call the remote function with the raw options.
*/
$callRaw: (options: {
method: string;
args: unknown[];
event?: boolean;
optional?: boolean;
}) => Promise<Awaited<ReturnType<any>>[]>;
}
type ProxifiedRemoteFunctions<RemoteFunctions extends object = Record<string, unknown>> = { [K in keyof RemoteFunctions]: BirpcFn<RemoteFunctions[K]> };
type BirpcReturn<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = Proxify extends true ? ProxifiedRemoteFunctions<RemoteFunctions> & BirpcReturnBuiltin<RemoteFunctions, LocalFunctions> : BirpcReturnBuiltin<RemoteFunctions, LocalFunctions>;
type PendingCallHandler = (options: Pick<PromiseEntry, 'method' | 'reject'>) => void | Promise<void>;
interface PromiseEntry {
resolve: (arg: any) => void;
reject: (error: any) => void;
method: string;
timeoutId?: ReturnType<typeof setTimeout>;
}
declare const setTimeout: typeof globalThis.setTimeout;
type WorkerRPC = BirpcReturn<RuntimeRPC, RunnerRPC>;
interface ContextTestEnvironment {
name: string;
options: Record<string, any> | null;
}
interface WorkerTestEnvironment {
name: string;
options: Record<string, any> | null;
}
type TestExecutionMethod = "run" | "collect";
interface WorkerExecuteContext {
files: FileSpecification[];
providedContext: Record<string, any>;
invalidates?: string[];
environment: ContextTestEnvironment;
/** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */
workerId: number;
}
interface ContextRPC {
pool: string;
config: SerializedConfig;
projectName: string;
environment: WorkerTestEnvironment;
rpc: WorkerRPC;
files: FileSpecification[];
providedContext: Record<string, any>;
invalidates?: string[];
/** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */
workerId: number;
}
interface WorkerSetupContext {
environment: WorkerTestEnvironment;
pool: string;
config: SerializedConfig;
projectName: string;
rpc: WorkerRPC;
}
interface WorkerGlobalState {
ctx: ContextRPC;
config: SerializedConfig;
rpc: WorkerRPC;
current?: Task;
filepath?: string;
metaEnv: {
[key: string]: any;
BASE_URL: string;
MODE: string;
DEV: boolean;
PROD: boolean;
SSR: boolean;
};
environment: Environment;
evaluatedModules: EvaluatedModules;
resolvingModules: Set<string>;
moduleExecutionInfo: Map<string, any>;
onCancel: (listener: (reason: CancelReason) => unknown) => void;
onCleanup: (listener: () => unknown) => void;
providedContext: Record<string, any>;
durations: {
environment: number;
prepare: number;
};
onFilterStackTrace?: (trace: string) => string;
}
export type { BirpcOptions as B, ContextRPC as C, TestExecutionMethod as T, WorkerGlobalState as W, WorkerSetupContext as a, BirpcReturn as b, ContextTestEnvironment as c, WorkerExecuteContext as d, WorkerTestEnvironment as e };