vitest 5.0.0-beta.3 → 5.0.0-beta.4
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/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/chunks/{base.Bay6B1Dz.js → base.BEGVMQrS.js} +6 -6
- package/dist/chunks/{browser.d.DM1g8UNp.d.ts → browser.d.BGxB4Xum.d.ts} +4 -25
- package/dist/chunks/{cac.DoK9yX-i.js → cac.CyXAEMkE.js} +22 -31
- package/dist/chunks/{cli-api.BCY9ylNq.js → cli-api.DJMXq34b.js} +502 -549
- package/dist/chunks/{config.d.C0UMwus7.d.ts → config.d.DXq1aBpy.d.ts} +7 -26
- package/dist/chunks/{creator.BqL2U_x4.js → creator.D66cVXYh.js} +2 -2
- package/dist/chunks/{defaults.DVfzlTkU.js → defaults.CUUnbOrq.js} +5 -3
- package/dist/chunks/global.d.BtKPuz2X.d.ts +194 -0
- package/dist/chunks/{globals.8_qjZdeE.js → globals.BuY-yD0m.js} +2 -1
- package/dist/chunks/{index.ukHtlBbI.js → index.CE58PZNH.js} +355 -146
- package/dist/chunks/{index.PuMGMNHF.js → index.CcluKS59.js} +4 -4
- package/dist/chunks/{index.CbgUM9E5.js → index.nQFVd50u.js} +2 -1
- package/dist/chunks/{init-forks.OoZmDo1g.js → init-forks.Ce3vGWgL.js} +1 -1
- package/dist/chunks/{init-threads.eSHAowcx.js → init-threads.8e1OLv5v.js} +1 -1
- package/dist/chunks/{init.YjNsCb-_.js → init.6qx-LaHs.js} +30 -2
- package/dist/chunks/{nativeModuleMocker.DKpFw0pk.js → nativeModuleMocker.DDZfQXLs.js} +1 -1
- package/dist/chunks/{plugin.d.C00LxKL6.d.ts → plugin.d.B7MTG_Fe.d.ts} +71 -82
- package/dist/chunks/{rpc.d.7JZuxZ8u.d.ts → rpc.d.OQ_EZi1Z.d.ts} +18 -2
- package/dist/chunks/{setup-common.eQsbxe88.js → setup-common.DdEF_hkE.js} +1 -1
- package/dist/chunks/{vm.BE_VOfSs.js → vm.Bu7mmcZq.js} +2 -2
- package/dist/chunks/{worker.d.Dv3hDCFf.d.ts → worker.d.yR22cs6X.d.ts} +3 -2
- package/dist/cli.js +1 -1
- package/dist/config.cjs +1 -1
- package/dist/config.d.ts +6 -8
- package/dist/config.js +1 -1
- package/dist/index.d.ts +23 -40
- package/dist/index.js +2 -1
- package/dist/module-evaluator.d.ts +4 -1
- package/dist/module-evaluator.js +14 -19
- package/dist/node.d.ts +20 -12
- package/dist/node.js +5 -5
- package/dist/runtime.js +2 -2
- package/dist/worker.d.ts +3 -3
- package/dist/worker.js +7 -6
- package/dist/workers/forks.js +8 -7
- package/dist/workers/runVmTests.js +4 -3
- package/dist/workers/threads.js +8 -7
- package/dist/workers/vmForks.js +4 -4
- package/dist/workers/vmThreads.js +4 -4
- package/package.json +15 -15
- package/dist/chunks/global.d.DZbA5YnY.d.ts +0 -101
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import { TestSyntaxError, getCurrentTest,
|
|
1
|
+
import { TestSyntaxError, getCurrentTest, createTaskCollector, getCurrentSuite, getHooks, getFn, afterAll, afterEach, aroundAll, aroundEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, recordArtifact, suite, test } from '@vitest/runner';
|
|
2
2
|
import { i as isChildProcess, w as waitForImportsToResolve, r as resetModules, g as getWorkerState } from './utils.BX5Fg8C4.js';
|
|
3
3
|
import { getSafeTimers, delay } from '@vitest/utils/timers';
|
|
4
4
|
import { isMockFunction, fn, spyOn, restoreAllMocks, resetAllMocks, clearAllMocks } from '@vitest/spy';
|
|
5
|
-
import { getType, isObject, noop, assertTypes, ordinal, createSimpleStackTrace, getCallLastIndex
|
|
5
|
+
import { getType, isObject, noop, assertTypes, ordinal, createSimpleStackTrace, getCallLastIndex } from '@vitest/utils/helpers';
|
|
6
6
|
import { positionToOffset, offsetToLineNumber, lineSplitRE } from '@vitest/utils/offset';
|
|
7
7
|
import { parseSingleStack, parseErrorStacktrace } from '@vitest/utils/source-map';
|
|
8
8
|
import { c as commonjsGlobal, g as getDefaultExportFromCjs } from './_commonjsHelpers.D26ty3Ew.js';
|
|
9
9
|
import { R as RealDate, b as resetDate, m as mockDate, r as rpc, V as VitestEvaluatedModules } from './rpc.DFRWVnRh.js';
|
|
10
10
|
import * as chai from 'chai';
|
|
11
11
|
import { use, util } from 'chai';
|
|
12
|
-
import { getNames,
|
|
12
|
+
import { getNames, getTests, getTestName, createChainable, matchesTags } from '@vitest/runner/utils';
|
|
13
13
|
import { processError } from '@vitest/utils/error';
|
|
14
14
|
import { g as getSerializers, a as addSerializer } from './plugins.DrsmdUE2.js';
|
|
15
15
|
import { format } from '@vitest/pretty-format';
|
|
16
16
|
import { printDiffOrStringify, diff } from '@vitest/utils/diff';
|
|
17
17
|
import { stringify, inspect } from '@vitest/utils/display';
|
|
18
18
|
import c from 'tinyrainbow';
|
|
19
|
-
import { normalize } from 'pathe';
|
|
19
|
+
import { isAbsolute, relative, normalize } from 'pathe';
|
|
20
|
+
import { Bench } from 'tinybench';
|
|
20
21
|
import { expectTypeOf } from 'expect-type';
|
|
21
22
|
|
|
22
23
|
const ChaiStyleAssertions = (chai, utils) => {
|
|
@@ -1590,6 +1591,48 @@ const JestExtend = (chai, utils) => {
|
|
|
1590
1591
|
});
|
|
1591
1592
|
};
|
|
1592
1593
|
|
|
1594
|
+
function isBenchResult(value) {
|
|
1595
|
+
return typeof value === "object" && value !== null && "latency" in value && typeof value.latency?.mean === "number";
|
|
1596
|
+
}
|
|
1597
|
+
function formatOps(ops) {
|
|
1598
|
+
return ops.toLocaleString("en-US", {
|
|
1599
|
+
minimumFractionDigits: 2,
|
|
1600
|
+
maximumFractionDigits: 2
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1603
|
+
const benchMatchers = {
|
|
1604
|
+
toBeFasterThan(actual, expected, options) {
|
|
1605
|
+
const { matcherHint, RECEIVED_COLOR, EXPECTED_COLOR } = this.utils;
|
|
1606
|
+
const delta = options?.delta ?? 0;
|
|
1607
|
+
if (!isBenchResult(actual)) throw new TypeError(`${matcherHint(".toBeFasterThan")} expects the actual value to be a benchmark result.`);
|
|
1608
|
+
if (!isBenchResult(expected)) throw new TypeError(`${matcherHint(".toBeFasterThan")} expects the expected value to be a benchmark result.`);
|
|
1609
|
+
const threshold = expected.latency.mean * (1 - delta);
|
|
1610
|
+
const pass = actual.latency.mean < threshold;
|
|
1611
|
+
return {
|
|
1612
|
+
pass,
|
|
1613
|
+
message: () => {
|
|
1614
|
+
const relation = ((actual.latency.mean - expected.latency.mean) / expected.latency.mean * 100).toFixed(2);
|
|
1615
|
+
return pass ? `${matcherHint(".not.toBeFasterThan")}\n\nExpected to not be faster, but was ${Math.abs(Number(relation))}% faster.\n\nReceived: ${RECEIVED_COLOR(formatOps(actual.throughput.mean))} ops/sec\nExpected: ${EXPECTED_COLOR(formatOps(expected.throughput.mean))} ops/sec\n` : `${matcherHint(".toBeFasterThan")}\n\nExpected to be faster${delta > 0 ? ` by at least ${(delta * 100).toFixed(0)}%` : ""}, but was ${Number(relation) > 0 ? `${relation}% slower` : `only ${Math.abs(Number(relation))}% faster`}.\n\nReceived: ${RECEIVED_COLOR(formatOps(actual.throughput.mean))} ops/sec\nExpected: ${EXPECTED_COLOR(formatOps(expected.throughput.mean))} ops/sec\n`;
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1618
|
+
},
|
|
1619
|
+
toBeSlowerThan(actual, expected, options) {
|
|
1620
|
+
const { matcherHint, RECEIVED_COLOR, EXPECTED_COLOR } = this.utils;
|
|
1621
|
+
const delta = options?.delta ?? 0;
|
|
1622
|
+
if (!isBenchResult(actual)) throw new TypeError(`${matcherHint(".toBeSlowerThan")} expects the actual value to be a benchmark result.`);
|
|
1623
|
+
if (!isBenchResult(expected)) throw new TypeError(`${matcherHint(".toBeSlowerThan")} expects the expected value to be a benchmark result.`);
|
|
1624
|
+
const threshold = expected.latency.mean * (1 + delta);
|
|
1625
|
+
const pass = actual.latency.mean > threshold;
|
|
1626
|
+
return {
|
|
1627
|
+
pass,
|
|
1628
|
+
message: () => {
|
|
1629
|
+
const relation = ((actual.latency.mean - expected.latency.mean) / expected.latency.mean * 100).toFixed(2);
|
|
1630
|
+
return pass ? `${matcherHint(".not.toBeSlowerThan")}\n\nExpected to not be slower, but was ${relation}% slower.\n\nReceived: ${RECEIVED_COLOR(formatOps(actual.throughput.mean))} ops/sec\nExpected: ${EXPECTED_COLOR(formatOps(expected.throughput.mean))} ops/sec\n` : `${matcherHint(".toBeSlowerThan")}\n\nExpected to be slower${delta > 0 ? ` by at least ${(delta * 100).toFixed(0)}%` : ""}, but was ${Number(relation) < 0 ? `${Math.abs(Number(relation))}% faster` : `only ${relation}% slower`}.\n\nReceived: ${RECEIVED_COLOR(formatOps(actual.throughput.mean))} ops/sec\nExpected: ${EXPECTED_COLOR(formatOps(expected.throughput.mean))} ops/sec\n`;
|
|
1631
|
+
}
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
|
|
1593
1636
|
var fakeTimersSrc = {};
|
|
1594
1637
|
|
|
1595
1638
|
var global;
|
|
@@ -5649,7 +5692,7 @@ class FakeTimers {
|
|
|
5649
5692
|
}
|
|
5650
5693
|
}
|
|
5651
5694
|
|
|
5652
|
-
function copyStackTrace$
|
|
5695
|
+
function copyStackTrace$2(target, source) {
|
|
5653
5696
|
if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
|
|
5654
5697
|
return target;
|
|
5655
5698
|
}
|
|
@@ -5670,7 +5713,7 @@ function waitFor(callback, options = {}) {
|
|
|
5670
5713
|
const handleTimeout = () => {
|
|
5671
5714
|
if (intervalId) clearInterval(intervalId);
|
|
5672
5715
|
let error = lastError;
|
|
5673
|
-
if (!error) error = copyStackTrace$
|
|
5716
|
+
if (!error) error = copyStackTrace$2(/* @__PURE__ */ new Error("Timed out in waitFor!"), STACK_TRACE_ERROR);
|
|
5674
5717
|
reject(error);
|
|
5675
5718
|
};
|
|
5676
5719
|
const checkCallback = () => {
|
|
@@ -5711,7 +5754,7 @@ function waitUntil(callback, options = {}) {
|
|
|
5711
5754
|
let intervalId;
|
|
5712
5755
|
const onReject = (error) => {
|
|
5713
5756
|
if (intervalId) clearInterval(intervalId);
|
|
5714
|
-
if (!error) error = copyStackTrace$
|
|
5757
|
+
if (!error) error = copyStackTrace$2(/* @__PURE__ */ new Error("Timed out in waitUntil!"), STACK_TRACE_ERROR);
|
|
5715
5758
|
reject(error);
|
|
5716
5759
|
};
|
|
5717
5760
|
const onResolve = (result) => {
|
|
@@ -5850,9 +5893,17 @@ function createVitest() {
|
|
|
5850
5893
|
defineHelper: (fn) => {
|
|
5851
5894
|
return function __VITEST_HELPER__(...args) {
|
|
5852
5895
|
const result = fn.apply(this, args);
|
|
5853
|
-
if (result && typeof result === "object" && typeof result.then === "function")
|
|
5854
|
-
|
|
5855
|
-
|
|
5896
|
+
if (result && typeof result === "object" && typeof result.then === "function") {
|
|
5897
|
+
const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
|
|
5898
|
+
return (async function __VITEST_HELPER__() {
|
|
5899
|
+
try {
|
|
5900
|
+
return await result;
|
|
5901
|
+
} catch (error) {
|
|
5902
|
+
if (error instanceof Error && !error.stack?.includes("__VITEST_HELPER__")) copyStackTrace$1(error, stackTraceError);
|
|
5903
|
+
throw error;
|
|
5904
|
+
}
|
|
5905
|
+
})();
|
|
5906
|
+
}
|
|
5856
5907
|
return result;
|
|
5857
5908
|
};
|
|
5858
5909
|
},
|
|
@@ -5979,6 +6030,10 @@ function getImporter(name) {
|
|
|
5979
6030
|
return stack.includes(` at Object.${name}`) || stack.includes(`${name}@`) || stack.includes(` at ${name} (`);
|
|
5980
6031
|
}) + 1])?.file || "";
|
|
5981
6032
|
}
|
|
6033
|
+
function copyStackTrace$1(target, source) {
|
|
6034
|
+
if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
|
|
6035
|
+
return target;
|
|
6036
|
+
}
|
|
5982
6037
|
|
|
5983
6038
|
// these matchers are not supported because they don't make sense with poll
|
|
5984
6039
|
const unsupported = [
|
|
@@ -7473,6 +7528,7 @@ function createExpect(test) {
|
|
|
7473
7528
|
chai.util.addMethod(expect, "assertions", assertions);
|
|
7474
7529
|
chai.util.addMethod(expect, "hasAssertions", hasAssertions);
|
|
7475
7530
|
expect.extend(customMatchers);
|
|
7531
|
+
expect.extend(benchMatchers);
|
|
7476
7532
|
return expect;
|
|
7477
7533
|
}
|
|
7478
7534
|
const globalExpect = createExpect();
|
|
@@ -7492,140 +7548,280 @@ function inject(key) {
|
|
|
7492
7548
|
return getWorkerState().providedContext[key];
|
|
7493
7549
|
}
|
|
7494
7550
|
|
|
7495
|
-
const
|
|
7496
|
-
const
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
}
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
}
|
|
7528
|
-
|
|
7529
|
-
function createBenchmarkResult(name) {
|
|
7530
|
-
return {
|
|
7551
|
+
const now = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
|
|
7552
|
+
const kRegistration = Symbol("registration");
|
|
7553
|
+
const kFromSource = Symbol("fromSource");
|
|
7554
|
+
const kPerProject = Symbol("perProject");
|
|
7555
|
+
const kWriteResult = Symbol("writeResult");
|
|
7556
|
+
const kFinalize = Symbol("finalize");
|
|
7557
|
+
function isFromRegistration(reg) {
|
|
7558
|
+
return kFromSource in reg;
|
|
7559
|
+
}
|
|
7560
|
+
function substitutePath(template, projectName) {
|
|
7561
|
+
return template.replace(/\$\{projectName\}/g, projectName ?? "");
|
|
7562
|
+
}
|
|
7563
|
+
function createBench(test, config) {
|
|
7564
|
+
let benchIdx = 0;
|
|
7565
|
+
const pending = /* @__PURE__ */ new Set();
|
|
7566
|
+
const createTinybench = (options) => {
|
|
7567
|
+
const currentIndex = ++benchIdx;
|
|
7568
|
+
return new Bench({
|
|
7569
|
+
signal: test.context.signal,
|
|
7570
|
+
name: `${test.fullTestName} ${currentIndex}`,
|
|
7571
|
+
retainSamples: config.benchmark.retainSamples,
|
|
7572
|
+
...options,
|
|
7573
|
+
now
|
|
7574
|
+
});
|
|
7575
|
+
};
|
|
7576
|
+
const resolveTemplate = (template) => substitutePath(template, config.benchmark.projectName);
|
|
7577
|
+
const resolveFromSource = async (source) => {
|
|
7578
|
+
if (typeof source === "function") return source();
|
|
7579
|
+
const resolved = resolveTemplate(source);
|
|
7580
|
+
const data = await rpc().readBenchmarkResult(resolved);
|
|
7581
|
+
if (data == null) throw new Error(`\`bench.from()\` could not find a result file at "${resolved}". Run the source benchmark first to create it.`);
|
|
7582
|
+
return data;
|
|
7583
|
+
};
|
|
7584
|
+
const taskFromBaseline = (name, data) => ({
|
|
7531
7585
|
name,
|
|
7586
|
+
latency: data.latency,
|
|
7587
|
+
throughput: data.throughput,
|
|
7588
|
+
period: data.period,
|
|
7589
|
+
totalTime: data.totalTime,
|
|
7532
7590
|
rank: 0,
|
|
7533
|
-
|
|
7534
|
-
|
|
7591
|
+
fromStore: true
|
|
7592
|
+
});
|
|
7593
|
+
const createCompareStorage = (bench, fromResults) => {
|
|
7594
|
+
return { get(name) {
|
|
7595
|
+
const stored = fromResults?.get(name);
|
|
7596
|
+
if (stored) return stored;
|
|
7597
|
+
const task = bench.getTask(name);
|
|
7598
|
+
if (!task) throw new Error(`task "${name}" was not defined`);
|
|
7599
|
+
return task.result;
|
|
7600
|
+
} };
|
|
7535
7601
|
};
|
|
7536
|
-
|
|
7537
|
-
const
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7602
|
+
const serializeBenchmark = (tinybenchTasks, name, taskMeta, fromTasks) => {
|
|
7603
|
+
const tasks = tinybenchTasks.map((t) => {
|
|
7604
|
+
const result = t.result;
|
|
7605
|
+
if (result.state === "errored") throw result.error;
|
|
7606
|
+
if (result.state !== "completed") throw new Error(`task "${t.name}" did not complete: received "${result.state}"`);
|
|
7607
|
+
return {
|
|
7608
|
+
name: t.name,
|
|
7609
|
+
latency: result.latency,
|
|
7610
|
+
throughput: result.throughput,
|
|
7611
|
+
period: result.period,
|
|
7612
|
+
totalTime: result.totalTime,
|
|
7613
|
+
rank: 0,
|
|
7614
|
+
...taskMeta?.get(t.name)
|
|
7615
|
+
};
|
|
7616
|
+
});
|
|
7617
|
+
if (fromTasks) tasks.push(...fromTasks);
|
|
7618
|
+
tasks.sort((a, b) => a.latency.mean - b.latency.mean);
|
|
7619
|
+
tasks.forEach((task, idx) => {
|
|
7620
|
+
task.rank = idx + 1;
|
|
7621
|
+
});
|
|
7622
|
+
return {
|
|
7623
|
+
name: name || test.fullTestName,
|
|
7624
|
+
tasks
|
|
7556
7625
|
};
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
}, { once: true });
|
|
7571
|
-
task.addEventListener("error", (e) => {
|
|
7572
|
-
const task = e.task;
|
|
7573
|
-
defer.reject(benchmark ? task.result.error : e);
|
|
7574
|
-
}, { once: true });
|
|
7626
|
+
};
|
|
7627
|
+
const recordBenchmark = async (tinybenchTasks, name, taskMeta, fromTasks) => {
|
|
7628
|
+
const serializedBenchmark = serializeBenchmark(tinybenchTasks, name, taskMeta, fromTasks);
|
|
7629
|
+
test.benchmarks.push(serializedBenchmark);
|
|
7630
|
+
await rpc().onTestBenchmark(test.id, serializedBenchmark);
|
|
7631
|
+
};
|
|
7632
|
+
const writeResultArtifact = async (template, result) => {
|
|
7633
|
+
const resolved = resolveTemplate(template);
|
|
7634
|
+
const data = {
|
|
7635
|
+
latency: result.latency,
|
|
7636
|
+
throughput: result.throughput,
|
|
7637
|
+
period: result.period,
|
|
7638
|
+
totalTime: result.totalTime
|
|
7575
7639
|
};
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7640
|
+
await rpc().writeBenchmarkResult(resolved, data);
|
|
7641
|
+
};
|
|
7642
|
+
const runBenchmarks = async (tinybench) => {
|
|
7643
|
+
const workerState = getWorkerState();
|
|
7644
|
+
const getterTracker = workerState.getterTracker;
|
|
7645
|
+
getterTracker?.resetInvocations();
|
|
7646
|
+
try {
|
|
7647
|
+
return await TestRunner.runBenchmarks(tinybench);
|
|
7648
|
+
} finally {
|
|
7649
|
+
const excessiveInvocations = config.benchmark.suppressExportGetterWarnings ? void 0 : getterTracker?.getExcessiveInvocations();
|
|
7650
|
+
if (excessiveInvocations?.length) {
|
|
7651
|
+
const entries = excessiveInvocations.map(({ moduleId, exportName }) => ` - ${formatModuleId(moduleId, workerState.config.root)} > ${exportName}`).join("\n");
|
|
7652
|
+
console.warn([
|
|
7653
|
+
c.yellow(c.bold("Benchmark Warning")),
|
|
7654
|
+
`Benchmark ${c.bold(`"${tinybench.name}"`)} accessed module export getters too many times.`,
|
|
7655
|
+
"",
|
|
7656
|
+
"This can make results unreliable because export getters add overhead.",
|
|
7657
|
+
"See https://vitest.dev/guide/benchmarking#module-runner-overhead",
|
|
7658
|
+
"",
|
|
7659
|
+
"Tracked exports:",
|
|
7660
|
+
entries
|
|
7661
|
+
].join("\n"));
|
|
7662
|
+
}
|
|
7663
|
+
}
|
|
7664
|
+
};
|
|
7665
|
+
const runSingle = async (name, fn, fnOpts, options, meta, writeResult) => {
|
|
7666
|
+
const tinybench = createTinybench(options).add(name, fn, fnOpts);
|
|
7667
|
+
const tasks = await runBenchmarks(tinybench);
|
|
7668
|
+
const task = tinybench.getTask(name);
|
|
7669
|
+
if (task.result.state === "errored") throw task.result.error;
|
|
7670
|
+
await recordBenchmark(tasks, tinybench.name, meta ? new Map([[name, meta]]) : void 0);
|
|
7671
|
+
if (writeResult) await writeResultArtifact(writeResult, task.result);
|
|
7672
|
+
return task.result;
|
|
7673
|
+
};
|
|
7674
|
+
const runFrom = async (name, source) => {
|
|
7675
|
+
const data = await resolveFromSource(source);
|
|
7676
|
+
const benchmark = {
|
|
7677
|
+
name: test.fullTestName,
|
|
7678
|
+
tasks: [{
|
|
7679
|
+
...taskFromBaseline(name, data),
|
|
7680
|
+
rank: 1
|
|
7681
|
+
}]
|
|
7682
|
+
};
|
|
7683
|
+
test.benchmarks.push(benchmark);
|
|
7684
|
+
await rpc().onTestBenchmark(test.id, benchmark);
|
|
7685
|
+
return data;
|
|
7686
|
+
};
|
|
7687
|
+
const bench = (nameOrFunction, a, b) => {
|
|
7688
|
+
validateBenchmarkProject(config);
|
|
7689
|
+
const { fn, fnOpts, writeResult, perProject } = normalizeBenchArgs(a, b);
|
|
7690
|
+
const name = typeof nameOrFunction === "function" ? nameOrFunction.name || "<anonymous>" : nameOrFunction;
|
|
7691
|
+
const meta = perProject ? { perProject: true } : void 0;
|
|
7692
|
+
const registration = {
|
|
7693
|
+
[kRegistration]: true,
|
|
7694
|
+
name,
|
|
7695
|
+
fn,
|
|
7696
|
+
fnOpts,
|
|
7697
|
+
run: (options) => {
|
|
7698
|
+
pending.delete(registration);
|
|
7699
|
+
return runSingle(name, fn, fnOpts, options, meta, writeResult);
|
|
7700
|
+
}
|
|
7701
|
+
};
|
|
7702
|
+
if (perProject) registration[kPerProject] = true;
|
|
7703
|
+
if (writeResult) registration[kWriteResult] = writeResult;
|
|
7704
|
+
pending.add(registration);
|
|
7705
|
+
return registration;
|
|
7706
|
+
};
|
|
7707
|
+
bench.from = (nameOrFunction, source) => {
|
|
7708
|
+
validateBenchmarkProject(config);
|
|
7709
|
+
if (typeof nameOrFunction !== "string" && typeof nameOrFunction !== "function") throw new TypeError("`bench.from()` requires a name (string or named function) as its first argument.");
|
|
7710
|
+
if (typeof source !== "string" && typeof source !== "function") throw new TypeError("`bench.from()` expects a string path or a function returning the result data as its second argument.");
|
|
7711
|
+
const name = typeof nameOrFunction === "function" ? nameOrFunction.name || "<anonymous>" : nameOrFunction;
|
|
7712
|
+
const registration = {
|
|
7713
|
+
[kRegistration]: true,
|
|
7714
|
+
[kFromSource]: source,
|
|
7715
|
+
name,
|
|
7716
|
+
run: () => {
|
|
7717
|
+
pending.delete(registration);
|
|
7718
|
+
return runFrom(name, source);
|
|
7719
|
+
}
|
|
7720
|
+
};
|
|
7721
|
+
pending.add(registration);
|
|
7722
|
+
return registration;
|
|
7723
|
+
};
|
|
7724
|
+
bench.compare = async (...args) => {
|
|
7725
|
+
validateBenchmarkProject(config);
|
|
7726
|
+
// extract optional trailing BenchCompareOptions argument
|
|
7727
|
+
const lastArg = args[args.length - 1];
|
|
7728
|
+
const benchOptions = lastArg != null && typeof lastArg === "object" && !(kRegistration in lastArg) ? args.pop() : void 0;
|
|
7729
|
+
const registrations = args;
|
|
7730
|
+
// Mark every passed-in registration as consumed before validation so a
|
|
7731
|
+
// throwing `bench.compare()` (wrong arity, wrong shape) doesn't also
|
|
7732
|
+
// trigger the unrun-bench warning — the user's intent was to consume them.
|
|
7733
|
+
for (const reg of registrations) if (reg != null && typeof reg === "object" && kRegistration in reg) pending.delete(reg);
|
|
7734
|
+
if (registrations.length < 2) throw new SyntaxError(`\`bench.compare()\` requires at least 2 benchmarks, received ${registrations.length} instead. ${registrations.length === 1 ? "Consider calling `bench().run()`. " : "Define benchmarks by calling `bench()`. "}See https://vitest.dev/guide/benchmarking#comparing-benchmarks`);
|
|
7735
|
+
for (const reg of registrations) if (reg == null || typeof reg !== "object" || !(kRegistration in reg)) throw new SyntaxError("`bench.compare()` expects every argument to be the return value of `bench` or `bench.from`.");
|
|
7736
|
+
const runnable = [];
|
|
7737
|
+
const fromEntries = [];
|
|
7738
|
+
for (const reg of registrations) if (isFromRegistration(reg)) fromEntries.push(reg);
|
|
7739
|
+
else runnable.push(reg);
|
|
7740
|
+
const taskMeta = /* @__PURE__ */ new Map();
|
|
7741
|
+
for (const reg of runnable) if (reg[kPerProject]) taskMeta.set(reg.name, { perProject: true });
|
|
7742
|
+
const fromResults = /* @__PURE__ */ new Map();
|
|
7743
|
+
const fromTasks = [];
|
|
7744
|
+
if (fromEntries.length > 0) {
|
|
7745
|
+
const resolved = await Promise.all(fromEntries.map(async (reg) => {
|
|
7746
|
+
return {
|
|
7747
|
+
reg,
|
|
7748
|
+
data: await resolveFromSource(reg[kFromSource])
|
|
7749
|
+
};
|
|
7750
|
+
}));
|
|
7751
|
+
for (const { reg, data } of resolved) {
|
|
7752
|
+
fromResults.set(reg.name, data);
|
|
7753
|
+
fromTasks.push(taskFromBaseline(reg.name, data));
|
|
7754
|
+
}
|
|
7755
|
+
}
|
|
7756
|
+
const tinybench = createTinybench(benchOptions);
|
|
7757
|
+
runnable.forEach((reg) => {
|
|
7758
|
+
tinybench.add(reg.name, reg.fn, reg.fnOpts);
|
|
7587
7759
|
});
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
const
|
|
7592
|
-
|
|
7593
|
-
await task.warmup();
|
|
7594
|
-
tasks.push([await new Promise((resolve) => setTimeout(async () => {
|
|
7595
|
-
resolve(await task.run());
|
|
7596
|
-
})), benchmark]);
|
|
7760
|
+
let tasks = [];
|
|
7761
|
+
if (runnable.length > 0) {
|
|
7762
|
+
tasks = await runBenchmarks(tinybench);
|
|
7763
|
+
const errors = tinybench.tasks.filter((task) => task.result.state === "errored").map((task) => task.result.error);
|
|
7764
|
+
if (errors.length > 0) throw new AggregateError(errors, "Some benchmarks failed");
|
|
7597
7765
|
}
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
await
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7766
|
+
await recordBenchmark(tasks, tinybench.name, taskMeta, fromTasks);
|
|
7767
|
+
// write artifacts for every runnable registration that requested it. We
|
|
7768
|
+
// do this after recording so a write failure can't be confused with a
|
|
7769
|
+
// benchmark failure in the reporter output.
|
|
7770
|
+
await Promise.all(runnable.filter((reg) => reg[kWriteResult] != null).map((reg) => {
|
|
7771
|
+
const task = tinybench.getTask(reg.name);
|
|
7772
|
+
return writeResultArtifact(reg[kWriteResult], task.result);
|
|
7773
|
+
}));
|
|
7774
|
+
return createCompareStorage(tinybench, fromResults);
|
|
7775
|
+
};
|
|
7776
|
+
bench[kFinalize] = () => {
|
|
7777
|
+
if (pending.size === 0) return;
|
|
7778
|
+
const names = [...pending].map((reg) => `"${reg.name}"`).join(", ");
|
|
7779
|
+
pending.clear();
|
|
7780
|
+
console.warn([
|
|
7781
|
+
c.yellow(c.bold("Benchmark Warning")),
|
|
7782
|
+
`Test ${c.bold(`"${test.fullTestName}"`)} registered benchmarks that never ran: ${names}.`,
|
|
7783
|
+
"",
|
|
7784
|
+
"Call `.run()` on the registration, or pass it to `bench.compare()`.",
|
|
7785
|
+
"See https://vitest.dev/guide/benchmarking#defining-a-benchmark"
|
|
7786
|
+
].join("\n"));
|
|
7787
|
+
};
|
|
7788
|
+
return bench;
|
|
7607
7789
|
}
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
}
|
|
7621
|
-
return this.moduleRunner.import(filepath);
|
|
7622
|
-
}
|
|
7623
|
-
async runSuite(suite) {
|
|
7624
|
-
await runBenchmarkSuite(suite, this);
|
|
7625
|
-
}
|
|
7626
|
-
async runTask() {
|
|
7627
|
-
throw new Error("`test()` and `it()` is only available in test mode.");
|
|
7790
|
+
function formatModuleId(moduleId, root) {
|
|
7791
|
+
if (!root || !isAbsolute(moduleId)) return moduleId;
|
|
7792
|
+
return relative(root, moduleId);
|
|
7793
|
+
}
|
|
7794
|
+
function normalizeBenchArgs(a, b) {
|
|
7795
|
+
if (typeof a === "function") {
|
|
7796
|
+
if (b !== void 0) throw new TypeError("`bench()` does not accept options as the third argument. Pass options as the second argument instead: `bench(name, options, fn)`.");
|
|
7797
|
+
return {
|
|
7798
|
+
fn: a,
|
|
7799
|
+
fnOpts: void 0,
|
|
7800
|
+
writeResult: void 0,
|
|
7801
|
+
perProject: false
|
|
7802
|
+
};
|
|
7628
7803
|
}
|
|
7804
|
+
if (typeof b !== "function") throw new TypeError("`bench()` expects a benchmark function. Call `bench(name, fn)` or `bench(name, options, fn)`.");
|
|
7805
|
+
// Strip vitest-specific fields only when present so we don't allocate a new
|
|
7806
|
+
// object — preserving referential identity matters: users inspect
|
|
7807
|
+
// `registration.fnOpts` and tinybench's `add` sees the same object the
|
|
7808
|
+
// caller passed in.
|
|
7809
|
+
if (a.writeResult === void 0 && a.perProject === void 0) return {
|
|
7810
|
+
fn: b,
|
|
7811
|
+
fnOpts: a,
|
|
7812
|
+
writeResult: void 0,
|
|
7813
|
+
perProject: false
|
|
7814
|
+
};
|
|
7815
|
+
const { writeResult, perProject, ...fnOpts } = a;
|
|
7816
|
+
return {
|
|
7817
|
+
fn: b,
|
|
7818
|
+
fnOpts: Object.keys(fnOpts).length > 0 ? fnOpts : void 0,
|
|
7819
|
+
writeResult,
|
|
7820
|
+
perProject: perProject ?? false
|
|
7821
|
+
};
|
|
7822
|
+
}
|
|
7823
|
+
function validateBenchmarkProject(config) {
|
|
7824
|
+
if (!config.benchmark.enabled) throw new Error("Cannot use the `bench` test-context fixture within a regular test run. Benchmarks are inherently flaky, so Vitest runs them in a dedicated project based on the `benchmark.include` pattern (default `**/*.{bench,benchmark}.?(c|m)[jt]s?(x)`). Move this code to a file matched by `benchmark.include`, and make sure `bench` is destructured from the test context (`test('...', async ({ bench }) => { ... })`) — it is not a top-level export of `vitest`. See https://vitest.dev/guide/benchmarking#stability");
|
|
7629
7825
|
}
|
|
7630
7826
|
|
|
7631
7827
|
class TestRunner {
|
|
@@ -7634,7 +7830,11 @@ class TestRunner {
|
|
|
7634
7830
|
moduleRunner;
|
|
7635
7831
|
cancelRun = false;
|
|
7636
7832
|
assertionsErrors = /* @__PURE__ */ new WeakMap();
|
|
7833
|
+
benchInstances = /* @__PURE__ */ new WeakMap();
|
|
7637
7834
|
pool = this.workerState.ctx.pool;
|
|
7835
|
+
/**
|
|
7836
|
+
* @internal
|
|
7837
|
+
*/
|
|
7638
7838
|
_otel;
|
|
7639
7839
|
viteEnvironment;
|
|
7640
7840
|
viteModuleRunner;
|
|
@@ -7660,7 +7860,7 @@ class TestRunner {
|
|
|
7660
7860
|
onCleanupWorkerContext(listener) {
|
|
7661
7861
|
this.workerState.onCleanup(listener);
|
|
7662
7862
|
}
|
|
7663
|
-
onAfterRunFiles() {
|
|
7863
|
+
onAfterRunFiles(_files) {
|
|
7664
7864
|
this.snapshotClient.clear();
|
|
7665
7865
|
this.workerState.current = void 0;
|
|
7666
7866
|
}
|
|
@@ -7707,7 +7907,7 @@ class TestRunner {
|
|
|
7707
7907
|
if (suite.mode !== "skip" && "filepath" in suite) await this.snapshotClient.setup(suite.file.filepath, this.workerState.config.snapshotOptions);
|
|
7708
7908
|
this.workerState.current = suite;
|
|
7709
7909
|
}
|
|
7710
|
-
onBeforeTryTask(test) {
|
|
7910
|
+
onBeforeTryTask(test, _options) {
|
|
7711
7911
|
clearModuleMocks(this.config);
|
|
7712
7912
|
this.snapshotClient.clearTest(test.file.filepath, test.id);
|
|
7713
7913
|
setState({
|
|
@@ -7721,6 +7921,7 @@ class TestRunner {
|
|
|
7721
7921
|
}, globalThis[GLOBAL_EXPECT]);
|
|
7722
7922
|
}
|
|
7723
7923
|
onAfterTryTask(test) {
|
|
7924
|
+
this.benchInstances.get(test)?.[kFinalize]();
|
|
7724
7925
|
const { assertionCalls, expectedAssertionsNumber, expectedAssertionsNumberErrorGen, isExpectingAssertions, isExpectingAssertionsError } = test.context._local ? test.context.expect.getState() : getState(globalThis[GLOBAL_EXPECT]);
|
|
7725
7926
|
if (expectedAssertionsNumber !== null && assertionCalls !== expectedAssertionsNumber) throw expectedAssertionsNumberErrorGen();
|
|
7726
7927
|
if (isExpectingAssertions === true && assertionCalls === 0) throw isExpectingAssertionsError;
|
|
@@ -7737,6 +7938,16 @@ class TestRunner {
|
|
|
7737
7938
|
Object.defineProperty(context, "_local", { get() {
|
|
7738
7939
|
return _expect != null;
|
|
7739
7940
|
} });
|
|
7941
|
+
let _bench;
|
|
7942
|
+
const runnerConfig = this.config;
|
|
7943
|
+
const benchInstances = this.benchInstances;
|
|
7944
|
+
Object.defineProperty(context, "bench", { get() {
|
|
7945
|
+
if (!_bench) {
|
|
7946
|
+
_bench = createBench(context.task, runnerConfig);
|
|
7947
|
+
benchInstances.set(context.task, _bench);
|
|
7948
|
+
}
|
|
7949
|
+
return _bench;
|
|
7950
|
+
} });
|
|
7740
7951
|
return context;
|
|
7741
7952
|
}
|
|
7742
7953
|
getImportDurations() {
|
|
@@ -7771,13 +7982,13 @@ class TestRunner {
|
|
|
7771
7982
|
static setTestFn = getFn;
|
|
7772
7983
|
static matchesTags = matchesTags;
|
|
7773
7984
|
/**
|
|
7774
|
-
* @
|
|
7985
|
+
* @experimental
|
|
7986
|
+
* A function that runs tinybench tasks.
|
|
7987
|
+
* Can be overriden to run tasks in a special environment.
|
|
7775
7988
|
*/
|
|
7776
|
-
static
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
*/
|
|
7780
|
-
static getBenchOptions = getBenchOptions;
|
|
7989
|
+
static async runBenchmarks(tinybench) {
|
|
7990
|
+
return await tinybench.run();
|
|
7991
|
+
}
|
|
7781
7992
|
}
|
|
7782
7993
|
function clearModuleMocks(config) {
|
|
7783
7994
|
const { clearMocks, mockReset, restoreMocks, unstubEnvs, unstubGlobals } = config;
|
|
@@ -7792,7 +8003,6 @@ const assertType = function assertType() {};
|
|
|
7792
8003
|
|
|
7793
8004
|
var index = /*#__PURE__*/Object.freeze({
|
|
7794
8005
|
__proto__: null,
|
|
7795
|
-
BenchmarkRunner: NodeBenchmarkRunner,
|
|
7796
8006
|
EvaluatedModules: VitestEvaluatedModules,
|
|
7797
8007
|
Snapshots: Snapshots,
|
|
7798
8008
|
TestRunner: TestRunner,
|
|
@@ -7804,7 +8014,6 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
7804
8014
|
assertType: assertType,
|
|
7805
8015
|
beforeAll: beforeAll,
|
|
7806
8016
|
beforeEach: beforeEach,
|
|
7807
|
-
bench: bench,
|
|
7808
8017
|
chai: chai,
|
|
7809
8018
|
createExpect: createExpect,
|
|
7810
8019
|
describe: describe,
|
|
@@ -7822,4 +8031,4 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
7822
8031
|
vitest: vitest
|
|
7823
8032
|
});
|
|
7824
8033
|
|
|
7825
|
-
export {
|
|
8034
|
+
export { Snapshots as S, TestRunner as T, assert as a, assertType as b, createExpect as c, inject as d, vitest as e, globalExpect as g, index as i, should as s, vi as v };
|