| 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,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
-1
@@ -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'; |
+3
-3
@@ -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'; |
+2
-1
@@ -74,3 +74,4 @@ 'use strict'; | ||
| slowTestThreshold: 300, | ||
| disableConsoleIntercept: false | ||
| disableConsoleIntercept: false, | ||
| detectAsyncLeaks: false | ||
| }); | ||
@@ -77,0 +78,0 @@ |
+8
-7
| 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
-1
@@ -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'; |
+2
-2
@@ -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'; |
+44
-11
@@ -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 @@ * |
+2
-2
@@ -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'; |
+20
-10
@@ -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. |
+22
-23
| 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
-1
@@ -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'; |
+3
-3
@@ -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'; |
+6
-5
@@ -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'; |
+116
-1
@@ -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 |
+20
-13
| { | ||
| "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 }; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 5 instances in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 25 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 5 instances in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 25 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1870095
2.09%49995
1.93%373
-8.13%30
3.45%30
11.11%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated
Updated