vitest 4.0.0-beta.8 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +86 -102
- package/browser/context.d.ts +7 -0
- package/browser/context.js +20 -0
- package/dist/browser.d.ts +26 -9
- package/dist/browser.js +17 -7
- package/dist/chunks/base.CtHM3ryk.js +128 -0
- package/dist/chunks/{benchmark.UW6Ezvxy.js → benchmark.DHKMYAts.js} +2 -2
- package/dist/chunks/{browser.d.DOMmqJQx.d.ts → browser.d.B9iJzZyn.d.ts} +3 -3
- package/dist/chunks/{cac.By1HvRIk.js → cac.B99MQg-w.js} +47 -91
- package/dist/chunks/{cli-api.C-JHgQgp.js → cli-api.PwHwIMss.js} +1544 -310
- package/dist/chunks/{config.d._GBBbReY.d.ts → config.d.u2CUDWwS.d.ts} +6 -19
- package/dist/chunks/{console.B0quX7yH.js → console.CTJL2nuH.js} +4 -6
- package/dist/chunks/{coverage.DarITf6U.js → coverage.FU3w4IrQ.js} +128 -1142
- package/dist/chunks/{creator.KEg6n5IC.js → creator.DucAaYBz.js} +10 -37
- package/dist/chunks/{defaults.CXFFjsi8.js → defaults.BOqNVLsY.js} +0 -1
- package/dist/chunks/environment.d.CrsxCzP1.d.ts +29 -0
- package/dist/chunks/evaluatedModules.Dg1zASAC.js +17 -0
- package/dist/chunks/{global.d.K6uBQHzY.d.ts → global.d.BgJSTpgQ.d.ts} +2 -17
- package/dist/chunks/{globals.lgsmH00r.js → globals.BGT_RUsD.js} +12 -9
- package/dist/chunks/{index.BuwjkI-q.js → index.BdSLhLDZ.js} +3 -3
- package/dist/chunks/{index.DfviD7lX.js → index.CbWINfS7.js} +49 -21
- package/dist/chunks/{index.AzwzFtyi.js → index.CcRZ6fUh.js} +1493 -114
- package/dist/chunks/{index.X0nbfr6-.js → index.Dc3xnDvT.js} +48 -289
- package/dist/chunks/{index.AR8aAkCC.js → index.RwjEGCQ0.js} +7 -8
- package/dist/chunks/init-forks.DSafeltJ.js +54 -0
- package/dist/chunks/init-threads.SUtZ-067.js +17 -0
- package/dist/chunks/init.B2EESLQM.js +213 -0
- package/dist/chunks/{inspector.CvQD-Nie.js → inspector.DLZxSeU3.js} +2 -6
- package/dist/chunks/{moduleRunner.d.CX4DuqOx.d.ts → moduleRunner.d.YtNsMIoJ.d.ts} +12 -14
- package/dist/chunks/{node.BOqcT2jW.js → node.BwAWWjHZ.js} +3 -4
- package/dist/chunks/{plugin.d.CHe6slQs.d.ts → plugin.d.DQU1R5px.d.ts} +1 -1
- package/dist/chunks/{reporters.d.37tJQ2uV.d.ts → reporters.d.BMKt7f6I.d.ts} +1066 -1030
- package/dist/chunks/{index.CsFXYRkW.js → resolveSnapshotEnvironment.DJJKMKxb.js} +18 -24
- package/dist/chunks/{rpc.RpPylpp0.js → rpc.cD77ENhU.js} +13 -14
- package/dist/chunks/{setup-common.hLGRxhC8.js → setup-common.DR1sucx6.js} +8 -8
- package/dist/chunks/{startModuleRunner.C8TW8zTN.js → startModuleRunner.C2tTvmF9.js} +131 -110
- package/dist/chunks/test.C3RPt8JR.js +214 -0
- package/dist/chunks/{utils.C7__0Iv5.js → utils.CG9h5ccR.js} +3 -15
- package/dist/chunks/{vi.BfdOiD4j.js → vi.BZvkKVkM.js} +73 -176
- package/dist/chunks/{vm.BHBje7cC.js → vm.DBeOXrP9.js} +29 -33
- package/dist/chunks/{worker.d.DYlqbejz.d.ts → worker.d.BFk-vvBU.d.ts} +42 -6
- package/dist/cli.js +12 -11
- package/dist/config.cjs +0 -1
- package/dist/config.d.ts +12 -14
- package/dist/config.js +1 -1
- package/dist/coverage.d.ts +8 -7
- package/dist/coverage.js +3 -14
- package/dist/environments.d.ts +3 -6
- package/dist/environments.js +1 -1
- package/dist/index.d.ts +24 -30
- package/dist/index.js +12 -11
- package/dist/module-evaluator.d.ts +6 -4
- package/dist/module-evaluator.js +14 -16
- package/dist/module-runner.js +5 -5
- package/dist/node.d.ts +83 -27
- package/dist/node.js +23 -20
- package/dist/reporters.d.ts +11 -10
- package/dist/reporters.js +12 -11
- package/dist/runners.d.ts +1 -1
- package/dist/runners.js +14 -216
- package/dist/snapshot.js +3 -3
- package/dist/suite.js +4 -3
- package/dist/worker.d.ts +26 -0
- package/dist/worker.js +45 -166
- package/dist/workers/forks.js +41 -35
- package/dist/workers/runVmTests.js +25 -22
- package/dist/workers/threads.js +41 -23
- package/dist/workers/vmForks.js +26 -39
- package/dist/workers/vmThreads.js +26 -29
- package/package.json +48 -35
- package/worker.d.ts +1 -0
- package/browser.d.ts +0 -1
- package/dist/chunks/base.BXI97p6t.js +0 -39
- package/dist/chunks/environment.d.2fYMoz3o.d.ts +0 -66
- package/dist/chunks/moduleTransport.I-bgQy0S.js +0 -19
- package/dist/chunks/resolver.Bx6lE0iq.js +0 -119
- package/dist/chunks/runBaseTests.D6sfuWBM.js +0 -99
- package/dist/chunks/typechecker.DSo_maXz.js +0 -762
- package/dist/chunks/utils.C2YI6McM.js +0 -52
- package/dist/chunks/worker.d.BKu8cnnX.d.ts +0 -8
- package/dist/workers.d.ts +0 -38
- package/dist/workers.js +0 -31
- package/execute.d.ts +0 -1
- package/utils.d.ts +0 -1
- package/workers.d.ts +0 -1
|
@@ -1,36 +1,21 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { g as getWorkerState } from './utils.C7__0Iv5.js';
|
|
1
|
+
import { chai } from '@vitest/expect';
|
|
2
|
+
import { l as loadDiffConfig, b as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.DR1sucx6.js';
|
|
3
|
+
import { r as rpc } from './rpc.cD77ENhU.js';
|
|
4
|
+
import { g as getWorkerState } from './utils.CG9h5ccR.js';
|
|
5
|
+
import { V as VitestTestRunner, N as NodeBenchmarkRunner } from './test.C3RPt8JR.js';
|
|
7
6
|
|
|
8
7
|
function setupChaiConfig(config) {
|
|
9
8
|
Object.assign(chai.config, config);
|
|
10
9
|
}
|
|
11
10
|
|
|
12
|
-
async function resolveSnapshotEnvironment(config, executor) {
|
|
13
|
-
if (!config.snapshotEnvironment) {
|
|
14
|
-
const { VitestNodeSnapshotEnvironment } = await import('./node.BOqcT2jW.js');
|
|
15
|
-
return new VitestNodeSnapshotEnvironment();
|
|
16
|
-
}
|
|
17
|
-
const mod = await executor.import(config.snapshotEnvironment);
|
|
18
|
-
if (typeof mod.default !== "object" || !mod.default) throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`");
|
|
19
|
-
return mod.default;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const runnersFile = resolve(distDir, "runners.js");
|
|
23
11
|
async function getTestRunnerConstructor(config, moduleRunner) {
|
|
24
|
-
if (!config.runner)
|
|
25
|
-
const { VitestTestRunner, NodeBenchmarkRunner } = await moduleRunner.import(join("/@fs/", runnersFile));
|
|
26
|
-
return config.mode === "test" ? VitestTestRunner : NodeBenchmarkRunner;
|
|
27
|
-
}
|
|
12
|
+
if (!config.runner) return config.mode === "test" ? VitestTestRunner : NodeBenchmarkRunner;
|
|
28
13
|
const mod = await moduleRunner.import(config.runner);
|
|
29
14
|
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}`);
|
|
30
15
|
return mod.default;
|
|
31
16
|
}
|
|
32
17
|
async function resolveTestRunner(config, moduleRunner) {
|
|
33
|
-
const
|
|
18
|
+
const testRunner = new (await (getTestRunnerConstructor(config, moduleRunner)))(config);
|
|
34
19
|
if (Object.defineProperty(testRunner, "moduleRunner", {
|
|
35
20
|
value: moduleRunner,
|
|
36
21
|
enumerable: false,
|
|
@@ -76,11 +61,20 @@ async function resolveTestRunner(config, moduleRunner) {
|
|
|
76
61
|
const originalOnAfterRunTask = testRunner.onAfterRunTask;
|
|
77
62
|
return testRunner.onAfterRunTask = async (test) => {
|
|
78
63
|
if (config.bail && test.result?.state === "fail") {
|
|
79
|
-
|
|
80
|
-
if (currentFailures >= config.bail) rpc().onCancel("test-failure"), testRunner.cancel?.("test-failure");
|
|
64
|
+
if (1 + await rpc().getCountOfFailedTests() >= config.bail) rpc().onCancel("test-failure"), testRunner.cancel?.("test-failure");
|
|
81
65
|
}
|
|
82
66
|
await originalOnAfterRunTask?.call(testRunner, test);
|
|
83
67
|
}, testRunner;
|
|
84
68
|
}
|
|
85
69
|
|
|
70
|
+
async function resolveSnapshotEnvironment(config, executor) {
|
|
71
|
+
if (!config.snapshotEnvironment) {
|
|
72
|
+
const { VitestNodeSnapshotEnvironment } = await import('./node.BwAWWjHZ.js');
|
|
73
|
+
return new VitestNodeSnapshotEnvironment();
|
|
74
|
+
}
|
|
75
|
+
const mod = await executor.import(config.snapshotEnvironment);
|
|
76
|
+
if (typeof mod.default !== "object" || !mod.default) throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`");
|
|
77
|
+
return mod.default;
|
|
78
|
+
}
|
|
79
|
+
|
|
86
80
|
export { resolveSnapshotEnvironment as a, resolveTestRunner as r, setupChaiConfig as s };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { getSafeTimers } from '@vitest/utils';
|
|
1
|
+
import { getSafeTimers } from '@vitest/utils/timers';
|
|
2
2
|
import { c as createBirpc } from './index.Bgo3tNWt.js';
|
|
3
|
-
import { g as getWorkerState } from './utils.
|
|
3
|
+
import { g as getWorkerState } from './utils.CG9h5ccR.js';
|
|
4
4
|
|
|
5
5
|
const { get } = Reflect;
|
|
6
6
|
function withSafeTimers(fn) {
|
|
@@ -9,8 +9,7 @@ function withSafeTimers(fn) {
|
|
|
9
9
|
if (globalThis.setTimeout = setTimeout, globalThis.clearTimeout = clearTimeout, setImmediate) globalThis.setImmediate = setImmediate;
|
|
10
10
|
if (clearImmediate) globalThis.clearImmediate = clearImmediate;
|
|
11
11
|
if (globalThis.process && nextTick) globalThis.process.nextTick = nextTick;
|
|
12
|
-
|
|
13
|
-
return result;
|
|
12
|
+
return fn();
|
|
14
13
|
} finally {
|
|
15
14
|
if (globalThis.setTimeout = currentSetTimeout, globalThis.clearTimeout = currentClearTimeout, globalThis.setImmediate = currentSetImmediate, globalThis.clearImmediate = currentClearImmediate, globalThis.process && nextTick) nextTick(() => {
|
|
16
15
|
globalThis.process.nextTick = currentNextTick;
|
|
@@ -27,17 +26,17 @@ function createRuntimeRpc(options) {
|
|
|
27
26
|
let setCancel = (_reason) => {};
|
|
28
27
|
const onCancel = new Promise((resolve) => {
|
|
29
28
|
setCancel = resolve;
|
|
30
|
-
})
|
|
31
|
-
eventNames: [
|
|
32
|
-
"onUserConsoleLog",
|
|
33
|
-
"onCollected",
|
|
34
|
-
"onCancel"
|
|
35
|
-
],
|
|
36
|
-
timeout: -1,
|
|
37
|
-
...options
|
|
38
|
-
}));
|
|
29
|
+
});
|
|
39
30
|
return {
|
|
40
|
-
rpc,
|
|
31
|
+
rpc: createSafeRpc(createBirpc({ onCancel: setCancel }, {
|
|
32
|
+
eventNames: [
|
|
33
|
+
"onUserConsoleLog",
|
|
34
|
+
"onCollected",
|
|
35
|
+
"onCancel"
|
|
36
|
+
],
|
|
37
|
+
timeout: -1,
|
|
38
|
+
...options
|
|
39
|
+
})),
|
|
41
40
|
onCancel
|
|
42
41
|
};
|
|
43
42
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { r as resolveCoverageProviderModule } from './coverage.D_JHT54q.js';
|
|
2
2
|
import { addSerializer } from '@vitest/snapshot';
|
|
3
|
-
import { setSafeTimers } from '@vitest/utils';
|
|
4
|
-
import { g as getWorkerState } from './utils.
|
|
3
|
+
import { setSafeTimers } from '@vitest/utils/timers';
|
|
4
|
+
import { g as getWorkerState } from './utils.CG9h5ccR.js';
|
|
5
5
|
|
|
6
6
|
async function startCoverageInsideWorker(options, loader, runtimeOptions) {
|
|
7
7
|
const coverageModule = await resolveCoverageProviderModule(options, loader);
|
|
@@ -18,10 +18,10 @@ async function stopCoverageInsideWorker(options, loader, runtimeOptions) {
|
|
|
18
18
|
|
|
19
19
|
let globalSetup = false;
|
|
20
20
|
async function setupCommonEnv(config) {
|
|
21
|
-
if (setupDefines(config
|
|
21
|
+
if (setupDefines(config), setupEnv(config.env), !globalSetup && (globalSetup = true, setSafeTimers(), config.globals)) (await import('./globals.BGT_RUsD.js')).registerApiGlobally();
|
|
22
22
|
}
|
|
23
|
-
function setupDefines(
|
|
24
|
-
for (const key in defines) globalThis[key] = defines[key];
|
|
23
|
+
function setupDefines(config) {
|
|
24
|
+
for (const key in config.defines) globalThis[key] = config.defines[key];
|
|
25
25
|
}
|
|
26
26
|
function setupEnv(env) {
|
|
27
27
|
const state = getWorkerState(), { PROD, DEV,...restEnvs } = env;
|
|
@@ -35,14 +35,14 @@ async function loadDiffConfig(config, moduleRunner) {
|
|
|
35
35
|
throw new Error(`invalid diff config file ${config.diff}. Must have a default export with config object`);
|
|
36
36
|
}
|
|
37
37
|
async function loadSnapshotSerializers(config, moduleRunner) {
|
|
38
|
-
const files = config.snapshotSerializers
|
|
38
|
+
const files = config.snapshotSerializers;
|
|
39
|
+
(await Promise.all(files.map(async (file) => {
|
|
39
40
|
const mo = await moduleRunner.import(file);
|
|
40
41
|
if (!mo || typeof mo.default !== "object" || mo.default === null) throw new Error(`invalid snapshot serializer file ${file}. Must export a default object`);
|
|
41
42
|
const config = mo.default;
|
|
42
43
|
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.`);
|
|
43
44
|
return config;
|
|
44
|
-
}));
|
|
45
|
-
snapshotSerializers.forEach((serializer) => addSerializer(serializer));
|
|
45
|
+
}))).forEach((serializer) => addSerializer(serializer));
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export { stopCoverageInsideWorker as a, loadSnapshotSerializers as b, setupCommonEnv as c, loadDiffConfig as l, startCoverageInsideWorker as s, takeCoverageInsideWorker as t };
|
|
@@ -1,68 +1,15 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import { builtinModules, isBuiltin } from 'node:module';
|
|
3
|
-
import {
|
|
2
|
+
import nodeModule, { builtinModules, isBuiltin } from 'node:module';
|
|
3
|
+
import { isBareImport } from '@vitest/utils/helpers';
|
|
4
4
|
import { pathToFileURL } from 'node:url';
|
|
5
5
|
import { normalize as normalize$1, join as join$1 } from 'pathe';
|
|
6
6
|
import { distDir } from '../path.js';
|
|
7
|
-
import {
|
|
7
|
+
import { serializeValue } from '@vitest/utils/serialize';
|
|
8
8
|
import { VitestModuleEvaluator, unwrapId } from '../module-evaluator.js';
|
|
9
9
|
import { resolve as resolve$1, isAbsolute as isAbsolute$1 } from 'node:path';
|
|
10
10
|
import vm from 'node:vm';
|
|
11
11
|
import { MockerRegistry, mockObject, RedirectedModule, AutomockedModule } from '@vitest/mocker';
|
|
12
|
-
import
|
|
13
|
-
import { V as VitestTransport } from './moduleTransport.I-bgQy0S.js';
|
|
14
|
-
|
|
15
|
-
const bareVitestRegexp = /^@?vitest(?:\/|$)/, normalizedDistDir = normalize$1(distDir), relativeIds = {}, externalizeMap = /* @__PURE__ */ new Map();
|
|
16
|
-
// all Vitest imports always need to be externalized
|
|
17
|
-
function getCachedVitestImport(id, state) {
|
|
18
|
-
if (id.startsWith("/@fs/") || id.startsWith("\\@fs\\")) id = id.slice(process.platform === "win32" ? 5 : 4);
|
|
19
|
-
if (externalizeMap.has(id)) return {
|
|
20
|
-
externalize: externalizeMap.get(id),
|
|
21
|
-
type: "module"
|
|
22
|
-
};
|
|
23
|
-
// always externalize Vitest because we import from there before running tests
|
|
24
|
-
// so we already have it cached by Node.js
|
|
25
|
-
const root = state().config.root, relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length));
|
|
26
|
-
if (id.includes(distDir) || id.includes(normalizedDistDir)) {
|
|
27
|
-
const externalize = id.startsWith("file://") ? id : pathToFileURL(id).toString();
|
|
28
|
-
return externalizeMap.set(id, externalize), {
|
|
29
|
-
externalize,
|
|
30
|
-
type: "module"
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
if (relativeRoot && relativeRoot !== "/" && id.startsWith(relativeRoot)) {
|
|
34
|
-
const path = join$1(root, id), externalize = pathToFileURL(path).toString();
|
|
35
|
-
return externalizeMap.set(id, externalize), {
|
|
36
|
-
externalize,
|
|
37
|
-
type: "module"
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
return bareVitestRegexp.test(id) ? (externalizeMap.set(id, id), {
|
|
41
|
-
externalize: id,
|
|
42
|
-
type: "module"
|
|
43
|
-
}) : null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const dispose = [];
|
|
47
|
-
function listenForErrors(state) {
|
|
48
|
-
dispose.forEach((fn) => fn()), dispose.length = 0;
|
|
49
|
-
function catchError(err, type, event) {
|
|
50
|
-
const worker = state(), listeners = process.listeners(event);
|
|
51
|
-
// if there is another listener, assume that it's handled by user code
|
|
52
|
-
// one is Vitest's own listener
|
|
53
|
-
if (listeners.length > 1) return;
|
|
54
|
-
const error = processError(err);
|
|
55
|
-
if (typeof error === "object" && error != null) {
|
|
56
|
-
if (error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0, worker.filepath) error.VITEST_TEST_PATH = worker.filepath;
|
|
57
|
-
error.VITEST_AFTER_ENV_TEARDOWN = worker.environmentTeardownRun;
|
|
58
|
-
}
|
|
59
|
-
state().rpc.onUnhandledError(error, type);
|
|
60
|
-
}
|
|
61
|
-
const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException"), unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection");
|
|
62
|
-
process.on("uncaughtException", uncaughtException), process.on("unhandledRejection", unhandledRejection), dispose.push(() => {
|
|
63
|
-
process.off("uncaughtException", uncaughtException), process.off("unhandledRejection", unhandledRejection);
|
|
64
|
-
});
|
|
65
|
-
}
|
|
12
|
+
import * as viteModuleRunner from 'vite/module-runner';
|
|
66
13
|
|
|
67
14
|
const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
|
|
68
15
|
function normalizeWindowsPath(input = "") {
|
|
@@ -81,8 +28,8 @@ const _UNC_REGEX = /^[/\\]{2}/, _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\
|
|
|
81
28
|
for (const seg of segments) {
|
|
82
29
|
if (!seg) continue;
|
|
83
30
|
if (path.length > 0) {
|
|
84
|
-
const pathTrailing = path[path.length - 1] === "/", segLeading = seg[0] === "/"
|
|
85
|
-
if (
|
|
31
|
+
const pathTrailing = path[path.length - 1] === "/", segLeading = seg[0] === "/";
|
|
32
|
+
if (pathTrailing && segLeading) path += seg.slice(1);
|
|
86
33
|
else path += pathTrailing || segLeading ? seg : `/${seg}`;
|
|
87
34
|
} else path += seg;
|
|
88
35
|
}
|
|
@@ -167,17 +114,14 @@ function findMockRedirect(root, mockPath, external) {
|
|
|
167
114
|
const baseOriginal = basename(path);
|
|
168
115
|
function findFile(mockFolder, baseOriginal) {
|
|
169
116
|
const files = readdirSync(mockFolder);
|
|
170
|
-
for (const file of files) {
|
|
171
|
-
const
|
|
172
|
-
if
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const indexFile = findFile(path, "index");
|
|
179
|
-
if (indexFile) return indexFile;
|
|
180
|
-
}
|
|
117
|
+
for (const file of files) if (basename(file, extname(file)) === baseOriginal) {
|
|
118
|
+
const path = resolve(mockFolder, file);
|
|
119
|
+
// if the same name, return the file
|
|
120
|
+
if (statSync(path).isFile()) return path;
|
|
121
|
+
{
|
|
122
|
+
// find folder/index.{js,ts}
|
|
123
|
+
const indexFile = findFile(path, "index");
|
|
124
|
+
if (indexFile) return indexFile;
|
|
181
125
|
}
|
|
182
126
|
}
|
|
183
127
|
return null;
|
|
@@ -188,7 +132,7 @@ function findMockRedirect(root, mockPath, external) {
|
|
|
188
132
|
return existsSync(fullPath) ? fullPath : null;
|
|
189
133
|
}
|
|
190
134
|
const builtins = new Set([
|
|
191
|
-
...builtinModules,
|
|
135
|
+
...nodeModule.builtinModules,
|
|
192
136
|
"assert/strict",
|
|
193
137
|
"diagnostics_channel",
|
|
194
138
|
"dns/promises",
|
|
@@ -209,7 +153,7 @@ const builtins = new Set([
|
|
|
209
153
|
"node:test/reporters"
|
|
210
154
|
]), NODE_BUILTIN_NAMESPACE = "node:";
|
|
211
155
|
function isNodeBuiltin(id) {
|
|
212
|
-
return prefixedBuiltins$1.has(id) ? true : builtins.has(id.startsWith(NODE_BUILTIN_NAMESPACE) ? id.slice(5) : id);
|
|
156
|
+
return nodeModule.isBuiltin ? nodeModule.isBuiltin(id) : prefixedBuiltins$1.has(id) ? true : builtins.has(id.startsWith(NODE_BUILTIN_NAMESPACE) ? id.slice(5) : id);
|
|
213
157
|
}
|
|
214
158
|
|
|
215
159
|
const spyModulePath = resolve$1(distDir, "spy.js");
|
|
@@ -233,6 +177,7 @@ class VitestMocker {
|
|
|
233
177
|
Array,
|
|
234
178
|
Map
|
|
235
179
|
};
|
|
180
|
+
if (options.spyModule) this.spyModule = options.spyModule;
|
|
236
181
|
const Symbol = this.primitives.Symbol;
|
|
237
182
|
this.filterPublicKeys = [
|
|
238
183
|
"__esModule",
|
|
@@ -330,16 +275,16 @@ class VitestMocker {
|
|
|
330
275
|
if (prop === "then") {
|
|
331
276
|
if (target instanceof Promise) return target.then.bind(target);
|
|
332
277
|
} else if (!(prop in target)) {
|
|
333
|
-
if (this.filterPublicKeys.includes(prop)) return
|
|
278
|
+
if (this.filterPublicKeys.includes(prop)) return;
|
|
334
279
|
throw this.createError(`[vitest] No "${String(prop)}" export is defined on the "${mock.raw}" mock. Did you forget to return it from "vi.mock"?
|
|
335
280
|
If you need to partially mock a module, you can use "importOriginal" helper inside:
|
|
336
|
-
`,
|
|
281
|
+
`, `vi.mock(import("${mock.raw}"), async (importOriginal) => {
|
|
337
282
|
const actual = await importOriginal()
|
|
338
283
|
return {
|
|
339
284
|
...actual,
|
|
340
285
|
// your mocked methods
|
|
341
286
|
}
|
|
342
|
-
})`)
|
|
287
|
+
})`);
|
|
343
288
|
}
|
|
344
289
|
return val;
|
|
345
290
|
} });
|
|
@@ -354,8 +299,7 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
|
|
|
354
299
|
return `mock:${dep}`;
|
|
355
300
|
}
|
|
356
301
|
getDependencyMock(id) {
|
|
357
|
-
|
|
358
|
-
return registry.getById(fixLeadingSlashes(id));
|
|
302
|
+
return this.getMockerRegistry().getById(fixLeadingSlashes(id));
|
|
359
303
|
}
|
|
360
304
|
findMockRedirect(mockPath, external) {
|
|
361
305
|
return findMockRedirect(this.root, mockPath, external);
|
|
@@ -370,8 +314,7 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
|
|
|
370
314
|
}, object, mockExports);
|
|
371
315
|
}
|
|
372
316
|
unmockPath(id) {
|
|
373
|
-
|
|
374
|
-
registry.deleteById(id), this.invalidateModuleById(id);
|
|
317
|
+
this.getMockerRegistry().deleteById(id), this.invalidateModuleById(id);
|
|
375
318
|
}
|
|
376
319
|
mockPath(originalId, id, url, external, mockType, factory) {
|
|
377
320
|
const registry = this.getMockerRegistry();
|
|
@@ -386,8 +329,8 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
|
|
|
386
329
|
this.invalidateModuleById(id);
|
|
387
330
|
}
|
|
388
331
|
async importActual(rawId, importer, callstack) {
|
|
389
|
-
const { url } = await this.resolveId(rawId, importer), node = await this.moduleRunner.fetchModule(url, importer)
|
|
390
|
-
return
|
|
332
|
+
const { url } = await this.resolveId(rawId, importer), node = await this.moduleRunner.fetchModule(url, importer);
|
|
333
|
+
return await this.moduleRunner.cachedRequest(node.url, node, callstack || [importer], void 0, true);
|
|
391
334
|
}
|
|
392
335
|
async importMock(rawId, importer) {
|
|
393
336
|
const { id, url, external } = await this.resolveId(rawId, importer);
|
|
@@ -472,11 +415,8 @@ const prefixedBuiltins = new Set([
|
|
|
472
415
|
// C:\root\id.js -> /id.js
|
|
473
416
|
// TODO: expose this in vite/module-runner
|
|
474
417
|
function normalizeModuleId(file) {
|
|
475
|
-
if (prefixedBuiltins.has(file)) return file;
|
|
476
|
-
// unix style, but Windows path still starts with the drive letter to check the root
|
|
477
|
-
const unixFile = slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/");
|
|
478
418
|
// if it's not in the root, keep it as a path, not a URL
|
|
479
|
-
return
|
|
419
|
+
return prefixedBuiltins.has(file) ? file : slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/");
|
|
480
420
|
}
|
|
481
421
|
const windowsSlashRE = /\\/g;
|
|
482
422
|
function slash(p) {
|
|
@@ -488,18 +428,53 @@ function fixLeadingSlashes(id) {
|
|
|
488
428
|
return id.startsWith("//") ? id.replace(multipleSlashRe, "/") : id;
|
|
489
429
|
}
|
|
490
430
|
|
|
431
|
+
const nodeBuiltins = builtinModules.filter((id) => !id.includes(":"));
|
|
432
|
+
class VitestTransport {
|
|
433
|
+
constructor(options) {
|
|
434
|
+
this.options = options;
|
|
435
|
+
}
|
|
436
|
+
async invoke(event) {
|
|
437
|
+
if (event.type !== "custom") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support Vite HMR events.`) };
|
|
438
|
+
if (event.event !== "vite:invoke") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support ${event.event} event.`) };
|
|
439
|
+
const { name, data } = event.data;
|
|
440
|
+
if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) };
|
|
441
|
+
if (name === "getBuiltins") return { result: [...nodeBuiltins, /^node:/] };
|
|
442
|
+
try {
|
|
443
|
+
return { result: await this.options.fetchModule(...data) };
|
|
444
|
+
} catch (error) {
|
|
445
|
+
return { error };
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const createNodeImportMeta = (modulePath) => {
|
|
451
|
+
if (!viteModuleRunner.createDefaultImportMeta) throw new Error(`createNodeImportMeta is not supported in this version of Vite.`);
|
|
452
|
+
const defaultMeta = viteModuleRunner.createDefaultImportMeta(modulePath), href = defaultMeta.url, importMetaResolver = createImportMetaResolver();
|
|
453
|
+
return {
|
|
454
|
+
...defaultMeta,
|
|
455
|
+
main: false,
|
|
456
|
+
resolve(id, parent) {
|
|
457
|
+
return (importMetaResolver ?? defaultMeta.resolve)(id, parent ?? href);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
};
|
|
461
|
+
function createImportMetaResolver() {
|
|
462
|
+
if (import.meta.resolve) return (specifier, importer) => import.meta.resolve(specifier, importer);
|
|
463
|
+
}
|
|
491
464
|
// @ts-expect-error overriding private method
|
|
492
|
-
class VitestModuleRunner extends ModuleRunner {
|
|
465
|
+
class VitestModuleRunner extends viteModuleRunner.ModuleRunner {
|
|
493
466
|
mocker;
|
|
494
467
|
moduleExecutionInfo;
|
|
495
|
-
constructor(
|
|
496
|
-
const transport = new VitestTransport(options.transport), evaluatedModules = options.evaluatedModules;
|
|
468
|
+
constructor(vitestOptions) {
|
|
469
|
+
const options = vitestOptions, transport = new VitestTransport(options.transport), evaluatedModules = options.evaluatedModules;
|
|
497
470
|
if (super({
|
|
498
471
|
transport,
|
|
499
472
|
hmr: false,
|
|
500
473
|
evaluatedModules,
|
|
501
|
-
sourcemapInterceptor: "prepareStackTrace"
|
|
502
|
-
|
|
474
|
+
sourcemapInterceptor: "prepareStackTrace",
|
|
475
|
+
createImportMeta: vitestOptions.createImportMeta
|
|
476
|
+
}, options.evaluator), this.vitestOptions = vitestOptions, this.moduleExecutionInfo = options.getWorkerState().moduleExecutionInfo, this.mocker = options.mocker || new VitestMocker(this, {
|
|
477
|
+
spyModule: options.spyModule,
|
|
503
478
|
context: options.vm?.context,
|
|
504
479
|
resolveId: options.transport.resolveId,
|
|
505
480
|
get root() {
|
|
@@ -519,12 +494,11 @@ class VitestModuleRunner extends ModuleRunner {
|
|
|
519
494
|
});
|
|
520
495
|
}
|
|
521
496
|
async import(rawId) {
|
|
522
|
-
const resolved = await this.
|
|
523
|
-
return
|
|
497
|
+
const resolved = await this.vitestOptions.transport.resolveId(rawId);
|
|
498
|
+
return super.import(resolved ? resolved.url : rawId);
|
|
524
499
|
}
|
|
525
500
|
async fetchModule(url, importer) {
|
|
526
|
-
|
|
527
|
-
return module;
|
|
501
|
+
return await this.cachedModule(url, importer);
|
|
528
502
|
}
|
|
529
503
|
_cachedRequest(url, module, callstack = [], metadata) {
|
|
530
504
|
// @ts-expect-error "cachedRequest" is private
|
|
@@ -558,10 +532,62 @@ class VitestModuleRunner extends ModuleRunner {
|
|
|
558
532
|
}
|
|
559
533
|
}
|
|
560
534
|
|
|
535
|
+
const bareVitestRegexp = /^@?vitest(?:\/|$)/, normalizedDistDir = normalize$1(distDir), relativeIds = {}, externalizeMap = /* @__PURE__ */ new Map();
|
|
536
|
+
// all Vitest imports always need to be externalized
|
|
537
|
+
function getCachedVitestImport(id, state) {
|
|
538
|
+
if (id.startsWith("/@fs/") || id.startsWith("\\@fs\\")) id = id.slice(process.platform === "win32" ? 5 : 4);
|
|
539
|
+
if (externalizeMap.has(id)) return {
|
|
540
|
+
externalize: externalizeMap.get(id),
|
|
541
|
+
type: "module"
|
|
542
|
+
};
|
|
543
|
+
// always externalize Vitest because we import from there before running tests
|
|
544
|
+
// so we already have it cached by Node.js
|
|
545
|
+
const root = state().config.root, relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length));
|
|
546
|
+
if (id.includes(distDir) || id.includes(normalizedDistDir)) {
|
|
547
|
+
const externalize = id.startsWith("file://") ? id : pathToFileURL(id).toString();
|
|
548
|
+
return externalizeMap.set(id, externalize), {
|
|
549
|
+
externalize,
|
|
550
|
+
type: "module"
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
if (relativeRoot && relativeRoot !== "/" && id.startsWith(relativeRoot)) {
|
|
554
|
+
const path = join$1(root, id), externalize = pathToFileURL(path).toString();
|
|
555
|
+
return externalizeMap.set(id, externalize), {
|
|
556
|
+
externalize,
|
|
557
|
+
type: "module"
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
return bareVitestRegexp.test(id) ? (externalizeMap.set(id, id), {
|
|
561
|
+
externalize: id,
|
|
562
|
+
type: "module"
|
|
563
|
+
}) : null;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const dispose = [];
|
|
567
|
+
function listenForErrors(state) {
|
|
568
|
+
dispose.forEach((fn) => fn()), dispose.length = 0;
|
|
569
|
+
function catchError(err, type, event) {
|
|
570
|
+
const worker = state();
|
|
571
|
+
// if there is another listener, assume that it's handled by user code
|
|
572
|
+
// one is Vitest's own listener
|
|
573
|
+
if (process.listeners(event).length > 1) return;
|
|
574
|
+
const error = serializeValue(err);
|
|
575
|
+
if (typeof error === "object" && error != null) {
|
|
576
|
+
if (error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0, worker.filepath) error.VITEST_TEST_PATH = worker.filepath;
|
|
577
|
+
error.VITEST_AFTER_ENV_TEARDOWN = worker.environmentTeardownRun;
|
|
578
|
+
}
|
|
579
|
+
state().rpc.onUnhandledError(error, type);
|
|
580
|
+
}
|
|
581
|
+
const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException"), unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection");
|
|
582
|
+
process.on("uncaughtException", uncaughtException), process.on("unhandledRejection", unhandledRejection), dispose.push(() => {
|
|
583
|
+
process.off("uncaughtException", uncaughtException), process.off("unhandledRejection", unhandledRejection);
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
|
|
561
587
|
const { readFileSync } = fs, browserExternalId = "__vite-browser-external", browserExternalLength = 24;
|
|
562
588
|
const VITEST_VM_CONTEXT_SYMBOL = "__vitest_vm_context__";
|
|
563
589
|
const cwd = process.cwd(), isWindows = process.platform === "win32";
|
|
564
|
-
|
|
590
|
+
function startVitestModuleRunner(options) {
|
|
565
591
|
const state = () => globalThis.__vitest_worker__ || options.state, rpc = () => state().rpc;
|
|
566
592
|
process.exit = (code = process.exitCode || 0) => {
|
|
567
593
|
throw new Error(`process.exit unexpectedly called with "${code}"`);
|
|
@@ -581,6 +607,7 @@ async function startVitestModuleRunner(options) {
|
|
|
581
607
|
},
|
|
582
608
|
getCurrentTestFilepath: () => state().filepath
|
|
583
609
|
}), moduleRunner = new VitestModuleRunner({
|
|
610
|
+
spyModule: options.spyModule,
|
|
584
611
|
evaluatedModules: options.evaluatedModules,
|
|
585
612
|
evaluator,
|
|
586
613
|
mocker: options.mocker,
|
|
@@ -590,10 +617,7 @@ async function startVitestModuleRunner(options) {
|
|
|
590
617
|
if (isWindows) {
|
|
591
618
|
if (id[1] === ":") {
|
|
592
619
|
// The drive letter is different for whatever reason, we need to normalize it to CWD
|
|
593
|
-
if (id[0] !== cwd[0] && id[0].toUpperCase() === cwd[0].toUpperCase())
|
|
594
|
-
const isUpperCase = cwd[0].toUpperCase() === cwd[0];
|
|
595
|
-
id = (isUpperCase ? id[0].toUpperCase() : id[0].toLowerCase()) + id.slice(1);
|
|
596
|
-
}
|
|
620
|
+
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);
|
|
597
621
|
// always mark absolute windows paths, otherwise Vite will externalize it
|
|
598
622
|
id = `/@id/${id}`;
|
|
599
623
|
}
|
|
@@ -618,14 +642,10 @@ async function startVitestModuleRunner(options) {
|
|
|
618
642
|
type: "builtin"
|
|
619
643
|
};
|
|
620
644
|
const result = await rpc().fetch(id, importer, environment(), options);
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
...result
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
return result;
|
|
645
|
+
return "cached" in result ? {
|
|
646
|
+
code: readFileSync(result.tmp, "utf-8"),
|
|
647
|
+
...result
|
|
648
|
+
} : result;
|
|
629
649
|
} catch (cause) {
|
|
630
650
|
// rethrow vite error if it cannot load the module because it's not resolved
|
|
631
651
|
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 '")) {
|
|
@@ -642,9 +662,10 @@ async function startVitestModuleRunner(options) {
|
|
|
642
662
|
}
|
|
643
663
|
},
|
|
644
664
|
getWorkerState: state,
|
|
645
|
-
vm
|
|
665
|
+
vm,
|
|
666
|
+
createImportMeta: options.createImportMeta
|
|
646
667
|
});
|
|
647
|
-
return
|
|
668
|
+
return moduleRunner;
|
|
648
669
|
}
|
|
649
670
|
function toBuiltin(id) {
|
|
650
671
|
if (id.startsWith(browserExternalId)) id = id.slice(browserExternalLength);
|
|
@@ -652,4 +673,4 @@ function toBuiltin(id) {
|
|
|
652
673
|
return id;
|
|
653
674
|
}
|
|
654
675
|
|
|
655
|
-
export { VitestModuleRunner as V, VITEST_VM_CONTEXT_SYMBOL as a, startVitestModuleRunner as s };
|
|
676
|
+
export { VitestModuleRunner as V, VITEST_VM_CONTEXT_SYMBOL as a, VitestTransport as b, createNodeImportMeta as c, startVitestModuleRunner as s };
|