| 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.5lgR0kvt.js'; | ||
| import { l as loadEnvironment, e as emitModuleRunner, a as listenForErrors } from './init.Borgldul.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.BdSYEN5x.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.z3ZfZiWN.js'; | ||
| import { g as globalExpect, v as vi } from './test.PnxXDGpZ.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.IcAjQV7n.js'; | ||
| import { g as getWorkerState, r as resetModules, p as provideWorkerState, a as getSafeWorkerState } from './utils.BX5Fg8C4.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.3WNpx0tS.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.wQT5wU7r.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 }; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
| import { Console } from 'node:console'; | ||
| import { relative } from 'node:path'; | ||
| import { Writable } from 'node:stream'; | ||
| import { getSafeTimers } from '@vitest/utils/timers'; | ||
| import c from 'tinyrainbow'; | ||
| import { R as RealDate } from './rpc.MzXet3jl.js'; | ||
| import { g as getWorkerState } from './utils.BX5Fg8C4.js'; | ||
| import './index.Chj8NDwU.js'; | ||
| const UNKNOWN_TEST_ID = "__vitest__unknown_test__"; | ||
| function getTaskIdByStack(root) { | ||
| const stack = (/* @__PURE__ */ new Error("STACK_TRACE_ERROR")).stack?.split("\n"); | ||
| if (!stack) return UNKNOWN_TEST_ID; | ||
| const index = stack.findIndex((line) => line.includes("at Console.value")); | ||
| const line = index === -1 ? null : stack[index + 2]; | ||
| if (!line) return UNKNOWN_TEST_ID; | ||
| const filepath = line.match(/at\s(.*)\s?/)?.[1]; | ||
| if (filepath) return relative(root, filepath); | ||
| return UNKNOWN_TEST_ID; | ||
| } | ||
| function createCustomConsole(defaultState) { | ||
| const stdoutBuffer = /* @__PURE__ */ new Map(); | ||
| const stderrBuffer = /* @__PURE__ */ new Map(); | ||
| const timers = /* @__PURE__ */ new Map(); | ||
| const { queueMicrotask } = getSafeTimers(); | ||
| function queueCancelableMicrotask(callback) { | ||
| let canceled = false; | ||
| queueMicrotask(() => { | ||
| if (!canceled) callback(); | ||
| }); | ||
| return () => { | ||
| canceled = true; | ||
| }; | ||
| } | ||
| const state = () => defaultState || getWorkerState(); | ||
| // group sync console.log calls with micro task | ||
| function schedule(taskId) { | ||
| const timer = timers.get(taskId); | ||
| const { stdoutTime, stderrTime } = timer; | ||
| timer.cancel?.(); | ||
| timer.cancel = queueCancelableMicrotask(() => { | ||
| if (stderrTime < stdoutTime) { | ||
| sendStderr(taskId); | ||
| sendStdout(taskId); | ||
| } else { | ||
| sendStdout(taskId); | ||
| sendStderr(taskId); | ||
| } | ||
| }); | ||
| } | ||
| function sendStdout(taskId) { | ||
| sendBuffer("stdout", taskId); | ||
| } | ||
| function sendStderr(taskId) { | ||
| sendBuffer("stderr", taskId); | ||
| } | ||
| function sendBuffer(type, taskId) { | ||
| const buffers = type === "stdout" ? stdoutBuffer : stderrBuffer; | ||
| const buffer = buffers.get(taskId); | ||
| if (!buffer) return; | ||
| if (state().config.printConsoleTrace) buffer.forEach(([buffer, origin]) => { | ||
| sendLog(type, taskId, String(buffer), buffer.length, origin); | ||
| }); | ||
| else sendLog(type, taskId, buffer.map((i) => String(i[0])).join(""), buffer.length); | ||
| const timer = timers.get(taskId); | ||
| buffers.delete(taskId); | ||
| if (type === "stderr") timer.stderrTime = 0; | ||
| else timer.stdoutTime = 0; | ||
| } | ||
| function sendLog(type, taskId, content, size, origin) { | ||
| const timer = timers.get(taskId); | ||
| const time = type === "stderr" ? timer.stderrTime : timer.stdoutTime; | ||
| state().rpc.onUserConsoleLog({ | ||
| type, | ||
| content: content || "<empty line>", | ||
| taskId, | ||
| time: time || RealDate.now(), | ||
| size, | ||
| origin | ||
| }); | ||
| } | ||
| return new Console({ | ||
| stdout: new Writable({ write(data, encoding, callback) { | ||
| const s = state(); | ||
| const id = s?.current?.id || s?.current?.suite?.id || s.current?.file.id || getTaskIdByStack(s.config.root); | ||
| let timer = timers.get(id); | ||
| if (timer) timer.stdoutTime = timer.stdoutTime || RealDate.now(); | ||
| else { | ||
| timer = { | ||
| stdoutTime: RealDate.now(), | ||
| stderrTime: RealDate.now() | ||
| }; | ||
| timers.set(id, timer); | ||
| } | ||
| let buffer = stdoutBuffer.get(id); | ||
| if (!buffer) { | ||
| buffer = []; | ||
| stdoutBuffer.set(id, buffer); | ||
| } | ||
| if (state().config.printConsoleTrace) { | ||
| const limit = Error.stackTraceLimit; | ||
| Error.stackTraceLimit = limit + 6; | ||
| const trace = (/* @__PURE__ */ new Error("STACK_TRACE")).stack?.split("\n").slice(7).join("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| buffer.push([data, trace]); | ||
| } else buffer.push([data, void 0]); | ||
| schedule(id); | ||
| callback(); | ||
| } }), | ||
| stderr: new Writable({ write(data, encoding, callback) { | ||
| const s = state(); | ||
| const id = s?.current?.id || s?.current?.suite?.id || s.current?.file.id || getTaskIdByStack(s.config.root); | ||
| let timer = timers.get(id); | ||
| if (timer) timer.stderrTime = timer.stderrTime || RealDate.now(); | ||
| else { | ||
| timer = { | ||
| stderrTime: RealDate.now(), | ||
| stdoutTime: RealDate.now() | ||
| }; | ||
| timers.set(id, timer); | ||
| } | ||
| let buffer = stderrBuffer.get(id); | ||
| if (!buffer) { | ||
| buffer = []; | ||
| stderrBuffer.set(id, buffer); | ||
| } | ||
| if (state().config.printConsoleTrace) { | ||
| const limit = Error.stackTraceLimit; | ||
| Error.stackTraceLimit = limit + 6; | ||
| const stack = (/* @__PURE__ */ new Error("STACK_TRACE")).stack?.split("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| if (stack?.some((line) => line.includes("at Console.trace"))) buffer.push([data, void 0]); | ||
| else { | ||
| const trace = stack?.slice(7).join("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| buffer.push([data, trace]); | ||
| } | ||
| } else buffer.push([data, void 0]); | ||
| schedule(id); | ||
| callback(); | ||
| } }), | ||
| colorMode: c.isColorSupported, | ||
| groupIndentation: 2 | ||
| }); | ||
| } | ||
| export { UNKNOWN_TEST_ID, createCustomConsole }; |
| import { g as globalApis } from './constants.CPYnjOGj.js'; | ||
| import { i as index } from './index.IcAjQV7n.js'; | ||
| import './test.PnxXDGpZ.js'; | ||
| import '@vitest/runner'; | ||
| import '@vitest/utils/helpers'; | ||
| import '@vitest/utils/timers'; | ||
| import './benchmark.D0SlKNbZ.js'; | ||
| import '@vitest/runner/utils'; | ||
| import './utils.BX5Fg8C4.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.MzXet3jl.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 { createHook } from 'node:async_hooks'; | ||
| import { l as loadDiffConfig, a as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.z3ZfZiWN.js'; | ||
| import { r as rpc } from './rpc.MzXet3jl.js'; | ||
| import { g as getWorkerState } from './utils.BX5Fg8C4.js'; | ||
| import { T as TestRunner, N as NodeBenchmarkRunner } from './test.PnxXDGpZ.js'; | ||
| function setupChaiConfig(config) { | ||
| Object.assign(chai.config, config); | ||
| } | ||
| async function resolveSnapshotEnvironment(config, moduleRunner) { | ||
| if (!config.snapshotEnvironment) { | ||
| const { VitestNodeSnapshotEnvironment } = await import('./node.COQbm6gK.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 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.DpkD7Zj4.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 }; |
Sorry, the diff of this file is too big to display
| import { URL as URL$1 } from 'node:url'; | ||
| import { Console } from 'node:console'; | ||
| // SEE https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/interfaces.js | ||
| const LIVING_KEYS = [ | ||
| "DOMException", | ||
| "EventTarget", | ||
| "NamedNodeMap", | ||
| "Node", | ||
| "Attr", | ||
| "Element", | ||
| "DocumentFragment", | ||
| "DOMImplementation", | ||
| "Document", | ||
| "XMLDocument", | ||
| "CharacterData", | ||
| "Text", | ||
| "CDATASection", | ||
| "ProcessingInstruction", | ||
| "Comment", | ||
| "DocumentType", | ||
| "NodeList", | ||
| "RadioNodeList", | ||
| "HTMLCollection", | ||
| "HTMLOptionsCollection", | ||
| "DOMStringMap", | ||
| "DOMTokenList", | ||
| "StyleSheetList", | ||
| "HTMLElement", | ||
| "HTMLHeadElement", | ||
| "HTMLTitleElement", | ||
| "HTMLBaseElement", | ||
| "HTMLLinkElement", | ||
| "HTMLMetaElement", | ||
| "HTMLStyleElement", | ||
| "HTMLBodyElement", | ||
| "HTMLHeadingElement", | ||
| "HTMLParagraphElement", | ||
| "HTMLHRElement", | ||
| "HTMLPreElement", | ||
| "HTMLUListElement", | ||
| "HTMLOListElement", | ||
| "HTMLLIElement", | ||
| "HTMLMenuElement", | ||
| "HTMLDListElement", | ||
| "HTMLDivElement", | ||
| "HTMLAnchorElement", | ||
| "HTMLAreaElement", | ||
| "HTMLBRElement", | ||
| "HTMLButtonElement", | ||
| "HTMLCanvasElement", | ||
| "HTMLDataElement", | ||
| "HTMLDataListElement", | ||
| "HTMLDetailsElement", | ||
| "HTMLDialogElement", | ||
| "HTMLDirectoryElement", | ||
| "HTMLFieldSetElement", | ||
| "HTMLFontElement", | ||
| "HTMLFormElement", | ||
| "HTMLHtmlElement", | ||
| "HTMLImageElement", | ||
| "HTMLInputElement", | ||
| "HTMLLabelElement", | ||
| "HTMLLegendElement", | ||
| "HTMLMapElement", | ||
| "HTMLMarqueeElement", | ||
| "HTMLMediaElement", | ||
| "HTMLMeterElement", | ||
| "HTMLModElement", | ||
| "HTMLOptGroupElement", | ||
| "HTMLOptionElement", | ||
| "HTMLOutputElement", | ||
| "HTMLPictureElement", | ||
| "HTMLProgressElement", | ||
| "HTMLQuoteElement", | ||
| "HTMLScriptElement", | ||
| "HTMLSelectElement", | ||
| "HTMLSlotElement", | ||
| "HTMLSourceElement", | ||
| "HTMLSpanElement", | ||
| "HTMLTableCaptionElement", | ||
| "HTMLTableCellElement", | ||
| "HTMLTableColElement", | ||
| "HTMLTableElement", | ||
| "HTMLTimeElement", | ||
| "HTMLTableRowElement", | ||
| "HTMLTableSectionElement", | ||
| "HTMLTemplateElement", | ||
| "HTMLTextAreaElement", | ||
| "HTMLUnknownElement", | ||
| "HTMLFrameElement", | ||
| "HTMLFrameSetElement", | ||
| "HTMLIFrameElement", | ||
| "HTMLEmbedElement", | ||
| "HTMLObjectElement", | ||
| "HTMLParamElement", | ||
| "HTMLVideoElement", | ||
| "HTMLAudioElement", | ||
| "HTMLTrackElement", | ||
| "HTMLFormControlsCollection", | ||
| "SVGElement", | ||
| "SVGGraphicsElement", | ||
| "SVGSVGElement", | ||
| "SVGTitleElement", | ||
| "SVGAnimatedString", | ||
| "SVGNumber", | ||
| "SVGStringList", | ||
| "Event", | ||
| "CloseEvent", | ||
| "CustomEvent", | ||
| "MessageEvent", | ||
| "ErrorEvent", | ||
| "HashChangeEvent", | ||
| "PopStateEvent", | ||
| "StorageEvent", | ||
| "ProgressEvent", | ||
| "PageTransitionEvent", | ||
| "SubmitEvent", | ||
| "UIEvent", | ||
| "FocusEvent", | ||
| "InputEvent", | ||
| "MouseEvent", | ||
| "KeyboardEvent", | ||
| "TouchEvent", | ||
| "CompositionEvent", | ||
| "WheelEvent", | ||
| "BarProp", | ||
| "External", | ||
| "Location", | ||
| "History", | ||
| "Screen", | ||
| "Crypto", | ||
| "Performance", | ||
| "Navigator", | ||
| "PluginArray", | ||
| "MimeTypeArray", | ||
| "Plugin", | ||
| "MimeType", | ||
| "FileReader", | ||
| "FormData", | ||
| "Blob", | ||
| "File", | ||
| "FileList", | ||
| "ValidityState", | ||
| "DOMParser", | ||
| "XMLSerializer", | ||
| "XMLHttpRequestEventTarget", | ||
| "XMLHttpRequestUpload", | ||
| "XMLHttpRequest", | ||
| "WebSocket", | ||
| "NodeFilter", | ||
| "NodeIterator", | ||
| "TreeWalker", | ||
| "AbstractRange", | ||
| "Range", | ||
| "StaticRange", | ||
| "Selection", | ||
| "Storage", | ||
| "CustomElementRegistry", | ||
| "ShadowRoot", | ||
| "MutationObserver", | ||
| "MutationRecord", | ||
| "Uint8Array", | ||
| "Uint16Array", | ||
| "Uint32Array", | ||
| "Uint8ClampedArray", | ||
| "Int8Array", | ||
| "Int16Array", | ||
| "Int32Array", | ||
| "Float32Array", | ||
| "Float64Array", | ||
| "ArrayBuffer", | ||
| "DOMRectReadOnly", | ||
| "DOMRect", | ||
| "Image", | ||
| "Audio", | ||
| "Option", | ||
| "CSS" | ||
| ]; | ||
| const OTHER_KEYS = [ | ||
| "addEventListener", | ||
| "alert", | ||
| "blur", | ||
| "cancelAnimationFrame", | ||
| "close", | ||
| "confirm", | ||
| "createPopup", | ||
| "dispatchEvent", | ||
| "document", | ||
| "focus", | ||
| "frames", | ||
| "getComputedStyle", | ||
| "history", | ||
| "innerHeight", | ||
| "innerWidth", | ||
| "length", | ||
| "location", | ||
| "matchMedia", | ||
| "moveBy", | ||
| "moveTo", | ||
| "name", | ||
| "navigator", | ||
| "open", | ||
| "outerHeight", | ||
| "outerWidth", | ||
| "pageXOffset", | ||
| "pageYOffset", | ||
| "parent", | ||
| "postMessage", | ||
| "print", | ||
| "prompt", | ||
| "removeEventListener", | ||
| "requestAnimationFrame", | ||
| "resizeBy", | ||
| "resizeTo", | ||
| "screen", | ||
| "screenLeft", | ||
| "screenTop", | ||
| "screenX", | ||
| "screenY", | ||
| "scroll", | ||
| "scrollBy", | ||
| "scrollLeft", | ||
| "scrollTo", | ||
| "scrollTop", | ||
| "scrollX", | ||
| "scrollY", | ||
| "self", | ||
| "stop", | ||
| "top", | ||
| "Window", | ||
| "window" | ||
| ]; | ||
| const KEYS = LIVING_KEYS.concat(OTHER_KEYS); | ||
| const skipKeys = [ | ||
| "window", | ||
| "self", | ||
| "top", | ||
| "parent" | ||
| ]; | ||
| function getWindowKeys(global, win, additionalKeys = []) { | ||
| const keysArray = [...additionalKeys, ...KEYS]; | ||
| return new Set(keysArray.concat(Object.getOwnPropertyNames(win)).filter((k) => { | ||
| if (skipKeys.includes(k)) return false; | ||
| if (k in global) return keysArray.includes(k); | ||
| return true; | ||
| })); | ||
| } | ||
| function isClassLikeName(name) { | ||
| return name[0] === name[0].toUpperCase(); | ||
| } | ||
| function populateGlobal(global, win, options = {}) { | ||
| const { bindFunctions = false } = options; | ||
| const keys = getWindowKeys(global, win, options.additionalKeys); | ||
| const originals = /* @__PURE__ */ new Map(); | ||
| const overridenKeys = new Set([...KEYS, ...options.additionalKeys || []]); | ||
| const overrideObject = /* @__PURE__ */ new Map(); | ||
| for (const key of keys) { | ||
| const boundFunction = bindFunctions && typeof win[key] === "function" && !isClassLikeName(key) && win[key].bind(win); | ||
| if (overridenKeys.has(key) && key in global) originals.set(key, global[key]); | ||
| Object.defineProperty(global, key, { | ||
| get() { | ||
| if (overrideObject.has(key)) return overrideObject.get(key); | ||
| if (boundFunction) return boundFunction; | ||
| return win[key]; | ||
| }, | ||
| set(v) { | ||
| overrideObject.set(key, v); | ||
| }, | ||
| configurable: true | ||
| }); | ||
| } | ||
| global.window = global; | ||
| global.self = global; | ||
| global.top = global; | ||
| global.parent = global; | ||
| if (global.global) global.global = global; | ||
| // rewrite defaultView to reference the same global context | ||
| if (global.document && global.document.defaultView) Object.defineProperty(global.document, "defaultView", { | ||
| get: () => global, | ||
| enumerable: true, | ||
| configurable: true | ||
| }); | ||
| skipKeys.forEach((k) => keys.add(k)); | ||
| return { | ||
| keys, | ||
| skipKeys, | ||
| originals | ||
| }; | ||
| } | ||
| var edge = { | ||
| name: "edge-runtime", | ||
| viteEnvironment: "ssr", | ||
| async setupVM() { | ||
| const { EdgeVM } = await import('@edge-runtime/vm'); | ||
| const vm = new EdgeVM({ extend: (context) => { | ||
| context.global = context; | ||
| context.Buffer = Buffer; | ||
| return context; | ||
| } }); | ||
| return { | ||
| getVmContext() { | ||
| return vm.context; | ||
| }, | ||
| teardown() { | ||
| // nothing to teardown | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global) { | ||
| const { EdgeVM } = await import('@edge-runtime/vm'); | ||
| const { keys, originals } = populateGlobal(global, new EdgeVM({ extend: (context) => { | ||
| context.global = context; | ||
| context.Buffer = Buffer; | ||
| KEYS.forEach((key) => { | ||
| if (key in global) context[key] = global[key]; | ||
| }); | ||
| return context; | ||
| } }).context, { bindFunctions: true }); | ||
| return { teardown(global) { | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((v, k) => global[k] = v); | ||
| } }; | ||
| } | ||
| }; | ||
| async function teardownWindow(win) { | ||
| if (win.close && win.happyDOM.abort) { | ||
| await win.happyDOM.abort(); | ||
| win.close(); | ||
| } else win.happyDOM.cancelAsync(); | ||
| } | ||
| var happy = { | ||
| name: "happy-dom", | ||
| viteEnvironment: "client", | ||
| async setupVM({ happyDOM = {} }) { | ||
| const { Window } = await import('happy-dom'); | ||
| let win = new Window({ | ||
| ...happyDOM, | ||
| console: console && globalThis.console ? globalThis.console : void 0, | ||
| url: happyDOM.url || "http://localhost:3000", | ||
| settings: { | ||
| ...happyDOM.settings, | ||
| disableErrorCapturing: true | ||
| } | ||
| }); | ||
| // TODO: browser doesn't expose Buffer, but a lot of dependencies use it | ||
| win.Buffer = Buffer; | ||
| // inject structuredClone if it exists | ||
| if (typeof structuredClone !== "undefined" && !win.structuredClone) win.structuredClone = structuredClone; | ||
| return { | ||
| getVmContext() { | ||
| return win; | ||
| }, | ||
| async teardown() { | ||
| await teardownWindow(win); | ||
| win = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global, { happyDOM = {} }) { | ||
| // happy-dom v3 introduced a breaking change to Window, but | ||
| // provides GlobalWindow as a way to use previous behaviour | ||
| const { Window, GlobalWindow } = await import('happy-dom'); | ||
| const win = new (GlobalWindow || Window)({ | ||
| ...happyDOM, | ||
| console: console && global.console ? global.console : void 0, | ||
| url: happyDOM.url || "http://localhost:3000", | ||
| settings: { | ||
| ...happyDOM.settings, | ||
| disableErrorCapturing: true | ||
| } | ||
| }); | ||
| const { keys, originals } = populateGlobal(global, win, { | ||
| bindFunctions: true, | ||
| additionalKeys: [ | ||
| "Request", | ||
| "Response", | ||
| "MessagePort", | ||
| "fetch", | ||
| "Headers", | ||
| "AbortController", | ||
| "AbortSignal", | ||
| "URL", | ||
| "URLSearchParams", | ||
| "FormData" | ||
| ] | ||
| }); | ||
| return { async teardown(global) { | ||
| await teardownWindow(win); | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((v, k) => global[k] = v); | ||
| } }; | ||
| } | ||
| }; | ||
| function catchWindowErrors(window) { | ||
| let userErrorListenerCount = 0; | ||
| function throwUnhandlerError(e) { | ||
| if (userErrorListenerCount === 0 && e.error != null) { | ||
| e.preventDefault(); | ||
| process.emit("uncaughtException", e.error); | ||
| } | ||
| } | ||
| const addEventListener = window.addEventListener.bind(window); | ||
| const removeEventListener = window.removeEventListener.bind(window); | ||
| window.addEventListener("error", throwUnhandlerError); | ||
| window.addEventListener = function(...args) { | ||
| if (args[0] === "error") userErrorListenerCount++; | ||
| return addEventListener.apply(this, args); | ||
| }; | ||
| window.removeEventListener = function(...args) { | ||
| if (args[0] === "error" && userErrorListenerCount) userErrorListenerCount--; | ||
| return removeEventListener.apply(this, args); | ||
| }; | ||
| return function clearErrorHandlers() { | ||
| window.removeEventListener("error", throwUnhandlerError); | ||
| }; | ||
| } | ||
| let NodeFormData_; | ||
| let NodeBlob_; | ||
| let NodeRequest_; | ||
| var jsdom = { | ||
| name: "jsdom", | ||
| viteEnvironment: "client", | ||
| async setupVM({ jsdom = {} }) { | ||
| // delay initialization because it takes ~1s | ||
| NodeFormData_ = globalThis.FormData; | ||
| NodeBlob_ = globalThis.Blob; | ||
| NodeRequest_ = globalThis.Request; | ||
| const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom'); | ||
| const { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false, ...restOptions } = jsdom; | ||
| let virtualConsole; | ||
| if (console && globalThis.console) { | ||
| virtualConsole = new VirtualConsole(); | ||
| // jsdom <27 | ||
| if ("sendTo" in virtualConsole) virtualConsole.sendTo(globalThis.console); | ||
| else virtualConsole.forwardTo(globalThis.console); | ||
| } | ||
| let dom = new JSDOM(html, { | ||
| pretendToBeVisual, | ||
| resources: resources ?? (userAgent ? new ResourceLoader({ userAgent }) : void 0), | ||
| runScripts, | ||
| url, | ||
| virtualConsole, | ||
| cookieJar: cookieJar ? new CookieJar() : void 0, | ||
| includeNodeLocations, | ||
| contentType, | ||
| userAgent, | ||
| ...restOptions | ||
| }); | ||
| const clearAddEventListenerPatch = patchAddEventListener(dom.window); | ||
| const clearWindowErrors = catchWindowErrors(dom.window); | ||
| const utils = createCompatUtils(dom.window); | ||
| // TODO: browser doesn't expose Buffer, but a lot of dependencies use it | ||
| dom.window.Buffer = Buffer; | ||
| dom.window.jsdom = dom; | ||
| dom.window.Request = createCompatRequest(utils); | ||
| dom.window.URL = createJSDOMCompatURL(utils); | ||
| for (const name of [ | ||
| "structuredClone", | ||
| "BroadcastChannel", | ||
| "MessageChannel", | ||
| "MessagePort", | ||
| "TextEncoder", | ||
| "TextDecoder" | ||
| ]) { | ||
| const value = globalThis[name]; | ||
| if (typeof value !== "undefined" && typeof dom.window[name] === "undefined") dom.window[name] = value; | ||
| } | ||
| for (const name of [ | ||
| "fetch", | ||
| "Response", | ||
| "Headers", | ||
| "AbortController", | ||
| "AbortSignal", | ||
| "URLSearchParams" | ||
| ]) { | ||
| const value = globalThis[name]; | ||
| if (typeof value !== "undefined") dom.window[name] = value; | ||
| } | ||
| return { | ||
| getVmContext() { | ||
| return dom.getInternalVMContext(); | ||
| }, | ||
| teardown() { | ||
| clearAddEventListenerPatch(); | ||
| clearWindowErrors(); | ||
| dom.window.close(); | ||
| dom = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global, { jsdom = {} }) { | ||
| // delay initialization because it takes ~1s | ||
| NodeFormData_ = globalThis.FormData; | ||
| NodeBlob_ = globalThis.Blob; | ||
| NodeRequest_ = globalThis.Request; | ||
| const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom'); | ||
| const { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false, ...restOptions } = jsdom; | ||
| let virtualConsole; | ||
| if (console && globalThis.console) { | ||
| virtualConsole = new VirtualConsole(); | ||
| // jsdom <27 | ||
| if ("sendTo" in virtualConsole) virtualConsole.sendTo(globalThis.console); | ||
| else virtualConsole.forwardTo(globalThis.console); | ||
| } | ||
| const dom = new JSDOM(html, { | ||
| pretendToBeVisual, | ||
| resources: resources ?? (userAgent ? new ResourceLoader({ userAgent }) : void 0), | ||
| runScripts, | ||
| url, | ||
| virtualConsole, | ||
| cookieJar: cookieJar ? new CookieJar() : void 0, | ||
| includeNodeLocations, | ||
| contentType, | ||
| userAgent, | ||
| ...restOptions | ||
| }); | ||
| const clearAddEventListenerPatch = patchAddEventListener(dom.window); | ||
| const { keys, originals } = populateGlobal(global, dom.window, { bindFunctions: true }); | ||
| const clearWindowErrors = catchWindowErrors(global); | ||
| const utils = createCompatUtils(dom.window); | ||
| global.jsdom = dom; | ||
| global.Request = createCompatRequest(utils); | ||
| global.URL = createJSDOMCompatURL(utils); | ||
| return { teardown(global) { | ||
| clearAddEventListenerPatch(); | ||
| clearWindowErrors(); | ||
| dom.window.close(); | ||
| delete global.jsdom; | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((v, k) => global[k] = v); | ||
| } }; | ||
| } | ||
| }; | ||
| function createCompatRequest(utils) { | ||
| class Request extends NodeRequest_ { | ||
| constructor(...args) { | ||
| const [input, init] = args; | ||
| if (init?.body != null) { | ||
| const compatInit = { ...init }; | ||
| if (init.body instanceof utils.window.Blob) compatInit.body = utils.makeCompatBlob(init.body); | ||
| if (init.body instanceof utils.window.FormData) compatInit.body = utils.makeCompatFormData(init.body); | ||
| super(input, compatInit); | ||
| } else super(...args); | ||
| } | ||
| static [Symbol.hasInstance](instance) { | ||
| return instance instanceof NodeRequest_; | ||
| } | ||
| } | ||
| return Request; | ||
| } | ||
| function createJSDOMCompatURL(utils) { | ||
| class URL extends URL$1 { | ||
| static createObjectURL(blob) { | ||
| if (blob instanceof utils.window.Blob) { | ||
| const compatBlob = utils.makeCompatBlob(blob); | ||
| return URL$1.createObjectURL(compatBlob); | ||
| } | ||
| return URL$1.createObjectURL(blob); | ||
| } | ||
| static [Symbol.hasInstance](instance) { | ||
| return instance instanceof URL$1; | ||
| } | ||
| } | ||
| return URL; | ||
| } | ||
| function createCompatUtils(window) { | ||
| // this returns a hidden Symbol(impl) | ||
| // this is cursed, and jsdom should just implement fetch API itself | ||
| const implSymbol = Object.getOwnPropertySymbols(Object.getOwnPropertyDescriptors(new window.Blob()))[0]; | ||
| const utils = { | ||
| window, | ||
| makeCompatFormData(formData) { | ||
| const nodeFormData = new NodeFormData_(); | ||
| formData.forEach((value, key) => { | ||
| if (value instanceof window.Blob) nodeFormData.append(key, utils.makeCompatBlob(value)); | ||
| else nodeFormData.append(key, value); | ||
| }); | ||
| return nodeFormData; | ||
| }, | ||
| makeCompatBlob(blob) { | ||
| const buffer = blob[implSymbol]._buffer; | ||
| return new NodeBlob_([buffer], { type: blob.type }); | ||
| } | ||
| }; | ||
| return utils; | ||
| } | ||
| function patchAddEventListener(window) { | ||
| const abortControllers = /* @__PURE__ */ new WeakMap(); | ||
| const JSDOMAbortSignal = window.AbortSignal; | ||
| const JSDOMAbortController = window.AbortController; | ||
| const originalAddEventListener = window.EventTarget.prototype.addEventListener; | ||
| function getJsdomAbortController(signal) { | ||
| if (!abortControllers.has(signal)) { | ||
| const jsdomAbortController = new JSDOMAbortController(); | ||
| signal.addEventListener("abort", () => { | ||
| jsdomAbortController.abort(signal.reason); | ||
| }); | ||
| abortControllers.set(signal, jsdomAbortController); | ||
| } | ||
| return abortControllers.get(signal); | ||
| } | ||
| window.EventTarget.prototype.addEventListener = function addEventListener(type, callback, options) { | ||
| if (typeof options === "object" && options?.signal != null) { | ||
| const { signal, ...otherOptions } = options; | ||
| // - this happens because AbortSignal is provided by Node.js, | ||
| // but jsdom APIs require jsdom's AbortSignal, while Node APIs | ||
| // (like fetch and Request) require a Node.js AbortSignal | ||
| // - disable narrow typing with "as any" because we need it later | ||
| if (!(signal instanceof JSDOMAbortSignal)) { | ||
| const jsdomCompatOptions = Object.create(null); | ||
| Object.assign(jsdomCompatOptions, otherOptions); | ||
| jsdomCompatOptions.signal = getJsdomAbortController(signal).signal; | ||
| return originalAddEventListener.call(this, type, callback, jsdomCompatOptions); | ||
| } | ||
| } | ||
| return originalAddEventListener.call(this, type, callback, options); | ||
| }; | ||
| return () => { | ||
| window.EventTarget.prototype.addEventListener = originalAddEventListener; | ||
| }; | ||
| } | ||
| // some globals we do not want, either because deprecated or we set it ourselves | ||
| const denyList = new Set([ | ||
| "GLOBAL", | ||
| "root", | ||
| "global", | ||
| "Buffer", | ||
| "ArrayBuffer", | ||
| "Uint8Array" | ||
| ]); | ||
| const nodeGlobals = /* @__PURE__ */ new Map(); | ||
| function populateNodeGlobals() { | ||
| if (nodeGlobals.size !== 0) return; | ||
| const names = Object.getOwnPropertyNames(globalThis); | ||
| const length = names.length; | ||
| for (let i = 0; i < length; i++) { | ||
| const globalName = names[i]; | ||
| if (!denyList.has(globalName)) { | ||
| const descriptor = Object.getOwnPropertyDescriptor(globalThis, globalName); | ||
| if (!descriptor) throw new Error(`No property descriptor for ${globalName}, this is a bug in Vitest.`); | ||
| nodeGlobals.set(globalName, descriptor); | ||
| } | ||
| } | ||
| } | ||
| var node = { | ||
| name: "node", | ||
| viteEnvironment: "ssr", | ||
| async setupVM() { | ||
| populateNodeGlobals(); | ||
| const vm = await import('node:vm'); | ||
| let context = vm.createContext(); | ||
| let global = vm.runInContext("this", context); | ||
| const contextGlobals = new Set(Object.getOwnPropertyNames(global)); | ||
| for (const [nodeGlobalsKey, descriptor] of nodeGlobals) if (!contextGlobals.has(nodeGlobalsKey)) if (descriptor.configurable) Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| get() { | ||
| // @ts-expect-error: no index signature | ||
| const val = globalThis[nodeGlobalsKey]; | ||
| // override lazy getter | ||
| Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| value: val, | ||
| writable: descriptor.writable === true || nodeGlobalsKey === "performance" | ||
| }); | ||
| return val; | ||
| }, | ||
| set(val) { | ||
| // override lazy getter | ||
| Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| value: val, | ||
| writable: true | ||
| }); | ||
| } | ||
| }); | ||
| else if ("value" in descriptor) Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: false, | ||
| enumerable: descriptor.enumerable, | ||
| value: descriptor.value, | ||
| writable: descriptor.writable | ||
| }); | ||
| else Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: false, | ||
| enumerable: descriptor.enumerable, | ||
| get: descriptor.get, | ||
| set: descriptor.set | ||
| }); | ||
| global.global = global; | ||
| global.Buffer = Buffer; | ||
| global.ArrayBuffer = ArrayBuffer; | ||
| // TextEncoder (global or via 'util') references a Uint8Array constructor | ||
| // different than the global one used by users in tests. This makes sure the | ||
| // same constructor is referenced by both. | ||
| global.Uint8Array = Uint8Array; | ||
| return { | ||
| getVmContext() { | ||
| return context; | ||
| }, | ||
| teardown() { | ||
| context = void 0; | ||
| global = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global) { | ||
| global.console.Console = Console; | ||
| return { teardown(global) { | ||
| delete global.console.Console; | ||
| } }; | ||
| } | ||
| }; | ||
| const environments = { | ||
| node, | ||
| jsdom, | ||
| "happy-dom": happy, | ||
| "edge-runtime": edge | ||
| }; | ||
| export { environments as e, populateGlobal as p }; |
| 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.PnxXDGpZ.js'; | ||
| import { b as bench } from './benchmark.D0SlKNbZ.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 }; |
| import { i as init } from './init.Borgldul.js'; | ||
| if (!process.send) throw new Error("Expected worker to be run in node:child_process"); | ||
| // Store globals in case tests overwrite them | ||
| const processExit = process.exit.bind(process); | ||
| const processSend = process.send.bind(process); | ||
| const processOn = process.on.bind(process); | ||
| const processOff = process.off.bind(process); | ||
| const processRemoveAllListeners = process.removeAllListeners.bind(process); | ||
| // Work-around for nodejs/node#55094 | ||
| if (process.execArgv.some((execArg) => execArg.startsWith("--prof") || execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"))) processOn("SIGTERM", () => processExit()); | ||
| processOn("error", onError); | ||
| function workerInit(options) { | ||
| const { runTests } = options; | ||
| init({ | ||
| post: (v) => processSend(v), | ||
| on: (cb) => processOn("message", cb), | ||
| off: (cb) => processOff("message", cb), | ||
| teardown: () => { | ||
| processRemoveAllListeners("message"); | ||
| processOff("error", onError); | ||
| }, | ||
| runTests: (state, traces) => executeTests("run", state, traces), | ||
| collectTests: (state, traces) => executeTests("collect", state, traces), | ||
| setup: options.setup | ||
| }); | ||
| async function executeTests(method, state, traces) { | ||
| try { | ||
| await runTests(method, state, traces); | ||
| } finally { | ||
| process.exit = processExit; | ||
| } | ||
| } | ||
| } | ||
| // Prevent leaving worker in loops where it tries to send message to closed main | ||
| // thread, errors, and tries to send the error. | ||
| function onError(error) { | ||
| if (error?.code === "ERR_IPC_CHANNEL_CLOSED" || error?.code === "EPIPE") processExit(1); | ||
| } | ||
| export { workerInit as w }; |
| import { isMainThread, parentPort } from 'node:worker_threads'; | ||
| import { i as init } from './init.Borgldul.js'; | ||
| if (isMainThread || !parentPort) throw new Error("Expected worker to be run in node:worker_threads"); | ||
| function workerInit(options) { | ||
| const { runTests } = options; | ||
| init({ | ||
| post: (response) => parentPort.postMessage(response), | ||
| on: (callback) => parentPort.on("message", callback), | ||
| off: (callback) => parentPort.off("message", callback), | ||
| teardown: () => parentPort.removeAllListeners("message"), | ||
| runTests: async (state, traces) => runTests("run", state, traces), | ||
| collectTests: async (state, traces) => runTests("collect", state, traces), | ||
| setup: options.setup | ||
| }); | ||
| } | ||
| export { workerInit as w }; |
| import { readFileSync } from 'node:fs'; | ||
| import { isBuiltin } from 'node:module'; | ||
| import { pathToFileURL } from 'node:url'; | ||
| import { resolve } from 'pathe'; | ||
| import { ModuleRunner, EvaluatedModules } from 'vite/module-runner'; | ||
| import { b as VitestTransport } from './startVitestModuleRunner.BdSYEN5x.js'; | ||
| import { e as environments } from './index.EY6TCHpo.js'; | ||
| import { serializeValue } from '@vitest/utils/serialize'; | ||
| import { serializeError } from '@vitest/utils/error'; | ||
| import { T as Traces } from './traces.CCmnQaNT.js'; | ||
| import { o as onCancel, a as rpcDone, c as createRuntimeRpc } from './rpc.MzXet3jl.js'; | ||
| import { createStackString, parseStacktrace } from '@vitest/utils/source-map'; | ||
| import { s as setupInspect } from './inspector.CvyFGlXm.js'; | ||
| import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js'; | ||
| import { E as EnvironmentTeardownError } from './utils.BX5Fg8C4.js'; | ||
| function isBuiltinEnvironment(env) { | ||
| return env in environments; | ||
| } | ||
| const isWindows = process.platform === "win32"; | ||
| const _loaders = /* @__PURE__ */ new Map(); | ||
| function createEnvironmentLoader(root, rpc) { | ||
| const cachedLoader = _loaders.get(root); | ||
| if (!cachedLoader || cachedLoader.isClosed()) { | ||
| _loaders.delete(root); | ||
| const moduleRunner = new ModuleRunner({ | ||
| hmr: false, | ||
| sourcemapInterceptor: "prepareStackTrace", | ||
| transport: new VitestTransport({ | ||
| async fetchModule(id, importer, options) { | ||
| const result = await rpc.fetch(id, importer, "__vitest__", options); | ||
| if ("cached" in result) return { | ||
| code: readFileSync(result.tmp, "utf-8"), | ||
| ...result | ||
| }; | ||
| if (isWindows && "externalize" in result) | ||
| // TODO: vitest returns paths for external modules, but Vite returns file:// | ||
| // https://github.com/vitejs/vite/pull/20449 | ||
| result.externalize = isBuiltin(id) || /^(?:node:|data:|http:|https:|file:)/.test(id) ? result.externalize : pathToFileURL(result.externalize).toString(); | ||
| return result; | ||
| }, | ||
| async resolveId(id, importer) { | ||
| return rpc.resolve(id, importer, "__vitest__"); | ||
| } | ||
| }, new EvaluatedModules(), /* @__PURE__ */ new WeakMap()) | ||
| }); | ||
| _loaders.set(root, moduleRunner); | ||
| } | ||
| return _loaders.get(root); | ||
| } | ||
| async function loadNativeEnvironment(name, root, traces) { | ||
| const packageId = name[0] === "." || name[0] === "/" ? pathToFileURL(resolve(root, name)).toString() : import.meta.resolve(`vitest-environment-${name}`, pathToFileURL(root).toString()); | ||
| return resolveEnvironmentFromModule(name, packageId, await traces.$("vitest.runtime.environment.import", () => import(packageId))); | ||
| } | ||
| function resolveEnvironmentFromModule(name, packageId, pkg) { | ||
| if (!pkg || !pkg.default || typeof pkg.default !== "object") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "setup" or/and "setupVM" method.`); | ||
| const environment = pkg.default; | ||
| if (environment.transformMode != null && environment.transformMode !== "web" && environment.transformMode !== "ssr") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "transformMode" method equal to "ssr" or "web", received "${environment.transformMode}".`); | ||
| if (environment.transformMode) { | ||
| console.warn(`The Vitest environment ${environment.name} defines the "transformMode". This options was deprecated in Vitest 4 and will be removed in the next major version. Please, use "viteEnvironment" instead.`); | ||
| // keep for backwards compat | ||
| environment.viteEnvironment ??= environment.transformMode === "ssr" ? "ssr" : "client"; | ||
| } | ||
| return environment; | ||
| } | ||
| async function loadEnvironment(name, root, rpc, traces, viteModuleRunner) { | ||
| if (isBuiltinEnvironment(name)) return { environment: environments[name] }; | ||
| if (!viteModuleRunner) return { environment: await loadNativeEnvironment(name, root, traces) }; | ||
| const loader = createEnvironmentLoader(root, rpc); | ||
| const packageId = name[0] === "." || name[0] === "/" ? resolve(root, name) : (await traces.$("vitest.runtime.environment.resolve", () => rpc.resolve(`vitest-environment-${name}`, void 0, "__vitest__")))?.id ?? resolve(root, name); | ||
| return { | ||
| environment: resolveEnvironmentFromModule(name, packageId, await traces.$("vitest.runtime.environment.import", () => loader.import(packageId))), | ||
| loader | ||
| }; | ||
| } | ||
| const cleanupListeners = /* @__PURE__ */ new Set(); | ||
| const moduleRunnerListeners = /* @__PURE__ */ new Set(); | ||
| function onCleanup(cb) { | ||
| cleanupListeners.add(cb); | ||
| } | ||
| async function cleanup() { | ||
| await Promise.all([...cleanupListeners].map((l) => l())); | ||
| } | ||
| function onModuleRunner(cb) { | ||
| moduleRunnerListeners.add(cb); | ||
| } | ||
| function emitModuleRunner(moduleRunner) { | ||
| moduleRunnerListeners.forEach((l) => l(moduleRunner)); | ||
| } | ||
| // Store globals in case tests overwrite them | ||
| const processListeners = process.listeners.bind(process); | ||
| const processOn = process.on.bind(process); | ||
| const processOff = process.off.bind(process); | ||
| const dispose = []; | ||
| function listenForErrors(state) { | ||
| dispose.forEach((fn) => fn()); | ||
| dispose.length = 0; | ||
| function catchError(err, type, event) { | ||
| const worker = state(); | ||
| // if there is another listener, assume that it's handled by user code | ||
| // one is Vitest's own listener | ||
| if (processListeners(event).length > 1) return; | ||
| const error = serializeValue(err); | ||
| if (typeof error === "object" && error != null) { | ||
| error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0; | ||
| if (worker.filepath) error.VITEST_TEST_PATH = worker.filepath; | ||
| } | ||
| state().rpc.onUnhandledError(error, type); | ||
| } | ||
| const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException"); | ||
| const unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection"); | ||
| processOn("uncaughtException", uncaughtException); | ||
| processOn("unhandledRejection", unhandledRejection); | ||
| dispose.push(() => { | ||
| processOff("uncaughtException", uncaughtException); | ||
| processOff("unhandledRejection", unhandledRejection); | ||
| }); | ||
| } | ||
| const resolvingModules = /* @__PURE__ */ new Set(); | ||
| async function execute(method, ctx, worker, traces) { | ||
| const prepareStart = performance.now(); | ||
| const cleanups = [setupInspect(ctx)]; | ||
| // RPC is used to communicate between worker (be it a thread worker or child process or a custom implementation) and the main thread | ||
| const rpc = ctx.rpc; | ||
| try { | ||
| // do not close the RPC channel so that we can get the error messages sent to the main thread | ||
| cleanups.push(async () => { | ||
| await Promise.all(rpc.$rejectPendingCalls(({ method, reject }) => { | ||
| reject(new EnvironmentTeardownError(`[vitest-worker]: Closing rpc while "${method}" was pending`)); | ||
| })); | ||
| }); | ||
| const state = { | ||
| ctx, | ||
| evaluatedModules: new VitestEvaluatedModules(), | ||
| resolvingModules, | ||
| moduleExecutionInfo: /* @__PURE__ */ new Map(), | ||
| config: ctx.config, | ||
| environment: null, | ||
| durations: { | ||
| environment: 0, | ||
| prepare: prepareStart | ||
| }, | ||
| rpc, | ||
| onCancel, | ||
| onCleanup: onCleanup, | ||
| providedContext: ctx.providedContext, | ||
| onFilterStackTrace(stack) { | ||
| return createStackString(parseStacktrace(stack)); | ||
| }, | ||
| metaEnv: createImportMetaEnvProxy() | ||
| }; | ||
| const methodName = method === "collect" ? "collectTests" : "runTests"; | ||
| if (!worker[methodName] || typeof worker[methodName] !== "function") throw new TypeError(`Test worker should expose "runTests" method. Received "${typeof worker.runTests}".`); | ||
| await worker[methodName](state, traces); | ||
| } finally { | ||
| await rpcDone().catch(() => {}); | ||
| await Promise.all(cleanups.map((fn) => fn())).catch(() => {}); | ||
| } | ||
| } | ||
| function run(ctx, worker, traces) { | ||
| return execute("run", ctx, worker, traces); | ||
| } | ||
| function collect(ctx, worker, traces) { | ||
| return execute("collect", ctx, worker, traces); | ||
| } | ||
| async function teardown() { | ||
| await cleanup(); | ||
| } | ||
| const env = process.env; | ||
| function createImportMetaEnvProxy() { | ||
| // packages/vitest/src/node/plugins/index.ts:146 | ||
| const booleanKeys = [ | ||
| "DEV", | ||
| "PROD", | ||
| "SSR" | ||
| ]; | ||
| return new Proxy(env, { | ||
| get(_, key) { | ||
| if (typeof key !== "string") return; | ||
| if (booleanKeys.includes(key)) return !!process.env[key]; | ||
| return process.env[key]; | ||
| }, | ||
| set(_, key, value) { | ||
| if (typeof key !== "string") return true; | ||
| if (booleanKeys.includes(key)) process.env[key] = value ? "1" : ""; | ||
| else process.env[key] = value; | ||
| return true; | ||
| } | ||
| }); | ||
| } | ||
| const __vitest_worker_response__ = true; | ||
| const memoryUsage = process.memoryUsage.bind(process); | ||
| let reportMemory = false; | ||
| let traces; | ||
| /** @experimental */ | ||
| function init(worker) { | ||
| worker.on(onMessage); | ||
| if (worker.onModuleRunner) onModuleRunner(worker.onModuleRunner); | ||
| let runPromise; | ||
| let isRunning = false; | ||
| let workerTeardown; | ||
| let setupContext; | ||
| function send(response) { | ||
| worker.post(worker.serialize ? worker.serialize(response) : response); | ||
| } | ||
| async function onMessage(rawMessage) { | ||
| const message = worker.deserialize ? worker.deserialize(rawMessage) : rawMessage; | ||
| if (message?.__vitest_worker_request__ !== true) return; | ||
| switch (message.type) { | ||
| case "start": { | ||
| process.env.VITEST_POOL_ID = String(message.poolId); | ||
| process.env.VITEST_WORKER_ID = String(message.workerId); | ||
| reportMemory = message.options.reportMemory; | ||
| traces ??= await new Traces({ | ||
| enabled: message.traces.enabled, | ||
| sdkPath: message.traces.sdkPath | ||
| }).waitInit(); | ||
| const { environment, config, pool } = message.context; | ||
| const context = traces.getContextFromCarrier(message.traces.otelCarrier); | ||
| // record telemetry as part of "start" | ||
| traces.recordInitSpan(context); | ||
| try { | ||
| setupContext = { | ||
| environment, | ||
| config, | ||
| pool, | ||
| rpc: createRuntimeRpc(worker), | ||
| projectName: config.name || "", | ||
| traces | ||
| }; | ||
| workerTeardown = await traces.$("vitest.runtime.setup", { context }, () => worker.setup?.(setupContext)); | ||
| send({ | ||
| type: "started", | ||
| __vitest_worker_response__ | ||
| }); | ||
| } catch (error) { | ||
| send({ | ||
| type: "started", | ||
| __vitest_worker_response__, | ||
| error: serializeError(error) | ||
| }); | ||
| } | ||
| break; | ||
| } | ||
| case "run": | ||
| // Prevent concurrent execution if worker is already running | ||
| if (isRunning) { | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests")) | ||
| }); | ||
| return; | ||
| } | ||
| try { | ||
| process.env.VITEST_WORKER_ID = String(message.context.workerId); | ||
| } catch (error) { | ||
| return send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(error), | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } | ||
| isRunning = true; | ||
| try { | ||
| const tracesContext = traces.getContextFromCarrier(message.otelCarrier); | ||
| runPromise = traces.$("vitest.runtime.run", { | ||
| context: tracesContext, | ||
| attributes: { | ||
| "vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [], | ||
| "vitest.worker.id": message.context.workerId | ||
| } | ||
| }, () => run({ | ||
| ...setupContext, | ||
| ...message.context | ||
| }, worker, traces).catch((error) => serializeError(error))); | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: await runPromise, | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } finally { | ||
| runPromise = void 0; | ||
| isRunning = false; | ||
| } | ||
| break; | ||
| case "collect": | ||
| // Prevent concurrent execution if worker is already running | ||
| if (isRunning) { | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests")) | ||
| }); | ||
| return; | ||
| } | ||
| try { | ||
| process.env.VITEST_WORKER_ID = String(message.context.workerId); | ||
| } catch (error) { | ||
| return send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(error), | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } | ||
| isRunning = true; | ||
| try { | ||
| const tracesContext = traces.getContextFromCarrier(message.otelCarrier); | ||
| runPromise = traces.$("vitest.runtime.collect", { | ||
| context: tracesContext, | ||
| attributes: { | ||
| "vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [], | ||
| "vitest.worker.id": message.context.workerId | ||
| } | ||
| }, () => collect({ | ||
| ...setupContext, | ||
| ...message.context | ||
| }, worker, traces).catch((error) => serializeError(error))); | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: await runPromise, | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } finally { | ||
| runPromise = void 0; | ||
| isRunning = false; | ||
| } | ||
| break; | ||
| case "stop": | ||
| await runPromise; | ||
| try { | ||
| const context = traces.getContextFromCarrier(message.otelCarrier); | ||
| const error = await traces.$("vitest.runtime.teardown", { context }, async () => { | ||
| const error = await teardown().catch((error) => serializeError(error)); | ||
| await workerTeardown?.(); | ||
| return error; | ||
| }); | ||
| await traces.finish(); | ||
| send({ | ||
| type: "stopped", | ||
| error, | ||
| __vitest_worker_response__ | ||
| }); | ||
| } catch (error) { | ||
| send({ | ||
| type: "stopped", | ||
| error: serializeError(error), | ||
| __vitest_worker_response__ | ||
| }); | ||
| } | ||
| worker.teardown?.(); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| function getFilesWithLocations(files) { | ||
| return files.flatMap((file) => { | ||
| if (!file.testLocations) return file.filepath; | ||
| return file.testLocations.map((location) => { | ||
| return `${file}:${location}`; | ||
| }); | ||
| }); | ||
| } | ||
| export { listenForErrors as a, emitModuleRunner as e, init as i, loadEnvironment as l }; |
| import module$1, { isBuiltin } from 'node:module'; | ||
| import { fileURLToPath, pathToFileURL } from 'node:url'; | ||
| import { automockModule, createManualModuleSource, collectModuleExports } from '@vitest/mocker/transforms'; | ||
| import { cleanUrl, createDefer } from '@vitest/utils/helpers'; | ||
| import { p as parse } from './acorn.B2iPLyUM.js'; | ||
| import { isAbsolute } from 'pathe'; | ||
| import { t as toBuiltin } from './modules.BJuCwlRJ.js'; | ||
| import { B as BareModuleMocker, n as normalizeModuleId } from './startVitestModuleRunner.BdSYEN5x.js'; | ||
| import 'node:fs'; | ||
| import './utils.BX5Fg8C4.js'; | ||
| import '@vitest/utils/timers'; | ||
| import '../path.js'; | ||
| import 'node:path'; | ||
| import '../module-evaluator.js'; | ||
| import 'node:vm'; | ||
| import 'vite/module-runner'; | ||
| import './traces.CCmnQaNT.js'; | ||
| import '@vitest/mocker'; | ||
| import '@vitest/mocker/redirect'; | ||
| class NativeModuleMocker extends BareModuleMocker { | ||
| wrapDynamicImport(moduleFactory) { | ||
| if (typeof moduleFactory === "function") return new Promise((resolve, reject) => { | ||
| this.resolveMocks().finally(() => { | ||
| moduleFactory().then(resolve, reject); | ||
| }); | ||
| }); | ||
| return moduleFactory; | ||
| } | ||
| resolveMockedModule(url, parentURL) { | ||
| // don't mock modules inside of packages because there is | ||
| // a high chance that it uses `require` which is not mockable | ||
| // because we use top-level await in "manual" mocks. | ||
| // for the sake of consistency we don't support mocking anything at all | ||
| if (parentURL.includes("/node_modules/")) return; | ||
| const moduleId = normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url); | ||
| const mockedModule = this.getDependencyMock(moduleId); | ||
| if (!mockedModule) return; | ||
| if (mockedModule.type === "redirect") return { | ||
| url: pathToFileURL(mockedModule.redirect).toString(), | ||
| shortCircuit: true | ||
| }; | ||
| if (mockedModule.type === "automock" || mockedModule.type === "autospy") return { | ||
| url: injectQuery(url, parentURL, `mock=${mockedModule.type}`), | ||
| shortCircuit: true | ||
| }; | ||
| if (mockedModule.type === "manual") return { | ||
| url: injectQuery(url, parentURL, "mock=manual"), | ||
| shortCircuit: true | ||
| }; | ||
| } | ||
| loadAutomock(url, result) { | ||
| const moduleId = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| let source; | ||
| if (isBuiltin(moduleId)) { | ||
| const builtinModule = getBuiltinModule(moduleId); | ||
| const exports$1 = Object.keys(builtinModule); | ||
| source = ` | ||
| import * as builtinModule from '${toBuiltin(moduleId)}?mock=actual' | ||
| ${exports$1.map((key, index) => { | ||
| return ` | ||
| const __${index} = builtinModule["${key}"] | ||
| export { __${index} as "${key}" } | ||
| `; | ||
| }).join("")}`; | ||
| } else source = result.source?.toString(); | ||
| if (source == null) return; | ||
| const mockType = url.includes("mock=automock") ? "automock" : "autospy"; | ||
| const transformedCode = transformCode(source, result.format || "module", moduleId); | ||
| try { | ||
| const ms = automockModule(transformedCode, mockType, (code) => parse(code, { | ||
| sourceType: "module", | ||
| ecmaVersion: "latest" | ||
| }), { id: moduleId }); | ||
| return { | ||
| format: "module", | ||
| source: `${ms.toString()}\n//# sourceMappingURL=${genSourceMapUrl(ms.generateMap({ | ||
| hires: "boundary", | ||
| source: moduleId | ||
| }))}`, | ||
| shortCircuit: true | ||
| }; | ||
| } catch (cause) { | ||
| throw new Error(`Cannot automock '${url}' because it failed to parse.`, { cause }); | ||
| } | ||
| } | ||
| loadManualMock(url, result) { | ||
| const moduleId = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| // should not be possible | ||
| if (this.getDependencyMock(moduleId)?.type !== "manual") { | ||
| console.warn(`Vitest detected unregistered manual mock ${moduleId}. This is a bug in Vitest. Please, open a new issue with reproduction.`); | ||
| return; | ||
| } | ||
| if (isBuiltin(moduleId)) { | ||
| const builtinModule = getBuiltinModule(toBuiltin(moduleId)); | ||
| return { | ||
| format: "module", | ||
| source: createManualModuleSource(moduleId, Object.keys(builtinModule)), | ||
| shortCircuit: true | ||
| }; | ||
| } | ||
| if (!result.source) return; | ||
| const transformedCode = transformCode(result.source.toString(), result.format || "module", moduleId); | ||
| if (transformedCode == null) return; | ||
| const format = result.format?.startsWith("module") ? "module" : "commonjs"; | ||
| try { | ||
| return { | ||
| format: "module", | ||
| source: createManualModuleSource(moduleId, collectModuleExports(moduleId, transformedCode, format)), | ||
| shortCircuit: true | ||
| }; | ||
| } catch (cause) { | ||
| throw new Error(`Failed to mock '${url}'. See the cause for more information.`, { cause }); | ||
| } | ||
| } | ||
| processedModules = /* @__PURE__ */ new Map(); | ||
| checkCircularManualMock(url) { | ||
| const id = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| this.processedModules.set(id, (this.processedModules.get(id) ?? 0) + 1); | ||
| // the module is mocked and requested a second time, let's resolve | ||
| // the factory function that will redefine the exports later | ||
| if (this.originalModulePromises.has(id)) { | ||
| const factoryPromise = this.factoryPromises.get(id); | ||
| this.originalModulePromises.get(id)?.resolve({ __factoryPromise: factoryPromise }); | ||
| } | ||
| } | ||
| originalModulePromises = /* @__PURE__ */ new Map(); | ||
| factoryPromises = /* @__PURE__ */ new Map(); | ||
| // potential performance improvement: | ||
| // store by URL, not ids, no need to call url.*to* methods and normalizeModuleId | ||
| getFactoryModule(id) { | ||
| const mock = this.getMockerRegistry().getById(id); | ||
| if (!mock || mock.type !== "manual") throw new Error(`Mock ${id} wasn't registered. This is probably a Vitest error. Please, open a new issue with reproduction.`); | ||
| const mockResult = mock.resolve(); | ||
| if (mockResult instanceof Promise) { | ||
| // to avoid circular dependency, we resolve this function as {__factoryPromise} in `checkCircularManualMock` | ||
| // when it's requested the second time. then the exports are exposed as `undefined`, | ||
| // but later redefined when the promise is actually resolved | ||
| const promise = createDefer(); | ||
| promise.finally(() => { | ||
| this.originalModulePromises.delete(id); | ||
| }); | ||
| mockResult.then(promise.resolve, promise.reject).finally(() => { | ||
| this.factoryPromises.delete(id); | ||
| }); | ||
| this.factoryPromises.set(id, mockResult); | ||
| this.originalModulePromises.set(id, promise); | ||
| // Node.js on windows processes all the files first, and then runs them | ||
| // unlike Node.js logic on Mac and Unix where it also runs the code while evaluating | ||
| // So on Linux/Mac this `if` won't be hit because `checkCircularManualMock` will resolve it | ||
| // And on Windows, the `checkCircularManualMock` will never have `originalModulePromises` | ||
| // because `getFactoryModule` is not called until the evaluation phase | ||
| // But if we track how many times the module was transformed, | ||
| // we can deduce when to return `__factoryPromise` to support circular modules | ||
| if ((this.processedModules.get(id) ?? 0) > 1) { | ||
| this.processedModules.set(id, (this.processedModules.get(id) ?? 1) - 1); | ||
| promise.resolve({ __factoryPromise: mockResult }); | ||
| } | ||
| return promise; | ||
| } | ||
| return mockResult; | ||
| } | ||
| importActual(rawId, importer) { | ||
| const resolvedId = import.meta.resolve(rawId, pathToFileURL(importer).toString()); | ||
| const url = new URL(resolvedId); | ||
| url.searchParams.set("mock", "actual"); | ||
| return import(url.toString()); | ||
| } | ||
| importMock(rawId, importer) { | ||
| const resolvedId = import.meta.resolve(rawId, pathToFileURL(importer).toString()); | ||
| // file is already mocked | ||
| if (resolvedId.includes("mock=")) return import(resolvedId); | ||
| const filename = fileURLToPath(resolvedId); | ||
| const external = !isAbsolute(filename) || this.isModuleDirectory(resolvedId) ? normalizeModuleId(rawId) : null; | ||
| // file is not mocked, automock or redirect it | ||
| const redirect = this.findMockRedirect(filename, external); | ||
| if (redirect) return import(pathToFileURL(redirect).toString()); | ||
| const url = new URL(resolvedId); | ||
| url.searchParams.set("mock", "automock"); | ||
| return import(url.toString()); | ||
| } | ||
| } | ||
| const replacePercentageRE = /%/g; | ||
| function injectQuery(url, importer, queryToInject) { | ||
| const { search, hash } = new URL(url.replace(replacePercentageRE, "%25"), importer); | ||
| return `${cleanUrl(url)}?${queryToInject}${search ? `&${search.slice(1)}` : ""}${hash ?? ""}`; | ||
| } | ||
| let __require; | ||
| function getBuiltinModule(moduleId) { | ||
| __require ??= module$1.createRequire(import.meta.url); | ||
| return __require(`${moduleId}?mock=actual`); | ||
| } | ||
| function genSourceMapUrl(map) { | ||
| if (typeof map !== "string") map = JSON.stringify(map); | ||
| return `data:application/json;base64,${Buffer.from(map).toString("base64")}`; | ||
| } | ||
| function transformCode(code, format, filename) { | ||
| if (format.includes("typescript")) { | ||
| if (!module$1.stripTypeScriptTypes) throw new Error(`Cannot parse '${filename}' because "module.stripTypeScriptTypes" is not supported. Module mocking requires Node.js 22.15 or higher. This is NOT a bug of Vitest.`); | ||
| return module$1.stripTypeScriptTypes(code); | ||
| } | ||
| return code; | ||
| } | ||
| export { NativeModuleMocker }; |
| import { DevEnvironment } from 'vite'; | ||
| import { V as Vitest, T as TestProject, a as TestProjectConfiguration } from './reporters.d.CRDGoPlb.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 { getSafeTimers } from '@vitest/utils/timers'; | ||
| import { c as createBirpc } from './index.Chj8NDwU.js'; | ||
| import { g as getWorkerState } from './utils.BX5Fg8C4.js'; | ||
| /* Ported from https://github.com/boblauer/MockDate/blob/master/src/mockdate.ts */ | ||
| /* | ||
| The MIT License (MIT) | ||
| Copyright (c) 2014 Bob Lauer | ||
| 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. | ||
| */ | ||
| const RealDate = Date; | ||
| let now = null; | ||
| class MockDate extends RealDate { | ||
| constructor(y, m, d, h, M, s, ms) { | ||
| super(); | ||
| let date; | ||
| switch (arguments.length) { | ||
| case 0: | ||
| if (now !== null) date = new RealDate(now.valueOf()); | ||
| else date = new RealDate(); | ||
| break; | ||
| case 1: | ||
| date = new RealDate(y); | ||
| break; | ||
| default: | ||
| d = typeof d === "undefined" ? 1 : d; | ||
| h = h || 0; | ||
| M = M || 0; | ||
| s = s || 0; | ||
| ms = ms || 0; | ||
| date = new RealDate(y, m, d, h, M, s, ms); | ||
| break; | ||
| } | ||
| Object.setPrototypeOf(date, MockDate.prototype); | ||
| return date; | ||
| } | ||
| } | ||
| MockDate.UTC = RealDate.UTC; | ||
| MockDate.now = function() { | ||
| return new MockDate().valueOf(); | ||
| }; | ||
| MockDate.parse = function(dateString) { | ||
| return RealDate.parse(dateString); | ||
| }; | ||
| MockDate.toString = function() { | ||
| return RealDate.toString(); | ||
| }; | ||
| function mockDate(date) { | ||
| const dateObj = new RealDate(date.valueOf()); | ||
| if (Number.isNaN(dateObj.getTime())) throw new TypeError(`mockdate: The time set is an invalid date: ${date}`); | ||
| // @ts-expect-error global | ||
| globalThis.Date = MockDate; | ||
| now = dateObj.valueOf(); | ||
| } | ||
| function resetDate() { | ||
| globalThis.Date = RealDate; | ||
| } | ||
| const { get } = Reflect; | ||
| function withSafeTimers(fn) { | ||
| const { setTimeout, clearTimeout, nextTick, setImmediate, clearImmediate } = getSafeTimers(); | ||
| const currentSetTimeout = globalThis.setTimeout; | ||
| const currentClearTimeout = globalThis.clearTimeout; | ||
| const currentSetImmediate = globalThis.setImmediate; | ||
| const currentClearImmediate = globalThis.clearImmediate; | ||
| const currentNextTick = globalThis.process?.nextTick; | ||
| try { | ||
| globalThis.setTimeout = setTimeout; | ||
| globalThis.clearTimeout = clearTimeout; | ||
| if (setImmediate) globalThis.setImmediate = setImmediate; | ||
| if (clearImmediate) globalThis.clearImmediate = clearImmediate; | ||
| if (globalThis.process && nextTick) globalThis.process.nextTick = nextTick; | ||
| return fn(); | ||
| } finally { | ||
| globalThis.setTimeout = currentSetTimeout; | ||
| globalThis.clearTimeout = currentClearTimeout; | ||
| globalThis.setImmediate = currentSetImmediate; | ||
| globalThis.clearImmediate = currentClearImmediate; | ||
| if (globalThis.process && nextTick) nextTick(() => { | ||
| globalThis.process.nextTick = currentNextTick; | ||
| }); | ||
| } | ||
| } | ||
| const promises = /* @__PURE__ */ new Set(); | ||
| async function rpcDone() { | ||
| if (!promises.size) return; | ||
| const awaitable = Array.from(promises); | ||
| return Promise.all(awaitable); | ||
| } | ||
| const onCancelCallbacks = []; | ||
| function onCancel(callback) { | ||
| onCancelCallbacks.push(callback); | ||
| } | ||
| function createRuntimeRpc(options) { | ||
| return createSafeRpc(createBirpc({ async onCancel(reason) { | ||
| await Promise.all(onCancelCallbacks.map((fn) => fn(reason))); | ||
| } }, { | ||
| eventNames: ["onCancel"], | ||
| timeout: -1, | ||
| ...options | ||
| })); | ||
| } | ||
| function createSafeRpc(rpc) { | ||
| return new Proxy(rpc, { get(target, p, handler) { | ||
| // keep $rejectPendingCalls as sync function | ||
| if (p === "$rejectPendingCalls") return rpc.$rejectPendingCalls; | ||
| const sendCall = get(target, p, handler); | ||
| const safeSendCall = (...args) => withSafeTimers(async () => { | ||
| const result = sendCall(...args); | ||
| promises.add(result); | ||
| try { | ||
| return await result; | ||
| } finally { | ||
| promises.delete(result); | ||
| } | ||
| }); | ||
| safeSendCall.asEvent = sendCall.asEvent; | ||
| return safeSendCall; | ||
| } }); | ||
| } | ||
| function rpc() { | ||
| const { rpc } = getWorkerState(); | ||
| return rpc; | ||
| } | ||
| export { RealDate as R, rpcDone as a, resetDate as b, createRuntimeRpc as c, mockDate as m, onCancel as o, rpc as r }; |
| 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.BX5Fg8C4.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.DA6L6i5h.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 }; |
| import fs from 'node:fs'; | ||
| import { isBareImport } from '@vitest/utils/helpers'; | ||
| import { i as isBuiltin, a as isBrowserExternal, t as toBuiltin } from './modules.BJuCwlRJ.js'; | ||
| import { E as EnvironmentTeardownError, a as getSafeWorkerState } from './utils.BX5Fg8C4.js'; | ||
| import { pathToFileURL } from 'node:url'; | ||
| import { normalize, join } from 'pathe'; | ||
| import { distDir } from '../path.js'; | ||
| import { VitestModuleEvaluator, unwrapId } from '../module-evaluator.js'; | ||
| import { isAbsolute, resolve } from 'node:path'; | ||
| import vm from 'node:vm'; | ||
| import { MockerRegistry, mockObject, RedirectedModule, AutomockedModule } from '@vitest/mocker'; | ||
| import { findMockRedirect } from '@vitest/mocker/redirect'; | ||
| import * as viteModuleRunner from 'vite/module-runner'; | ||
| import { T as Traces } from './traces.CCmnQaNT.js'; | ||
| class BareModuleMocker { | ||
| static pendingIds = []; | ||
| spyModule; | ||
| primitives; | ||
| registries = /* @__PURE__ */ new Map(); | ||
| mockContext = { callstack: null }; | ||
| _otel; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this._otel = options.traces; | ||
| this.primitives = { | ||
| Object, | ||
| Error, | ||
| Function, | ||
| RegExp, | ||
| Symbol: globalThis.Symbol, | ||
| Array, | ||
| Map | ||
| }; | ||
| if (options.spyModule) this.spyModule = options.spyModule; | ||
| } | ||
| get root() { | ||
| return this.options.root; | ||
| } | ||
| get moduleDirectories() { | ||
| return this.options.moduleDirectories || []; | ||
| } | ||
| getMockerRegistry() { | ||
| const suite = this.getSuiteFilepath(); | ||
| if (!this.registries.has(suite)) this.registries.set(suite, new MockerRegistry()); | ||
| return this.registries.get(suite); | ||
| } | ||
| reset() { | ||
| this.registries.clear(); | ||
| } | ||
| invalidateModuleById(_id) { | ||
| // implemented by mockers that control the module runner | ||
| } | ||
| isModuleDirectory(path) { | ||
| return this.moduleDirectories.some((dir) => path.includes(dir)); | ||
| } | ||
| getSuiteFilepath() { | ||
| return this.options.getCurrentTestFilepath() || "global"; | ||
| } | ||
| createError(message, codeFrame) { | ||
| const Error = this.primitives.Error; | ||
| const error = new Error(message); | ||
| Object.assign(error, { codeFrame }); | ||
| return error; | ||
| } | ||
| async resolveId(rawId, importer) { | ||
| return this._otel.$("vitest.mocker.resolve_id", { attributes: { | ||
| "vitest.module.raw_id": rawId, | ||
| "vitest.module.importer": rawId | ||
| } }, async (span) => { | ||
| const result = await this.options.resolveId(rawId, importer); | ||
| if (!result) { | ||
| span.addEvent("could not resolve id, fallback to unresolved values"); | ||
| const id = normalizeModuleId(rawId); | ||
| span.setAttributes({ | ||
| "vitest.module.id": id, | ||
| "vitest.module.url": rawId, | ||
| "vitest.module.external": id, | ||
| "vitest.module.fallback": true | ||
| }); | ||
| return { | ||
| id, | ||
| url: rawId, | ||
| external: id | ||
| }; | ||
| } | ||
| // external is node_module or unresolved module | ||
| // for example, some people mock "vscode" and don't have it installed | ||
| const external = !isAbsolute(result.file) || this.isModuleDirectory(result.file) ? normalizeModuleId(rawId) : null; | ||
| const id = normalizeModuleId(result.id); | ||
| span.setAttributes({ | ||
| "vitest.module.id": id, | ||
| "vitest.module.url": result.url, | ||
| "vitest.module.external": external ?? false | ||
| }); | ||
| return { | ||
| ...result, | ||
| id, | ||
| external | ||
| }; | ||
| }); | ||
| } | ||
| async resolveMocks() { | ||
| if (!BareModuleMocker.pendingIds.length) return; | ||
| await Promise.all(BareModuleMocker.pendingIds.map(async (mock) => { | ||
| const { id, url, external } = await this.resolveId(mock.id, mock.importer); | ||
| if (mock.action === "unmock") this.unmockPath(id); | ||
| if (mock.action === "mock") this.mockPath(mock.id, id, url, external, mock.type, mock.factory); | ||
| })); | ||
| BareModuleMocker.pendingIds = []; | ||
| } | ||
| // public method to avoid circular dependency | ||
| getMockContext() { | ||
| return this.mockContext; | ||
| } | ||
| // path used to store mocked dependencies | ||
| getMockPath(dep) { | ||
| return `mock:${dep}`; | ||
| } | ||
| getDependencyMock(id) { | ||
| return this.getMockerRegistry().getById(fixLeadingSlashes(id)); | ||
| } | ||
| getDependencyMockByUrl(url) { | ||
| return this.getMockerRegistry().get(url); | ||
| } | ||
| findMockRedirect(mockPath, external) { | ||
| return findMockRedirect(this.root, mockPath, external); | ||
| } | ||
| mockObject(object, mockExportsOrModuleType, moduleType) { | ||
| let mockExports; | ||
| if (mockExportsOrModuleType === "automock" || mockExportsOrModuleType === "autospy") { | ||
| moduleType = mockExportsOrModuleType; | ||
| mockExports = void 0; | ||
| } else mockExports = mockExportsOrModuleType; | ||
| moduleType ??= "automock"; | ||
| const createMockInstance = this.spyModule?.createMockInstance; | ||
| if (!createMockInstance) throw this.createError("[vitest] `spyModule` is not defined. This is a Vitest error. Please open a new issue with reproduction."); | ||
| return mockObject({ | ||
| globalConstructors: this.primitives, | ||
| createMockInstance, | ||
| type: moduleType | ||
| }, object, mockExports); | ||
| } | ||
| unmockPath(id) { | ||
| this.getMockerRegistry().deleteById(id); | ||
| this.invalidateModuleById(id); | ||
| } | ||
| mockPath(originalId, id, url, external, mockType, factory) { | ||
| const registry = this.getMockerRegistry(); | ||
| if (mockType === "manual") registry.register("manual", originalId, id, url, factory); | ||
| else if (mockType === "autospy") registry.register("autospy", originalId, id, url); | ||
| else { | ||
| const redirect = this.findMockRedirect(id, external); | ||
| if (redirect) registry.register("redirect", originalId, id, url, redirect); | ||
| else registry.register("automock", originalId, id, url); | ||
| } | ||
| // every time the mock is registered, we remove the previous one from the cache | ||
| this.invalidateModuleById(id); | ||
| } | ||
| async importActual(_rawId, _importer, _callstack) { | ||
| throw new Error(`importActual is not implemented`); | ||
| } | ||
| async importMock(_rawId, _importer, _callstack) { | ||
| throw new Error(`importMock is not implemented`); | ||
| } | ||
| queueMock(id, importer, factoryOrOptions) { | ||
| const mockType = getMockType(factoryOrOptions); | ||
| BareModuleMocker.pendingIds.push({ | ||
| action: "mock", | ||
| id, | ||
| importer, | ||
| factory: typeof factoryOrOptions === "function" ? factoryOrOptions : void 0, | ||
| type: mockType | ||
| }); | ||
| } | ||
| queueUnmock(id, importer) { | ||
| BareModuleMocker.pendingIds.push({ | ||
| action: "unmock", | ||
| id, | ||
| importer | ||
| }); | ||
| } | ||
| } | ||
| function getMockType(factoryOrOptions) { | ||
| if (!factoryOrOptions) return "automock"; | ||
| if (typeof factoryOrOptions === "function") return "manual"; | ||
| return factoryOrOptions.spy ? "autospy" : "automock"; | ||
| } | ||
| // unique id that is not available as "$bare_import" like "test" | ||
| // https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix | ||
| const prefixedBuiltins = new Set([ | ||
| "node:sea", | ||
| "node:sqlite", | ||
| "node:test", | ||
| "node:test/reporters" | ||
| ]); | ||
| const isWindows$1 = process.platform === "win32"; | ||
| // transform file url to id | ||
| // virtual:custom -> virtual:custom | ||
| // \0custom -> \0custom | ||
| // /root/id -> /id | ||
| // /root/id.js -> /id.js | ||
| // C:/root/id.js -> /id.js | ||
| // C:\root\id.js -> /id.js | ||
| // TODO: expose this in vite/module-runner | ||
| function normalizeModuleId(file) { | ||
| if (prefixedBuiltins.has(file)) return file; | ||
| // if it's not in the root, keep it as a path, not a URL | ||
| return slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/"); | ||
| } | ||
| const windowsSlashRE = /\\/g; | ||
| function slash(p) { | ||
| return p.replace(windowsSlashRE, "/"); | ||
| } | ||
| const multipleSlashRe = /^\/+/; | ||
| // module-runner incorrectly replaces file:///path with `///path` | ||
| function fixLeadingSlashes(id) { | ||
| if (id.startsWith("//")) return id.replace(multipleSlashRe, "/"); | ||
| return id; | ||
| } | ||
| // copied from vite/src/shared/utils.ts | ||
| const postfixRE = /[?#].*$/; | ||
| function cleanUrl(url) { | ||
| return url.replace(postfixRE, ""); | ||
| } | ||
| function splitFileAndPostfix(path) { | ||
| const file = cleanUrl(path); | ||
| return { | ||
| file, | ||
| postfix: path.slice(file.length) | ||
| }; | ||
| } | ||
| function injectQuery(url, queryToInject) { | ||
| const { file, postfix } = splitFileAndPostfix(url); | ||
| return `${file}?${queryToInject}${postfix[0] === "?" ? `&${postfix.slice(1)}` : postfix}`; | ||
| } | ||
| function removeQuery(url, queryToRemove) { | ||
| return url.replace(/* @__PURE__ */ new RegExp(`[?&]${queryToRemove}(?=[&#]|$)`), "").replace(/\?$/, ""); | ||
| } | ||
| const spyModulePath = resolve(distDir, "spy.js"); | ||
| class VitestMocker extends BareModuleMocker { | ||
| filterPublicKeys; | ||
| constructor(moduleRunner, options) { | ||
| super(options); | ||
| this.moduleRunner = moduleRunner; | ||
| this.options = options; | ||
| const context = this.options.context; | ||
| if (context) this.primitives = vm.runInContext("({ Object, Error, Function, RegExp, Symbol, Array, Map })", context); | ||
| const Symbol = this.primitives.Symbol; | ||
| this.filterPublicKeys = [ | ||
| "__esModule", | ||
| Symbol.asyncIterator, | ||
| Symbol.hasInstance, | ||
| Symbol.isConcatSpreadable, | ||
| Symbol.iterator, | ||
| Symbol.match, | ||
| Symbol.matchAll, | ||
| Symbol.replace, | ||
| Symbol.search, | ||
| Symbol.split, | ||
| Symbol.species, | ||
| Symbol.toPrimitive, | ||
| Symbol.toStringTag, | ||
| Symbol.unscopables | ||
| ]; | ||
| } | ||
| get evaluatedModules() { | ||
| return this.moduleRunner.evaluatedModules; | ||
| } | ||
| async initializeSpyModule() { | ||
| if (this.spyModule) return; | ||
| this.spyModule = await this.moduleRunner.import(spyModulePath); | ||
| } | ||
| reset() { | ||
| this.registries.clear(); | ||
| } | ||
| invalidateModuleById(id) { | ||
| const mockId = this.getMockPath(id); | ||
| const node = this.evaluatedModules.getModuleById(mockId); | ||
| if (node) { | ||
| this.evaluatedModules.invalidateModule(node); | ||
| node.mockedExports = void 0; | ||
| } | ||
| } | ||
| ensureModule(id, url) { | ||
| const node = this.evaluatedModules.ensureModule(id, url); | ||
| // TODO | ||
| node.meta = { | ||
| id, | ||
| url, | ||
| code: "", | ||
| file: null, | ||
| invalidate: false | ||
| }; | ||
| return node; | ||
| } | ||
| async callFunctionMock(id, url, mock) { | ||
| const node = this.ensureModule(id, url); | ||
| if (node.exports) return node.exports; | ||
| const exports$1 = await mock.resolve(); | ||
| const moduleExports = new Proxy(exports$1, { get: (target, prop) => { | ||
| const val = target[prop]; | ||
| // 'then' can exist on non-Promise objects, need nested instanceof check for logic to work | ||
| if (prop === "then") { | ||
| if (target instanceof Promise) return target.then.bind(target); | ||
| } else if (!(prop in target)) { | ||
| if (this.filterPublicKeys.includes(prop)) return; | ||
| throw this.createError(`[vitest] No "${String(prop)}" export is defined on the "${mock.raw}" mock. Did you forget to return it from "vi.mock"? | ||
| If you need to partially mock a module, you can use "importOriginal" helper inside: | ||
| `, `vi.mock(import("${mock.raw}"), async (importOriginal) => { | ||
| const actual = await importOriginal() | ||
| return { | ||
| ...actual, | ||
| // your mocked methods | ||
| } | ||
| })`); | ||
| } | ||
| return val; | ||
| } }); | ||
| node.exports = moduleExports; | ||
| return moduleExports; | ||
| } | ||
| async importActual(rawId, importer, callstack) { | ||
| const { url } = await this.resolveId(rawId, importer); | ||
| const actualUrl = injectQuery(url, "_vitest_original"); | ||
| const node = await this.moduleRunner.fetchModule(actualUrl, importer); | ||
| return await this.moduleRunner.cachedRequest(node.url, node, callstack || [importer], void 0, true); | ||
| } | ||
| async importMock(rawId, importer) { | ||
| const { id, url, external } = await this.resolveId(rawId, importer); | ||
| let mock = this.getDependencyMock(id); | ||
| if (!mock) { | ||
| const redirect = this.findMockRedirect(id, external); | ||
| if (redirect) mock = new RedirectedModule(rawId, id, rawId, redirect); | ||
| else mock = new AutomockedModule(rawId, id, rawId); | ||
| } | ||
| if (mock.type === "automock" || mock.type === "autospy") { | ||
| const node = await this.moduleRunner.fetchModule(url, importer); | ||
| const mod = await this.moduleRunner.cachedRequest(url, node, [importer], void 0, true); | ||
| const Object = this.primitives.Object; | ||
| return this.mockObject(mod, Object.create(Object.prototype), mock.type); | ||
| } | ||
| if (mock.type === "manual") return this.callFunctionMock(id, url, mock); | ||
| const node = await this.moduleRunner.fetchModule(mock.redirect); | ||
| return this.moduleRunner.cachedRequest(mock.redirect, node, [importer], void 0, true); | ||
| } | ||
| async requestWithMockedModule(url, evaluatedNode, callstack, mock) { | ||
| return this._otel.$("vitest.mocker.evaluate", async (span) => { | ||
| const mockId = this.getMockPath(evaluatedNode.id); | ||
| span.setAttributes({ | ||
| "vitest.module.id": mockId, | ||
| "vitest.mock.type": mock.type, | ||
| "vitest.mock.id": mock.id, | ||
| "vitest.mock.url": mock.url, | ||
| "vitest.mock.raw": mock.raw | ||
| }); | ||
| if (mock.type === "automock" || mock.type === "autospy") { | ||
| const cache = this.evaluatedModules.getModuleById(mockId); | ||
| if (cache && cache.mockedExports) return cache.mockedExports; | ||
| const Object = this.primitives.Object; | ||
| // we have to define a separate object that will copy all properties into itself | ||
| // and can't just use the same `exports` define automatically by Vite before the evaluator | ||
| const exports$1 = Object.create(null); | ||
| Object.defineProperty(exports$1, Symbol.toStringTag, { | ||
| value: "Module", | ||
| configurable: true, | ||
| writable: true | ||
| }); | ||
| const node = this.ensureModule(mockId, this.getMockPath(evaluatedNode.url)); | ||
| node.meta = evaluatedNode.meta; | ||
| node.file = evaluatedNode.file; | ||
| node.mockedExports = exports$1; | ||
| const mod = await this.moduleRunner.cachedRequest(url, node, callstack, void 0, true); | ||
| this.mockObject(mod, exports$1, mock.type); | ||
| return exports$1; | ||
| } | ||
| if (mock.type === "manual" && !callstack.includes(mockId) && !callstack.includes(url)) try { | ||
| callstack.push(mockId); | ||
| // this will not work if user does Promise.all(import(), import()) | ||
| // we can also use AsyncLocalStorage to store callstack, but this won't work in the browser | ||
| // maybe we should improve mock API in the future? | ||
| this.mockContext.callstack = callstack; | ||
| return await this.callFunctionMock(mockId, this.getMockPath(url), mock); | ||
| } finally { | ||
| this.mockContext.callstack = null; | ||
| const indexMock = callstack.indexOf(mockId); | ||
| callstack.splice(indexMock, 1); | ||
| } | ||
| else if (mock.type === "redirect" && !callstack.includes(mock.redirect)) { | ||
| span.setAttribute("vitest.mock.redirect", mock.redirect); | ||
| return mock.redirect; | ||
| } | ||
| }); | ||
| } | ||
| async mockedRequest(url, evaluatedNode, callstack) { | ||
| const mock = this.getDependencyMock(evaluatedNode.id); | ||
| if (!mock) return; | ||
| return this.requestWithMockedModule(url, evaluatedNode, callstack, mock); | ||
| } | ||
| } | ||
| class VitestTransport { | ||
| constructor(options, evaluatedModules, callstacks) { | ||
| this.options = options; | ||
| this.evaluatedModules = evaluatedModules; | ||
| this.callstacks = callstacks; | ||
| } | ||
| async invoke(event) { | ||
| if (event.type !== "custom") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support Vite HMR events.`) }; | ||
| if (event.event !== "vite:invoke") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support ${event.event} event.`) }; | ||
| const { name, data } = event.data; | ||
| if (name === "getBuiltins") | ||
| // we return an empty array here to avoid client-side builtin check, | ||
| // as we need builtins to go through `fetchModule` | ||
| return { result: [] }; | ||
| if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) }; | ||
| try { | ||
| return { result: await this.options.fetchModule(...data) }; | ||
| } catch (cause) { | ||
| if (cause instanceof EnvironmentTeardownError) { | ||
| const [id, importer] = data; | ||
| let message = `Cannot load '${id}'${importer ? ` imported from ${importer}` : ""} after the environment was torn down. This is not a bug in Vitest.`; | ||
| const moduleNode = importer ? this.evaluatedModules.getModuleById(importer) : void 0; | ||
| const callstack = moduleNode ? this.callstacks.get(moduleNode) : void 0; | ||
| if (callstack) message += ` The last recorded callstack:\n- ${[ | ||
| ...callstack, | ||
| importer, | ||
| id | ||
| ].reverse().join("\n- ")}`; | ||
| const error = new EnvironmentTeardownError(message); | ||
| if (cause.stack) error.stack = cause.stack.replace(cause.message, error.message); | ||
| return { error }; | ||
| } | ||
| return { error: cause }; | ||
| } | ||
| } | ||
| } | ||
| const createNodeImportMeta = (modulePath) => { | ||
| if (!viteModuleRunner.createDefaultImportMeta) throw new Error(`createNodeImportMeta is not supported in this version of Vite.`); | ||
| const defaultMeta = viteModuleRunner.createDefaultImportMeta(modulePath); | ||
| const href = defaultMeta.url; | ||
| const importMetaResolver = createImportMetaResolver(); | ||
| return { | ||
| ...defaultMeta, | ||
| main: false, | ||
| resolve(id, parent) { | ||
| return (importMetaResolver ?? defaultMeta.resolve)(id, parent ?? href); | ||
| } | ||
| }; | ||
| }; | ||
| function createImportMetaResolver() { | ||
| if (!import.meta.resolve) return; | ||
| return (specifier, importer) => import.meta.resolve(specifier, importer); | ||
| } | ||
| // @ts-expect-error overriding private method | ||
| class VitestModuleRunner extends viteModuleRunner.ModuleRunner { | ||
| mocker; | ||
| moduleExecutionInfo; | ||
| _otel; | ||
| _callstacks; | ||
| constructor(vitestOptions) { | ||
| const options = vitestOptions; | ||
| const evaluatedModules = options.evaluatedModules; | ||
| const callstacks = /* @__PURE__ */ new WeakMap(); | ||
| const transport = new VitestTransport(options.transport, evaluatedModules, callstacks); | ||
| super({ | ||
| transport, | ||
| hmr: false, | ||
| evaluatedModules, | ||
| sourcemapInterceptor: "prepareStackTrace", | ||
| createImportMeta: vitestOptions.createImportMeta | ||
| }, options.evaluator); | ||
| this.vitestOptions = vitestOptions; | ||
| this._callstacks = callstacks; | ||
| this._otel = vitestOptions.traces || new Traces({ enabled: false }); | ||
| this.moduleExecutionInfo = options.getWorkerState().moduleExecutionInfo; | ||
| this.mocker = options.mocker || new VitestMocker(this, { | ||
| spyModule: options.spyModule, | ||
| context: options.vm?.context, | ||
| traces: this._otel, | ||
| resolveId: options.transport.resolveId, | ||
| get root() { | ||
| return options.getWorkerState().config.root; | ||
| }, | ||
| get moduleDirectories() { | ||
| return options.getWorkerState().config.deps.moduleDirectories || []; | ||
| }, | ||
| getCurrentTestFilepath() { | ||
| return options.getWorkerState().filepath; | ||
| } | ||
| }); | ||
| if (options.vm) options.vm.context.__vitest_mocker__ = this.mocker; | ||
| else Object.defineProperty(globalThis, "__vitest_mocker__", { | ||
| configurable: true, | ||
| writable: true, | ||
| value: this.mocker | ||
| }); | ||
| } | ||
| /** | ||
| * Vite checks that the module has exports emulating the Node.js behaviour, | ||
| * but Vitest is more relaxed. | ||
| * | ||
| * We should keep the Vite behavour when there is a `strict` flag. | ||
| * @internal | ||
| */ | ||
| processImport(exports$1) { | ||
| return exports$1; | ||
| } | ||
| async import(rawId) { | ||
| const resolved = await this._otel.$("vitest.module.resolve_id", { attributes: { "vitest.module.raw_id": rawId } }, async (span) => { | ||
| const result = await this.vitestOptions.transport.resolveId(rawId); | ||
| if (result) span.setAttributes({ | ||
| "vitest.module.url": result.url, | ||
| "vitest.module.file": result.file, | ||
| "vitest.module.id": result.id | ||
| }); | ||
| return result; | ||
| }); | ||
| return super.import(resolved ? resolved.url : rawId); | ||
| } | ||
| async fetchModule(url, importer) { | ||
| return await this.cachedModule(url, importer); | ||
| } | ||
| _cachedRequest(url, module, callstack = [], metadata) { | ||
| // @ts-expect-error "cachedRequest" is private | ||
| return super.cachedRequest(url, module, callstack, metadata); | ||
| } | ||
| /** | ||
| * @internal | ||
| */ | ||
| async cachedRequest(url, mod, callstack = [], metadata, ignoreMock = false) { | ||
| // Track for a better error message if dynamic import is not resolved properly | ||
| this._callstacks.set(mod, callstack); | ||
| if (ignoreMock) return this._cachedRequest(url, mod, callstack, metadata); | ||
| let mocked; | ||
| if (mod.meta && "mockedModule" in mod.meta) { | ||
| const mockedModule = mod.meta.mockedModule; | ||
| const mockId = this.mocker.getMockPath(mod.id); | ||
| // bypass mock and force "importActual" behavior when: | ||
| // - mock was removed by doUnmock (stale mockedModule in meta) | ||
| // - self-import: mock factory/file is importing the module it's mocking | ||
| const isStale = !this.mocker.getDependencyMock(mod.id); | ||
| const isSelfImport = callstack.includes(mockId) || callstack.includes(url) || "redirect" in mockedModule && callstack.includes(mockedModule.redirect); | ||
| if (isStale || isSelfImport) { | ||
| const node = await this.fetchModule(injectQuery(url, "_vitest_original")); | ||
| return this._cachedRequest(node.url, node, callstack, metadata); | ||
| } | ||
| mocked = await this.mocker.requestWithMockedModule(url, mod, callstack, mockedModule); | ||
| } else mocked = await this.mocker.mockedRequest(url, mod, callstack); | ||
| if (typeof mocked === "string") { | ||
| const node = await this.fetchModule(mocked); | ||
| return this._cachedRequest(mocked, node, callstack, metadata); | ||
| } | ||
| if (mocked != null && typeof mocked === "object") return mocked; | ||
| return this._cachedRequest(url, mod, callstack, metadata); | ||
| } | ||
| /** @internal */ | ||
| _invalidateSubTreeById(ids, invalidated = /* @__PURE__ */ new Set()) { | ||
| for (const id of ids) { | ||
| if (invalidated.has(id)) continue; | ||
| const node = this.evaluatedModules.getModuleById(id); | ||
| if (!node) continue; | ||
| invalidated.add(id); | ||
| const subIds = Array.from(this.evaluatedModules.idToModuleMap).filter(([, mod]) => mod.importers.has(id)).map(([key]) => key); | ||
| if (subIds.length) this._invalidateSubTreeById(subIds, invalidated); | ||
| this.evaluatedModules.invalidateModule(node); | ||
| } | ||
| } | ||
| } | ||
| const bareVitestRegexp = /^@?vitest(?:\/|$)/; | ||
| const normalizedDistDir = normalize(distDir); | ||
| const relativeIds = {}; | ||
| const externalizeMap = /* @__PURE__ */ new Map(); | ||
| // all Vitest imports always need to be externalized | ||
| function getCachedVitestImport(id, state) { | ||
| if (id.startsWith("/@fs/") || id.startsWith("\\@fs\\")) id = id.slice(process.platform === "win32" ? 5 : 4); | ||
| if (externalizeMap.has(id)) return { | ||
| externalize: externalizeMap.get(id), | ||
| type: "module" | ||
| }; | ||
| // always externalize Vitest because we import from there before running tests | ||
| // so we already have it cached by Node.js | ||
| const root = state().config.root; | ||
| const relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length)); | ||
| if (id.includes(distDir) || id.includes(normalizedDistDir)) { | ||
| const externalize = id.startsWith("file://") ? id : pathToFileURL(id).toString(); | ||
| externalizeMap.set(id, externalize); | ||
| return { | ||
| externalize, | ||
| type: "module" | ||
| }; | ||
| } | ||
| if (relativeRoot && relativeRoot !== "/" && id.startsWith(relativeRoot)) { | ||
| const externalize = pathToFileURL(join(root, id)).toString(); | ||
| externalizeMap.set(id, externalize); | ||
| return { | ||
| externalize, | ||
| type: "module" | ||
| }; | ||
| } | ||
| if (bareVitestRegexp.test(id)) { | ||
| externalizeMap.set(id, id); | ||
| return { | ||
| externalize: id, | ||
| type: "module" | ||
| }; | ||
| } | ||
| return null; | ||
| } | ||
| const { readFileSync } = fs; | ||
| const VITEST_VM_CONTEXT_SYMBOL = "__vitest_vm_context__"; | ||
| const cwd = process.cwd(); | ||
| const isWindows = process.platform === "win32"; | ||
| function startVitestModuleRunner(options) { | ||
| const traces = options.traces; | ||
| const state = () => getSafeWorkerState() || options.state; | ||
| const rpc = () => state().rpc; | ||
| const environment = () => { | ||
| const environment = state().environment; | ||
| return environment.viteEnvironment || environment.name; | ||
| }; | ||
| const vm = options.context && options.externalModulesExecutor ? { | ||
| context: options.context, | ||
| externalModulesExecutor: options.externalModulesExecutor | ||
| } : void 0; | ||
| const evaluator = options.evaluator || new VitestModuleEvaluator(vm, { | ||
| traces, | ||
| evaluatedModules: options.evaluatedModules, | ||
| get moduleExecutionInfo() { | ||
| return state().moduleExecutionInfo; | ||
| }, | ||
| get interopDefault() { | ||
| return state().config.deps.interopDefault; | ||
| }, | ||
| getCurrentTestFilepath: () => state().filepath | ||
| }); | ||
| const moduleRunner = new VitestModuleRunner({ | ||
| spyModule: options.spyModule, | ||
| evaluatedModules: options.evaluatedModules, | ||
| evaluator, | ||
| traces, | ||
| mocker: options.mocker, | ||
| transport: { | ||
| async fetchModule(id, importer, options) { | ||
| const resolvingModules = state().resolvingModules; | ||
| if (isWindows) { | ||
| if (id[1] === ":") { | ||
| // The drive letter is different for whatever reason, we need to normalize it to CWD | ||
| if (id[0] !== cwd[0] && id[0].toUpperCase() === cwd[0].toUpperCase()) id = (cwd[0].toUpperCase() === cwd[0] ? id[0].toUpperCase() : id[0].toLowerCase()) + id.slice(1); | ||
| // always mark absolute windows paths, otherwise Vite will externalize it | ||
| id = `/@id/${id}`; | ||
| } | ||
| } | ||
| const vitest = getCachedVitestImport(id, state); | ||
| if (vitest) return vitest; | ||
| // strip _vitest_original query added by importActual so that | ||
| // the plugin pipeline sees the original import id (e.g. virtual modules's load hook) | ||
| const isImportActual = id.includes("_vitest_original"); | ||
| if (isImportActual) id = removeQuery(id, "_vitest_original"); | ||
| const rawId = unwrapId(id); | ||
| resolvingModules.add(rawId); | ||
| try { | ||
| if (VitestMocker.pendingIds.length) await moduleRunner.mocker.resolveMocks(); | ||
| if (!isImportActual) { | ||
| const resolvedMock = moduleRunner.mocker.getDependencyMockByUrl(id); | ||
| if (resolvedMock?.type === "manual" || resolvedMock?.type === "redirect") return { | ||
| code: "", | ||
| file: null, | ||
| id: resolvedMock.id, | ||
| url: resolvedMock.url, | ||
| invalidate: false, | ||
| mockedModule: resolvedMock | ||
| }; | ||
| } | ||
| if (isBuiltin(rawId)) return { | ||
| externalize: rawId, | ||
| type: "builtin" | ||
| }; | ||
| if (isBrowserExternal(rawId)) return { | ||
| externalize: toBuiltin(rawId), | ||
| type: "builtin" | ||
| }; | ||
| // if module is invalidated, the worker will be recreated, | ||
| // so cached is always true in a single worker | ||
| if (options?.cached) return { cache: true }; | ||
| const otelCarrier = traces?.getContextCarrier(); | ||
| const result = await rpc().fetch(id, importer, environment(), options, otelCarrier); | ||
| if ("cached" in result) return { | ||
| code: readFileSync(result.tmp, "utf-8"), | ||
| ...result | ||
| }; | ||
| return result; | ||
| } catch (cause) { | ||
| // rethrow vite error if it cannot load the module because it's not resolved | ||
| if (typeof cause === "object" && cause != null && cause.code === "ERR_LOAD_URL" || typeof cause?.message === "string" && cause.message.includes("Failed to load url") || typeof cause?.message === "string" && cause.message.startsWith("Cannot find module '")) { | ||
| const error = new Error(`Cannot find ${isBareImport(id) ? "package" : "module"} '${id}'${importer ? ` imported from ${importer}` : ""}`, { cause }); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| throw cause; | ||
| } finally { | ||
| resolvingModules.delete(rawId); | ||
| } | ||
| }, | ||
| resolveId(id, importer) { | ||
| return rpc().resolve(id, importer, environment()); | ||
| } | ||
| }, | ||
| getWorkerState: state, | ||
| vm, | ||
| createImportMeta: options.createImportMeta | ||
| }); | ||
| return moduleRunner; | ||
| } | ||
| export { BareModuleMocker as B, VITEST_VM_CONTEXT_SYMBOL as V, VitestModuleRunner as a, VitestTransport as b, createNodeImportMeta as c, normalizeModuleId as n, startVitestModuleRunner as s }; |
Sorry, the diff of this file is too big to display
| import { fileURLToPath, pathToFileURL } from 'node:url'; | ||
| import vm, { isContext, runInContext } from 'node:vm'; | ||
| import { dirname, basename, extname, normalize, resolve } from 'pathe'; | ||
| import { l as loadEnvironment, a as listenForErrors, e as emitModuleRunner } from './init.Borgldul.js'; | ||
| import { distDir } from '../path.js'; | ||
| import { createCustomConsole } from './console.3WNpx0tS.js'; | ||
| import fs from 'node:fs'; | ||
| import { createRequire, Module, isBuiltin } from 'node:module'; | ||
| import { toArray, isBareImport } from '@vitest/utils/helpers'; | ||
| import { findNearestPackageData } from '@vitest/utils/resolver'; | ||
| import { dirname as dirname$1 } from 'node:path'; | ||
| import { CSS_LANGS_RE, KNOWN_ASSET_RE } from '@vitest/utils/constants'; | ||
| import { getDefaultRequestStubs } from '../module-evaluator.js'; | ||
| import { s as startVitestModuleRunner, V as VITEST_VM_CONTEXT_SYMBOL, c as createNodeImportMeta } from './startVitestModuleRunner.BdSYEN5x.js'; | ||
| import { p as provideWorkerState } from './utils.BX5Fg8C4.js'; | ||
| function interopCommonJsModule(interopDefault, mod) { | ||
| if (isPrimitive(mod) || Array.isArray(mod) || mod instanceof Promise) return { | ||
| keys: [], | ||
| moduleExports: {}, | ||
| defaultExport: mod | ||
| }; | ||
| if (interopDefault !== false && "__esModule" in mod && !isPrimitive(mod.default)) { | ||
| const defaultKets = Object.keys(mod.default); | ||
| const moduleKeys = Object.keys(mod); | ||
| const allKeys = new Set([...defaultKets, ...moduleKeys]); | ||
| allKeys.delete("default"); | ||
| return { | ||
| keys: Array.from(allKeys), | ||
| moduleExports: new Proxy(mod, { get(mod, prop) { | ||
| return mod[prop] ?? mod.default?.[prop]; | ||
| } }), | ||
| defaultExport: mod | ||
| }; | ||
| } | ||
| return { | ||
| keys: Object.keys(mod).filter((key) => key !== "default"), | ||
| moduleExports: mod, | ||
| defaultExport: mod | ||
| }; | ||
| } | ||
| function isPrimitive(obj) { | ||
| return !(obj != null && (typeof obj === "object" || typeof obj === "function")); | ||
| } | ||
| const SyntheticModule = vm.SyntheticModule; | ||
| const SourceTextModule = vm.SourceTextModule; | ||
| const _require = createRequire(import.meta.url); | ||
| const requiresCache = /* @__PURE__ */ new WeakMap(); | ||
| class CommonjsExecutor { | ||
| context; | ||
| requireCache = /* @__PURE__ */ new Map(); | ||
| publicRequireCache = this.createProxyCache(); | ||
| moduleCache = /* @__PURE__ */ new Map(); | ||
| builtinCache = Object.create(null); | ||
| extensions = Object.create(null); | ||
| fs; | ||
| Module; | ||
| interopDefault; | ||
| constructor(options) { | ||
| this.context = options.context; | ||
| this.fs = options.fileMap; | ||
| this.interopDefault = options.interopDefault; | ||
| const primitives = vm.runInContext("({ Object, Array, Error })", this.context); | ||
| // eslint-disable-next-line ts/no-this-alias | ||
| const executor = this; | ||
| this.Module = class Module$1 { | ||
| exports; | ||
| isPreloading = false; | ||
| id; | ||
| filename; | ||
| loaded; | ||
| parent; | ||
| children = []; | ||
| path; | ||
| paths = []; | ||
| constructor(id = "", parent) { | ||
| this.exports = primitives.Object.create(Object.prototype); | ||
| // in our case the path should always be resolved already | ||
| this.path = dirname(id); | ||
| this.id = id; | ||
| this.filename = id; | ||
| this.loaded = false; | ||
| this.parent = parent; | ||
| } | ||
| get require() { | ||
| const require = requiresCache.get(this); | ||
| if (require) return require; | ||
| const _require = Module$1.createRequire(this.id); | ||
| requiresCache.set(this, _require); | ||
| return _require; | ||
| } | ||
| static getSourceMapsSupport = () => ({ | ||
| enabled: false, | ||
| nodeModules: false, | ||
| generatedCode: false | ||
| }); | ||
| static setSourceMapsSupport = () => { | ||
| // noop | ||
| }; | ||
| static register = () => { | ||
| throw new Error(`[vitest] "register" is not available when running in Vitest.`); | ||
| }; | ||
| static registerHooks = () => { | ||
| throw new Error(`[vitest] "registerHooks" is not available when running in Vitest.`); | ||
| }; | ||
| _compile(code, filename) { | ||
| const cjsModule = Module$1.wrap(code); | ||
| const script = new vm.Script(cjsModule, { | ||
| filename, | ||
| importModuleDynamically: options.importModuleDynamically | ||
| }); | ||
| // @ts-expect-error mark script with current identifier | ||
| script.identifier = filename; | ||
| const fn = script.runInContext(executor.context); | ||
| const __dirname = dirname(filename); | ||
| executor.requireCache.set(filename, this); | ||
| try { | ||
| fn(this.exports, this.require, this, filename, __dirname); | ||
| return this.exports; | ||
| } finally { | ||
| this.loaded = true; | ||
| } | ||
| } | ||
| // exposed for external use, Node.js does the opposite | ||
| static _load = (request, parent, _isMain) => { | ||
| return Module$1.createRequire(parent?.filename ?? request)(request); | ||
| }; | ||
| static wrap = (script) => { | ||
| return Module$1.wrapper[0] + script + Module$1.wrapper[1]; | ||
| }; | ||
| static wrapper = new primitives.Array("(function (exports, require, module, __filename, __dirname) { ", "\n});"); | ||
| static builtinModules = Module.builtinModules; | ||
| static findSourceMap = Module.findSourceMap; | ||
| static SourceMap = Module.SourceMap; | ||
| static syncBuiltinESMExports = Module.syncBuiltinESMExports; | ||
| static _cache = executor.publicRequireCache; | ||
| static _extensions = executor.extensions; | ||
| static createRequire = (filename) => { | ||
| return executor.createRequire(filename); | ||
| }; | ||
| static runMain = () => { | ||
| throw new primitives.Error("[vitest] \"runMain\" is not implemented."); | ||
| }; | ||
| // @ts-expect-error not typed | ||
| static _resolveFilename = Module._resolveFilename; | ||
| // @ts-expect-error not typed | ||
| static _findPath = Module._findPath; | ||
| // @ts-expect-error not typed | ||
| static _initPaths = Module._initPaths; | ||
| // @ts-expect-error not typed | ||
| static _preloadModules = Module._preloadModules; | ||
| // @ts-expect-error not typed | ||
| static _resolveLookupPaths = Module._resolveLookupPaths; | ||
| // @ts-expect-error not typed | ||
| static globalPaths = Module.globalPaths; | ||
| static isBuiltin = Module.isBuiltin; | ||
| static constants = Module.constants; | ||
| static enableCompileCache = Module.enableCompileCache; | ||
| static getCompileCacheDir = Module.getCompileCacheDir; | ||
| static flushCompileCache = Module.flushCompileCache; | ||
| static stripTypeScriptTypes = Module.stripTypeScriptTypes; | ||
| static findPackageJSON = Module.findPackageJSON; | ||
| static Module = Module$1; | ||
| }; | ||
| this.extensions[".js"] = this.requireJs; | ||
| this.extensions[".json"] = this.requireJson; | ||
| } | ||
| requireJs = (m, filename) => { | ||
| const content = this.fs.readFile(filename); | ||
| m._compile(content, filename); | ||
| }; | ||
| requireJson = (m, filename) => { | ||
| const code = this.fs.readFile(filename); | ||
| m.exports = JSON.parse(code); | ||
| }; | ||
| static cjsConditions; | ||
| static getCjsConditions() { | ||
| if (!CommonjsExecutor.cjsConditions) CommonjsExecutor.cjsConditions = parseCjsConditions(process.execArgv, process.env.NODE_OPTIONS); | ||
| return CommonjsExecutor.cjsConditions; | ||
| } | ||
| createRequire = (filename) => { | ||
| const _require = createRequire(filename); | ||
| const resolve = (id, options) => { | ||
| return _require.resolve(id, { | ||
| ...options, | ||
| conditions: CommonjsExecutor.getCjsConditions() | ||
| }); | ||
| }; | ||
| const require = ((id) => { | ||
| const resolved = resolve(id); | ||
| if (extname(resolved) === ".node" || isBuiltin(resolved)) return this.requireCoreModule(resolved); | ||
| const module = new this.Module(resolved); | ||
| return this.loadCommonJSModule(module, resolved); | ||
| }); | ||
| require.resolve = resolve; | ||
| require.resolve.paths = _require.resolve.paths; | ||
| Object.defineProperty(require, "extensions", { | ||
| get: () => this.extensions, | ||
| set: () => {}, | ||
| configurable: true | ||
| }); | ||
| require.main = void 0; | ||
| require.cache = this.publicRequireCache; | ||
| return require; | ||
| }; | ||
| createProxyCache() { | ||
| return new Proxy(Object.create(null), { | ||
| defineProperty: () => true, | ||
| deleteProperty: () => true, | ||
| set: () => true, | ||
| get: (_, key) => this.requireCache.get(key), | ||
| has: (_, key) => this.requireCache.has(key), | ||
| ownKeys: () => Array.from(this.requireCache.keys()), | ||
| getOwnPropertyDescriptor() { | ||
| return { | ||
| configurable: true, | ||
| enumerable: true | ||
| }; | ||
| } | ||
| }); | ||
| } | ||
| // very naive implementation for Node.js require | ||
| loadCommonJSModule(module, filename) { | ||
| const cached = this.requireCache.get(filename); | ||
| if (cached) return cached.exports; | ||
| const extension = this.findLongestRegisteredExtension(filename); | ||
| (this.extensions[extension] || this.extensions[".js"])(module, filename); | ||
| return module.exports; | ||
| } | ||
| findLongestRegisteredExtension(filename) { | ||
| const name = basename(filename); | ||
| let currentExtension; | ||
| let index; | ||
| let startIndex = 0; | ||
| // eslint-disable-next-line no-cond-assign | ||
| while ((index = name.indexOf(".", startIndex)) !== -1) { | ||
| startIndex = index + 1; | ||
| if (index === 0) continue; | ||
| currentExtension = name.slice(index); | ||
| if (this.extensions[currentExtension]) return currentExtension; | ||
| } | ||
| return ".js"; | ||
| } | ||
| getCoreSyntheticModule(identifier) { | ||
| if (this.moduleCache.has(identifier)) return this.moduleCache.get(identifier); | ||
| const exports$1 = this.require(identifier); | ||
| const keys = Object.keys(exports$1); | ||
| const module = new SyntheticModule([...keys, "default"], () => { | ||
| for (const key of keys) module.setExport(key, exports$1[key]); | ||
| module.setExport("default", exports$1); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| getCjsSyntheticModule(path, identifier) { | ||
| if (this.moduleCache.has(identifier)) return this.moduleCache.get(identifier); | ||
| const exports$1 = this.require(path); | ||
| // TODO: technically module should be parsed to find static exports, implement for strict mode in #2854 | ||
| const { keys, moduleExports, defaultExport } = interopCommonJsModule(this.interopDefault, exports$1); | ||
| const module = new SyntheticModule([...keys, "default"], function() { | ||
| for (const key of keys) this.setExport(key, moduleExports[key]); | ||
| this.setExport("default", defaultExport); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| // TODO: use this in strict mode, when available in #2854 | ||
| // private _getNamedCjsExports(path: string): Set<string> { | ||
| // const cachedNamedExports = this.cjsNamedExportsMap.get(path) | ||
| // if (cachedNamedExports) { | ||
| // return cachedNamedExports | ||
| // } | ||
| // if (extname(path) === '.node') { | ||
| // const moduleExports = this.require(path) | ||
| // const namedExports = new Set(Object.keys(moduleExports)) | ||
| // this.cjsNamedExportsMap.set(path, namedExports) | ||
| // return namedExports | ||
| // } | ||
| // const code = this.fs.readFile(path) | ||
| // const { exports, reexports } = parseCjs(code, path) | ||
| // const namedExports = new Set(exports) | ||
| // this.cjsNamedExportsMap.set(path, namedExports) | ||
| // for (const reexport of reexports) { | ||
| // if (isNodeBuiltin(reexport)) { | ||
| // const exports = this.require(reexport) | ||
| // if (exports !== null && typeof exports === 'object') { | ||
| // for (const e of Object.keys(exports)) { | ||
| // namedExports.add(e) | ||
| // } | ||
| // } | ||
| // } | ||
| // else { | ||
| // const require = this.createRequire(path) | ||
| // const resolved = require.resolve(reexport) | ||
| // const exports = this._getNamedCjsExports(resolved) | ||
| // for (const e of exports) { | ||
| // namedExports.add(e) | ||
| // } | ||
| // } | ||
| // } | ||
| // return namedExports | ||
| // } | ||
| require(identifier) { | ||
| if (extname(identifier) === ".node" || isBuiltin(identifier)) return this.requireCoreModule(identifier); | ||
| const module = new this.Module(identifier); | ||
| return this.loadCommonJSModule(module, identifier); | ||
| } | ||
| requireCoreModule(identifier) { | ||
| const normalized = identifier.replace(/^node:/, ""); | ||
| if (this.builtinCache[normalized]) return this.builtinCache[normalized].exports; | ||
| const moduleExports = _require(identifier); | ||
| if (identifier === "node:module" || identifier === "module") { | ||
| const module = new this.Module("/module.js"); | ||
| module.exports = this.Module; | ||
| this.builtinCache[normalized] = module; | ||
| return module.exports; | ||
| } | ||
| this.builtinCache[normalized] = _require.cache[normalized]; | ||
| // TODO: should we wrap module to rethrow context errors? | ||
| return moduleExports; | ||
| } | ||
| } | ||
| // The "module-sync" exports condition (added in Node 22.12/20.19 when | ||
| // require(esm) was unflagged) can resolve to ESM files that our CJS | ||
| // vm.Script executor cannot handle. We exclude it by passing explicit | ||
| // CJS conditions to require.resolve (Node 22.12+). | ||
| // Must be a Set because Node's internal resolver calls conditions.has(). | ||
| // User-specified --conditions/-C flags are respected, except module-sync. | ||
| function parseCjsConditions(execArgv, nodeOptions) { | ||
| const conditions = [ | ||
| "node", | ||
| "require", | ||
| "node-addons" | ||
| ]; | ||
| const args = [...execArgv, ...nodeOptions?.split(/\s+/) ?? []]; | ||
| for (let i = 0; i < args.length; i++) { | ||
| const arg = args[i]; | ||
| const eqMatch = arg.match(/^(?:--conditions|-C)=(.+)$/); | ||
| if (eqMatch) conditions.push(eqMatch[1]); | ||
| else if ((arg === "--conditions" || arg === "-C") && i + 1 < args.length) conditions.push(args[++i]); | ||
| } | ||
| return new Set(conditions.filter((c) => c !== "module-sync")); | ||
| } | ||
| const dataURIRegex = /^data:(?<mime>text\/javascript|application\/json|application\/wasm)(?:;(?<encoding>charset=utf-8|base64))?,(?<code>.*)$/; | ||
| class EsmExecutor { | ||
| moduleCache = /* @__PURE__ */ new Map(); | ||
| esmLinkMap = /* @__PURE__ */ new WeakMap(); | ||
| context; | ||
| #httpIp = IPnumber("127.0.0.0"); | ||
| constructor(executor, options) { | ||
| this.executor = executor; | ||
| this.context = options.context; | ||
| } | ||
| async evaluateModule(m) { | ||
| if (m.status === "unlinked") this.esmLinkMap.set(m, m.link((identifier, referencer) => this.executor.resolveModule(identifier, referencer.identifier))); | ||
| await this.esmLinkMap.get(m); | ||
| if (m.status === "linked") await m.evaluate(); | ||
| return m; | ||
| } | ||
| async createEsModule(fileURL, getCode) { | ||
| const cached = this.moduleCache.get(fileURL); | ||
| if (cached) return cached; | ||
| const promise = this.loadEsModule(fileURL, getCode); | ||
| this.moduleCache.set(fileURL, promise); | ||
| return promise; | ||
| } | ||
| async loadEsModule(fileURL, getCode) { | ||
| const code = await getCode(); | ||
| // TODO: should not be allowed in strict mode, implement in #2854 | ||
| if (fileURL.endsWith(".json")) { | ||
| const m = new SyntheticModule(["default"], function() { | ||
| const result = JSON.parse(code); | ||
| this.setExport("default", result); | ||
| }); | ||
| this.moduleCache.set(fileURL, m); | ||
| return m; | ||
| } | ||
| const m = new SourceTextModule(code, { | ||
| identifier: fileURL, | ||
| context: this.context, | ||
| importModuleDynamically: this.executor.importModuleDynamically, | ||
| initializeImportMeta: (meta, mod) => { | ||
| meta.url = mod.identifier; | ||
| if (mod.identifier.startsWith("file:")) { | ||
| const filename = fileURLToPath(mod.identifier); | ||
| meta.filename = filename; | ||
| meta.dirname = dirname$1(filename); | ||
| } | ||
| meta.resolve = (specifier, importer) => { | ||
| return this.executor.resolve(specifier, importer != null ? importer.toString() : mod.identifier); | ||
| }; | ||
| } | ||
| }); | ||
| this.moduleCache.set(fileURL, m); | ||
| return m; | ||
| } | ||
| async createWebAssemblyModule(fileUrl, getCode) { | ||
| const cached = this.moduleCache.get(fileUrl); | ||
| if (cached) return cached; | ||
| const m = this.loadWebAssemblyModule(getCode(), fileUrl); | ||
| this.moduleCache.set(fileUrl, m); | ||
| return m; | ||
| } | ||
| async createNetworkModule(fileUrl) { | ||
| // https://nodejs.org/api/esm.html#https-and-http-imports | ||
| if (fileUrl.startsWith("http:")) { | ||
| const url = new URL(fileUrl); | ||
| if (url.hostname !== "localhost" && url.hostname !== "::1" && (IPnumber(url.hostname) & IPmask(8)) !== this.#httpIp) throw new Error( | ||
| // we don't know the importer, so it's undefined (the same happens in --pool=threads) | ||
| `import of '${fileUrl}' by undefined is not supported: http can only be used to load local resources (use https instead).` | ||
| ); | ||
| } | ||
| return this.createEsModule(fileUrl, () => fetch(fileUrl).then((r) => r.text())); | ||
| } | ||
| async loadWebAssemblyModule(source, identifier) { | ||
| const cached = this.moduleCache.get(identifier); | ||
| if (cached) return cached; | ||
| const wasmModule = await WebAssembly.compile(source); | ||
| const exports$1 = WebAssembly.Module.exports(wasmModule); | ||
| const imports = WebAssembly.Module.imports(wasmModule); | ||
| const moduleLookup = {}; | ||
| for (const { module } of imports) if (moduleLookup[module] === void 0) moduleLookup[module] = await this.executor.resolveModule(module, identifier); | ||
| const evaluateModule = (module) => this.evaluateModule(module); | ||
| return new SyntheticModule(exports$1.map(({ name }) => name), async function() { | ||
| const importsObject = {}; | ||
| for (const { module, name } of imports) { | ||
| if (!importsObject[module]) importsObject[module] = {}; | ||
| await evaluateModule(moduleLookup[module]); | ||
| importsObject[module][name] = moduleLookup[module].namespace[name]; | ||
| } | ||
| const wasmInstance = new WebAssembly.Instance(wasmModule, importsObject); | ||
| for (const { name } of exports$1) this.setExport(name, wasmInstance.exports[name]); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| } | ||
| cacheModule(identifier, module) { | ||
| this.moduleCache.set(identifier, module); | ||
| } | ||
| resolveCachedModule(identifier) { | ||
| return this.moduleCache.get(identifier); | ||
| } | ||
| async createDataModule(identifier) { | ||
| const cached = this.moduleCache.get(identifier); | ||
| if (cached) return cached; | ||
| const match = identifier.match(dataURIRegex); | ||
| if (!match || !match.groups) throw new Error("Invalid data URI"); | ||
| const mime = match.groups.mime; | ||
| const encoding = match.groups.encoding; | ||
| if (mime === "application/wasm") { | ||
| if (!encoding) throw new Error("Missing data URI encoding"); | ||
| if (encoding !== "base64") throw new Error(`Invalid data URI encoding: ${encoding}`); | ||
| const module = this.loadWebAssemblyModule(Buffer.from(match.groups.code, "base64"), identifier); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| let code = match.groups.code; | ||
| if (!encoding || encoding === "charset=utf-8") code = decodeURIComponent(code); | ||
| else if (encoding === "base64") code = Buffer.from(code, "base64").toString(); | ||
| else throw new Error(`Invalid data URI encoding: ${encoding}`); | ||
| if (mime === "application/json") { | ||
| const module = new SyntheticModule(["default"], function() { | ||
| const obj = JSON.parse(code); | ||
| this.setExport("default", obj); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| return this.createEsModule(identifier, () => code); | ||
| } | ||
| } | ||
| function IPnumber(address) { | ||
| const ip = address.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/); | ||
| if (ip) return (+ip[1] << 24) + (+ip[2] << 16) + (+ip[3] << 8) + +ip[4]; | ||
| throw new Error(`Expected IP address, received ${address}`); | ||
| } | ||
| function IPmask(maskSize) { | ||
| return -1 << 32 - maskSize; | ||
| } | ||
| const CLIENT_ID = "/@vite/client"; | ||
| const CLIENT_FILE = pathToFileURL(CLIENT_ID).href; | ||
| class ViteExecutor { | ||
| esm; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this.esm = options.esmExecutor; | ||
| } | ||
| resolve = (identifier) => { | ||
| if (identifier === CLIENT_ID) return identifier; | ||
| }; | ||
| get workerState() { | ||
| return this.options.context.__vitest_worker__; | ||
| } | ||
| async createViteModule(fileUrl) { | ||
| if (fileUrl === CLIENT_FILE || fileUrl === CLIENT_ID) return this.createViteClientModule(); | ||
| const cached = this.esm.resolveCachedModule(fileUrl); | ||
| if (cached) return cached; | ||
| return this.esm.createEsModule(fileUrl, async () => { | ||
| try { | ||
| const result = await this.options.transform(fileUrl); | ||
| if (result.code) return result.code; | ||
| } catch (cause) { | ||
| // rethrow vite error if it cannot load the module because it's not resolved | ||
| if (typeof cause === "object" && cause.code === "ERR_LOAD_URL" || typeof cause?.message === "string" && cause.message.includes("Failed to load url")) { | ||
| const error = new Error(`Cannot find module '${fileUrl}'`, { cause }); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| } | ||
| throw new Error(`[vitest] Failed to transform ${fileUrl}. Does the file exist?`); | ||
| }); | ||
| } | ||
| createViteClientModule() { | ||
| const identifier = CLIENT_ID; | ||
| const cached = this.esm.resolveCachedModule(identifier); | ||
| if (cached) return cached; | ||
| const stub = this.options.viteClientModule; | ||
| const moduleKeys = Object.keys(stub); | ||
| const module = new SyntheticModule(moduleKeys, function() { | ||
| moduleKeys.forEach((key) => { | ||
| this.setExport(key, stub[key]); | ||
| }); | ||
| }, { | ||
| context: this.options.context, | ||
| identifier | ||
| }); | ||
| this.esm.cacheModule(identifier, module); | ||
| return module; | ||
| } | ||
| canResolve = (fileUrl) => { | ||
| if (fileUrl === CLIENT_FILE) return true; | ||
| const config = this.workerState.config.deps?.web || {}; | ||
| const [modulePath] = fileUrl.split("?"); | ||
| if (config.transformCss && CSS_LANGS_RE.test(modulePath)) return true; | ||
| if (config.transformAssets && KNOWN_ASSET_RE.test(modulePath)) return true; | ||
| if (toArray(config.transformGlobPattern).some((pattern) => pattern.test(modulePath))) return true; | ||
| return false; | ||
| }; | ||
| } | ||
| const { existsSync } = fs; | ||
| // always defined when we use vm pool | ||
| const nativeResolve = import.meta.resolve; | ||
| // TODO: improve Node.js strict mode support in #2854 | ||
| class ExternalModulesExecutor { | ||
| cjs; | ||
| esm; | ||
| vite; | ||
| context; | ||
| fs; | ||
| resolvers = []; | ||
| #networkSupported = null; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this.context = options.context; | ||
| this.fs = options.fileMap; | ||
| this.esm = new EsmExecutor(this, { context: this.context }); | ||
| this.cjs = new CommonjsExecutor({ | ||
| context: this.context, | ||
| importModuleDynamically: this.importModuleDynamically, | ||
| fileMap: options.fileMap, | ||
| interopDefault: options.interopDefault | ||
| }); | ||
| this.vite = new ViteExecutor({ | ||
| esmExecutor: this.esm, | ||
| context: this.context, | ||
| transform: options.transform, | ||
| viteClientModule: options.viteClientModule | ||
| }); | ||
| this.resolvers = [this.vite.resolve]; | ||
| } | ||
| async import(identifier) { | ||
| const module = await this.createModule(identifier); | ||
| await this.esm.evaluateModule(module); | ||
| return module.namespace; | ||
| } | ||
| require(identifier) { | ||
| return this.cjs.require(identifier); | ||
| } | ||
| createRequire(identifier) { | ||
| return this.cjs.createRequire(identifier); | ||
| } | ||
| // dynamic import can be used in both ESM and CJS, so we have it in the executor | ||
| importModuleDynamically = async (specifier, referencer) => { | ||
| const module = await this.resolveModule(specifier, referencer.identifier); | ||
| return await this.esm.evaluateModule(module); | ||
| }; | ||
| resolveModule = async (specifier, referencer) => { | ||
| let identifier = this.resolve(specifier, referencer); | ||
| if (identifier instanceof Promise) identifier = await identifier; | ||
| return await this.createModule(identifier); | ||
| }; | ||
| resolve(specifier, parent) { | ||
| for (const resolver of this.resolvers) { | ||
| const id = resolver(specifier, parent); | ||
| if (id) return id; | ||
| } | ||
| // import.meta.resolve can be asynchronous in older +18 Node versions | ||
| return nativeResolve(specifier, parent); | ||
| } | ||
| getModuleInformation(identifier) { | ||
| if (identifier.startsWith("data:")) return { | ||
| type: "data", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| const extension = extname(identifier); | ||
| if (extension === ".node" || isBuiltin(identifier)) return { | ||
| type: "builtin", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| if (this.isNetworkSupported && (identifier.startsWith("http:") || identifier.startsWith("https:"))) return { | ||
| type: "network", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| const isFileUrl = identifier.startsWith("file://"); | ||
| const pathUrl = isFileUrl ? fileURLToPath(identifier.split("?")[0]) : identifier; | ||
| const fileUrl = isFileUrl ? identifier : pathToFileURL(pathUrl).toString(); | ||
| let type; | ||
| if (this.vite.canResolve(fileUrl)) type = "vite"; | ||
| else if (extension === ".mjs") type = "module"; | ||
| else if (extension === ".cjs") type = "commonjs"; | ||
| else if (extension === ".wasm") | ||
| // still experimental on NodeJS --experimental-wasm-modules | ||
| // cf. ESM_FILE_FORMAT(url) in https://nodejs.org/docs/latest-v20.x/api/esm.html#resolution-algorithm | ||
| type = "wasm"; | ||
| else type = findNearestPackageData(normalize(pathUrl)).type === "module" ? "module" : "commonjs"; | ||
| return { | ||
| type, | ||
| path: pathUrl, | ||
| url: fileUrl | ||
| }; | ||
| } | ||
| createModule(identifier) { | ||
| const { type, url, path } = this.getModuleInformation(identifier); | ||
| // create ERR_MODULE_NOT_FOUND on our own since latest NodeJS's import.meta.resolve doesn't throw on non-existing namespace or path | ||
| // https://github.com/nodejs/node/pull/49038 | ||
| if ((type === "module" || type === "commonjs" || type === "wasm") && !existsSync(path)) { | ||
| const error = /* @__PURE__ */ new Error(`Cannot find ${isBareImport(path) ? "package" : "module"} '${path}'`); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| switch (type) { | ||
| case "data": return this.esm.createDataModule(identifier); | ||
| case "builtin": return this.cjs.getCoreSyntheticModule(identifier); | ||
| case "vite": return this.vite.createViteModule(url); | ||
| case "wasm": return this.esm.createWebAssemblyModule(url, () => this.fs.readBuffer(path)); | ||
| case "module": return this.esm.createEsModule(url, () => this.fs.readFileAsync(path)); | ||
| case "commonjs": return this.cjs.getCjsSyntheticModule(path, identifier); | ||
| case "network": return this.esm.createNetworkModule(url); | ||
| default: return type; | ||
| } | ||
| } | ||
| get isNetworkSupported() { | ||
| if (this.#networkSupported == null) if (process.execArgv.includes("--experimental-network-imports")) this.#networkSupported = true; | ||
| else if (process.env.NODE_OPTIONS?.includes("--experimental-network-imports")) this.#networkSupported = true; | ||
| else this.#networkSupported = false; | ||
| return this.#networkSupported; | ||
| } | ||
| } | ||
| const { promises, readFileSync } = fs; | ||
| class FileMap { | ||
| fsCache = /* @__PURE__ */ new Map(); | ||
| fsBufferCache = /* @__PURE__ */ new Map(); | ||
| async readFileAsync(path) { | ||
| const cached = this.fsCache.get(path); | ||
| if (cached != null) return cached; | ||
| const source = await promises.readFile(path, "utf-8"); | ||
| this.fsCache.set(path, source); | ||
| return source; | ||
| } | ||
| readFile(path) { | ||
| const cached = this.fsCache.get(path); | ||
| if (cached != null) return cached; | ||
| const source = readFileSync(path, "utf-8"); | ||
| this.fsCache.set(path, source); | ||
| return source; | ||
| } | ||
| readBuffer(path) { | ||
| const cached = this.fsBufferCache.get(path); | ||
| if (cached != null) return cached; | ||
| const buffer = readFileSync(path); | ||
| this.fsBufferCache.set(path, buffer); | ||
| return buffer; | ||
| } | ||
| } | ||
| const entryFile = pathToFileURL(resolve(distDir, "workers/runVmTests.js")).href; | ||
| const fileMap = new FileMap(); | ||
| const packageCache = /* @__PURE__ */ new Map(); | ||
| async function runVmTests(method, state, traces) { | ||
| const { ctx, rpc } = state; | ||
| const beforeEnvironmentTime = performance.now(); | ||
| const { environment } = await loadEnvironment(ctx.environment.name, ctx.config.root, rpc, traces, true); | ||
| state.environment = environment; | ||
| if (!environment.setupVM) { | ||
| const envName = ctx.environment.name; | ||
| const packageId = envName[0] === "." ? envName : `vitest-environment-${envName}`; | ||
| throw new TypeError(`Environment "${ctx.environment.name}" is not a valid environment. Path "${packageId}" doesn't support vm environment because it doesn't provide "setupVM" method.`); | ||
| } | ||
| const vm = await traces.$("vitest.runtime.environment.setup", { attributes: { | ||
| "vitest.environment": environment.name, | ||
| "vitest.environment.vite_environment": environment.viteEnvironment || environment.name | ||
| } }, () => environment.setupVM(ctx.environment.options || ctx.config.environmentOptions || {})); | ||
| state.durations.environment = performance.now() - beforeEnvironmentTime; | ||
| process.env.VITEST_VM_POOL = "1"; | ||
| if (!vm.getVmContext) throw new TypeError(`Environment ${environment.name} doesn't provide "getVmContext" method. It should return a context created by "vm.createContext" method.`); | ||
| const context = vm.getVmContext(); | ||
| if (!isContext(context)) throw new TypeError(`Environment ${environment.name} doesn't provide a valid context. It should be created by "vm.createContext" method.`); | ||
| provideWorkerState(context, state); | ||
| // this is unfortunately needed for our own dependencies | ||
| // we need to find a way to not rely on this by default | ||
| // because browser doesn't provide these globals | ||
| context.process = process; | ||
| context.global = context; | ||
| context.console = state.config.disableConsoleIntercept ? console : createCustomConsole(state); | ||
| // TODO: don't hardcode setImmediate in fake timers defaults | ||
| context.setImmediate = setImmediate; | ||
| context.clearImmediate = clearImmediate; | ||
| const stubs = getDefaultRequestStubs(context); | ||
| const externalModulesExecutor = new ExternalModulesExecutor({ | ||
| context, | ||
| fileMap, | ||
| packageCache, | ||
| transform: rpc.transform, | ||
| viteClientModule: stubs["/@vite/client"] | ||
| }); | ||
| process.exit = (code = process.exitCode || 0) => { | ||
| throw new Error(`process.exit unexpectedly called with "${code}"`); | ||
| }; | ||
| listenForErrors(() => state); | ||
| const moduleRunner = startVitestModuleRunner({ | ||
| context, | ||
| evaluatedModules: state.evaluatedModules, | ||
| state, | ||
| externalModulesExecutor, | ||
| createImportMeta: createNodeImportMeta, | ||
| traces | ||
| }); | ||
| emitModuleRunner(moduleRunner); | ||
| Object.defineProperty(context, VITEST_VM_CONTEXT_SYMBOL, { | ||
| value: { | ||
| context, | ||
| externalModulesExecutor | ||
| }, | ||
| configurable: true, | ||
| enumerable: false, | ||
| writable: false | ||
| }); | ||
| context.__vitest_mocker__ = moduleRunner.mocker; | ||
| if (ctx.config.serializedDefines) try { | ||
| runInContext(ctx.config.serializedDefines, context, { filename: "virtual:load-defines.js" }); | ||
| } catch (error) { | ||
| throw new Error(`Failed to load custom "defines": ${error.message}`); | ||
| } | ||
| await moduleRunner.mocker.initializeSpyModule(); | ||
| const { run } = await moduleRunner.import(entryFile); | ||
| try { | ||
| await run(method, ctx.files, ctx.config, moduleRunner, traces); | ||
| } finally { | ||
| await traces.$("vitest.runtime.environment.teardown", () => vm.teardown?.()); | ||
| } | ||
| } | ||
| function setupVmWorker(context) { | ||
| if (context.config.experimental.viteModuleRunner === false) throw new Error(`Pool "${context.pool}" cannot run with "experimental.viteModuleRunner: false". Please, use "threads" or "forks" instead.`); | ||
| } | ||
| export { runVmTests as r, setupVmWorker as s }; |
@@ -7,2 +7,2 @@ // @ts-ignore -- @vitest/browser-playwright might not be installed | ||
| export * from '@vitest/browser-preview/context' | ||
| export { BrowserCommands, FsOptions } from 'vitest/internal/browser' | ||
| export { BrowserCommands, CDPSession, FsOptions } from 'vitest/internal/browser' |
@@ -44,4 +44,5 @@ import { a as SerializedCoverageConfig, S as SerializedConfig } from './chunks/config.d.EJLVE3es.js'; | ||
| } | ||
| interface CDPSession {} | ||
| export { loadDiffConfig, loadSnapshotSerializers, setupCommonEnv, startCoverageInsideWorker, stopCoverageInsideWorker, takeCoverageInsideWorker }; | ||
| export type { BrowserCommands, FsOptions }; | ||
| export type { BrowserCommands, CDPSession, FsOptions }; |
+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.BRHvdzsc.js'; | ||
| export { l as loadDiffConfig, a as loadSnapshotSerializers, s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker, t as takeCoverageInsideWorker } from './chunks/setup-common.z3ZfZiWN.js'; | ||
| export { T as Traces } from './chunks/traces.CCmnQaNT.js'; | ||
@@ -3,0 +3,0 @@ export { collectTests, startTests } from '@vitest/runner'; |
+2
-2
@@ -1,2 +0,2 @@ | ||
| import { c as createCLI } from './chunks/cac.BvpGf9db.js'; | ||
| import { c as createCLI } from './chunks/cac.Vtz91O0H.js'; | ||
| import '@vitest/utils/helpers'; | ||
@@ -7,3 +7,3 @@ import 'events'; | ||
| import './chunks/constants.CPYnjOGj.js'; | ||
| import './chunks/index.mNs4_sfP.js'; | ||
| import './chunks/index.DpkD7Zj4.js'; | ||
| import 'node:fs'; | ||
@@ -10,0 +10,0 @@ import 'node:fs/promises'; |
+3
-3
| 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.pZWLB1PG.js'; | ||
| export { a as TestProjectConfiguration, d as TestProjectInlineConfiguration, e as TestUserConfig, W as WatcherTriggerPattern } from './chunks/reporters.d.pZWLB1PG.js'; | ||
| import { V as VitestPluginContext } from './chunks/plugin.d.BA1SfGdt.js'; | ||
| import { I as InlineConfig, C as CoverageV8Options, R as ResolvedCoverageOptions, U as UserWorkspaceConfig, b as UserProjectConfigFn, c as UserProjectConfigExport } from './chunks/reporters.d.CRDGoPlb.js'; | ||
| export { a as TestProjectConfiguration, d as TestProjectInlineConfiguration, e as TestUserConfig, W as WatcherTriggerPattern } from './chunks/reporters.d.CRDGoPlb.js'; | ||
| import { V as VitestPluginContext } from './chunks/plugin.d.pmonRL8Y.js'; | ||
| import { F as FakeTimerInstallOpts } from './chunks/config.d.EJLVE3es.js'; | ||
@@ -7,0 +7,0 @@ export { TestTagDefinition } from '@vitest/runner'; |
@@ -1,2 +0,2 @@ | ||
| import { R as ResolvedCoverageOptions, V as Vitest, aY as CoverageMap, am as ReportContext, T as TestProject } from './chunks/reporters.d.pZWLB1PG.js'; | ||
| import { R as ResolvedCoverageOptions, V as Vitest, aX as CoverageMap, al as ReportContext, T as TestProject } from './chunks/reporters.d.CRDGoPlb.js'; | ||
| import { TransformResult } from 'vite'; | ||
@@ -3,0 +3,0 @@ import { A as AfterSuiteRunMeta } from './chunks/rpc.d.BFMWpdph.js'; |
@@ -1,2 +0,2 @@ | ||
| export { e as builtinEnvironments, p as populateGlobal } from './chunks/index.CyBMJtT7.js'; | ||
| export { e as builtinEnvironments, p as populateGlobal } from './chunks/index.EY6TCHpo.js'; | ||
| import 'node:url'; | ||
@@ -3,0 +3,0 @@ import 'node:console'; |
+3
-3
@@ -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.BwzWwv9M.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.PnxXDGpZ.js'; | ||
| export { b as bench } from './chunks/benchmark.D0SlKNbZ.js'; | ||
| export { V as EvaluatedModules } from './chunks/evaluatedModules.Dg1zASAC.js'; | ||
| export { a as assertType } from './chunks/index.DqEi5Ycp.js'; | ||
| export { a as assertType } from './chunks/index.IcAjQV7n.js'; | ||
| export { expectTypeOf } from 'expect-type'; | ||
@@ -19,4 +19,4 @@ export { afterAll, afterEach, aroundAll, aroundEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, recordArtifact, suite, test } from '@vitest/runner'; | ||
| import './chunks/_commonjsHelpers.D26ty3Ew.js'; | ||
| import './chunks/rpc.CYazvPD1.js'; | ||
| import './chunks/rpc.MzXet3jl.js'; | ||
| import './chunks/index.Chj8NDwU.js'; | ||
| import 'vite/module-runner'; |
+4
-4
@@ -6,5 +6,5 @@ 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.pZWLB1PG.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.pZWLB1PG.js'; | ||
| export { C as CacheKeyIdGenerator, a as CacheKeyIdGeneratorContext, V as VitestPluginContext } from './chunks/plugin.d.BA1SfGdt.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.CRDGoPlb.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 CSSModuleScopeStrategy, O as CoverageIstanbulOptions, Q as CoverageOptions, S as CoverageProvider, X as CoverageProviderModule, Y as CoverageReporter, C as CoverageV8Options, Z as CustomProviderOptions, _ as DefaultReporter, $ as DepsOptimizationOptions, a0 as DotReporter, a1 as EnvironmentOptions, a2 as GithubActionsReporter, a3 as HTMLOptions, a4 as HangingProcessReporter, I as InlineConfig, a5 as JUnitOptions, a6 as JUnitReporter, a7 as JsonAssertionResult, a8 as JsonOptions, a9 as JsonReporter, aa as JsonTestResult, ab as JsonTestResults, ac as ModuleDiagnostic, ad as OnServerRestartHandler, ae as OnTestsRerunHandler, af as ParentProjectBrowser, ag as Pool, ah as PoolRunnerInitializer, ai as PoolTask, aj as ProjectBrowser, ak as ProjectConfig, al as ReportContext, am as ReportedHookContext, an as Reporter, ao as ReportersMap, ap as ResolveSnapshotPathHandler, aq as ResolveSnapshotPathHandlerContext, ar as ResolvedBrowserOptions, R as ResolvedCoverageOptions, as as ResolvedProjectConfig, at as SerializedTestProject, au as TapFlatReporter, av as TapReporter, aw as TaskOptions, ax as TestCase, ay as TestCollection, az as TestDiagnostic, aA as TestModule, aB as TestModuleState, aC as TestResult, aD as TestResultFailed, aE as TestResultPassed, aF as TestResultSkipped, aG as TestRunEndReason, aH as TestRunResult, aI as TestSequencerConstructor, aJ as TestSpecificationOptions, aK as TestState, aL as TestSuite, aM as TestSuiteState, aN as ToMatchScreenshotComparators, aO as ToMatchScreenshotOptions, aP as TypecheckConfig, U as UserWorkspaceConfig, aQ as VerboseBenchmarkReporter, aR as VerboseReporter, aS as VitestEnvironment, aT as VitestPackageInstaller, W as WatcherTriggerPattern, aU as WorkerResponse, aV as _BrowserNames, aW as experimental_getRunnerTask } from './chunks/reporters.d.CRDGoPlb.js'; | ||
| export { C as CacheKeyIdGenerator, a as CacheKeyIdGeneratorContext, V as VitestPluginContext } from './chunks/plugin.d.pmonRL8Y.js'; | ||
| export { BaseCoverageProvider } from './coverage.js'; | ||
@@ -22,2 +22,3 @@ import { Awaitable } from '@vitest/utils'; | ||
| export { generateFileHash } from '@vitest/runner/utils'; | ||
| export { CDPSession } from 'vitest/browser'; | ||
| import './chunks/browser.d.X3SXoOCV.js'; | ||
@@ -34,3 +35,2 @@ import './chunks/traces.d.402V_yFI.js'; | ||
| import '@vitest/utils/source-map'; | ||
| import 'vitest/browser'; | ||
| import './chunks/coverage.d.BZtK59WP.js'; | ||
@@ -37,0 +37,0 @@ import '@vitest/snapshot/manager'; |
+6
-6
| 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.D__YrL6a.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.D__YrL6a.js'; | ||
| export { p as parseCLI } from './chunks/cac.BvpGf9db.js'; | ||
| import { V as Vitest, a as VitestPlugin } from './chunks/cli-api.Bqj5xGy5.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.Bqj5xGy5.js'; | ||
| export { p as parseCLI } from './chunks/cac.Vtz91O0H.js'; | ||
| import { r as resolveConfig$2 } from './chunks/coverage.DUqi2f6q.js'; | ||
@@ -13,6 +13,6 @@ export { B as BaseCoverageProvider, a as BaseSequencer, b as resolveApiServerConfig } from './chunks/coverage.DUqi2f6q.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.mNs4_sfP.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.DpkD7Zj4.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.CPRfxlYj.js'; | ||
| export { B as BenchmarkReporter, a as BenchmarkReportsMap, V as VerboseBenchmarkReporter } from './chunks/index.CHsi7RlU.js'; | ||
| import 'node:fs'; | ||
@@ -31,2 +31,3 @@ import './chunks/coverage.D_JHT54q.js'; | ||
| import '@vitest/snapshot/manager'; | ||
| import '@vitest/utils/serialize'; | ||
| import './chunks/nativeModuleRunner.BIakptoF.js'; | ||
@@ -68,3 +69,2 @@ import 'vite/module-runner'; | ||
| import 'es-module-lexer'; | ||
| import '@vitest/utils/serialize'; | ||
| import '@vitest/utils/source-map'; | ||
@@ -71,0 +71,0 @@ import '@vitest/utils/source-map/node'; |
@@ -1,2 +0,2 @@ | ||
| 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.pZWLB1PG.js'; | ||
| export { m as BaseReporter, n as BenchmarkBuiltinReporters, o as BenchmarkReporter, p as BenchmarkReportsMap, K as BuiltinReporterOptions, M as BuiltinReporters, _ as DefaultReporter, a0 as DotReporter, a2 as GithubActionsReporter, a4 as HangingProcessReporter, a6 as JUnitReporter, a7 as JsonAssertionResult, a9 as JsonReporter, aa as JsonTestResult, ab as JsonTestResults, am as ReportedHookContext, an as Reporter, ao as ReportersMap, au as TapFlatReporter, av as TapReporter, aG as TestRunEndReason, aQ as VerboseBenchmarkReporter, aR as VerboseReporter } from './chunks/reporters.d.CRDGoPlb.js'; | ||
| import '@vitest/runner'; | ||
@@ -3,0 +3,0 @@ import '@vitest/utils'; |
@@ -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.mNs4_sfP.js'; | ||
| export { B as BenchmarkReporter, a as BenchmarkReportsMap, V as VerboseBenchmarkReporter } from './chunks/index.CPRfxlYj.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.DpkD7Zj4.js'; | ||
| export { B as BenchmarkReporter, a as BenchmarkReportsMap, V as VerboseBenchmarkReporter } from './chunks/index.CHsi7RlU.js'; | ||
| import 'node:fs'; | ||
@@ -4,0 +4,0 @@ import 'node:fs/promises'; |
+2
-2
@@ -1,2 +0,2 @@ | ||
| export { N as NodeBenchmarkRunner, T as VitestTestRunner } from './chunks/test.BwzWwv9M.js'; | ||
| export { N as NodeBenchmarkRunner, T as VitestTestRunner } from './chunks/test.PnxXDGpZ.js'; | ||
| import '@vitest/runner'; | ||
@@ -16,5 +16,5 @@ import '@vitest/utils/helpers'; | ||
| import './chunks/_commonjsHelpers.D26ty3Ew.js'; | ||
| import './chunks/rpc.CYazvPD1.js'; | ||
| import './chunks/rpc.MzXet3jl.js'; | ||
| import './chunks/index.Chj8NDwU.js'; | ||
| console.warn("Importing from \"vitest/runners\" is deprecated since Vitest 4.1. Please use \"vitest\" instead."); |
+2
-2
| import { VitestModuleEvaluator } from './module-evaluator.js'; | ||
| import { V as VITEST_VM_CONTEXT_SYMBOL, s as startVitestModuleRunner, a as VitestModuleRunner } from './chunks/startVitestModuleRunner.BRvQz4ko.js'; | ||
| import { V as VITEST_VM_CONTEXT_SYMBOL, s as startVitestModuleRunner, a as VitestModuleRunner } from './chunks/startVitestModuleRunner.BdSYEN5x.js'; | ||
| import { g as getWorkerState } from './chunks/utils.BX5Fg8C4.js'; | ||
| export { e as builtinEnvironments, p as populateGlobal } from './chunks/index.CyBMJtT7.js'; | ||
| export { e as builtinEnvironments, p as populateGlobal } from './chunks/index.EY6TCHpo.js'; | ||
| export { VitestNodeSnapshotEnvironment as VitestSnapshotEnvironment } from './chunks/node.COQbm6gK.js'; | ||
@@ -6,0 +6,0 @@ import 'node:module'; |
+9
-9
@@ -1,9 +0,9 @@ | ||
| export { r as runBaseTests, s as setupEnvironment } from './chunks/base.BzdSbvqu.js'; | ||
| export { i as init } from './chunks/init.DzWSvu83.js'; | ||
| export { r as runBaseTests, s as setupEnvironment } from './chunks/base.C98-6XAz.js'; | ||
| export { i as init } from './chunks/init.Borgldul.js'; | ||
| import 'node:vm'; | ||
| import '@vitest/spy'; | ||
| import './chunks/index.Bd3kKDSS.js'; | ||
| import './chunks/index.5lgR0kvt.js'; | ||
| import '@vitest/expect'; | ||
| import 'node:async_hooks'; | ||
| import './chunks/setup-common.BRHvdzsc.js'; | ||
| import './chunks/setup-common.z3ZfZiWN.js'; | ||
| import './chunks/coverage.D_JHT54q.js'; | ||
@@ -13,5 +13,5 @@ import '@vitest/snapshot'; | ||
| import './chunks/utils.BX5Fg8C4.js'; | ||
| import './chunks/rpc.CYazvPD1.js'; | ||
| import './chunks/rpc.MzXet3jl.js'; | ||
| import './chunks/index.Chj8NDwU.js'; | ||
| import './chunks/test.BwzWwv9M.js'; | ||
| import './chunks/test.PnxXDGpZ.js'; | ||
| import '@vitest/runner'; | ||
@@ -40,3 +40,3 @@ import '@vitest/utils/helpers'; | ||
| import './chunks/evaluatedModules.Dg1zASAC.js'; | ||
| import './chunks/startVitestModuleRunner.BRvQz4ko.js'; | ||
| import './chunks/startVitestModuleRunner.BdSYEN5x.js'; | ||
| import './chunks/modules.BJuCwlRJ.js'; | ||
@@ -52,6 +52,6 @@ import './path.js'; | ||
| import '@vitest/utils/constants'; | ||
| import './chunks/index.DqEi5Ycp.js'; | ||
| import './chunks/index.IcAjQV7n.js'; | ||
| import 'expect-type'; | ||
| import './chunks/index.CyBMJtT7.js'; | ||
| import './chunks/index.EY6TCHpo.js'; | ||
| import 'node:console'; | ||
| import '@vitest/utils/serialize'; |
+10
-10
@@ -1,9 +0,9 @@ | ||
| import { r as runBaseTests, s as setupBaseEnvironment } from '../chunks/base.BzdSbvqu.js'; | ||
| import { w as workerInit } from '../chunks/init-forks.Uz2iUy-b.js'; | ||
| import { r as runBaseTests, s as setupBaseEnvironment } from '../chunks/base.C98-6XAz.js'; | ||
| import { w as workerInit } from '../chunks/init-forks.BwPkXyLk.js'; | ||
| import 'node:vm'; | ||
| import '@vitest/spy'; | ||
| import '../chunks/index.Bd3kKDSS.js'; | ||
| import '../chunks/index.5lgR0kvt.js'; | ||
| import '@vitest/expect'; | ||
| import 'node:async_hooks'; | ||
| import '../chunks/setup-common.BRHvdzsc.js'; | ||
| import '../chunks/setup-common.z3ZfZiWN.js'; | ||
| import '../chunks/coverage.D_JHT54q.js'; | ||
@@ -13,5 +13,5 @@ import '@vitest/snapshot'; | ||
| import '../chunks/utils.BX5Fg8C4.js'; | ||
| import '../chunks/rpc.CYazvPD1.js'; | ||
| import '../chunks/rpc.MzXet3jl.js'; | ||
| import '../chunks/index.Chj8NDwU.js'; | ||
| import '../chunks/test.BwzWwv9M.js'; | ||
| import '../chunks/test.PnxXDGpZ.js'; | ||
| import '@vitest/runner'; | ||
@@ -26,3 +26,3 @@ import '@vitest/utils/helpers'; | ||
| import '../chunks/_commonjsHelpers.D26ty3Ew.js'; | ||
| import '../chunks/init.DzWSvu83.js'; | ||
| import '../chunks/init.Borgldul.js'; | ||
| import 'node:fs'; | ||
@@ -32,3 +32,3 @@ import 'node:module'; | ||
| import 'vite/module-runner'; | ||
| import '../chunks/startVitestModuleRunner.BRvQz4ko.js'; | ||
| import '../chunks/startVitestModuleRunner.BdSYEN5x.js'; | ||
| import '../chunks/modules.BJuCwlRJ.js'; | ||
@@ -41,3 +41,3 @@ import '../path.js'; | ||
| import '@vitest/mocker/redirect'; | ||
| import '../chunks/index.CyBMJtT7.js'; | ||
| import '../chunks/index.EY6TCHpo.js'; | ||
| import 'node:console'; | ||
@@ -58,3 +58,3 @@ import '@vitest/utils/serialize'; | ||
| import '@vitest/utils/constants'; | ||
| import '../chunks/index.DqEi5Ycp.js'; | ||
| import '../chunks/index.IcAjQV7n.js'; | ||
| import 'expect-type'; | ||
@@ -61,0 +61,0 @@ |
@@ -8,11 +8,11 @@ import { createRequire } from 'node:module'; | ||
| import { KNOWN_ASSET_TYPES } from '@vitest/utils/constants'; | ||
| import { s as setupChaiConfig, r as resolveTestRunner, a as resolveSnapshotEnvironment, d as detectAsyncLeaks } from '../chunks/index.Bd3kKDSS.js'; | ||
| import { s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker } from '../chunks/setup-common.BRHvdzsc.js'; | ||
| import { i as index } from '../chunks/index.DqEi5Ycp.js'; | ||
| import { s as setupChaiConfig, r as resolveTestRunner, a as resolveSnapshotEnvironment, d as detectAsyncLeaks } from '../chunks/index.5lgR0kvt.js'; | ||
| import { s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker } from '../chunks/setup-common.z3ZfZiWN.js'; | ||
| import { i as index } from '../chunks/index.IcAjQV7n.js'; | ||
| import { c as closeInspector } from '../chunks/inspector.CvyFGlXm.js'; | ||
| import { g as getWorkerState } from '../chunks/utils.BX5Fg8C4.js'; | ||
| import { g as globalExpect } from '../chunks/test.BwzWwv9M.js'; | ||
| import { g as globalExpect } from '../chunks/test.PnxXDGpZ.js'; | ||
| import '@vitest/expect'; | ||
| import 'node:async_hooks'; | ||
| import '../chunks/rpc.CYazvPD1.js'; | ||
| import '../chunks/rpc.MzXet3jl.js'; | ||
| import '@vitest/utils/timers'; | ||
@@ -19,0 +19,0 @@ import '../chunks/index.Chj8NDwU.js'; |
+10
-10
@@ -1,9 +0,9 @@ | ||
| import { s as setupBaseEnvironment, r as runBaseTests } from '../chunks/base.BzdSbvqu.js'; | ||
| import { w as workerInit } from '../chunks/init-threads.u8FhyhU_.js'; | ||
| import { s as setupBaseEnvironment, r as runBaseTests } from '../chunks/base.C98-6XAz.js'; | ||
| import { w as workerInit } from '../chunks/init-threads.BuSVu8Ns.js'; | ||
| import 'node:vm'; | ||
| import '@vitest/spy'; | ||
| import '../chunks/index.Bd3kKDSS.js'; | ||
| import '../chunks/index.5lgR0kvt.js'; | ||
| import '@vitest/expect'; | ||
| import 'node:async_hooks'; | ||
| import '../chunks/setup-common.BRHvdzsc.js'; | ||
| import '../chunks/setup-common.z3ZfZiWN.js'; | ||
| import '../chunks/coverage.D_JHT54q.js'; | ||
@@ -13,5 +13,5 @@ import '@vitest/snapshot'; | ||
| import '../chunks/utils.BX5Fg8C4.js'; | ||
| import '../chunks/rpc.CYazvPD1.js'; | ||
| import '../chunks/rpc.MzXet3jl.js'; | ||
| import '../chunks/index.Chj8NDwU.js'; | ||
| import '../chunks/test.BwzWwv9M.js'; | ||
| import '../chunks/test.PnxXDGpZ.js'; | ||
| import '@vitest/runner'; | ||
@@ -26,3 +26,3 @@ import '@vitest/utils/helpers'; | ||
| import '../chunks/_commonjsHelpers.D26ty3Ew.js'; | ||
| import '../chunks/init.DzWSvu83.js'; | ||
| import '../chunks/init.Borgldul.js'; | ||
| import 'node:fs'; | ||
@@ -32,3 +32,3 @@ import 'node:module'; | ||
| import 'vite/module-runner'; | ||
| import '../chunks/startVitestModuleRunner.BRvQz4ko.js'; | ||
| import '../chunks/startVitestModuleRunner.BdSYEN5x.js'; | ||
| import '../chunks/modules.BJuCwlRJ.js'; | ||
@@ -41,3 +41,3 @@ import '../path.js'; | ||
| import '@vitest/mocker/redirect'; | ||
| import '../chunks/index.CyBMJtT7.js'; | ||
| import '../chunks/index.EY6TCHpo.js'; | ||
| import 'node:console'; | ||
@@ -58,3 +58,3 @@ import '@vitest/utils/serialize'; | ||
| import '@vitest/utils/constants'; | ||
| import '../chunks/index.DqEi5Ycp.js'; | ||
| import '../chunks/index.IcAjQV7n.js'; | ||
| import 'expect-type'; | ||
@@ -61,0 +61,0 @@ import 'node:worker_threads'; |
@@ -1,4 +0,4 @@ | ||
| import { w as workerInit } from '../chunks/init-forks.Uz2iUy-b.js'; | ||
| import { r as runVmTests, s as setupVmWorker } from '../chunks/vm.D32oUcpO.js'; | ||
| import '../chunks/init.DzWSvu83.js'; | ||
| import { w as workerInit } from '../chunks/init-forks.BwPkXyLk.js'; | ||
| import { r as runVmTests, s as setupVmWorker } from '../chunks/vm.V092iA4c.js'; | ||
| import '../chunks/init.Borgldul.js'; | ||
| import 'node:fs'; | ||
@@ -9,3 +9,3 @@ import 'node:module'; | ||
| import 'vite/module-runner'; | ||
| import '../chunks/startVitestModuleRunner.BRvQz4ko.js'; | ||
| import '../chunks/startVitestModuleRunner.BdSYEN5x.js'; | ||
| import '@vitest/utils/helpers'; | ||
@@ -22,7 +22,7 @@ import '../chunks/modules.BJuCwlRJ.js'; | ||
| import '@vitest/mocker/redirect'; | ||
| import '../chunks/index.CyBMJtT7.js'; | ||
| import '../chunks/index.EY6TCHpo.js'; | ||
| import 'node:console'; | ||
| import '@vitest/utils/serialize'; | ||
| import '@vitest/utils/error'; | ||
| import '../chunks/rpc.CYazvPD1.js'; | ||
| import '../chunks/rpc.MzXet3jl.js'; | ||
| import '../chunks/index.Chj8NDwU.js'; | ||
@@ -32,3 +32,3 @@ import '@vitest/utils/source-map'; | ||
| import '../chunks/evaluatedModules.Dg1zASAC.js'; | ||
| import '../chunks/console.DpQfzR9G.js'; | ||
| import '../chunks/console.3WNpx0tS.js'; | ||
| import 'node:stream'; | ||
@@ -35,0 +35,0 @@ import 'tinyrainbow'; |
@@ -1,5 +0,5 @@ | ||
| import { w as workerInit } from '../chunks/init-threads.u8FhyhU_.js'; | ||
| import { s as setupVmWorker, r as runVmTests } from '../chunks/vm.D32oUcpO.js'; | ||
| import { w as workerInit } from '../chunks/init-threads.BuSVu8Ns.js'; | ||
| import { s as setupVmWorker, r as runVmTests } from '../chunks/vm.V092iA4c.js'; | ||
| import 'node:worker_threads'; | ||
| import '../chunks/init.DzWSvu83.js'; | ||
| import '../chunks/init.Borgldul.js'; | ||
| import 'node:fs'; | ||
@@ -10,3 +10,3 @@ import 'node:module'; | ||
| import 'vite/module-runner'; | ||
| import '../chunks/startVitestModuleRunner.BRvQz4ko.js'; | ||
| import '../chunks/startVitestModuleRunner.BdSYEN5x.js'; | ||
| import '@vitest/utils/helpers'; | ||
@@ -23,7 +23,7 @@ import '../chunks/modules.BJuCwlRJ.js'; | ||
| import '@vitest/mocker/redirect'; | ||
| import '../chunks/index.CyBMJtT7.js'; | ||
| import '../chunks/index.EY6TCHpo.js'; | ||
| import 'node:console'; | ||
| import '@vitest/utils/serialize'; | ||
| import '@vitest/utils/error'; | ||
| import '../chunks/rpc.CYazvPD1.js'; | ||
| import '../chunks/rpc.MzXet3jl.js'; | ||
| import '../chunks/index.Chj8NDwU.js'; | ||
@@ -33,3 +33,3 @@ import '@vitest/utils/source-map'; | ||
| import '../chunks/evaluatedModules.Dg1zASAC.js'; | ||
| import '../chunks/console.DpQfzR9G.js'; | ||
| import '../chunks/console.3WNpx0tS.js'; | ||
| import 'node:stream'; | ||
@@ -36,0 +36,0 @@ import 'tinyrainbow'; |
+14
-14
| { | ||
| "name": "vitest", | ||
| "type": "module", | ||
| "version": "4.1.0-beta.5", | ||
| "version": "4.1.0-beta.6", | ||
| "description": "Next generation testing framework powered by Vite", | ||
@@ -135,6 +135,6 @@ "author": "Anthony Fu <anthonyfu117@hotmail.com>", | ||
| "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0", | ||
| "@vitest/browser-playwright": "4.1.0-beta.5", | ||
| "@vitest/browser-preview": "4.1.0-beta.5", | ||
| "@vitest/browser-webdriverio": "4.1.0-beta.5", | ||
| "@vitest/ui": "4.1.0-beta.5" | ||
| "@vitest/browser-playwright": "4.1.0-beta.6", | ||
| "@vitest/browser-webdriverio": "4.1.0-beta.6", | ||
| "@vitest/ui": "4.1.0-beta.6", | ||
| "@vitest/browser-preview": "4.1.0-beta.6" | ||
| }, | ||
@@ -187,9 +187,9 @@ "peerDependenciesMeta": { | ||
| "why-is-node-running": "^2.3.0", | ||
| "@vitest/expect": "4.1.0-beta.5", | ||
| "@vitest/pretty-format": "4.1.0-beta.5", | ||
| "@vitest/mocker": "4.1.0-beta.5", | ||
| "@vitest/runner": "4.1.0-beta.5", | ||
| "@vitest/snapshot": "4.1.0-beta.5", | ||
| "@vitest/utils": "4.1.0-beta.5", | ||
| "@vitest/spy": "4.1.0-beta.5" | ||
| "@vitest/mocker": "4.1.0-beta.6", | ||
| "@vitest/expect": "4.1.0-beta.6", | ||
| "@vitest/pretty-format": "4.1.0-beta.6", | ||
| "@vitest/spy": "4.1.0-beta.6", | ||
| "@vitest/runner": "4.1.0-beta.6", | ||
| "@vitest/snapshot": "4.1.0-beta.6", | ||
| "@vitest/utils": "4.1.0-beta.6" | ||
| }, | ||
@@ -207,3 +207,3 @@ "devDependencies": { | ||
| "@types/jsdom": "^27.0.0", | ||
| "@types/node": "^24.10.13", | ||
| "@types/node": "^24.11.0", | ||
| "@types/picomatch": "^4.0.2", | ||
@@ -217,3 +217,3 @@ "@types/prompts": "^2.4.9", | ||
| "empathic": "^2.0.0", | ||
| "flatted": "3.3.3", | ||
| "flatted": "3.3.4", | ||
| "happy-dom": "^20.7.0", | ||
@@ -220,0 +220,0 @@ "jsdom": "^27.4.0", |
+1
-1
| # vitest | ||
| [](https://www.npmjs.com/package/vitest) | ||
| [](https://npmx.dev/package/vitest) | ||
@@ -5,0 +5,0 @@ Next generation testing framework powered by Vite. |
| 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.Bd3kKDSS.js'; | ||
| import { l as loadEnvironment, e as emitModuleRunner, a as listenForErrors } from './init.DzWSvu83.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.BRvQz4ko.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.BRHvdzsc.js'; | ||
| import { g as globalExpect, v as vi } from './test.BwzWwv9M.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.DqEi5Ycp.js'; | ||
| import { g as getWorkerState, r as resetModules, p as provideWorkerState, a as getSafeWorkerState } from './utils.BX5Fg8C4.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.DpQfzR9G.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.Bt11nCqn.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 }; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
| import { Console } from 'node:console'; | ||
| import { relative } from 'node:path'; | ||
| import { Writable } from 'node:stream'; | ||
| import { getSafeTimers } from '@vitest/utils/timers'; | ||
| import c from 'tinyrainbow'; | ||
| import { R as RealDate } from './rpc.CYazvPD1.js'; | ||
| import { g as getWorkerState } from './utils.BX5Fg8C4.js'; | ||
| import './index.Chj8NDwU.js'; | ||
| const UNKNOWN_TEST_ID = "__vitest__unknown_test__"; | ||
| function getTaskIdByStack(root) { | ||
| const stack = (/* @__PURE__ */ new Error("STACK_TRACE_ERROR")).stack?.split("\n"); | ||
| if (!stack) return UNKNOWN_TEST_ID; | ||
| const index = stack.findIndex((line) => line.includes("at Console.value")); | ||
| const line = index === -1 ? null : stack[index + 2]; | ||
| if (!line) return UNKNOWN_TEST_ID; | ||
| const filepath = line.match(/at\s(.*)\s?/)?.[1]; | ||
| if (filepath) return relative(root, filepath); | ||
| return UNKNOWN_TEST_ID; | ||
| } | ||
| function createCustomConsole(defaultState) { | ||
| const stdoutBuffer = /* @__PURE__ */ new Map(); | ||
| const stderrBuffer = /* @__PURE__ */ new Map(); | ||
| const timers = /* @__PURE__ */ new Map(); | ||
| const { queueMicrotask } = getSafeTimers(); | ||
| function queueCancelableMicrotask(callback) { | ||
| let canceled = false; | ||
| queueMicrotask(() => { | ||
| if (!canceled) callback(); | ||
| }); | ||
| return () => { | ||
| canceled = true; | ||
| }; | ||
| } | ||
| const state = () => defaultState || getWorkerState(); | ||
| // group sync console.log calls with micro task | ||
| function schedule(taskId) { | ||
| const timer = timers.get(taskId); | ||
| const { stdoutTime, stderrTime } = timer; | ||
| timer.cancel?.(); | ||
| timer.cancel = queueCancelableMicrotask(() => { | ||
| if (stderrTime < stdoutTime) { | ||
| sendStderr(taskId); | ||
| sendStdout(taskId); | ||
| } else { | ||
| sendStdout(taskId); | ||
| sendStderr(taskId); | ||
| } | ||
| }); | ||
| } | ||
| function sendStdout(taskId) { | ||
| sendBuffer("stdout", taskId); | ||
| } | ||
| function sendStderr(taskId) { | ||
| sendBuffer("stderr", taskId); | ||
| } | ||
| function sendBuffer(type, taskId) { | ||
| const buffers = type === "stdout" ? stdoutBuffer : stderrBuffer; | ||
| const buffer = buffers.get(taskId); | ||
| if (!buffer) return; | ||
| if (state().config.printConsoleTrace) buffer.forEach(([buffer, origin]) => { | ||
| sendLog(type, taskId, String(buffer), buffer.length, origin); | ||
| }); | ||
| else sendLog(type, taskId, buffer.map((i) => String(i[0])).join(""), buffer.length); | ||
| const timer = timers.get(taskId); | ||
| buffers.delete(taskId); | ||
| if (type === "stderr") timer.stderrTime = 0; | ||
| else timer.stdoutTime = 0; | ||
| } | ||
| function sendLog(type, taskId, content, size, origin) { | ||
| const timer = timers.get(taskId); | ||
| const time = type === "stderr" ? timer.stderrTime : timer.stdoutTime; | ||
| state().rpc.onUserConsoleLog({ | ||
| type, | ||
| content: content || "<empty line>", | ||
| taskId, | ||
| time: time || RealDate.now(), | ||
| size, | ||
| origin | ||
| }); | ||
| } | ||
| return new Console({ | ||
| stdout: new Writable({ write(data, encoding, callback) { | ||
| const s = state(); | ||
| const id = s?.current?.id || s?.current?.suite?.id || s.current?.file.id || getTaskIdByStack(s.config.root); | ||
| let timer = timers.get(id); | ||
| if (timer) timer.stdoutTime = timer.stdoutTime || RealDate.now(); | ||
| else { | ||
| timer = { | ||
| stdoutTime: RealDate.now(), | ||
| stderrTime: RealDate.now() | ||
| }; | ||
| timers.set(id, timer); | ||
| } | ||
| let buffer = stdoutBuffer.get(id); | ||
| if (!buffer) { | ||
| buffer = []; | ||
| stdoutBuffer.set(id, buffer); | ||
| } | ||
| if (state().config.printConsoleTrace) { | ||
| const limit = Error.stackTraceLimit; | ||
| Error.stackTraceLimit = limit + 6; | ||
| const trace = (/* @__PURE__ */ new Error("STACK_TRACE")).stack?.split("\n").slice(7).join("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| buffer.push([data, trace]); | ||
| } else buffer.push([data, void 0]); | ||
| schedule(id); | ||
| callback(); | ||
| } }), | ||
| stderr: new Writable({ write(data, encoding, callback) { | ||
| const s = state(); | ||
| const id = s?.current?.id || s?.current?.suite?.id || s.current?.file.id || getTaskIdByStack(s.config.root); | ||
| let timer = timers.get(id); | ||
| if (timer) timer.stderrTime = timer.stderrTime || RealDate.now(); | ||
| else { | ||
| timer = { | ||
| stderrTime: RealDate.now(), | ||
| stdoutTime: RealDate.now() | ||
| }; | ||
| timers.set(id, timer); | ||
| } | ||
| let buffer = stderrBuffer.get(id); | ||
| if (!buffer) { | ||
| buffer = []; | ||
| stderrBuffer.set(id, buffer); | ||
| } | ||
| if (state().config.printConsoleTrace) { | ||
| const limit = Error.stackTraceLimit; | ||
| Error.stackTraceLimit = limit + 6; | ||
| const stack = (/* @__PURE__ */ new Error("STACK_TRACE")).stack?.split("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| if (stack?.some((line) => line.includes("at Console.trace"))) buffer.push([data, void 0]); | ||
| else { | ||
| const trace = stack?.slice(7).join("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| buffer.push([data, trace]); | ||
| } | ||
| } else buffer.push([data, void 0]); | ||
| schedule(id); | ||
| callback(); | ||
| } }), | ||
| colorMode: c.isColorSupported, | ||
| groupIndentation: 2 | ||
| }); | ||
| } | ||
| export { UNKNOWN_TEST_ID, createCustomConsole }; |
| import { g as globalApis } from './constants.CPYnjOGj.js'; | ||
| import { i as index } from './index.DqEi5Ycp.js'; | ||
| import './test.BwzWwv9M.js'; | ||
| import '@vitest/runner'; | ||
| import '@vitest/utils/helpers'; | ||
| import '@vitest/utils/timers'; | ||
| import './benchmark.D0SlKNbZ.js'; | ||
| import '@vitest/runner/utils'; | ||
| import './utils.BX5Fg8C4.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.CYazvPD1.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 { createHook } from 'node:async_hooks'; | ||
| import { l as loadDiffConfig, a as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.BRHvdzsc.js'; | ||
| import { r as rpc } from './rpc.CYazvPD1.js'; | ||
| import { g as getWorkerState } from './utils.BX5Fg8C4.js'; | ||
| import { T as TestRunner, N as NodeBenchmarkRunner } from './test.BwzWwv9M.js'; | ||
| function setupChaiConfig(config) { | ||
| Object.assign(chai.config, config); | ||
| } | ||
| async function resolveSnapshotEnvironment(config, moduleRunner) { | ||
| if (!config.snapshotEnvironment) { | ||
| const { VitestNodeSnapshotEnvironment } = await import('./node.COQbm6gK.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 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.mNs4_sfP.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 { URL } from 'node:url'; | ||
| import { Console } from 'node:console'; | ||
| // SEE https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/interfaces.js | ||
| const LIVING_KEYS = [ | ||
| "DOMException", | ||
| "EventTarget", | ||
| "NamedNodeMap", | ||
| "Node", | ||
| "Attr", | ||
| "Element", | ||
| "DocumentFragment", | ||
| "DOMImplementation", | ||
| "Document", | ||
| "XMLDocument", | ||
| "CharacterData", | ||
| "Text", | ||
| "CDATASection", | ||
| "ProcessingInstruction", | ||
| "Comment", | ||
| "DocumentType", | ||
| "NodeList", | ||
| "RadioNodeList", | ||
| "HTMLCollection", | ||
| "HTMLOptionsCollection", | ||
| "DOMStringMap", | ||
| "DOMTokenList", | ||
| "StyleSheetList", | ||
| "HTMLElement", | ||
| "HTMLHeadElement", | ||
| "HTMLTitleElement", | ||
| "HTMLBaseElement", | ||
| "HTMLLinkElement", | ||
| "HTMLMetaElement", | ||
| "HTMLStyleElement", | ||
| "HTMLBodyElement", | ||
| "HTMLHeadingElement", | ||
| "HTMLParagraphElement", | ||
| "HTMLHRElement", | ||
| "HTMLPreElement", | ||
| "HTMLUListElement", | ||
| "HTMLOListElement", | ||
| "HTMLLIElement", | ||
| "HTMLMenuElement", | ||
| "HTMLDListElement", | ||
| "HTMLDivElement", | ||
| "HTMLAnchorElement", | ||
| "HTMLAreaElement", | ||
| "HTMLBRElement", | ||
| "HTMLButtonElement", | ||
| "HTMLCanvasElement", | ||
| "HTMLDataElement", | ||
| "HTMLDataListElement", | ||
| "HTMLDetailsElement", | ||
| "HTMLDialogElement", | ||
| "HTMLDirectoryElement", | ||
| "HTMLFieldSetElement", | ||
| "HTMLFontElement", | ||
| "HTMLFormElement", | ||
| "HTMLHtmlElement", | ||
| "HTMLImageElement", | ||
| "HTMLInputElement", | ||
| "HTMLLabelElement", | ||
| "HTMLLegendElement", | ||
| "HTMLMapElement", | ||
| "HTMLMarqueeElement", | ||
| "HTMLMediaElement", | ||
| "HTMLMeterElement", | ||
| "HTMLModElement", | ||
| "HTMLOptGroupElement", | ||
| "HTMLOptionElement", | ||
| "HTMLOutputElement", | ||
| "HTMLPictureElement", | ||
| "HTMLProgressElement", | ||
| "HTMLQuoteElement", | ||
| "HTMLScriptElement", | ||
| "HTMLSelectElement", | ||
| "HTMLSlotElement", | ||
| "HTMLSourceElement", | ||
| "HTMLSpanElement", | ||
| "HTMLTableCaptionElement", | ||
| "HTMLTableCellElement", | ||
| "HTMLTableColElement", | ||
| "HTMLTableElement", | ||
| "HTMLTimeElement", | ||
| "HTMLTableRowElement", | ||
| "HTMLTableSectionElement", | ||
| "HTMLTemplateElement", | ||
| "HTMLTextAreaElement", | ||
| "HTMLUnknownElement", | ||
| "HTMLFrameElement", | ||
| "HTMLFrameSetElement", | ||
| "HTMLIFrameElement", | ||
| "HTMLEmbedElement", | ||
| "HTMLObjectElement", | ||
| "HTMLParamElement", | ||
| "HTMLVideoElement", | ||
| "HTMLAudioElement", | ||
| "HTMLTrackElement", | ||
| "HTMLFormControlsCollection", | ||
| "SVGElement", | ||
| "SVGGraphicsElement", | ||
| "SVGSVGElement", | ||
| "SVGTitleElement", | ||
| "SVGAnimatedString", | ||
| "SVGNumber", | ||
| "SVGStringList", | ||
| "Event", | ||
| "CloseEvent", | ||
| "CustomEvent", | ||
| "MessageEvent", | ||
| "ErrorEvent", | ||
| "HashChangeEvent", | ||
| "PopStateEvent", | ||
| "StorageEvent", | ||
| "ProgressEvent", | ||
| "PageTransitionEvent", | ||
| "SubmitEvent", | ||
| "UIEvent", | ||
| "FocusEvent", | ||
| "InputEvent", | ||
| "MouseEvent", | ||
| "KeyboardEvent", | ||
| "TouchEvent", | ||
| "CompositionEvent", | ||
| "WheelEvent", | ||
| "BarProp", | ||
| "External", | ||
| "Location", | ||
| "History", | ||
| "Screen", | ||
| "Crypto", | ||
| "Performance", | ||
| "Navigator", | ||
| "PluginArray", | ||
| "MimeTypeArray", | ||
| "Plugin", | ||
| "MimeType", | ||
| "FileReader", | ||
| "FormData", | ||
| "Blob", | ||
| "File", | ||
| "FileList", | ||
| "ValidityState", | ||
| "DOMParser", | ||
| "XMLSerializer", | ||
| "XMLHttpRequestEventTarget", | ||
| "XMLHttpRequestUpload", | ||
| "XMLHttpRequest", | ||
| "WebSocket", | ||
| "NodeFilter", | ||
| "NodeIterator", | ||
| "TreeWalker", | ||
| "AbstractRange", | ||
| "Range", | ||
| "StaticRange", | ||
| "Selection", | ||
| "Storage", | ||
| "CustomElementRegistry", | ||
| "ShadowRoot", | ||
| "MutationObserver", | ||
| "MutationRecord", | ||
| "Uint8Array", | ||
| "Uint16Array", | ||
| "Uint32Array", | ||
| "Uint8ClampedArray", | ||
| "Int8Array", | ||
| "Int16Array", | ||
| "Int32Array", | ||
| "Float32Array", | ||
| "Float64Array", | ||
| "ArrayBuffer", | ||
| "DOMRectReadOnly", | ||
| "DOMRect", | ||
| "Image", | ||
| "Audio", | ||
| "Option", | ||
| "CSS" | ||
| ]; | ||
| const OTHER_KEYS = [ | ||
| "addEventListener", | ||
| "alert", | ||
| "blur", | ||
| "cancelAnimationFrame", | ||
| "close", | ||
| "confirm", | ||
| "createPopup", | ||
| "dispatchEvent", | ||
| "document", | ||
| "focus", | ||
| "frames", | ||
| "getComputedStyle", | ||
| "history", | ||
| "innerHeight", | ||
| "innerWidth", | ||
| "length", | ||
| "location", | ||
| "matchMedia", | ||
| "moveBy", | ||
| "moveTo", | ||
| "name", | ||
| "navigator", | ||
| "open", | ||
| "outerHeight", | ||
| "outerWidth", | ||
| "pageXOffset", | ||
| "pageYOffset", | ||
| "parent", | ||
| "postMessage", | ||
| "print", | ||
| "prompt", | ||
| "removeEventListener", | ||
| "requestAnimationFrame", | ||
| "resizeBy", | ||
| "resizeTo", | ||
| "screen", | ||
| "screenLeft", | ||
| "screenTop", | ||
| "screenX", | ||
| "screenY", | ||
| "scroll", | ||
| "scrollBy", | ||
| "scrollLeft", | ||
| "scrollTo", | ||
| "scrollTop", | ||
| "scrollX", | ||
| "scrollY", | ||
| "self", | ||
| "stop", | ||
| "top", | ||
| "Window", | ||
| "window" | ||
| ]; | ||
| const KEYS = LIVING_KEYS.concat(OTHER_KEYS); | ||
| const skipKeys = [ | ||
| "window", | ||
| "self", | ||
| "top", | ||
| "parent" | ||
| ]; | ||
| function getWindowKeys(global, win, additionalKeys = []) { | ||
| const keysArray = [...additionalKeys, ...KEYS]; | ||
| return new Set(keysArray.concat(Object.getOwnPropertyNames(win)).filter((k) => { | ||
| if (skipKeys.includes(k)) return false; | ||
| if (k in global) return keysArray.includes(k); | ||
| return true; | ||
| })); | ||
| } | ||
| function isClassLikeName(name) { | ||
| return name[0] === name[0].toUpperCase(); | ||
| } | ||
| function populateGlobal(global, win, options = {}) { | ||
| const { bindFunctions = false } = options; | ||
| const keys = getWindowKeys(global, win, options.additionalKeys); | ||
| const originals = /* @__PURE__ */ new Map(); | ||
| const overridenKeys = new Set([...KEYS, ...options.additionalKeys || []]); | ||
| const overrideObject = /* @__PURE__ */ new Map(); | ||
| for (const key of keys) { | ||
| const boundFunction = bindFunctions && typeof win[key] === "function" && !isClassLikeName(key) && win[key].bind(win); | ||
| if (overridenKeys.has(key) && key in global) originals.set(key, global[key]); | ||
| Object.defineProperty(global, key, { | ||
| get() { | ||
| if (overrideObject.has(key)) return overrideObject.get(key); | ||
| if (boundFunction) return boundFunction; | ||
| return win[key]; | ||
| }, | ||
| set(v) { | ||
| overrideObject.set(key, v); | ||
| }, | ||
| configurable: true | ||
| }); | ||
| } | ||
| global.window = global; | ||
| global.self = global; | ||
| global.top = global; | ||
| global.parent = global; | ||
| if (global.global) global.global = global; | ||
| // rewrite defaultView to reference the same global context | ||
| if (global.document && global.document.defaultView) Object.defineProperty(global.document, "defaultView", { | ||
| get: () => global, | ||
| enumerable: true, | ||
| configurable: true | ||
| }); | ||
| skipKeys.forEach((k) => keys.add(k)); | ||
| return { | ||
| keys, | ||
| skipKeys, | ||
| originals | ||
| }; | ||
| } | ||
| var edge = { | ||
| name: "edge-runtime", | ||
| viteEnvironment: "ssr", | ||
| async setupVM() { | ||
| const { EdgeVM } = await import('@edge-runtime/vm'); | ||
| const vm = new EdgeVM({ extend: (context) => { | ||
| context.global = context; | ||
| context.Buffer = Buffer; | ||
| return context; | ||
| } }); | ||
| return { | ||
| getVmContext() { | ||
| return vm.context; | ||
| }, | ||
| teardown() { | ||
| // nothing to teardown | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global) { | ||
| const { EdgeVM } = await import('@edge-runtime/vm'); | ||
| const { keys, originals } = populateGlobal(global, new EdgeVM({ extend: (context) => { | ||
| context.global = context; | ||
| context.Buffer = Buffer; | ||
| KEYS.forEach((key) => { | ||
| if (key in global) context[key] = global[key]; | ||
| }); | ||
| return context; | ||
| } }).context, { bindFunctions: true }); | ||
| return { teardown(global) { | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((v, k) => global[k] = v); | ||
| } }; | ||
| } | ||
| }; | ||
| async function teardownWindow(win) { | ||
| if (win.close && win.happyDOM.abort) { | ||
| await win.happyDOM.abort(); | ||
| win.close(); | ||
| } else win.happyDOM.cancelAsync(); | ||
| } | ||
| var happy = { | ||
| name: "happy-dom", | ||
| viteEnvironment: "client", | ||
| async setupVM({ happyDOM = {} }) { | ||
| const { Window } = await import('happy-dom'); | ||
| let win = new Window({ | ||
| ...happyDOM, | ||
| console: console && globalThis.console ? globalThis.console : void 0, | ||
| url: happyDOM.url || "http://localhost:3000", | ||
| settings: { | ||
| ...happyDOM.settings, | ||
| disableErrorCapturing: true | ||
| } | ||
| }); | ||
| // TODO: browser doesn't expose Buffer, but a lot of dependencies use it | ||
| win.Buffer = Buffer; | ||
| // inject structuredClone if it exists | ||
| if (typeof structuredClone !== "undefined" && !win.structuredClone) win.structuredClone = structuredClone; | ||
| return { | ||
| getVmContext() { | ||
| return win; | ||
| }, | ||
| async teardown() { | ||
| await teardownWindow(win); | ||
| win = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global, { happyDOM = {} }) { | ||
| // happy-dom v3 introduced a breaking change to Window, but | ||
| // provides GlobalWindow as a way to use previous behaviour | ||
| const { Window, GlobalWindow } = await import('happy-dom'); | ||
| const win = new (GlobalWindow || Window)({ | ||
| ...happyDOM, | ||
| console: console && global.console ? global.console : void 0, | ||
| url: happyDOM.url || "http://localhost:3000", | ||
| settings: { | ||
| ...happyDOM.settings, | ||
| disableErrorCapturing: true | ||
| } | ||
| }); | ||
| const { keys, originals } = populateGlobal(global, win, { | ||
| bindFunctions: true, | ||
| additionalKeys: [ | ||
| "Request", | ||
| "Response", | ||
| "MessagePort", | ||
| "fetch", | ||
| "Headers", | ||
| "AbortController", | ||
| "AbortSignal", | ||
| "URL", | ||
| "URLSearchParams", | ||
| "FormData" | ||
| ] | ||
| }); | ||
| return { async teardown(global) { | ||
| await teardownWindow(win); | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((v, k) => global[k] = v); | ||
| } }; | ||
| } | ||
| }; | ||
| function catchWindowErrors(window) { | ||
| let userErrorListenerCount = 0; | ||
| function throwUnhandlerError(e) { | ||
| if (userErrorListenerCount === 0 && e.error != null) { | ||
| e.preventDefault(); | ||
| process.emit("uncaughtException", e.error); | ||
| } | ||
| } | ||
| const addEventListener = window.addEventListener.bind(window); | ||
| const removeEventListener = window.removeEventListener.bind(window); | ||
| window.addEventListener("error", throwUnhandlerError); | ||
| window.addEventListener = function(...args) { | ||
| if (args[0] === "error") userErrorListenerCount++; | ||
| return addEventListener.apply(this, args); | ||
| }; | ||
| window.removeEventListener = function(...args) { | ||
| if (args[0] === "error" && userErrorListenerCount) userErrorListenerCount--; | ||
| return removeEventListener.apply(this, args); | ||
| }; | ||
| return function clearErrorHandlers() { | ||
| window.removeEventListener("error", throwUnhandlerError); | ||
| }; | ||
| } | ||
| let NodeFormData_; | ||
| let NodeBlob_; | ||
| let NodeRequest_; | ||
| var jsdom = { | ||
| name: "jsdom", | ||
| viteEnvironment: "client", | ||
| async setupVM({ jsdom = {} }) { | ||
| // delay initialization because it takes ~1s | ||
| NodeFormData_ = globalThis.FormData; | ||
| NodeBlob_ = globalThis.Blob; | ||
| NodeRequest_ = globalThis.Request; | ||
| const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom'); | ||
| const { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false, ...restOptions } = jsdom; | ||
| let virtualConsole; | ||
| if (console && globalThis.console) { | ||
| virtualConsole = new VirtualConsole(); | ||
| // jsdom <27 | ||
| if ("sendTo" in virtualConsole) virtualConsole.sendTo(globalThis.console); | ||
| else virtualConsole.forwardTo(globalThis.console); | ||
| } | ||
| let dom = new JSDOM(html, { | ||
| pretendToBeVisual, | ||
| resources: resources ?? (userAgent ? new ResourceLoader({ userAgent }) : void 0), | ||
| runScripts, | ||
| url, | ||
| virtualConsole, | ||
| cookieJar: cookieJar ? new CookieJar() : void 0, | ||
| includeNodeLocations, | ||
| contentType, | ||
| userAgent, | ||
| ...restOptions | ||
| }); | ||
| const clearAddEventListenerPatch = patchAddEventListener(dom.window); | ||
| const clearWindowErrors = catchWindowErrors(dom.window); | ||
| const utils = createCompatUtils(dom.window); | ||
| // TODO: browser doesn't expose Buffer, but a lot of dependencies use it | ||
| dom.window.Buffer = Buffer; | ||
| dom.window.jsdom = dom; | ||
| dom.window.Request = createCompatRequest(utils); | ||
| dom.window.URL = createJSDOMCompatURL(utils); | ||
| for (const name of [ | ||
| "structuredClone", | ||
| "BroadcastChannel", | ||
| "MessageChannel", | ||
| "MessagePort", | ||
| "TextEncoder", | ||
| "TextDecoder" | ||
| ]) { | ||
| const value = globalThis[name]; | ||
| if (typeof value !== "undefined" && typeof dom.window[name] === "undefined") dom.window[name] = value; | ||
| } | ||
| for (const name of [ | ||
| "fetch", | ||
| "Response", | ||
| "Headers", | ||
| "AbortController", | ||
| "AbortSignal", | ||
| "URLSearchParams" | ||
| ]) { | ||
| const value = globalThis[name]; | ||
| if (typeof value !== "undefined") dom.window[name] = value; | ||
| } | ||
| return { | ||
| getVmContext() { | ||
| return dom.getInternalVMContext(); | ||
| }, | ||
| teardown() { | ||
| clearAddEventListenerPatch(); | ||
| clearWindowErrors(); | ||
| dom.window.close(); | ||
| dom = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global, { jsdom = {} }) { | ||
| // delay initialization because it takes ~1s | ||
| NodeFormData_ = globalThis.FormData; | ||
| NodeBlob_ = globalThis.Blob; | ||
| NodeRequest_ = globalThis.Request; | ||
| const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom'); | ||
| const { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false, ...restOptions } = jsdom; | ||
| let virtualConsole; | ||
| if (console && globalThis.console) { | ||
| virtualConsole = new VirtualConsole(); | ||
| // jsdom <27 | ||
| if ("sendTo" in virtualConsole) virtualConsole.sendTo(globalThis.console); | ||
| else virtualConsole.forwardTo(globalThis.console); | ||
| } | ||
| const dom = new JSDOM(html, { | ||
| pretendToBeVisual, | ||
| resources: resources ?? (userAgent ? new ResourceLoader({ userAgent }) : void 0), | ||
| runScripts, | ||
| url, | ||
| virtualConsole, | ||
| cookieJar: cookieJar ? new CookieJar() : void 0, | ||
| includeNodeLocations, | ||
| contentType, | ||
| userAgent, | ||
| ...restOptions | ||
| }); | ||
| const clearAddEventListenerPatch = patchAddEventListener(dom.window); | ||
| const { keys, originals } = populateGlobal(global, dom.window, { bindFunctions: true }); | ||
| const clearWindowErrors = catchWindowErrors(global); | ||
| const utils = createCompatUtils(dom.window); | ||
| global.jsdom = dom; | ||
| global.Request = createCompatRequest(utils); | ||
| global.URL = createJSDOMCompatURL(utils); | ||
| return { teardown(global) { | ||
| clearAddEventListenerPatch(); | ||
| clearWindowErrors(); | ||
| dom.window.close(); | ||
| delete global.jsdom; | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((v, k) => global[k] = v); | ||
| } }; | ||
| } | ||
| }; | ||
| function createCompatRequest(utils) { | ||
| return class Request extends NodeRequest_ { | ||
| constructor(...args) { | ||
| const [input, init] = args; | ||
| if (init?.body != null) { | ||
| const compatInit = { ...init }; | ||
| if (init.body instanceof utils.window.Blob) compatInit.body = utils.makeCompatBlob(init.body); | ||
| if (init.body instanceof utils.window.FormData) compatInit.body = utils.makeCompatFormData(init.body); | ||
| super(input, compatInit); | ||
| } else super(...args); | ||
| } | ||
| static [Symbol.hasInstance](instance) { | ||
| return instance instanceof NodeRequest_; | ||
| } | ||
| }; | ||
| } | ||
| function createJSDOMCompatURL(utils) { | ||
| return class URL$1 extends URL { | ||
| static createObjectURL(blob) { | ||
| if (blob instanceof utils.window.Blob) { | ||
| const compatBlob = utils.makeCompatBlob(blob); | ||
| return URL.createObjectURL(compatBlob); | ||
| } | ||
| return URL.createObjectURL(blob); | ||
| } | ||
| static [Symbol.hasInstance](instance) { | ||
| return instance instanceof URL; | ||
| } | ||
| }; | ||
| } | ||
| function createCompatUtils(window) { | ||
| // this returns a hidden Symbol(impl) | ||
| // this is cursed, and jsdom should just implement fetch API itself | ||
| const implSymbol = Object.getOwnPropertySymbols(Object.getOwnPropertyDescriptors(new window.Blob()))[0]; | ||
| const utils = { | ||
| window, | ||
| makeCompatFormData(formData) { | ||
| const nodeFormData = new NodeFormData_(); | ||
| formData.forEach((value, key) => { | ||
| if (value instanceof window.Blob) nodeFormData.append(key, utils.makeCompatBlob(value)); | ||
| else nodeFormData.append(key, value); | ||
| }); | ||
| return nodeFormData; | ||
| }, | ||
| makeCompatBlob(blob) { | ||
| const buffer = blob[implSymbol]._buffer; | ||
| return new NodeBlob_([buffer], { type: blob.type }); | ||
| } | ||
| }; | ||
| return utils; | ||
| } | ||
| function patchAddEventListener(window) { | ||
| const abortControllers = /* @__PURE__ */ new WeakMap(); | ||
| const JSDOMAbortSignal = window.AbortSignal; | ||
| const JSDOMAbortController = window.AbortController; | ||
| const originalAddEventListener = window.EventTarget.prototype.addEventListener; | ||
| function getJsdomAbortController(signal) { | ||
| if (!abortControllers.has(signal)) { | ||
| const jsdomAbortController = new JSDOMAbortController(); | ||
| signal.addEventListener("abort", () => { | ||
| jsdomAbortController.abort(signal.reason); | ||
| }); | ||
| abortControllers.set(signal, jsdomAbortController); | ||
| } | ||
| return abortControllers.get(signal); | ||
| } | ||
| window.EventTarget.prototype.addEventListener = function addEventListener(type, callback, options) { | ||
| if (typeof options === "object" && options?.signal != null) { | ||
| const { signal, ...otherOptions } = options; | ||
| // - this happens because AbortSignal is provided by Node.js, | ||
| // but jsdom APIs require jsdom's AbortSignal, while Node APIs | ||
| // (like fetch and Request) require a Node.js AbortSignal | ||
| // - disable narrow typing with "as any" because we need it later | ||
| if (!(signal instanceof JSDOMAbortSignal)) { | ||
| const jsdomCompatOptions = Object.create(null); | ||
| Object.assign(jsdomCompatOptions, otherOptions); | ||
| jsdomCompatOptions.signal = getJsdomAbortController(signal).signal; | ||
| return originalAddEventListener.call(this, type, callback, jsdomCompatOptions); | ||
| } | ||
| } | ||
| return originalAddEventListener.call(this, type, callback, options); | ||
| }; | ||
| return () => { | ||
| window.EventTarget.prototype.addEventListener = originalAddEventListener; | ||
| }; | ||
| } | ||
| // some globals we do not want, either because deprecated or we set it ourselves | ||
| const denyList = new Set([ | ||
| "GLOBAL", | ||
| "root", | ||
| "global", | ||
| "Buffer", | ||
| "ArrayBuffer", | ||
| "Uint8Array" | ||
| ]); | ||
| const nodeGlobals = /* @__PURE__ */ new Map(); | ||
| function populateNodeGlobals() { | ||
| if (nodeGlobals.size !== 0) return; | ||
| const names = Object.getOwnPropertyNames(globalThis); | ||
| const length = names.length; | ||
| for (let i = 0; i < length; i++) { | ||
| const globalName = names[i]; | ||
| if (!denyList.has(globalName)) { | ||
| const descriptor = Object.getOwnPropertyDescriptor(globalThis, globalName); | ||
| if (!descriptor) throw new Error(`No property descriptor for ${globalName}, this is a bug in Vitest.`); | ||
| nodeGlobals.set(globalName, descriptor); | ||
| } | ||
| } | ||
| } | ||
| var node = { | ||
| name: "node", | ||
| viteEnvironment: "ssr", | ||
| async setupVM() { | ||
| populateNodeGlobals(); | ||
| const vm = await import('node:vm'); | ||
| let context = vm.createContext(); | ||
| let global = vm.runInContext("this", context); | ||
| const contextGlobals = new Set(Object.getOwnPropertyNames(global)); | ||
| for (const [nodeGlobalsKey, descriptor] of nodeGlobals) if (!contextGlobals.has(nodeGlobalsKey)) if (descriptor.configurable) Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| get() { | ||
| // @ts-expect-error: no index signature | ||
| const val = globalThis[nodeGlobalsKey]; | ||
| // override lazy getter | ||
| Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| value: val, | ||
| writable: descriptor.writable === true || nodeGlobalsKey === "performance" | ||
| }); | ||
| return val; | ||
| }, | ||
| set(val) { | ||
| // override lazy getter | ||
| Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| value: val, | ||
| writable: true | ||
| }); | ||
| } | ||
| }); | ||
| else if ("value" in descriptor) Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: false, | ||
| enumerable: descriptor.enumerable, | ||
| value: descriptor.value, | ||
| writable: descriptor.writable | ||
| }); | ||
| else Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: false, | ||
| enumerable: descriptor.enumerable, | ||
| get: descriptor.get, | ||
| set: descriptor.set | ||
| }); | ||
| global.global = global; | ||
| global.Buffer = Buffer; | ||
| global.ArrayBuffer = ArrayBuffer; | ||
| // TextEncoder (global or via 'util') references a Uint8Array constructor | ||
| // different than the global one used by users in tests. This makes sure the | ||
| // same constructor is referenced by both. | ||
| global.Uint8Array = Uint8Array; | ||
| return { | ||
| getVmContext() { | ||
| return context; | ||
| }, | ||
| teardown() { | ||
| context = void 0; | ||
| global = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global) { | ||
| global.console.Console = Console; | ||
| return { teardown(global) { | ||
| delete global.console.Console; | ||
| } }; | ||
| } | ||
| }; | ||
| const environments = { | ||
| node, | ||
| jsdom, | ||
| "happy-dom": happy, | ||
| "edge-runtime": edge | ||
| }; | ||
| export { environments as e, populateGlobal as p }; |
| 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.BwzWwv9M.js'; | ||
| import { b as bench } from './benchmark.D0SlKNbZ.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 { i as init } from './init.DzWSvu83.js'; | ||
| if (!process.send) throw new Error("Expected worker to be run in node:child_process"); | ||
| // Store globals in case tests overwrite them | ||
| const processExit = process.exit.bind(process); | ||
| const processSend = process.send.bind(process); | ||
| const processOn = process.on.bind(process); | ||
| const processOff = process.off.bind(process); | ||
| const processRemoveAllListeners = process.removeAllListeners.bind(process); | ||
| // Work-around for nodejs/node#55094 | ||
| if (process.execArgv.some((execArg) => execArg.startsWith("--prof") || execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"))) processOn("SIGTERM", () => processExit()); | ||
| processOn("error", onError); | ||
| function workerInit(options) { | ||
| const { runTests } = options; | ||
| init({ | ||
| post: (v) => processSend(v), | ||
| on: (cb) => processOn("message", cb), | ||
| off: (cb) => processOff("message", cb), | ||
| teardown: () => { | ||
| processRemoveAllListeners("message"); | ||
| processOff("error", onError); | ||
| }, | ||
| runTests: (state, traces) => executeTests("run", state, traces), | ||
| collectTests: (state, traces) => executeTests("collect", state, traces), | ||
| setup: options.setup | ||
| }); | ||
| async function executeTests(method, state, traces) { | ||
| try { | ||
| await runTests(method, state, traces); | ||
| } finally { | ||
| process.exit = processExit; | ||
| } | ||
| } | ||
| } | ||
| // Prevent leaving worker in loops where it tries to send message to closed main | ||
| // thread, errors, and tries to send the error. | ||
| function onError(error) { | ||
| if (error?.code === "ERR_IPC_CHANNEL_CLOSED" || error?.code === "EPIPE") processExit(1); | ||
| } | ||
| export { workerInit as w }; |
| import { isMainThread, parentPort } from 'node:worker_threads'; | ||
| import { i as init } from './init.DzWSvu83.js'; | ||
| if (isMainThread || !parentPort) throw new Error("Expected worker to be run in node:worker_threads"); | ||
| function workerInit(options) { | ||
| const { runTests } = options; | ||
| init({ | ||
| post: (response) => parentPort.postMessage(response), | ||
| on: (callback) => parentPort.on("message", callback), | ||
| off: (callback) => parentPort.off("message", callback), | ||
| teardown: () => parentPort.removeAllListeners("message"), | ||
| runTests: async (state, traces) => runTests("run", state, traces), | ||
| collectTests: async (state, traces) => runTests("collect", state, traces), | ||
| setup: options.setup | ||
| }); | ||
| } | ||
| export { workerInit as w }; |
| import { readFileSync } from 'node:fs'; | ||
| import { isBuiltin } from 'node:module'; | ||
| import { pathToFileURL } from 'node:url'; | ||
| import { resolve } from 'pathe'; | ||
| import { ModuleRunner, EvaluatedModules } from 'vite/module-runner'; | ||
| import { b as VitestTransport } from './startVitestModuleRunner.BRvQz4ko.js'; | ||
| import { e as environments } from './index.CyBMJtT7.js'; | ||
| import { serializeValue } from '@vitest/utils/serialize'; | ||
| import { serializeError } from '@vitest/utils/error'; | ||
| import { T as Traces } from './traces.CCmnQaNT.js'; | ||
| import { o as onCancel, a as rpcDone, c as createRuntimeRpc } from './rpc.CYazvPD1.js'; | ||
| import { createStackString, parseStacktrace } from '@vitest/utils/source-map'; | ||
| import { s as setupInspect } from './inspector.CvyFGlXm.js'; | ||
| import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js'; | ||
| import { E as EnvironmentTeardownError } from './utils.BX5Fg8C4.js'; | ||
| function isBuiltinEnvironment(env) { | ||
| return env in environments; | ||
| } | ||
| const isWindows = process.platform === "win32"; | ||
| const _loaders = /* @__PURE__ */ new Map(); | ||
| function createEnvironmentLoader(root, rpc) { | ||
| const cachedLoader = _loaders.get(root); | ||
| if (!cachedLoader || cachedLoader.isClosed()) { | ||
| _loaders.delete(root); | ||
| const moduleRunner = new ModuleRunner({ | ||
| hmr: false, | ||
| sourcemapInterceptor: "prepareStackTrace", | ||
| transport: new VitestTransport({ | ||
| async fetchModule(id, importer, options) { | ||
| const result = await rpc.fetch(id, importer, "__vitest__", options); | ||
| if ("cached" in result) return { | ||
| code: readFileSync(result.tmp, "utf-8"), | ||
| ...result | ||
| }; | ||
| if (isWindows && "externalize" in result) | ||
| // TODO: vitest returns paths for external modules, but Vite returns file:// | ||
| // https://github.com/vitejs/vite/pull/20449 | ||
| result.externalize = isBuiltin(id) || /^(?:node:|data:|http:|https:|file:)/.test(id) ? result.externalize : pathToFileURL(result.externalize).toString(); | ||
| return result; | ||
| }, | ||
| async resolveId(id, importer) { | ||
| return rpc.resolve(id, importer, "__vitest__"); | ||
| } | ||
| }, new EvaluatedModules(), /* @__PURE__ */ new WeakMap()) | ||
| }); | ||
| _loaders.set(root, moduleRunner); | ||
| } | ||
| return _loaders.get(root); | ||
| } | ||
| async function loadNativeEnvironment(name, root, traces) { | ||
| const packageId = name[0] === "." || name[0] === "/" ? pathToFileURL(resolve(root, name)).toString() : import.meta.resolve(`vitest-environment-${name}`, pathToFileURL(root).toString()); | ||
| return resolveEnvironmentFromModule(name, packageId, await traces.$("vitest.runtime.environment.import", () => import(packageId))); | ||
| } | ||
| function resolveEnvironmentFromModule(name, packageId, pkg) { | ||
| if (!pkg || !pkg.default || typeof pkg.default !== "object") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "setup" or/and "setupVM" method.`); | ||
| const environment = pkg.default; | ||
| if (environment.transformMode != null && environment.transformMode !== "web" && environment.transformMode !== "ssr") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "transformMode" method equal to "ssr" or "web", received "${environment.transformMode}".`); | ||
| if (environment.transformMode) { | ||
| console.warn(`The Vitest environment ${environment.name} defines the "transformMode". This options was deprecated in Vitest 4 and will be removed in the next major version. Please, use "viteEnvironment" instead.`); | ||
| // keep for backwards compat | ||
| environment.viteEnvironment ??= environment.transformMode === "ssr" ? "ssr" : "client"; | ||
| } | ||
| return environment; | ||
| } | ||
| async function loadEnvironment(name, root, rpc, traces, viteModuleRunner) { | ||
| if (isBuiltinEnvironment(name)) return { environment: environments[name] }; | ||
| if (!viteModuleRunner) return { environment: await loadNativeEnvironment(name, root, traces) }; | ||
| const loader = createEnvironmentLoader(root, rpc); | ||
| const packageId = name[0] === "." || name[0] === "/" ? resolve(root, name) : (await traces.$("vitest.runtime.environment.resolve", () => rpc.resolve(`vitest-environment-${name}`, void 0, "__vitest__")))?.id ?? resolve(root, name); | ||
| return { | ||
| environment: resolveEnvironmentFromModule(name, packageId, await traces.$("vitest.runtime.environment.import", () => loader.import(packageId))), | ||
| loader | ||
| }; | ||
| } | ||
| const cleanupListeners = /* @__PURE__ */ new Set(); | ||
| const moduleRunnerListeners = /* @__PURE__ */ new Set(); | ||
| function onCleanup(cb) { | ||
| cleanupListeners.add(cb); | ||
| } | ||
| async function cleanup() { | ||
| await Promise.all([...cleanupListeners].map((l) => l())); | ||
| } | ||
| function onModuleRunner(cb) { | ||
| moduleRunnerListeners.add(cb); | ||
| } | ||
| function emitModuleRunner(moduleRunner) { | ||
| moduleRunnerListeners.forEach((l) => l(moduleRunner)); | ||
| } | ||
| // Store globals in case tests overwrite them | ||
| const processListeners = process.listeners.bind(process); | ||
| const processOn = process.on.bind(process); | ||
| const processOff = process.off.bind(process); | ||
| const dispose = []; | ||
| function listenForErrors(state) { | ||
| dispose.forEach((fn) => fn()); | ||
| dispose.length = 0; | ||
| function catchError(err, type, event) { | ||
| const worker = state(); | ||
| // if there is another listener, assume that it's handled by user code | ||
| // one is Vitest's own listener | ||
| if (processListeners(event).length > 1) return; | ||
| const error = serializeValue(err); | ||
| if (typeof error === "object" && error != null) { | ||
| error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0; | ||
| if (worker.filepath) error.VITEST_TEST_PATH = worker.filepath; | ||
| } | ||
| state().rpc.onUnhandledError(error, type); | ||
| } | ||
| const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException"); | ||
| const unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection"); | ||
| processOn("uncaughtException", uncaughtException); | ||
| processOn("unhandledRejection", unhandledRejection); | ||
| dispose.push(() => { | ||
| processOff("uncaughtException", uncaughtException); | ||
| processOff("unhandledRejection", unhandledRejection); | ||
| }); | ||
| } | ||
| const resolvingModules = /* @__PURE__ */ new Set(); | ||
| async function execute(method, ctx, worker, traces) { | ||
| const prepareStart = performance.now(); | ||
| const cleanups = [setupInspect(ctx)]; | ||
| // RPC is used to communicate between worker (be it a thread worker or child process or a custom implementation) and the main thread | ||
| const rpc = ctx.rpc; | ||
| try { | ||
| // do not close the RPC channel so that we can get the error messages sent to the main thread | ||
| cleanups.push(async () => { | ||
| await Promise.all(rpc.$rejectPendingCalls(({ method, reject }) => { | ||
| reject(new EnvironmentTeardownError(`[vitest-worker]: Closing rpc while "${method}" was pending`)); | ||
| })); | ||
| }); | ||
| const state = { | ||
| ctx, | ||
| evaluatedModules: new VitestEvaluatedModules(), | ||
| resolvingModules, | ||
| moduleExecutionInfo: /* @__PURE__ */ new Map(), | ||
| config: ctx.config, | ||
| environment: null, | ||
| durations: { | ||
| environment: 0, | ||
| prepare: prepareStart | ||
| }, | ||
| rpc, | ||
| onCancel, | ||
| onCleanup: onCleanup, | ||
| providedContext: ctx.providedContext, | ||
| onFilterStackTrace(stack) { | ||
| return createStackString(parseStacktrace(stack)); | ||
| }, | ||
| metaEnv: createImportMetaEnvProxy() | ||
| }; | ||
| const methodName = method === "collect" ? "collectTests" : "runTests"; | ||
| if (!worker[methodName] || typeof worker[methodName] !== "function") throw new TypeError(`Test worker should expose "runTests" method. Received "${typeof worker.runTests}".`); | ||
| await worker[methodName](state, traces); | ||
| } finally { | ||
| await rpcDone().catch(() => {}); | ||
| await Promise.all(cleanups.map((fn) => fn())).catch(() => {}); | ||
| } | ||
| } | ||
| function run(ctx, worker, traces) { | ||
| return execute("run", ctx, worker, traces); | ||
| } | ||
| function collect(ctx, worker, traces) { | ||
| return execute("collect", ctx, worker, traces); | ||
| } | ||
| async function teardown() { | ||
| await cleanup(); | ||
| } | ||
| const env = process.env; | ||
| function createImportMetaEnvProxy() { | ||
| // packages/vitest/src/node/plugins/index.ts:146 | ||
| const booleanKeys = [ | ||
| "DEV", | ||
| "PROD", | ||
| "SSR" | ||
| ]; | ||
| return new Proxy(env, { | ||
| get(_, key) { | ||
| if (typeof key !== "string") return; | ||
| if (booleanKeys.includes(key)) return !!process.env[key]; | ||
| return process.env[key]; | ||
| }, | ||
| set(_, key, value) { | ||
| if (typeof key !== "string") return true; | ||
| if (booleanKeys.includes(key)) process.env[key] = value ? "1" : ""; | ||
| else process.env[key] = value; | ||
| return true; | ||
| } | ||
| }); | ||
| } | ||
| const __vitest_worker_response__ = true; | ||
| const memoryUsage = process.memoryUsage.bind(process); | ||
| let reportMemory = false; | ||
| let traces; | ||
| /** @experimental */ | ||
| function init(worker) { | ||
| worker.on(onMessage); | ||
| if (worker.onModuleRunner) onModuleRunner(worker.onModuleRunner); | ||
| let runPromise; | ||
| let isRunning = false; | ||
| let workerTeardown; | ||
| let setupContext; | ||
| function send(response) { | ||
| worker.post(worker.serialize ? worker.serialize(response) : response); | ||
| } | ||
| async function onMessage(rawMessage) { | ||
| const message = worker.deserialize ? worker.deserialize(rawMessage) : rawMessage; | ||
| if (message?.__vitest_worker_request__ !== true) return; | ||
| switch (message.type) { | ||
| case "start": { | ||
| process.env.VITEST_POOL_ID = String(message.poolId); | ||
| process.env.VITEST_WORKER_ID = String(message.workerId); | ||
| reportMemory = message.options.reportMemory; | ||
| traces ??= await new Traces({ | ||
| enabled: message.traces.enabled, | ||
| sdkPath: message.traces.sdkPath | ||
| }).waitInit(); | ||
| const { environment, config, pool } = message.context; | ||
| const context = traces.getContextFromCarrier(message.traces.otelCarrier); | ||
| // record telemetry as part of "start" | ||
| traces.recordInitSpan(context); | ||
| try { | ||
| setupContext = { | ||
| environment, | ||
| config, | ||
| pool, | ||
| rpc: createRuntimeRpc(worker), | ||
| projectName: config.name || "", | ||
| traces | ||
| }; | ||
| workerTeardown = await traces.$("vitest.runtime.setup", { context }, () => worker.setup?.(setupContext)); | ||
| send({ | ||
| type: "started", | ||
| __vitest_worker_response__ | ||
| }); | ||
| } catch (error) { | ||
| send({ | ||
| type: "started", | ||
| __vitest_worker_response__, | ||
| error: serializeError(error) | ||
| }); | ||
| } | ||
| break; | ||
| } | ||
| case "run": | ||
| // Prevent concurrent execution if worker is already running | ||
| if (isRunning) { | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests")) | ||
| }); | ||
| return; | ||
| } | ||
| try { | ||
| process.env.VITEST_WORKER_ID = String(message.context.workerId); | ||
| } catch (error) { | ||
| return send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(error), | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } | ||
| isRunning = true; | ||
| try { | ||
| const tracesContext = traces.getContextFromCarrier(message.otelCarrier); | ||
| runPromise = traces.$("vitest.runtime.run", { | ||
| context: tracesContext, | ||
| attributes: { | ||
| "vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [], | ||
| "vitest.worker.id": message.context.workerId | ||
| } | ||
| }, () => run({ | ||
| ...setupContext, | ||
| ...message.context | ||
| }, worker, traces).catch((error) => serializeError(error))); | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: await runPromise, | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } finally { | ||
| runPromise = void 0; | ||
| isRunning = false; | ||
| } | ||
| break; | ||
| case "collect": | ||
| // Prevent concurrent execution if worker is already running | ||
| if (isRunning) { | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests")) | ||
| }); | ||
| return; | ||
| } | ||
| try { | ||
| process.env.VITEST_WORKER_ID = String(message.context.workerId); | ||
| } catch (error) { | ||
| return send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(error), | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } | ||
| isRunning = true; | ||
| try { | ||
| const tracesContext = traces.getContextFromCarrier(message.otelCarrier); | ||
| runPromise = traces.$("vitest.runtime.collect", { | ||
| context: tracesContext, | ||
| attributes: { | ||
| "vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [], | ||
| "vitest.worker.id": message.context.workerId | ||
| } | ||
| }, () => collect({ | ||
| ...setupContext, | ||
| ...message.context | ||
| }, worker, traces).catch((error) => serializeError(error))); | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: await runPromise, | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } finally { | ||
| runPromise = void 0; | ||
| isRunning = false; | ||
| } | ||
| break; | ||
| case "stop": | ||
| await runPromise; | ||
| try { | ||
| const context = traces.getContextFromCarrier(message.otelCarrier); | ||
| const error = await traces.$("vitest.runtime.teardown", { context }, async () => { | ||
| const error = await teardown().catch((error) => serializeError(error)); | ||
| await workerTeardown?.(); | ||
| return error; | ||
| }); | ||
| await traces.finish(); | ||
| send({ | ||
| type: "stopped", | ||
| error, | ||
| __vitest_worker_response__ | ||
| }); | ||
| } catch (error) { | ||
| send({ | ||
| type: "stopped", | ||
| error: serializeError(error), | ||
| __vitest_worker_response__ | ||
| }); | ||
| } | ||
| worker.teardown?.(); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| function getFilesWithLocations(files) { | ||
| return files.flatMap((file) => { | ||
| if (!file.testLocations) return file.filepath; | ||
| return file.testLocations.map((location) => { | ||
| return `${file}:${location}`; | ||
| }); | ||
| }); | ||
| } | ||
| export { listenForErrors as a, emitModuleRunner as e, init as i, loadEnvironment as l }; |
| import module$1, { isBuiltin } from 'node:module'; | ||
| import { fileURLToPath, pathToFileURL } from 'node:url'; | ||
| import { automockModule, createManualModuleSource, collectModuleExports } from '@vitest/mocker/transforms'; | ||
| import { cleanUrl, createDefer } from '@vitest/utils/helpers'; | ||
| import { p as parse } from './acorn.B2iPLyUM.js'; | ||
| import { isAbsolute } from 'pathe'; | ||
| import { t as toBuiltin } from './modules.BJuCwlRJ.js'; | ||
| import { B as BareModuleMocker, n as normalizeModuleId } from './startVitestModuleRunner.BRvQz4ko.js'; | ||
| import 'node:fs'; | ||
| import './utils.BX5Fg8C4.js'; | ||
| import '@vitest/utils/timers'; | ||
| import '../path.js'; | ||
| import 'node:path'; | ||
| import '../module-evaluator.js'; | ||
| import 'node:vm'; | ||
| import 'vite/module-runner'; | ||
| import './traces.CCmnQaNT.js'; | ||
| import '@vitest/mocker'; | ||
| import '@vitest/mocker/redirect'; | ||
| class NativeModuleMocker extends BareModuleMocker { | ||
| wrapDynamicImport(moduleFactory) { | ||
| if (typeof moduleFactory === "function") return new Promise((resolve, reject) => { | ||
| this.resolveMocks().finally(() => { | ||
| moduleFactory().then(resolve, reject); | ||
| }); | ||
| }); | ||
| return moduleFactory; | ||
| } | ||
| resolveMockedModule(url, parentURL) { | ||
| // don't mock modules inside of packages because there is | ||
| // a high chance that it uses `require` which is not mockable | ||
| // because we use top-level await in "manual" mocks. | ||
| // for the sake of consistency we don't support mocking anything at all | ||
| if (parentURL.includes("/node_modules/")) return; | ||
| const moduleId = normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url); | ||
| const mockedModule = this.getDependencyMock(moduleId); | ||
| if (!mockedModule) return; | ||
| if (mockedModule.type === "redirect") return { | ||
| url: pathToFileURL(mockedModule.redirect).toString(), | ||
| shortCircuit: true | ||
| }; | ||
| if (mockedModule.type === "automock" || mockedModule.type === "autospy") return { | ||
| url: injectQuery(url, parentURL, `mock=${mockedModule.type}`), | ||
| shortCircuit: true | ||
| }; | ||
| if (mockedModule.type === "manual") return { | ||
| url: injectQuery(url, parentURL, "mock=manual"), | ||
| shortCircuit: true | ||
| }; | ||
| } | ||
| loadAutomock(url, result) { | ||
| const moduleId = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| let source; | ||
| if (isBuiltin(moduleId)) { | ||
| const builtinModule = getBuiltinModule(moduleId); | ||
| const exports$1 = Object.keys(builtinModule); | ||
| source = ` | ||
| import * as builtinModule from '${toBuiltin(moduleId)}?mock=actual' | ||
| ${exports$1.map((key, index) => { | ||
| return ` | ||
| const __${index} = builtinModule["${key}"] | ||
| export { __${index} as "${key}" } | ||
| `; | ||
| }).join("")}`; | ||
| } else source = result.source?.toString(); | ||
| if (source == null) return; | ||
| const mockType = url.includes("mock=automock") ? "automock" : "autospy"; | ||
| const transformedCode = transformCode(source, result.format || "module", moduleId); | ||
| try { | ||
| const ms = automockModule(transformedCode, mockType, (code) => parse(code, { | ||
| sourceType: "module", | ||
| ecmaVersion: "latest" | ||
| }), { id: moduleId }); | ||
| return { | ||
| format: "module", | ||
| source: `${ms.toString()}\n//# sourceMappingURL=${genSourceMapUrl(ms.generateMap({ | ||
| hires: "boundary", | ||
| source: moduleId | ||
| }))}`, | ||
| shortCircuit: true | ||
| }; | ||
| } catch (cause) { | ||
| throw new Error(`Cannot automock '${url}' because it failed to parse.`, { cause }); | ||
| } | ||
| } | ||
| loadManualMock(url, result) { | ||
| const moduleId = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| // should not be possible | ||
| if (this.getDependencyMock(moduleId)?.type !== "manual") { | ||
| console.warn(`Vitest detected unregistered manual mock ${moduleId}. This is a bug in Vitest. Please, open a new issue with reproduction.`); | ||
| return; | ||
| } | ||
| if (isBuiltin(moduleId)) { | ||
| const builtinModule = getBuiltinModule(toBuiltin(moduleId)); | ||
| return { | ||
| format: "module", | ||
| source: createManualModuleSource(moduleId, Object.keys(builtinModule)), | ||
| shortCircuit: true | ||
| }; | ||
| } | ||
| if (!result.source) return; | ||
| const transformedCode = transformCode(result.source.toString(), result.format || "module", moduleId); | ||
| if (transformedCode == null) return; | ||
| const format = result.format?.startsWith("module") ? "module" : "commonjs"; | ||
| try { | ||
| return { | ||
| format: "module", | ||
| source: createManualModuleSource(moduleId, collectModuleExports(moduleId, transformedCode, format)), | ||
| shortCircuit: true | ||
| }; | ||
| } catch (cause) { | ||
| throw new Error(`Failed to mock '${url}'. See the cause for more information.`, { cause }); | ||
| } | ||
| } | ||
| processedModules = /* @__PURE__ */ new Map(); | ||
| checkCircularManualMock(url) { | ||
| const id = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| this.processedModules.set(id, (this.processedModules.get(id) ?? 0) + 1); | ||
| // the module is mocked and requested a second time, let's resolve | ||
| // the factory function that will redefine the exports later | ||
| if (this.originalModulePromises.has(id)) { | ||
| const factoryPromise = this.factoryPromises.get(id); | ||
| this.originalModulePromises.get(id)?.resolve({ __factoryPromise: factoryPromise }); | ||
| } | ||
| } | ||
| originalModulePromises = /* @__PURE__ */ new Map(); | ||
| factoryPromises = /* @__PURE__ */ new Map(); | ||
| // potential performance improvement: | ||
| // store by URL, not ids, no need to call url.*to* methods and normalizeModuleId | ||
| getFactoryModule(id) { | ||
| const mock = this.getMockerRegistry().getById(id); | ||
| if (!mock || mock.type !== "manual") throw new Error(`Mock ${id} wasn't registered. This is probably a Vitest error. Please, open a new issue with reproduction.`); | ||
| const mockResult = mock.resolve(); | ||
| if (mockResult instanceof Promise) { | ||
| // to avoid circular dependency, we resolve this function as {__factoryPromise} in `checkCircularManualMock` | ||
| // when it's requested the second time. then the exports are exposed as `undefined`, | ||
| // but later redefined when the promise is actually resolved | ||
| const promise = createDefer(); | ||
| promise.finally(() => { | ||
| this.originalModulePromises.delete(id); | ||
| }); | ||
| mockResult.then(promise.resolve, promise.reject).finally(() => { | ||
| this.factoryPromises.delete(id); | ||
| }); | ||
| this.factoryPromises.set(id, mockResult); | ||
| this.originalModulePromises.set(id, promise); | ||
| // Node.js on windows processes all the files first, and then runs them | ||
| // unlike Node.js logic on Mac and Unix where it also runs the code while evaluating | ||
| // So on Linux/Mac this `if` won't be hit because `checkCircularManualMock` will resolve it | ||
| // And on Windows, the `checkCircularManualMock` will never have `originalModulePromises` | ||
| // because `getFactoryModule` is not called until the evaluation phase | ||
| // But if we track how many times the module was transformed, | ||
| // we can deduce when to return `__factoryPromise` to support circular modules | ||
| if ((this.processedModules.get(id) ?? 0) > 1) { | ||
| this.processedModules.set(id, (this.processedModules.get(id) ?? 1) - 1); | ||
| promise.resolve({ __factoryPromise: mockResult }); | ||
| } | ||
| return promise; | ||
| } | ||
| return mockResult; | ||
| } | ||
| importActual(rawId, importer) { | ||
| const resolvedId = import.meta.resolve(rawId, pathToFileURL(importer).toString()); | ||
| const url = new URL(resolvedId); | ||
| url.searchParams.set("mock", "actual"); | ||
| return import(url.toString()); | ||
| } | ||
| importMock(rawId, importer) { | ||
| const resolvedId = import.meta.resolve(rawId, pathToFileURL(importer).toString()); | ||
| // file is already mocked | ||
| if (resolvedId.includes("mock=")) return import(resolvedId); | ||
| const filename = fileURLToPath(resolvedId); | ||
| const external = !isAbsolute(filename) || this.isModuleDirectory(resolvedId) ? normalizeModuleId(rawId) : null; | ||
| // file is not mocked, automock or redirect it | ||
| const redirect = this.findMockRedirect(filename, external); | ||
| if (redirect) return import(pathToFileURL(redirect).toString()); | ||
| const url = new URL(resolvedId); | ||
| url.searchParams.set("mock", "automock"); | ||
| return import(url.toString()); | ||
| } | ||
| } | ||
| const replacePercentageRE = /%/g; | ||
| function injectQuery(url, importer, queryToInject) { | ||
| const { search, hash } = new URL(url.replace(replacePercentageRE, "%25"), importer); | ||
| return `${cleanUrl(url)}?${queryToInject}${search ? `&${search.slice(1)}` : ""}${hash ?? ""}`; | ||
| } | ||
| let __require; | ||
| function getBuiltinModule(moduleId) { | ||
| __require ??= module$1.createRequire(import.meta.url); | ||
| return __require(`${moduleId}?mock=actual`); | ||
| } | ||
| function genSourceMapUrl(map) { | ||
| if (typeof map !== "string") map = JSON.stringify(map); | ||
| return `data:application/json;base64,${Buffer.from(map).toString("base64")}`; | ||
| } | ||
| function transformCode(code, format, filename) { | ||
| if (format.includes("typescript")) { | ||
| if (!module$1.stripTypeScriptTypes) throw new Error(`Cannot parse '${filename}' because "module.stripTypeScriptTypes" is not supported. Module mocking requires Node.js 22.15 or higher. This is NOT a bug of Vitest.`); | ||
| return module$1.stripTypeScriptTypes(code); | ||
| } | ||
| return code; | ||
| } | ||
| export { NativeModuleMocker }; |
| import { DevEnvironment } from 'vite'; | ||
| import { V as Vitest, T as TestProject, a as TestProjectConfiguration } from './reporters.d.pZWLB1PG.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 { getSafeTimers } from '@vitest/utils/timers'; | ||
| import { c as createBirpc } from './index.Chj8NDwU.js'; | ||
| import { g as getWorkerState } from './utils.BX5Fg8C4.js'; | ||
| /* Ported from https://github.com/boblauer/MockDate/blob/master/src/mockdate.ts */ | ||
| /* | ||
| The MIT License (MIT) | ||
| Copyright (c) 2014 Bob Lauer | ||
| 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. | ||
| */ | ||
| const RealDate = Date; | ||
| let now = null; | ||
| class MockDate extends RealDate { | ||
| constructor(y, m, d, h, M, s, ms) { | ||
| super(); | ||
| let date; | ||
| switch (arguments.length) { | ||
| case 0: | ||
| if (now !== null) date = new RealDate(now.valueOf()); | ||
| else date = new RealDate(); | ||
| break; | ||
| case 1: | ||
| date = new RealDate(y); | ||
| break; | ||
| default: | ||
| d = typeof d === "undefined" ? 1 : d; | ||
| h = h || 0; | ||
| M = M || 0; | ||
| s = s || 0; | ||
| ms = ms || 0; | ||
| date = new RealDate(y, m, d, h, M, s, ms); | ||
| break; | ||
| } | ||
| Object.setPrototypeOf(date, MockDate.prototype); | ||
| return date; | ||
| } | ||
| } | ||
| MockDate.UTC = RealDate.UTC; | ||
| MockDate.now = function() { | ||
| return new MockDate().valueOf(); | ||
| }; | ||
| MockDate.parse = function(dateString) { | ||
| return RealDate.parse(dateString); | ||
| }; | ||
| MockDate.toString = function() { | ||
| return RealDate.toString(); | ||
| }; | ||
| function mockDate(date) { | ||
| const dateObj = new RealDate(date.valueOf()); | ||
| if (Number.isNaN(dateObj.getTime())) throw new TypeError(`mockdate: The time set is an invalid date: ${date}`); | ||
| // @ts-expect-error global | ||
| globalThis.Date = MockDate; | ||
| now = dateObj.valueOf(); | ||
| } | ||
| function resetDate() { | ||
| globalThis.Date = RealDate; | ||
| } | ||
| const { get } = Reflect; | ||
| function withSafeTimers(fn) { | ||
| const { setTimeout, clearTimeout, nextTick, setImmediate, clearImmediate } = getSafeTimers(); | ||
| const currentSetTimeout = globalThis.setTimeout; | ||
| const currentClearTimeout = globalThis.clearTimeout; | ||
| const currentSetImmediate = globalThis.setImmediate; | ||
| const currentClearImmediate = globalThis.clearImmediate; | ||
| const currentNextTick = globalThis.process?.nextTick; | ||
| try { | ||
| globalThis.setTimeout = setTimeout; | ||
| globalThis.clearTimeout = clearTimeout; | ||
| if (setImmediate) globalThis.setImmediate = setImmediate; | ||
| if (clearImmediate) globalThis.clearImmediate = clearImmediate; | ||
| if (globalThis.process && nextTick) globalThis.process.nextTick = nextTick; | ||
| return fn(); | ||
| } finally { | ||
| globalThis.setTimeout = currentSetTimeout; | ||
| globalThis.clearTimeout = currentClearTimeout; | ||
| globalThis.setImmediate = currentSetImmediate; | ||
| globalThis.clearImmediate = currentClearImmediate; | ||
| if (globalThis.process && nextTick) nextTick(() => { | ||
| globalThis.process.nextTick = currentNextTick; | ||
| }); | ||
| } | ||
| } | ||
| const promises = /* @__PURE__ */ new Set(); | ||
| async function rpcDone() { | ||
| if (!promises.size) return; | ||
| const awaitable = Array.from(promises); | ||
| return Promise.all(awaitable); | ||
| } | ||
| const onCancelCallbacks = []; | ||
| function onCancel(callback) { | ||
| onCancelCallbacks.push(callback); | ||
| } | ||
| function createRuntimeRpc(options) { | ||
| return createSafeRpc(createBirpc({ async onCancel(reason) { | ||
| await Promise.all(onCancelCallbacks.map((fn) => fn(reason))); | ||
| } }, { | ||
| eventNames: [ | ||
| "onUserConsoleLog", | ||
| "onCollected", | ||
| "onCancel" | ||
| ], | ||
| timeout: -1, | ||
| ...options | ||
| })); | ||
| } | ||
| function createSafeRpc(rpc) { | ||
| return new Proxy(rpc, { get(target, p, handler) { | ||
| // keep $rejectPendingCalls as sync function | ||
| if (p === "$rejectPendingCalls") return rpc.$rejectPendingCalls; | ||
| const sendCall = get(target, p, handler); | ||
| const safeSendCall = (...args) => withSafeTimers(async () => { | ||
| const result = sendCall(...args); | ||
| promises.add(result); | ||
| try { | ||
| return await result; | ||
| } finally { | ||
| promises.delete(result); | ||
| } | ||
| }); | ||
| safeSendCall.asEvent = sendCall.asEvent; | ||
| return safeSendCall; | ||
| } }); | ||
| } | ||
| function rpc() { | ||
| const { rpc } = getWorkerState(); | ||
| return rpc; | ||
| } | ||
| export { RealDate as R, rpcDone as a, resetDate as b, createRuntimeRpc as c, mockDate as m, onCancel as o, rpc as r }; |
| 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.BX5Fg8C4.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.DgrX1FjK.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 }; |
| import fs from 'node:fs'; | ||
| import { isBareImport } from '@vitest/utils/helpers'; | ||
| import { i as isBuiltin, a as isBrowserExternal, t as toBuiltin } from './modules.BJuCwlRJ.js'; | ||
| import { E as EnvironmentTeardownError, a as getSafeWorkerState } from './utils.BX5Fg8C4.js'; | ||
| import { pathToFileURL } from 'node:url'; | ||
| import { normalize, join } from 'pathe'; | ||
| import { distDir } from '../path.js'; | ||
| import { VitestModuleEvaluator, unwrapId } from '../module-evaluator.js'; | ||
| import { isAbsolute, resolve } from 'node:path'; | ||
| import vm from 'node:vm'; | ||
| import { MockerRegistry, mockObject, RedirectedModule, AutomockedModule } from '@vitest/mocker'; | ||
| import { findMockRedirect } from '@vitest/mocker/redirect'; | ||
| import * as viteModuleRunner from 'vite/module-runner'; | ||
| import { T as Traces } from './traces.CCmnQaNT.js'; | ||
| class BareModuleMocker { | ||
| static pendingIds = []; | ||
| spyModule; | ||
| primitives; | ||
| registries = /* @__PURE__ */ new Map(); | ||
| mockContext = { callstack: null }; | ||
| _otel; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this._otel = options.traces; | ||
| this.primitives = { | ||
| Object, | ||
| Error, | ||
| Function, | ||
| RegExp, | ||
| Symbol: globalThis.Symbol, | ||
| Array, | ||
| Map | ||
| }; | ||
| if (options.spyModule) this.spyModule = options.spyModule; | ||
| } | ||
| get root() { | ||
| return this.options.root; | ||
| } | ||
| get moduleDirectories() { | ||
| return this.options.moduleDirectories || []; | ||
| } | ||
| getMockerRegistry() { | ||
| const suite = this.getSuiteFilepath(); | ||
| if (!this.registries.has(suite)) this.registries.set(suite, new MockerRegistry()); | ||
| return this.registries.get(suite); | ||
| } | ||
| reset() { | ||
| this.registries.clear(); | ||
| } | ||
| invalidateModuleById(_id) { | ||
| // implemented by mockers that control the module runner | ||
| } | ||
| isModuleDirectory(path) { | ||
| return this.moduleDirectories.some((dir) => path.includes(dir)); | ||
| } | ||
| getSuiteFilepath() { | ||
| return this.options.getCurrentTestFilepath() || "global"; | ||
| } | ||
| createError(message, codeFrame) { | ||
| const Error = this.primitives.Error; | ||
| const error = new Error(message); | ||
| Object.assign(error, { codeFrame }); | ||
| return error; | ||
| } | ||
| async resolveId(rawId, importer) { | ||
| return this._otel.$("vitest.mocker.resolve_id", { attributes: { | ||
| "vitest.module.raw_id": rawId, | ||
| "vitest.module.importer": rawId | ||
| } }, async (span) => { | ||
| const result = await this.options.resolveId(rawId, importer); | ||
| if (!result) { | ||
| span.addEvent("could not resolve id, fallback to unresolved values"); | ||
| const id = normalizeModuleId(rawId); | ||
| span.setAttributes({ | ||
| "vitest.module.id": id, | ||
| "vitest.module.url": rawId, | ||
| "vitest.module.external": id, | ||
| "vitest.module.fallback": true | ||
| }); | ||
| return { | ||
| id, | ||
| url: rawId, | ||
| external: id | ||
| }; | ||
| } | ||
| // external is node_module or unresolved module | ||
| // for example, some people mock "vscode" and don't have it installed | ||
| const external = !isAbsolute(result.file) || this.isModuleDirectory(result.file) ? normalizeModuleId(rawId) : null; | ||
| const id = normalizeModuleId(result.id); | ||
| span.setAttributes({ | ||
| "vitest.module.id": id, | ||
| "vitest.module.url": result.url, | ||
| "vitest.module.external": external ?? false | ||
| }); | ||
| return { | ||
| ...result, | ||
| id, | ||
| external | ||
| }; | ||
| }); | ||
| } | ||
| async resolveMocks() { | ||
| if (!BareModuleMocker.pendingIds.length) return; | ||
| await Promise.all(BareModuleMocker.pendingIds.map(async (mock) => { | ||
| const { id, url, external } = await this.resolveId(mock.id, mock.importer); | ||
| if (mock.action === "unmock") this.unmockPath(id); | ||
| if (mock.action === "mock") this.mockPath(mock.id, id, url, external, mock.type, mock.factory); | ||
| })); | ||
| BareModuleMocker.pendingIds = []; | ||
| } | ||
| // public method to avoid circular dependency | ||
| getMockContext() { | ||
| return this.mockContext; | ||
| } | ||
| // path used to store mocked dependencies | ||
| getMockPath(dep) { | ||
| return `mock:${dep}`; | ||
| } | ||
| getDependencyMock(id) { | ||
| return this.getMockerRegistry().getById(fixLeadingSlashes(id)); | ||
| } | ||
| findMockRedirect(mockPath, external) { | ||
| return findMockRedirect(this.root, mockPath, external); | ||
| } | ||
| mockObject(object, mockExportsOrModuleType, moduleType) { | ||
| let mockExports; | ||
| if (mockExportsOrModuleType === "automock" || mockExportsOrModuleType === "autospy") { | ||
| moduleType = mockExportsOrModuleType; | ||
| mockExports = void 0; | ||
| } else mockExports = mockExportsOrModuleType; | ||
| moduleType ??= "automock"; | ||
| const createMockInstance = this.spyModule?.createMockInstance; | ||
| if (!createMockInstance) throw this.createError("[vitest] `spyModule` is not defined. This is a Vitest error. Please open a new issue with reproduction."); | ||
| return mockObject({ | ||
| globalConstructors: this.primitives, | ||
| createMockInstance, | ||
| type: moduleType | ||
| }, object, mockExports); | ||
| } | ||
| unmockPath(id) { | ||
| this.getMockerRegistry().deleteById(id); | ||
| this.invalidateModuleById(id); | ||
| } | ||
| mockPath(originalId, id, url, external, mockType, factory) { | ||
| const registry = this.getMockerRegistry(); | ||
| if (mockType === "manual") registry.register("manual", originalId, id, url, factory); | ||
| else if (mockType === "autospy") registry.register("autospy", originalId, id, url); | ||
| else { | ||
| const redirect = this.findMockRedirect(id, external); | ||
| if (redirect) registry.register("redirect", originalId, id, url, redirect); | ||
| else registry.register("automock", originalId, id, url); | ||
| } | ||
| // every time the mock is registered, we remove the previous one from the cache | ||
| this.invalidateModuleById(id); | ||
| } | ||
| async importActual(_rawId, _importer, _callstack) { | ||
| throw new Error(`importActual is not implemented`); | ||
| } | ||
| async importMock(_rawId, _importer, _callstack) { | ||
| throw new Error(`importMock is not implemented`); | ||
| } | ||
| queueMock(id, importer, factoryOrOptions) { | ||
| const mockType = getMockType(factoryOrOptions); | ||
| BareModuleMocker.pendingIds.push({ | ||
| action: "mock", | ||
| id, | ||
| importer, | ||
| factory: typeof factoryOrOptions === "function" ? factoryOrOptions : void 0, | ||
| type: mockType | ||
| }); | ||
| } | ||
| queueUnmock(id, importer) { | ||
| BareModuleMocker.pendingIds.push({ | ||
| action: "unmock", | ||
| id, | ||
| importer | ||
| }); | ||
| } | ||
| } | ||
| function getMockType(factoryOrOptions) { | ||
| if (!factoryOrOptions) return "automock"; | ||
| if (typeof factoryOrOptions === "function") return "manual"; | ||
| return factoryOrOptions.spy ? "autospy" : "automock"; | ||
| } | ||
| // unique id that is not available as "$bare_import" like "test" | ||
| // https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix | ||
| const prefixedBuiltins = new Set([ | ||
| "node:sea", | ||
| "node:sqlite", | ||
| "node:test", | ||
| "node:test/reporters" | ||
| ]); | ||
| const isWindows$1 = process.platform === "win32"; | ||
| // transform file url to id | ||
| // virtual:custom -> virtual:custom | ||
| // \0custom -> \0custom | ||
| // /root/id -> /id | ||
| // /root/id.js -> /id.js | ||
| // C:/root/id.js -> /id.js | ||
| // C:\root\id.js -> /id.js | ||
| // TODO: expose this in vite/module-runner | ||
| function normalizeModuleId(file) { | ||
| if (prefixedBuiltins.has(file)) return file; | ||
| // if it's not in the root, keep it as a path, not a URL | ||
| return slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/"); | ||
| } | ||
| const windowsSlashRE = /\\/g; | ||
| function slash(p) { | ||
| return p.replace(windowsSlashRE, "/"); | ||
| } | ||
| const multipleSlashRe = /^\/+/; | ||
| // module-runner incorrectly replaces file:///path with `///path` | ||
| function fixLeadingSlashes(id) { | ||
| if (id.startsWith("//")) return id.replace(multipleSlashRe, "/"); | ||
| return id; | ||
| } | ||
| const spyModulePath = resolve(distDir, "spy.js"); | ||
| class VitestMocker extends BareModuleMocker { | ||
| filterPublicKeys; | ||
| constructor(moduleRunner, options) { | ||
| super(options); | ||
| this.moduleRunner = moduleRunner; | ||
| this.options = options; | ||
| const context = this.options.context; | ||
| if (context) this.primitives = vm.runInContext("({ Object, Error, Function, RegExp, Symbol, Array, Map })", context); | ||
| const Symbol = this.primitives.Symbol; | ||
| this.filterPublicKeys = [ | ||
| "__esModule", | ||
| Symbol.asyncIterator, | ||
| Symbol.hasInstance, | ||
| Symbol.isConcatSpreadable, | ||
| Symbol.iterator, | ||
| Symbol.match, | ||
| Symbol.matchAll, | ||
| Symbol.replace, | ||
| Symbol.search, | ||
| Symbol.split, | ||
| Symbol.species, | ||
| Symbol.toPrimitive, | ||
| Symbol.toStringTag, | ||
| Symbol.unscopables | ||
| ]; | ||
| } | ||
| get evaluatedModules() { | ||
| return this.moduleRunner.evaluatedModules; | ||
| } | ||
| async initializeSpyModule() { | ||
| if (this.spyModule) return; | ||
| this.spyModule = await this.moduleRunner.import(spyModulePath); | ||
| } | ||
| reset() { | ||
| this.registries.clear(); | ||
| } | ||
| invalidateModuleById(id) { | ||
| const mockId = this.getMockPath(id); | ||
| const node = this.evaluatedModules.getModuleById(mockId); | ||
| if (node) { | ||
| this.evaluatedModules.invalidateModule(node); | ||
| node.mockedExports = void 0; | ||
| } | ||
| } | ||
| ensureModule(id, url) { | ||
| const node = this.evaluatedModules.ensureModule(id, url); | ||
| // TODO | ||
| node.meta = { | ||
| id, | ||
| url, | ||
| code: "", | ||
| file: null, | ||
| invalidate: false | ||
| }; | ||
| return node; | ||
| } | ||
| async callFunctionMock(id, url, mock) { | ||
| const node = this.ensureModule(id, url); | ||
| if (node.exports) return node.exports; | ||
| const exports$1 = await mock.resolve(); | ||
| const moduleExports = new Proxy(exports$1, { get: (target, prop) => { | ||
| const val = target[prop]; | ||
| // 'then' can exist on non-Promise objects, need nested instanceof check for logic to work | ||
| if (prop === "then") { | ||
| if (target instanceof Promise) return target.then.bind(target); | ||
| } else if (!(prop in target)) { | ||
| if (this.filterPublicKeys.includes(prop)) return; | ||
| throw this.createError(`[vitest] No "${String(prop)}" export is defined on the "${mock.raw}" mock. Did you forget to return it from "vi.mock"? | ||
| If you need to partially mock a module, you can use "importOriginal" helper inside: | ||
| `, `vi.mock(import("${mock.raw}"), async (importOriginal) => { | ||
| const actual = await importOriginal() | ||
| return { | ||
| ...actual, | ||
| // your mocked methods | ||
| } | ||
| })`); | ||
| } | ||
| return val; | ||
| } }); | ||
| node.exports = moduleExports; | ||
| return moduleExports; | ||
| } | ||
| async importActual(rawId, importer, callstack) { | ||
| const { url } = await this.resolveId(rawId, importer); | ||
| const node = await this.moduleRunner.fetchModule(url, importer); | ||
| return await this.moduleRunner.cachedRequest(node.url, node, callstack || [importer], void 0, true); | ||
| } | ||
| async importMock(rawId, importer) { | ||
| const { id, url, external } = await this.resolveId(rawId, importer); | ||
| let mock = this.getDependencyMock(id); | ||
| if (!mock) { | ||
| const redirect = this.findMockRedirect(id, external); | ||
| if (redirect) mock = new RedirectedModule(rawId, id, rawId, redirect); | ||
| else mock = new AutomockedModule(rawId, id, rawId); | ||
| } | ||
| if (mock.type === "automock" || mock.type === "autospy") { | ||
| const node = await this.moduleRunner.fetchModule(url, importer); | ||
| const mod = await this.moduleRunner.cachedRequest(url, node, [importer], void 0, true); | ||
| const Object = this.primitives.Object; | ||
| return this.mockObject(mod, Object.create(Object.prototype), mock.type); | ||
| } | ||
| if (mock.type === "manual") return this.callFunctionMock(id, url, mock); | ||
| const node = await this.moduleRunner.fetchModule(mock.redirect); | ||
| return this.moduleRunner.cachedRequest(mock.redirect, node, [importer], void 0, true); | ||
| } | ||
| async requestWithMockedModule(url, evaluatedNode, callstack, mock) { | ||
| return this._otel.$("vitest.mocker.evaluate", async (span) => { | ||
| const mockId = this.getMockPath(evaluatedNode.id); | ||
| span.setAttributes({ | ||
| "vitest.module.id": mockId, | ||
| "vitest.mock.type": mock.type, | ||
| "vitest.mock.id": mock.id, | ||
| "vitest.mock.url": mock.url, | ||
| "vitest.mock.raw": mock.raw | ||
| }); | ||
| if (mock.type === "automock" || mock.type === "autospy") { | ||
| const cache = this.evaluatedModules.getModuleById(mockId); | ||
| if (cache && cache.mockedExports) return cache.mockedExports; | ||
| const Object = this.primitives.Object; | ||
| // we have to define a separate object that will copy all properties into itself | ||
| // and can't just use the same `exports` define automatically by Vite before the evaluator | ||
| const exports$1 = Object.create(null); | ||
| Object.defineProperty(exports$1, Symbol.toStringTag, { | ||
| value: "Module", | ||
| configurable: true, | ||
| writable: true | ||
| }); | ||
| const node = this.ensureModule(mockId, this.getMockPath(evaluatedNode.url)); | ||
| node.meta = evaluatedNode.meta; | ||
| node.file = evaluatedNode.file; | ||
| node.mockedExports = exports$1; | ||
| const mod = await this.moduleRunner.cachedRequest(url, node, callstack, void 0, true); | ||
| this.mockObject(mod, exports$1, mock.type); | ||
| return exports$1; | ||
| } | ||
| if (mock.type === "manual" && !callstack.includes(mockId) && !callstack.includes(url)) try { | ||
| callstack.push(mockId); | ||
| // this will not work if user does Promise.all(import(), import()) | ||
| // we can also use AsyncLocalStorage to store callstack, but this won't work in the browser | ||
| // maybe we should improve mock API in the future? | ||
| this.mockContext.callstack = callstack; | ||
| return await this.callFunctionMock(mockId, this.getMockPath(url), mock); | ||
| } finally { | ||
| this.mockContext.callstack = null; | ||
| const indexMock = callstack.indexOf(mockId); | ||
| callstack.splice(indexMock, 1); | ||
| } | ||
| else if (mock.type === "redirect" && !callstack.includes(mock.redirect)) { | ||
| span.setAttribute("vitest.mock.redirect", mock.redirect); | ||
| return mock.redirect; | ||
| } | ||
| }); | ||
| } | ||
| async mockedRequest(url, evaluatedNode, callstack) { | ||
| const mock = this.getDependencyMock(evaluatedNode.id); | ||
| if (!mock) return; | ||
| return this.requestWithMockedModule(url, evaluatedNode, callstack, mock); | ||
| } | ||
| } | ||
| class VitestTransport { | ||
| constructor(options, evaluatedModules, callstacks) { | ||
| this.options = options; | ||
| this.evaluatedModules = evaluatedModules; | ||
| this.callstacks = callstacks; | ||
| } | ||
| async invoke(event) { | ||
| if (event.type !== "custom") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support Vite HMR events.`) }; | ||
| if (event.event !== "vite:invoke") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support ${event.event} event.`) }; | ||
| const { name, data } = event.data; | ||
| if (name === "getBuiltins") | ||
| // we return an empty array here to avoid client-side builtin check, | ||
| // as we need builtins to go through `fetchModule` | ||
| return { result: [] }; | ||
| if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) }; | ||
| try { | ||
| return { result: await this.options.fetchModule(...data) }; | ||
| } catch (cause) { | ||
| if (cause instanceof EnvironmentTeardownError) { | ||
| const [id, importer] = data; | ||
| let message = `Cannot load '${id}'${importer ? ` imported from ${importer}` : ""} after the environment was torn down. This is not a bug in Vitest.`; | ||
| const moduleNode = importer ? this.evaluatedModules.getModuleById(importer) : void 0; | ||
| const callstack = moduleNode ? this.callstacks.get(moduleNode) : void 0; | ||
| if (callstack) message += ` The last recorded callstack:\n- ${[ | ||
| ...callstack, | ||
| importer, | ||
| id | ||
| ].reverse().join("\n- ")}`; | ||
| const error = new EnvironmentTeardownError(message); | ||
| if (cause.stack) error.stack = cause.stack.replace(cause.message, error.message); | ||
| return { error }; | ||
| } | ||
| return { error: cause }; | ||
| } | ||
| } | ||
| } | ||
| const createNodeImportMeta = (modulePath) => { | ||
| if (!viteModuleRunner.createDefaultImportMeta) throw new Error(`createNodeImportMeta is not supported in this version of Vite.`); | ||
| const defaultMeta = viteModuleRunner.createDefaultImportMeta(modulePath); | ||
| const href = defaultMeta.url; | ||
| const importMetaResolver = createImportMetaResolver(); | ||
| return { | ||
| ...defaultMeta, | ||
| main: false, | ||
| resolve(id, parent) { | ||
| return (importMetaResolver ?? defaultMeta.resolve)(id, parent ?? href); | ||
| } | ||
| }; | ||
| }; | ||
| function createImportMetaResolver() { | ||
| if (!import.meta.resolve) return; | ||
| return (specifier, importer) => import.meta.resolve(specifier, importer); | ||
| } | ||
| // @ts-expect-error overriding private method | ||
| class VitestModuleRunner extends viteModuleRunner.ModuleRunner { | ||
| mocker; | ||
| moduleExecutionInfo; | ||
| _otel; | ||
| _callstacks; | ||
| constructor(vitestOptions) { | ||
| const options = vitestOptions; | ||
| const evaluatedModules = options.evaluatedModules; | ||
| const callstacks = /* @__PURE__ */ new WeakMap(); | ||
| const transport = new VitestTransport(options.transport, evaluatedModules, callstacks); | ||
| super({ | ||
| transport, | ||
| hmr: false, | ||
| evaluatedModules, | ||
| sourcemapInterceptor: "prepareStackTrace", | ||
| createImportMeta: vitestOptions.createImportMeta | ||
| }, options.evaluator); | ||
| this.vitestOptions = vitestOptions; | ||
| this._callstacks = callstacks; | ||
| this._otel = vitestOptions.traces || new Traces({ enabled: false }); | ||
| this.moduleExecutionInfo = options.getWorkerState().moduleExecutionInfo; | ||
| this.mocker = options.mocker || new VitestMocker(this, { | ||
| spyModule: options.spyModule, | ||
| context: options.vm?.context, | ||
| traces: this._otel, | ||
| resolveId: options.transport.resolveId, | ||
| get root() { | ||
| return options.getWorkerState().config.root; | ||
| }, | ||
| get moduleDirectories() { | ||
| return options.getWorkerState().config.deps.moduleDirectories || []; | ||
| }, | ||
| getCurrentTestFilepath() { | ||
| return options.getWorkerState().filepath; | ||
| } | ||
| }); | ||
| if (options.vm) options.vm.context.__vitest_mocker__ = this.mocker; | ||
| else Object.defineProperty(globalThis, "__vitest_mocker__", { | ||
| configurable: true, | ||
| writable: true, | ||
| value: this.mocker | ||
| }); | ||
| } | ||
| /** | ||
| * Vite checks that the module has exports emulating the Node.js behaviour, | ||
| * but Vitest is more relaxed. | ||
| * | ||
| * We should keep the Vite behavour when there is a `strict` flag. | ||
| * @internal | ||
| */ | ||
| processImport(exports$1) { | ||
| return exports$1; | ||
| } | ||
| async import(rawId) { | ||
| const resolved = await this._otel.$("vitest.module.resolve_id", { attributes: { "vitest.module.raw_id": rawId } }, async (span) => { | ||
| const result = await this.vitestOptions.transport.resolveId(rawId); | ||
| if (result) span.setAttributes({ | ||
| "vitest.module.url": result.url, | ||
| "vitest.module.file": result.file, | ||
| "vitest.module.id": result.id | ||
| }); | ||
| return result; | ||
| }); | ||
| return super.import(resolved ? resolved.url : rawId); | ||
| } | ||
| async fetchModule(url, importer) { | ||
| return await this.cachedModule(url, importer); | ||
| } | ||
| _cachedRequest(url, module, callstack = [], metadata) { | ||
| // @ts-expect-error "cachedRequest" is private | ||
| return super.cachedRequest(url, module, callstack, metadata); | ||
| } | ||
| /** | ||
| * @internal | ||
| */ | ||
| async cachedRequest(url, mod, callstack = [], metadata, ignoreMock = false) { | ||
| // Track for a better error message if dynamic import is not resolved properly | ||
| this._callstacks.set(mod, callstack); | ||
| if (ignoreMock) return this._cachedRequest(url, mod, callstack, metadata); | ||
| let mocked; | ||
| if (mod.meta && "mockedModule" in mod.meta) mocked = await this.mocker.requestWithMockedModule(url, mod, callstack, mod.meta.mockedModule); | ||
| else mocked = await this.mocker.mockedRequest(url, mod, callstack); | ||
| if (typeof mocked === "string") { | ||
| const node = await this.fetchModule(mocked); | ||
| return this._cachedRequest(mocked, node, callstack, metadata); | ||
| } | ||
| if (mocked != null && typeof mocked === "object") return mocked; | ||
| return this._cachedRequest(url, mod, callstack, metadata); | ||
| } | ||
| /** @internal */ | ||
| _invalidateSubTreeById(ids, invalidated = /* @__PURE__ */ new Set()) { | ||
| for (const id of ids) { | ||
| if (invalidated.has(id)) continue; | ||
| const node = this.evaluatedModules.getModuleById(id); | ||
| if (!node) continue; | ||
| invalidated.add(id); | ||
| const subIds = Array.from(this.evaluatedModules.idToModuleMap).filter(([, mod]) => mod.importers.has(id)).map(([key]) => key); | ||
| if (subIds.length) this._invalidateSubTreeById(subIds, invalidated); | ||
| this.evaluatedModules.invalidateModule(node); | ||
| } | ||
| } | ||
| } | ||
| const bareVitestRegexp = /^@?vitest(?:\/|$)/; | ||
| const normalizedDistDir = normalize(distDir); | ||
| const relativeIds = {}; | ||
| const externalizeMap = /* @__PURE__ */ new Map(); | ||
| // all Vitest imports always need to be externalized | ||
| function getCachedVitestImport(id, state) { | ||
| if (id.startsWith("/@fs/") || id.startsWith("\\@fs\\")) id = id.slice(process.platform === "win32" ? 5 : 4); | ||
| if (externalizeMap.has(id)) return { | ||
| externalize: externalizeMap.get(id), | ||
| type: "module" | ||
| }; | ||
| // always externalize Vitest because we import from there before running tests | ||
| // so we already have it cached by Node.js | ||
| const root = state().config.root; | ||
| const relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length)); | ||
| if (id.includes(distDir) || id.includes(normalizedDistDir)) { | ||
| const externalize = id.startsWith("file://") ? id : pathToFileURL(id).toString(); | ||
| externalizeMap.set(id, externalize); | ||
| return { | ||
| externalize, | ||
| type: "module" | ||
| }; | ||
| } | ||
| if (relativeRoot && relativeRoot !== "/" && id.startsWith(relativeRoot)) { | ||
| const externalize = pathToFileURL(join(root, id)).toString(); | ||
| externalizeMap.set(id, externalize); | ||
| return { | ||
| externalize, | ||
| type: "module" | ||
| }; | ||
| } | ||
| if (bareVitestRegexp.test(id)) { | ||
| externalizeMap.set(id, id); | ||
| return { | ||
| externalize: id, | ||
| type: "module" | ||
| }; | ||
| } | ||
| return null; | ||
| } | ||
| const { readFileSync } = fs; | ||
| const VITEST_VM_CONTEXT_SYMBOL = "__vitest_vm_context__"; | ||
| const cwd = process.cwd(); | ||
| const isWindows = process.platform === "win32"; | ||
| function startVitestModuleRunner(options) { | ||
| const traces = options.traces; | ||
| const state = () => getSafeWorkerState() || options.state; | ||
| const rpc = () => state().rpc; | ||
| const environment = () => { | ||
| const environment = state().environment; | ||
| return environment.viteEnvironment || environment.name; | ||
| }; | ||
| const vm = options.context && options.externalModulesExecutor ? { | ||
| context: options.context, | ||
| externalModulesExecutor: options.externalModulesExecutor | ||
| } : void 0; | ||
| const evaluator = options.evaluator || new VitestModuleEvaluator(vm, { | ||
| traces, | ||
| evaluatedModules: options.evaluatedModules, | ||
| get moduleExecutionInfo() { | ||
| return state().moduleExecutionInfo; | ||
| }, | ||
| get interopDefault() { | ||
| return state().config.deps.interopDefault; | ||
| }, | ||
| getCurrentTestFilepath: () => state().filepath | ||
| }); | ||
| const moduleRunner = new VitestModuleRunner({ | ||
| spyModule: options.spyModule, | ||
| evaluatedModules: options.evaluatedModules, | ||
| evaluator, | ||
| traces, | ||
| mocker: options.mocker, | ||
| transport: { | ||
| async fetchModule(id, importer, options) { | ||
| const resolvingModules = state().resolvingModules; | ||
| if (isWindows) { | ||
| if (id[1] === ":") { | ||
| // The drive letter is different for whatever reason, we need to normalize it to CWD | ||
| if (id[0] !== cwd[0] && id[0].toUpperCase() === cwd[0].toUpperCase()) id = (cwd[0].toUpperCase() === cwd[0] ? id[0].toUpperCase() : id[0].toLowerCase()) + id.slice(1); | ||
| // always mark absolute windows paths, otherwise Vite will externalize it | ||
| id = `/@id/${id}`; | ||
| } | ||
| } | ||
| const vitest = getCachedVitestImport(id, state); | ||
| if (vitest) return vitest; | ||
| const rawId = unwrapId(id); | ||
| resolvingModules.add(rawId); | ||
| try { | ||
| if (VitestMocker.pendingIds.length) await moduleRunner.mocker.resolveMocks(); | ||
| const resolvedMock = moduleRunner.mocker.getDependencyMock(rawId); | ||
| if (resolvedMock?.type === "manual" || resolvedMock?.type === "redirect") return { | ||
| code: "", | ||
| file: null, | ||
| id: resolvedMock.id, | ||
| url: resolvedMock.url, | ||
| invalidate: false, | ||
| mockedModule: resolvedMock | ||
| }; | ||
| if (isBuiltin(rawId)) return { | ||
| externalize: rawId, | ||
| type: "builtin" | ||
| }; | ||
| if (isBrowserExternal(rawId)) return { | ||
| externalize: toBuiltin(rawId), | ||
| type: "builtin" | ||
| }; | ||
| // if module is invalidated, the worker will be recreated, | ||
| // so cached is always true in a single worker | ||
| if (options?.cached) return { cache: true }; | ||
| const otelCarrier = traces?.getContextCarrier(); | ||
| const result = await rpc().fetch(id, importer, environment(), options, otelCarrier); | ||
| if ("cached" in result) return { | ||
| code: readFileSync(result.tmp, "utf-8"), | ||
| ...result | ||
| }; | ||
| return result; | ||
| } catch (cause) { | ||
| // rethrow vite error if it cannot load the module because it's not resolved | ||
| if (typeof cause === "object" && cause != null && cause.code === "ERR_LOAD_URL" || typeof cause?.message === "string" && cause.message.includes("Failed to load url") || typeof cause?.message === "string" && cause.message.startsWith("Cannot find module '")) { | ||
| const error = new Error(`Cannot find ${isBareImport(id) ? "package" : "module"} '${id}'${importer ? ` imported from ${importer}` : ""}`, { cause }); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| throw cause; | ||
| } finally { | ||
| resolvingModules.delete(rawId); | ||
| } | ||
| }, | ||
| resolveId(id, importer) { | ||
| return rpc().resolve(id, importer, environment()); | ||
| } | ||
| }, | ||
| getWorkerState: state, | ||
| vm, | ||
| createImportMeta: options.createImportMeta | ||
| }); | ||
| return moduleRunner; | ||
| } | ||
| export { BareModuleMocker as B, VITEST_VM_CONTEXT_SYMBOL as V, VitestModuleRunner as a, VitestTransport as b, createNodeImportMeta as c, normalizeModuleId as n, startVitestModuleRunner as s }; |
Sorry, the diff of this file is too big to display
| import { fileURLToPath, pathToFileURL } from 'node:url'; | ||
| import vm, { isContext, runInContext } from 'node:vm'; | ||
| import { dirname, basename, extname, normalize, resolve } from 'pathe'; | ||
| import { l as loadEnvironment, a as listenForErrors, e as emitModuleRunner } from './init.DzWSvu83.js'; | ||
| import { distDir } from '../path.js'; | ||
| import { createCustomConsole } from './console.DpQfzR9G.js'; | ||
| import fs from 'node:fs'; | ||
| import { createRequire, Module, isBuiltin } from 'node:module'; | ||
| import { toArray, isBareImport } from '@vitest/utils/helpers'; | ||
| import { findNearestPackageData } from '@vitest/utils/resolver'; | ||
| import { dirname as dirname$1 } from 'node:path'; | ||
| import { CSS_LANGS_RE, KNOWN_ASSET_RE } from '@vitest/utils/constants'; | ||
| import { getDefaultRequestStubs } from '../module-evaluator.js'; | ||
| import { s as startVitestModuleRunner, V as VITEST_VM_CONTEXT_SYMBOL, c as createNodeImportMeta } from './startVitestModuleRunner.BRvQz4ko.js'; | ||
| import { p as provideWorkerState } from './utils.BX5Fg8C4.js'; | ||
| function interopCommonJsModule(interopDefault, mod) { | ||
| if (isPrimitive(mod) || Array.isArray(mod) || mod instanceof Promise) return { | ||
| keys: [], | ||
| moduleExports: {}, | ||
| defaultExport: mod | ||
| }; | ||
| if (interopDefault !== false && "__esModule" in mod && !isPrimitive(mod.default)) { | ||
| const defaultKets = Object.keys(mod.default); | ||
| const moduleKeys = Object.keys(mod); | ||
| const allKeys = new Set([...defaultKets, ...moduleKeys]); | ||
| allKeys.delete("default"); | ||
| return { | ||
| keys: Array.from(allKeys), | ||
| moduleExports: new Proxy(mod, { get(mod, prop) { | ||
| return mod[prop] ?? mod.default?.[prop]; | ||
| } }), | ||
| defaultExport: mod | ||
| }; | ||
| } | ||
| return { | ||
| keys: Object.keys(mod).filter((key) => key !== "default"), | ||
| moduleExports: mod, | ||
| defaultExport: mod | ||
| }; | ||
| } | ||
| function isPrimitive(obj) { | ||
| return !(obj != null && (typeof obj === "object" || typeof obj === "function")); | ||
| } | ||
| const SyntheticModule = vm.SyntheticModule; | ||
| const SourceTextModule = vm.SourceTextModule; | ||
| const _require = createRequire(import.meta.url); | ||
| const requiresCache = /* @__PURE__ */ new WeakMap(); | ||
| class CommonjsExecutor { | ||
| context; | ||
| requireCache = /* @__PURE__ */ new Map(); | ||
| publicRequireCache = this.createProxyCache(); | ||
| moduleCache = /* @__PURE__ */ new Map(); | ||
| builtinCache = Object.create(null); | ||
| extensions = Object.create(null); | ||
| fs; | ||
| Module; | ||
| interopDefault; | ||
| constructor(options) { | ||
| this.context = options.context; | ||
| this.fs = options.fileMap; | ||
| this.interopDefault = options.interopDefault; | ||
| const primitives = vm.runInContext("({ Object, Array, Error })", this.context); | ||
| // eslint-disable-next-line ts/no-this-alias | ||
| const executor = this; | ||
| this.Module = class Module$1 { | ||
| exports; | ||
| isPreloading = false; | ||
| id; | ||
| filename; | ||
| loaded; | ||
| parent; | ||
| children = []; | ||
| path; | ||
| paths = []; | ||
| constructor(id = "", parent) { | ||
| this.exports = primitives.Object.create(Object.prototype); | ||
| // in our case the path should always be resolved already | ||
| this.path = dirname(id); | ||
| this.id = id; | ||
| this.filename = id; | ||
| this.loaded = false; | ||
| this.parent = parent; | ||
| } | ||
| get require() { | ||
| const require = requiresCache.get(this); | ||
| if (require) return require; | ||
| const _require = Module$1.createRequire(this.id); | ||
| requiresCache.set(this, _require); | ||
| return _require; | ||
| } | ||
| static getSourceMapsSupport = () => ({ | ||
| enabled: false, | ||
| nodeModules: false, | ||
| generatedCode: false | ||
| }); | ||
| static setSourceMapsSupport = () => { | ||
| // noop | ||
| }; | ||
| static register = () => { | ||
| throw new Error(`[vitest] "register" is not available when running in Vitest.`); | ||
| }; | ||
| static registerHooks = () => { | ||
| throw new Error(`[vitest] "registerHooks" is not available when running in Vitest.`); | ||
| }; | ||
| _compile(code, filename) { | ||
| const cjsModule = Module$1.wrap(code); | ||
| const script = new vm.Script(cjsModule, { | ||
| filename, | ||
| importModuleDynamically: options.importModuleDynamically | ||
| }); | ||
| // @ts-expect-error mark script with current identifier | ||
| script.identifier = filename; | ||
| const fn = script.runInContext(executor.context); | ||
| const __dirname = dirname(filename); | ||
| executor.requireCache.set(filename, this); | ||
| try { | ||
| fn(this.exports, this.require, this, filename, __dirname); | ||
| return this.exports; | ||
| } finally { | ||
| this.loaded = true; | ||
| } | ||
| } | ||
| // exposed for external use, Node.js does the opposite | ||
| static _load = (request, parent, _isMain) => { | ||
| return Module$1.createRequire(parent?.filename ?? request)(request); | ||
| }; | ||
| static wrap = (script) => { | ||
| return Module$1.wrapper[0] + script + Module$1.wrapper[1]; | ||
| }; | ||
| static wrapper = new primitives.Array("(function (exports, require, module, __filename, __dirname) { ", "\n});"); | ||
| static builtinModules = Module.builtinModules; | ||
| static findSourceMap = Module.findSourceMap; | ||
| static SourceMap = Module.SourceMap; | ||
| static syncBuiltinESMExports = Module.syncBuiltinESMExports; | ||
| static _cache = executor.publicRequireCache; | ||
| static _extensions = executor.extensions; | ||
| static createRequire = (filename) => { | ||
| return executor.createRequire(filename); | ||
| }; | ||
| static runMain = () => { | ||
| throw new primitives.Error("[vitest] \"runMain\" is not implemented."); | ||
| }; | ||
| // @ts-expect-error not typed | ||
| static _resolveFilename = Module._resolveFilename; | ||
| // @ts-expect-error not typed | ||
| static _findPath = Module._findPath; | ||
| // @ts-expect-error not typed | ||
| static _initPaths = Module._initPaths; | ||
| // @ts-expect-error not typed | ||
| static _preloadModules = Module._preloadModules; | ||
| // @ts-expect-error not typed | ||
| static _resolveLookupPaths = Module._resolveLookupPaths; | ||
| // @ts-expect-error not typed | ||
| static globalPaths = Module.globalPaths; | ||
| static isBuiltin = Module.isBuiltin; | ||
| static constants = Module.constants; | ||
| static enableCompileCache = Module.enableCompileCache; | ||
| static getCompileCacheDir = Module.getCompileCacheDir; | ||
| static flushCompileCache = Module.flushCompileCache; | ||
| static stripTypeScriptTypes = Module.stripTypeScriptTypes; | ||
| static findPackageJSON = Module.findPackageJSON; | ||
| static Module = Module$1; | ||
| }; | ||
| this.extensions[".js"] = this.requireJs; | ||
| this.extensions[".json"] = this.requireJson; | ||
| } | ||
| requireJs = (m, filename) => { | ||
| const content = this.fs.readFile(filename); | ||
| m._compile(content, filename); | ||
| }; | ||
| requireJson = (m, filename) => { | ||
| const code = this.fs.readFile(filename); | ||
| m.exports = JSON.parse(code); | ||
| }; | ||
| static cjsConditions; | ||
| static getCjsConditions() { | ||
| if (!CommonjsExecutor.cjsConditions) CommonjsExecutor.cjsConditions = parseCjsConditions(process.execArgv, process.env.NODE_OPTIONS); | ||
| return CommonjsExecutor.cjsConditions; | ||
| } | ||
| createRequire = (filename) => { | ||
| const _require = createRequire(filename); | ||
| const resolve = (id, options) => { | ||
| return _require.resolve(id, { | ||
| ...options, | ||
| conditions: CommonjsExecutor.getCjsConditions() | ||
| }); | ||
| }; | ||
| const require = ((id) => { | ||
| const resolved = resolve(id); | ||
| if (extname(resolved) === ".node" || isBuiltin(resolved)) return this.requireCoreModule(resolved); | ||
| const module = new this.Module(resolved); | ||
| return this.loadCommonJSModule(module, resolved); | ||
| }); | ||
| require.resolve = resolve; | ||
| require.resolve.paths = _require.resolve.paths; | ||
| Object.defineProperty(require, "extensions", { | ||
| get: () => this.extensions, | ||
| set: () => {}, | ||
| configurable: true | ||
| }); | ||
| require.main = void 0; | ||
| require.cache = this.publicRequireCache; | ||
| return require; | ||
| }; | ||
| createProxyCache() { | ||
| return new Proxy(Object.create(null), { | ||
| defineProperty: () => true, | ||
| deleteProperty: () => true, | ||
| set: () => true, | ||
| get: (_, key) => this.requireCache.get(key), | ||
| has: (_, key) => this.requireCache.has(key), | ||
| ownKeys: () => Array.from(this.requireCache.keys()), | ||
| getOwnPropertyDescriptor() { | ||
| return { | ||
| configurable: true, | ||
| enumerable: true | ||
| }; | ||
| } | ||
| }); | ||
| } | ||
| // very naive implementation for Node.js require | ||
| loadCommonJSModule(module, filename) { | ||
| const cached = this.requireCache.get(filename); | ||
| if (cached) return cached.exports; | ||
| const extension = this.findLongestRegisteredExtension(filename); | ||
| (this.extensions[extension] || this.extensions[".js"])(module, filename); | ||
| return module.exports; | ||
| } | ||
| findLongestRegisteredExtension(filename) { | ||
| const name = basename(filename); | ||
| let currentExtension; | ||
| let index; | ||
| let startIndex = 0; | ||
| // eslint-disable-next-line no-cond-assign | ||
| while ((index = name.indexOf(".", startIndex)) !== -1) { | ||
| startIndex = index + 1; | ||
| if (index === 0) continue; | ||
| currentExtension = name.slice(index); | ||
| if (this.extensions[currentExtension]) return currentExtension; | ||
| } | ||
| return ".js"; | ||
| } | ||
| getCoreSyntheticModule(identifier) { | ||
| if (this.moduleCache.has(identifier)) return this.moduleCache.get(identifier); | ||
| const exports$1 = this.require(identifier); | ||
| const keys = Object.keys(exports$1); | ||
| const module = new SyntheticModule([...keys, "default"], () => { | ||
| for (const key of keys) module.setExport(key, exports$1[key]); | ||
| module.setExport("default", exports$1); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| getCjsSyntheticModule(path, identifier) { | ||
| if (this.moduleCache.has(identifier)) return this.moduleCache.get(identifier); | ||
| const exports$1 = this.require(path); | ||
| // TODO: technically module should be parsed to find static exports, implement for strict mode in #2854 | ||
| const { keys, moduleExports, defaultExport } = interopCommonJsModule(this.interopDefault, exports$1); | ||
| const module = new SyntheticModule([...keys, "default"], function() { | ||
| for (const key of keys) this.setExport(key, moduleExports[key]); | ||
| this.setExport("default", defaultExport); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| // TODO: use this in strict mode, when available in #2854 | ||
| // private _getNamedCjsExports(path: string): Set<string> { | ||
| // const cachedNamedExports = this.cjsNamedExportsMap.get(path) | ||
| // if (cachedNamedExports) { | ||
| // return cachedNamedExports | ||
| // } | ||
| // if (extname(path) === '.node') { | ||
| // const moduleExports = this.require(path) | ||
| // const namedExports = new Set(Object.keys(moduleExports)) | ||
| // this.cjsNamedExportsMap.set(path, namedExports) | ||
| // return namedExports | ||
| // } | ||
| // const code = this.fs.readFile(path) | ||
| // const { exports, reexports } = parseCjs(code, path) | ||
| // const namedExports = new Set(exports) | ||
| // this.cjsNamedExportsMap.set(path, namedExports) | ||
| // for (const reexport of reexports) { | ||
| // if (isNodeBuiltin(reexport)) { | ||
| // const exports = this.require(reexport) | ||
| // if (exports !== null && typeof exports === 'object') { | ||
| // for (const e of Object.keys(exports)) { | ||
| // namedExports.add(e) | ||
| // } | ||
| // } | ||
| // } | ||
| // else { | ||
| // const require = this.createRequire(path) | ||
| // const resolved = require.resolve(reexport) | ||
| // const exports = this._getNamedCjsExports(resolved) | ||
| // for (const e of exports) { | ||
| // namedExports.add(e) | ||
| // } | ||
| // } | ||
| // } | ||
| // return namedExports | ||
| // } | ||
| require(identifier) { | ||
| if (extname(identifier) === ".node" || isBuiltin(identifier)) return this.requireCoreModule(identifier); | ||
| const module = new this.Module(identifier); | ||
| return this.loadCommonJSModule(module, identifier); | ||
| } | ||
| requireCoreModule(identifier) { | ||
| const normalized = identifier.replace(/^node:/, ""); | ||
| if (this.builtinCache[normalized]) return this.builtinCache[normalized].exports; | ||
| const moduleExports = _require(identifier); | ||
| if (identifier === "node:module" || identifier === "module") { | ||
| const module = new this.Module("/module.js"); | ||
| module.exports = this.Module; | ||
| this.builtinCache[normalized] = module; | ||
| return module.exports; | ||
| } | ||
| this.builtinCache[normalized] = _require.cache[normalized]; | ||
| // TODO: should we wrap module to rethrow context errors? | ||
| return moduleExports; | ||
| } | ||
| } | ||
| // The "module-sync" exports condition (added in Node 22.12/20.19 when | ||
| // require(esm) was unflagged) can resolve to ESM files that our CJS | ||
| // vm.Script executor cannot handle. We exclude it by passing explicit | ||
| // CJS conditions to require.resolve (Node 22.12+). | ||
| // Must be a Set because Node's internal resolver calls conditions.has(). | ||
| // User-specified --conditions/-C flags are respected, except module-sync. | ||
| function parseCjsConditions(execArgv, nodeOptions) { | ||
| const conditions = [ | ||
| "node", | ||
| "require", | ||
| "node-addons" | ||
| ]; | ||
| const args = [...execArgv, ...nodeOptions?.split(/\s+/) ?? []]; | ||
| for (let i = 0; i < args.length; i++) { | ||
| const arg = args[i]; | ||
| const eqMatch = arg.match(/^(?:--conditions|-C)=(.+)$/); | ||
| if (eqMatch) conditions.push(eqMatch[1]); | ||
| else if ((arg === "--conditions" || arg === "-C") && i + 1 < args.length) conditions.push(args[++i]); | ||
| } | ||
| return new Set(conditions.filter((c) => c !== "module-sync")); | ||
| } | ||
| const dataURIRegex = /^data:(?<mime>text\/javascript|application\/json|application\/wasm)(?:;(?<encoding>charset=utf-8|base64))?,(?<code>.*)$/; | ||
| class EsmExecutor { | ||
| moduleCache = /* @__PURE__ */ new Map(); | ||
| esmLinkMap = /* @__PURE__ */ new WeakMap(); | ||
| context; | ||
| #httpIp = IPnumber("127.0.0.0"); | ||
| constructor(executor, options) { | ||
| this.executor = executor; | ||
| this.context = options.context; | ||
| } | ||
| async evaluateModule(m) { | ||
| if (m.status === "unlinked") this.esmLinkMap.set(m, m.link((identifier, referencer) => this.executor.resolveModule(identifier, referencer.identifier))); | ||
| await this.esmLinkMap.get(m); | ||
| if (m.status === "linked") await m.evaluate(); | ||
| return m; | ||
| } | ||
| async createEsModule(fileURL, getCode) { | ||
| const cached = this.moduleCache.get(fileURL); | ||
| if (cached) return cached; | ||
| const promise = this.loadEsModule(fileURL, getCode); | ||
| this.moduleCache.set(fileURL, promise); | ||
| return promise; | ||
| } | ||
| async loadEsModule(fileURL, getCode) { | ||
| const code = await getCode(); | ||
| // TODO: should not be allowed in strict mode, implement in #2854 | ||
| if (fileURL.endsWith(".json")) { | ||
| const m = new SyntheticModule(["default"], function() { | ||
| const result = JSON.parse(code); | ||
| this.setExport("default", result); | ||
| }); | ||
| this.moduleCache.set(fileURL, m); | ||
| return m; | ||
| } | ||
| const m = new SourceTextModule(code, { | ||
| identifier: fileURL, | ||
| context: this.context, | ||
| importModuleDynamically: this.executor.importModuleDynamically, | ||
| initializeImportMeta: (meta, mod) => { | ||
| meta.url = mod.identifier; | ||
| if (mod.identifier.startsWith("file:")) { | ||
| const filename = fileURLToPath(mod.identifier); | ||
| meta.filename = filename; | ||
| meta.dirname = dirname$1(filename); | ||
| } | ||
| meta.resolve = (specifier, importer) => { | ||
| return this.executor.resolve(specifier, importer != null ? importer.toString() : mod.identifier); | ||
| }; | ||
| } | ||
| }); | ||
| this.moduleCache.set(fileURL, m); | ||
| return m; | ||
| } | ||
| async createWebAssemblyModule(fileUrl, getCode) { | ||
| const cached = this.moduleCache.get(fileUrl); | ||
| if (cached) return cached; | ||
| const m = this.loadWebAssemblyModule(getCode(), fileUrl); | ||
| this.moduleCache.set(fileUrl, m); | ||
| return m; | ||
| } | ||
| async createNetworkModule(fileUrl) { | ||
| // https://nodejs.org/api/esm.html#https-and-http-imports | ||
| if (fileUrl.startsWith("http:")) { | ||
| const url = new URL(fileUrl); | ||
| if (url.hostname !== "localhost" && url.hostname !== "::1" && (IPnumber(url.hostname) & IPmask(8)) !== this.#httpIp) throw new Error( | ||
| // we don't know the importer, so it's undefined (the same happens in --pool=threads) | ||
| `import of '${fileUrl}' by undefined is not supported: http can only be used to load local resources (use https instead).` | ||
| ); | ||
| } | ||
| return this.createEsModule(fileUrl, () => fetch(fileUrl).then((r) => r.text())); | ||
| } | ||
| async loadWebAssemblyModule(source, identifier) { | ||
| const cached = this.moduleCache.get(identifier); | ||
| if (cached) return cached; | ||
| const wasmModule = await WebAssembly.compile(source); | ||
| const exports$1 = WebAssembly.Module.exports(wasmModule); | ||
| const imports = WebAssembly.Module.imports(wasmModule); | ||
| const moduleLookup = {}; | ||
| for (const { module } of imports) if (moduleLookup[module] === void 0) moduleLookup[module] = await this.executor.resolveModule(module, identifier); | ||
| const evaluateModule = (module) => this.evaluateModule(module); | ||
| return new SyntheticModule(exports$1.map(({ name }) => name), async function() { | ||
| const importsObject = {}; | ||
| for (const { module, name } of imports) { | ||
| if (!importsObject[module]) importsObject[module] = {}; | ||
| await evaluateModule(moduleLookup[module]); | ||
| importsObject[module][name] = moduleLookup[module].namespace[name]; | ||
| } | ||
| const wasmInstance = new WebAssembly.Instance(wasmModule, importsObject); | ||
| for (const { name } of exports$1) this.setExport(name, wasmInstance.exports[name]); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| } | ||
| cacheModule(identifier, module) { | ||
| this.moduleCache.set(identifier, module); | ||
| } | ||
| resolveCachedModule(identifier) { | ||
| return this.moduleCache.get(identifier); | ||
| } | ||
| async createDataModule(identifier) { | ||
| const cached = this.moduleCache.get(identifier); | ||
| if (cached) return cached; | ||
| const match = identifier.match(dataURIRegex); | ||
| if (!match || !match.groups) throw new Error("Invalid data URI"); | ||
| const mime = match.groups.mime; | ||
| const encoding = match.groups.encoding; | ||
| if (mime === "application/wasm") { | ||
| if (!encoding) throw new Error("Missing data URI encoding"); | ||
| if (encoding !== "base64") throw new Error(`Invalid data URI encoding: ${encoding}`); | ||
| const module = this.loadWebAssemblyModule(Buffer.from(match.groups.code, "base64"), identifier); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| let code = match.groups.code; | ||
| if (!encoding || encoding === "charset=utf-8") code = decodeURIComponent(code); | ||
| else if (encoding === "base64") code = Buffer.from(code, "base64").toString(); | ||
| else throw new Error(`Invalid data URI encoding: ${encoding}`); | ||
| if (mime === "application/json") { | ||
| const module = new SyntheticModule(["default"], function() { | ||
| const obj = JSON.parse(code); | ||
| this.setExport("default", obj); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| return this.createEsModule(identifier, () => code); | ||
| } | ||
| } | ||
| function IPnumber(address) { | ||
| const ip = address.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/); | ||
| if (ip) return (+ip[1] << 24) + (+ip[2] << 16) + (+ip[3] << 8) + +ip[4]; | ||
| throw new Error(`Expected IP address, received ${address}`); | ||
| } | ||
| function IPmask(maskSize) { | ||
| return -1 << 32 - maskSize; | ||
| } | ||
| const CLIENT_ID = "/@vite/client"; | ||
| const CLIENT_FILE = pathToFileURL(CLIENT_ID).href; | ||
| class ViteExecutor { | ||
| esm; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this.esm = options.esmExecutor; | ||
| } | ||
| resolve = (identifier) => { | ||
| if (identifier === CLIENT_ID) return identifier; | ||
| }; | ||
| get workerState() { | ||
| return this.options.context.__vitest_worker__; | ||
| } | ||
| async createViteModule(fileUrl) { | ||
| if (fileUrl === CLIENT_FILE || fileUrl === CLIENT_ID) return this.createViteClientModule(); | ||
| const cached = this.esm.resolveCachedModule(fileUrl); | ||
| if (cached) return cached; | ||
| return this.esm.createEsModule(fileUrl, async () => { | ||
| try { | ||
| const result = await this.options.transform(fileUrl); | ||
| if (result.code) return result.code; | ||
| } catch (cause) { | ||
| // rethrow vite error if it cannot load the module because it's not resolved | ||
| if (typeof cause === "object" && cause.code === "ERR_LOAD_URL" || typeof cause?.message === "string" && cause.message.includes("Failed to load url")) { | ||
| const error = new Error(`Cannot find module '${fileUrl}'`, { cause }); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| } | ||
| throw new Error(`[vitest] Failed to transform ${fileUrl}. Does the file exist?`); | ||
| }); | ||
| } | ||
| createViteClientModule() { | ||
| const identifier = CLIENT_ID; | ||
| const cached = this.esm.resolveCachedModule(identifier); | ||
| if (cached) return cached; | ||
| const stub = this.options.viteClientModule; | ||
| const moduleKeys = Object.keys(stub); | ||
| const module = new SyntheticModule(moduleKeys, function() { | ||
| moduleKeys.forEach((key) => { | ||
| this.setExport(key, stub[key]); | ||
| }); | ||
| }, { | ||
| context: this.options.context, | ||
| identifier | ||
| }); | ||
| this.esm.cacheModule(identifier, module); | ||
| return module; | ||
| } | ||
| canResolve = (fileUrl) => { | ||
| if (fileUrl === CLIENT_FILE) return true; | ||
| const config = this.workerState.config.deps?.web || {}; | ||
| const [modulePath] = fileUrl.split("?"); | ||
| if (config.transformCss && CSS_LANGS_RE.test(modulePath)) return true; | ||
| if (config.transformAssets && KNOWN_ASSET_RE.test(modulePath)) return true; | ||
| if (toArray(config.transformGlobPattern).some((pattern) => pattern.test(modulePath))) return true; | ||
| return false; | ||
| }; | ||
| } | ||
| const { existsSync } = fs; | ||
| // always defined when we use vm pool | ||
| const nativeResolve = import.meta.resolve; | ||
| // TODO: improve Node.js strict mode support in #2854 | ||
| class ExternalModulesExecutor { | ||
| cjs; | ||
| esm; | ||
| vite; | ||
| context; | ||
| fs; | ||
| resolvers = []; | ||
| #networkSupported = null; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this.context = options.context; | ||
| this.fs = options.fileMap; | ||
| this.esm = new EsmExecutor(this, { context: this.context }); | ||
| this.cjs = new CommonjsExecutor({ | ||
| context: this.context, | ||
| importModuleDynamically: this.importModuleDynamically, | ||
| fileMap: options.fileMap, | ||
| interopDefault: options.interopDefault | ||
| }); | ||
| this.vite = new ViteExecutor({ | ||
| esmExecutor: this.esm, | ||
| context: this.context, | ||
| transform: options.transform, | ||
| viteClientModule: options.viteClientModule | ||
| }); | ||
| this.resolvers = [this.vite.resolve]; | ||
| } | ||
| async import(identifier) { | ||
| const module = await this.createModule(identifier); | ||
| await this.esm.evaluateModule(module); | ||
| return module.namespace; | ||
| } | ||
| require(identifier) { | ||
| return this.cjs.require(identifier); | ||
| } | ||
| createRequire(identifier) { | ||
| return this.cjs.createRequire(identifier); | ||
| } | ||
| // dynamic import can be used in both ESM and CJS, so we have it in the executor | ||
| importModuleDynamically = async (specifier, referencer) => { | ||
| const module = await this.resolveModule(specifier, referencer.identifier); | ||
| return await this.esm.evaluateModule(module); | ||
| }; | ||
| resolveModule = async (specifier, referencer) => { | ||
| let identifier = this.resolve(specifier, referencer); | ||
| if (identifier instanceof Promise) identifier = await identifier; | ||
| return await this.createModule(identifier); | ||
| }; | ||
| resolve(specifier, parent) { | ||
| for (const resolver of this.resolvers) { | ||
| const id = resolver(specifier, parent); | ||
| if (id) return id; | ||
| } | ||
| // import.meta.resolve can be asynchronous in older +18 Node versions | ||
| return nativeResolve(specifier, parent); | ||
| } | ||
| getModuleInformation(identifier) { | ||
| if (identifier.startsWith("data:")) return { | ||
| type: "data", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| const extension = extname(identifier); | ||
| if (extension === ".node" || isBuiltin(identifier)) return { | ||
| type: "builtin", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| if (this.isNetworkSupported && (identifier.startsWith("http:") || identifier.startsWith("https:"))) return { | ||
| type: "network", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| const isFileUrl = identifier.startsWith("file://"); | ||
| const pathUrl = isFileUrl ? fileURLToPath(identifier.split("?")[0]) : identifier; | ||
| const fileUrl = isFileUrl ? identifier : pathToFileURL(pathUrl).toString(); | ||
| let type; | ||
| if (this.vite.canResolve(fileUrl)) type = "vite"; | ||
| else if (extension === ".mjs") type = "module"; | ||
| else if (extension === ".cjs") type = "commonjs"; | ||
| else if (extension === ".wasm") | ||
| // still experimental on NodeJS --experimental-wasm-modules | ||
| // cf. ESM_FILE_FORMAT(url) in https://nodejs.org/docs/latest-v20.x/api/esm.html#resolution-algorithm | ||
| type = "wasm"; | ||
| else type = findNearestPackageData(normalize(pathUrl)).type === "module" ? "module" : "commonjs"; | ||
| return { | ||
| type, | ||
| path: pathUrl, | ||
| url: fileUrl | ||
| }; | ||
| } | ||
| createModule(identifier) { | ||
| const { type, url, path } = this.getModuleInformation(identifier); | ||
| // create ERR_MODULE_NOT_FOUND on our own since latest NodeJS's import.meta.resolve doesn't throw on non-existing namespace or path | ||
| // https://github.com/nodejs/node/pull/49038 | ||
| if ((type === "module" || type === "commonjs" || type === "wasm") && !existsSync(path)) { | ||
| const error = /* @__PURE__ */ new Error(`Cannot find ${isBareImport(path) ? "package" : "module"} '${path}'`); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| switch (type) { | ||
| case "data": return this.esm.createDataModule(identifier); | ||
| case "builtin": return this.cjs.getCoreSyntheticModule(identifier); | ||
| case "vite": return this.vite.createViteModule(url); | ||
| case "wasm": return this.esm.createWebAssemblyModule(url, () => this.fs.readBuffer(path)); | ||
| case "module": return this.esm.createEsModule(url, () => this.fs.readFileAsync(path)); | ||
| case "commonjs": return this.cjs.getCjsSyntheticModule(path, identifier); | ||
| case "network": return this.esm.createNetworkModule(url); | ||
| default: return type; | ||
| } | ||
| } | ||
| get isNetworkSupported() { | ||
| if (this.#networkSupported == null) if (process.execArgv.includes("--experimental-network-imports")) this.#networkSupported = true; | ||
| else if (process.env.NODE_OPTIONS?.includes("--experimental-network-imports")) this.#networkSupported = true; | ||
| else this.#networkSupported = false; | ||
| return this.#networkSupported; | ||
| } | ||
| } | ||
| const { promises, readFileSync } = fs; | ||
| class FileMap { | ||
| fsCache = /* @__PURE__ */ new Map(); | ||
| fsBufferCache = /* @__PURE__ */ new Map(); | ||
| async readFileAsync(path) { | ||
| const cached = this.fsCache.get(path); | ||
| if (cached != null) return cached; | ||
| const source = await promises.readFile(path, "utf-8"); | ||
| this.fsCache.set(path, source); | ||
| return source; | ||
| } | ||
| readFile(path) { | ||
| const cached = this.fsCache.get(path); | ||
| if (cached != null) return cached; | ||
| const source = readFileSync(path, "utf-8"); | ||
| this.fsCache.set(path, source); | ||
| return source; | ||
| } | ||
| readBuffer(path) { | ||
| const cached = this.fsBufferCache.get(path); | ||
| if (cached != null) return cached; | ||
| const buffer = readFileSync(path); | ||
| this.fsBufferCache.set(path, buffer); | ||
| return buffer; | ||
| } | ||
| } | ||
| const entryFile = pathToFileURL(resolve(distDir, "workers/runVmTests.js")).href; | ||
| const fileMap = new FileMap(); | ||
| const packageCache = /* @__PURE__ */ new Map(); | ||
| async function runVmTests(method, state, traces) { | ||
| const { ctx, rpc } = state; | ||
| const beforeEnvironmentTime = performance.now(); | ||
| const { environment } = await loadEnvironment(ctx.environment.name, ctx.config.root, rpc, traces, true); | ||
| state.environment = environment; | ||
| if (!environment.setupVM) { | ||
| const envName = ctx.environment.name; | ||
| const packageId = envName[0] === "." ? envName : `vitest-environment-${envName}`; | ||
| throw new TypeError(`Environment "${ctx.environment.name}" is not a valid environment. Path "${packageId}" doesn't support vm environment because it doesn't provide "setupVM" method.`); | ||
| } | ||
| const vm = await traces.$("vitest.runtime.environment.setup", { attributes: { | ||
| "vitest.environment": environment.name, | ||
| "vitest.environment.vite_environment": environment.viteEnvironment || environment.name | ||
| } }, () => environment.setupVM(ctx.environment.options || ctx.config.environmentOptions || {})); | ||
| state.durations.environment = performance.now() - beforeEnvironmentTime; | ||
| process.env.VITEST_VM_POOL = "1"; | ||
| if (!vm.getVmContext) throw new TypeError(`Environment ${environment.name} doesn't provide "getVmContext" method. It should return a context created by "vm.createContext" method.`); | ||
| const context = vm.getVmContext(); | ||
| if (!isContext(context)) throw new TypeError(`Environment ${environment.name} doesn't provide a valid context. It should be created by "vm.createContext" method.`); | ||
| provideWorkerState(context, state); | ||
| // this is unfortunately needed for our own dependencies | ||
| // we need to find a way to not rely on this by default | ||
| // because browser doesn't provide these globals | ||
| context.process = process; | ||
| context.global = context; | ||
| context.console = state.config.disableConsoleIntercept ? console : createCustomConsole(state); | ||
| // TODO: don't hardcode setImmediate in fake timers defaults | ||
| context.setImmediate = setImmediate; | ||
| context.clearImmediate = clearImmediate; | ||
| const stubs = getDefaultRequestStubs(context); | ||
| const externalModulesExecutor = new ExternalModulesExecutor({ | ||
| context, | ||
| fileMap, | ||
| packageCache, | ||
| transform: rpc.transform, | ||
| viteClientModule: stubs["/@vite/client"] | ||
| }); | ||
| process.exit = (code = process.exitCode || 0) => { | ||
| throw new Error(`process.exit unexpectedly called with "${code}"`); | ||
| }; | ||
| listenForErrors(() => state); | ||
| const moduleRunner = startVitestModuleRunner({ | ||
| context, | ||
| evaluatedModules: state.evaluatedModules, | ||
| state, | ||
| externalModulesExecutor, | ||
| createImportMeta: createNodeImportMeta, | ||
| traces | ||
| }); | ||
| emitModuleRunner(moduleRunner); | ||
| Object.defineProperty(context, VITEST_VM_CONTEXT_SYMBOL, { | ||
| value: { | ||
| context, | ||
| externalModulesExecutor | ||
| }, | ||
| configurable: true, | ||
| enumerable: false, | ||
| writable: false | ||
| }); | ||
| context.__vitest_mocker__ = moduleRunner.mocker; | ||
| if (ctx.config.serializedDefines) try { | ||
| runInContext(ctx.config.serializedDefines, context, { filename: "virtual:load-defines.js" }); | ||
| } catch (error) { | ||
| throw new Error(`Failed to load custom "defines": ${error.message}`); | ||
| } | ||
| await moduleRunner.mocker.initializeSpyModule(); | ||
| const { run } = await moduleRunner.import(entryFile); | ||
| try { | ||
| await run(method, ctx.files, ctx.config, moduleRunner, traces); | ||
| } finally { | ||
| await traces.$("vitest.runtime.environment.teardown", () => vm.teardown?.()); | ||
| } | ||
| } | ||
| function setupVmWorker(context) { | ||
| if (context.config.experimental.viteModuleRunner === false) throw new Error(`Pool "${context.pool}" cannot run with "experimental.viteModuleRunner: false". Please, use "threads" or "forks" instead.`); | ||
| } | ||
| export { runVmTests as r, setupVmWorker as s }; |
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 29 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
1879780
0.68%50258
0.66%383
3.23%+ 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
Updated
Updated
Updated
Updated
Updated