vitest 5.0.0-beta.5 → 5.0.0-beta.7
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 +165 -1
- package/dist/browser.d.ts +27 -14
- package/dist/browser.js +11 -14
- package/dist/chunks/{artifact.C0OHWdod.js → artifact.DC5WoEgy.js} +1310 -13
- package/dist/chunks/{base.BPbmtl-C.js → base.B0fUxpj9.js} +17 -13
- package/dist/chunks/{browser.d.B-p-y0sB.d.ts → browser.d.BFOby8YL.d.ts} +3 -3
- package/dist/chunks/{cac.DYQRhgb-.js → cac.B41kXwyU.js} +22 -24
- package/dist/chunks/check.Cz_-YojU.js +15 -0
- package/dist/chunks/cli-api.bqNN5viV.js +519 -0
- package/dist/chunks/{config.d.Bkl6J5iR.d.ts → config.d.DsC1jkby.d.ts} +877 -27
- package/dist/chunks/{console.DjVIMaXT.js → console.omGxyKMT.js} +5 -5
- package/dist/chunks/{coverage.CTzCuANN.js → coverage.BVb1JqW7.js} +7 -2
- package/dist/chunks/coverage.BfSEMtie.js +26 -0
- package/dist/chunks/coverage.d.ByaAMV4A.d.ts +88 -0
- package/dist/chunks/{creator.CJiHagNv.js → creator.BzMFaPC-.js} +54 -30
- package/dist/chunks/{defaults.CUUnbOrq.js → defaults.BJUmAuaO.js} +3 -2
- package/dist/chunks/display.CYwyMF4S.js +192 -0
- package/dist/chunks/{env.BKKtU2WC.js → env.DzFJjrmK.js} +1 -1
- package/dist/chunks/{environment.d.CrsxCzP1.d.ts → environment.d.4-rzQgpt.d.ts} +1 -1
- package/dist/chunks/globals.sd6Qutmc.js +28 -0
- package/dist/chunks/{cli-api.SMst4llK.js → index.5krd73UD.js} +14591 -13056
- package/dist/chunks/{index.CXzZ7KB8.js → index.CLtI1k_4.js} +627 -214
- package/dist/chunks/{index.DzNNaFWy.js → index.DxR-nMjO.js} +63 -10
- package/dist/chunks/index.DzTmMrSM.js +940 -0
- package/dist/chunks/{index.DugGyGng.js → index.JaztIWgW.js} +6 -5
- package/dist/chunks/{init-forks.CDWjf0q6.js → init-forks.CXzT841o.js} +1 -1
- package/dist/chunks/{init-threads.B-vZ8N2q.js → init-threads.Ch-Bw5j3.js} +1 -1
- package/dist/chunks/{init.gslB1aqB.js → init.CfiYZpFg.js} +41 -25
- package/dist/chunks/{native.DPzPHdi5.js → native.BUCvPRKp.js} +3 -4
- package/dist/chunks/{nativeModuleMocker.CrcWvO03.js → nativeModuleMocker.Uot80PXb.js} +2 -3
- package/dist/chunks/{index.CesbTg1C.js → nativeModuleRunner.BDnwGb8g.js} +39 -3
- package/dist/chunks/{node.C9I1sbE9.js → node.BPMnm_Q2.js} +1 -1
- package/dist/chunks/offset.Dy-5Fdfn.js +24 -0
- package/dist/chunks/pathe.M-eThtNZ.CbK_Vbae.js +489 -0
- package/dist/chunks/{plugin.d.BuiCQSo8.d.ts → plugin.d.BOjbmxWW.d.ts} +1757 -1566
- package/dist/chunks/{plugins.DrsmdUE2.js → plugins.CsoX-42X.js} +1 -1
- package/dist/chunks/resolver.CERfsKE-.js +48 -0
- package/dist/chunks/{rpc.d.BLxNuPAq.d.ts → rpc.d.BeasqWpO.d.ts} +14 -1
- package/dist/chunks/{rpc.DZEh5xnQ.js → rpc.iNjF664v.js} +2 -2
- package/dist/chunks/setup-common.vxjAyUtK.js +36 -0
- package/dist/chunks/setup.DasACXvo.js +5409 -0
- package/dist/chunks/source-map.DZdIqpIJ.js +1776 -0
- package/dist/chunks/spy.B8mHA9qu.js +422 -0
- package/dist/chunks/{task-utils.d.CLWcZaUf.d.ts → task-utils.d.BKHiHxSN.d.ts} +20 -2
- package/dist/chunks/tinyrainbow.Ht9iggcq.js +95 -0
- package/dist/chunks/{utils.DKODp04v.js → utils.CO-iLyCr.js} +41 -42
- package/dist/chunks/{vm._FqKqltU.js → vm.DoQh8CN9.js} +110 -11
- package/dist/chunks/{worker.d.Cb0Z-SnE.d.ts → worker.d.s_RdeZtI.d.ts} +14 -11
- package/dist/cli.js +4 -5
- package/dist/config.cjs +2 -1
- package/dist/config.d.ts +19 -17
- package/dist/config.js +2 -2
- package/dist/index.d.ts +241 -31
- package/dist/index.js +11 -16
- package/dist/module-evaluator.d.ts +40 -8
- package/dist/module-evaluator.js +73 -22
- package/dist/node.d.ts +225 -86
- package/dist/node.js +30 -66
- package/dist/runtime.d.ts +6 -11
- package/dist/runtime.js +4 -5
- package/dist/spy.js +1 -1
- package/dist/task-utils.js +1 -2
- package/dist/worker.d.ts +5 -10
- package/dist/worker.js +24 -36
- package/dist/workers/forks.js +21 -33
- package/dist/workers/runVmTests.js +15 -20
- package/dist/workers/threads.js +21 -33
- package/dist/workers/vmForks.js +13 -15
- package/dist/workers/vmThreads.js +13 -15
- package/package.json +20 -20
- package/dist/chunks/_commonjsHelpers.D26ty3Ew.js +0 -6
- package/dist/chunks/coverage.d.Dn6XbyQq.d.ts +0 -43
- package/dist/chunks/globals.D2wDMk06.js +0 -33
- package/dist/chunks/index.6dZyLbho.js +0 -6918
- package/dist/chunks/nativeModuleRunner.WlMdOB52.js +0 -36
- package/dist/chunks/setup-common.DRlwpHsL.js +0 -64
|
@@ -1,22 +1,17 @@
|
|
|
1
|
-
import { T as TestSyntaxError, g as getCurrentTest, c as createTaskCollector,
|
|
1
|
+
import { b as printDiffOrStringify, d as diff, a as processError, T as TestSyntaxError, g as getCurrentTest, c as createTaskCollector, e as getCurrentSuite, f as createChainable, h as getHooks, i as getFn, m as matchesTags, j as afterAll, k as afterEach, l as aroundAll, n as aroundEach, o as beforeAll, q as beforeEach, r as describe, t as it, u as onTestFailed, v as onTestFinished, w as recordArtifact, x as suite, y as test } from './artifact.DC5WoEgy.js';
|
|
2
2
|
import { i as isChildProcess, r as resetModules, g as getWorkerState } from './utils.DYj33du9.js';
|
|
3
|
-
import { getSafeTimers, delay } from '
|
|
4
|
-
import { isMockFunction, fn, spyOn, restoreAllMocks, resetAllMocks, clearAllMocks } from '
|
|
5
|
-
import { getType, isObject, noop, assertTypes, ordinal, createSimpleStackTrace, getCallLastIndex } from '
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { R as RealDate, b as resetDate, m as mockDate, r as rpc, V as VitestEvaluatedModules } from './rpc.DZEh5xnQ.js';
|
|
3
|
+
import { h as commonjsGlobal, a as getSafeTimers, f as parseSingleStack, i as delay, d as getDefaultExportFromCjs, j as parseErrorStacktrace } from './source-map.DZdIqpIJ.js';
|
|
4
|
+
import { i as isMockFunction, f as fn, a as spyOn, r as restoreAllMocks, b as resetAllMocks, c as clearAllMocks } from './spy.B8mHA9qu.js';
|
|
5
|
+
import { g as getType, v as isObject, p as noop, y as assertTypes, x as ordinal, D as createSimpleStackTrace, E as getCallLastIndex, i as isAbsolute, a as relative, n as normalize } from './pathe.M-eThtNZ.CbK_Vbae.js';
|
|
6
|
+
import { R as RealDate, b as resetDate, m as mockDate, r as rpc, V as VitestEvaluatedModules } from './rpc.iNjF664v.js';
|
|
7
|
+
import { s as stringify, i as inspect } from './display.CYwyMF4S.js';
|
|
8
|
+
import { y } from './tinyrainbow.Ht9iggcq.js';
|
|
10
9
|
import * as chai from 'chai';
|
|
11
10
|
import { use, util } from 'chai';
|
|
12
11
|
import { getNames, getTests, getTestName, createFileTask } from '../task-utils.js';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { format } from '
|
|
16
|
-
import { printDiffOrStringify, diff } from '@vitest/utils/diff';
|
|
17
|
-
import { stringify, inspect } from '@vitest/utils/display';
|
|
18
|
-
import c from 'tinyrainbow';
|
|
19
|
-
import { isAbsolute, relative, normalize } from 'pathe';
|
|
12
|
+
import { g as getSerializers, a as addSerializer } from './plugins.CsoX-42X.js';
|
|
13
|
+
import { p as positionToOffset, o as offsetToLineNumber, l as lineSplitRE } from './offset.Dy-5Fdfn.js';
|
|
14
|
+
import { f as format } from './index.DzTmMrSM.js';
|
|
20
15
|
import { Bench } from 'tinybench';
|
|
21
16
|
import { expectTypeOf } from 'expect-type';
|
|
22
17
|
|
|
@@ -119,11 +114,11 @@ ${printReceived(actual)}`
|
|
|
119
114
|
}
|
|
120
115
|
};
|
|
121
116
|
|
|
122
|
-
const EXPECTED_COLOR =
|
|
123
|
-
const RECEIVED_COLOR =
|
|
124
|
-
const INVERTED_COLOR =
|
|
125
|
-
const BOLD_WEIGHT =
|
|
126
|
-
const DIM_COLOR =
|
|
117
|
+
const EXPECTED_COLOR = y.green;
|
|
118
|
+
const RECEIVED_COLOR = y.red;
|
|
119
|
+
const INVERTED_COLOR = y.inverse;
|
|
120
|
+
const BOLD_WEIGHT = y.bold;
|
|
121
|
+
const DIM_COLOR = y.dim;
|
|
127
122
|
function matcherHint(matcherName, received = "received", expected = "expected", options = {}) {
|
|
128
123
|
const { comment = "", isDirectExpectCall = false, isNot = false, promise = "", secondArgument = "", expectedColor = EXPECTED_COLOR, receivedColor = RECEIVED_COLOR, secondArgumentColor = EXPECTED_COLOR } = options;
|
|
129
124
|
let hint = "";
|
|
@@ -1449,25 +1444,25 @@ const JestChaiExpect = (chai, utils) => {
|
|
|
1449
1444
|
});
|
|
1450
1445
|
};
|
|
1451
1446
|
function formatCalls(spy, msg, showActualCall) {
|
|
1452
|
-
if (spy.mock.calls.length) msg +=
|
|
1453
|
-
let methodCall =
|
|
1447
|
+
if (spy.mock.calls.length) msg += y.gray(`\n\nReceived:\n\n${spy.mock.calls.map((callArg, i) => {
|
|
1448
|
+
let methodCall = y.bold(` ${ordinal(i + 1)} ${spy.getMockName()} call:\n\n`);
|
|
1454
1449
|
if (showActualCall) methodCall += diff(showActualCall, callArg, { omitAnnotationLines: true });
|
|
1455
1450
|
else methodCall += stringify(callArg).split("\n").map((line) => ` ${line}`).join("\n");
|
|
1456
1451
|
methodCall += "\n";
|
|
1457
1452
|
return methodCall;
|
|
1458
1453
|
}).join("\n")}`);
|
|
1459
|
-
msg +=
|
|
1454
|
+
msg += y.gray(`\n\nNumber of calls: ${y.bold(spy.mock.calls.length)}\n`);
|
|
1460
1455
|
return msg;
|
|
1461
1456
|
}
|
|
1462
1457
|
function formatReturns(spy, results, msg, showActualReturn) {
|
|
1463
|
-
if (results.length) msg +=
|
|
1464
|
-
let methodCall =
|
|
1458
|
+
if (results.length) msg += y.gray(`\n\nReceived:\n\n${results.map((callReturn, i) => {
|
|
1459
|
+
let methodCall = y.bold(` ${ordinal(i + 1)} ${spy.getMockName()} call return:\n\n`);
|
|
1465
1460
|
if (showActualReturn) methodCall += diff(showActualReturn, callReturn.value, { omitAnnotationLines: true });
|
|
1466
1461
|
else methodCall += stringify(callReturn).split("\n").map((line) => ` ${line}`).join("\n");
|
|
1467
1462
|
methodCall += "\n";
|
|
1468
1463
|
return methodCall;
|
|
1469
1464
|
}).join("\n")}`);
|
|
1470
|
-
msg +=
|
|
1465
|
+
msg += y.gray(`\n\nNumber of calls: ${y.bold(spy.mock.calls.length)}\n`);
|
|
1471
1466
|
return msg;
|
|
1472
1467
|
}
|
|
1473
1468
|
|
|
@@ -2729,15 +2724,35 @@ function requireFakeTimersSrc () {
|
|
|
2729
2724
|
* @returns {void}
|
|
2730
2725
|
*/
|
|
2731
2726
|
|
|
2727
|
+
/**
|
|
2728
|
+
* @typedef {object} TemporalDuration
|
|
2729
|
+
* @property {number} years - years component
|
|
2730
|
+
* @property {number} months - months component
|
|
2731
|
+
* @property {number} weeks - weeks component
|
|
2732
|
+
* @property {number} days - days component
|
|
2733
|
+
* @property {number} hours - hours component
|
|
2734
|
+
* @property {number} minutes - minutes component
|
|
2735
|
+
* @property {number} seconds - seconds component
|
|
2736
|
+
* @property {number} milliseconds - milliseconds component
|
|
2737
|
+
* @property {number} microseconds - microseconds component
|
|
2738
|
+
* @property {number} nanoseconds - nanoseconds component
|
|
2739
|
+
* @property {(options: {unit: string, relativeTo?: unknown}) => number} total - converts to a single unit
|
|
2740
|
+
*/
|
|
2741
|
+
|
|
2742
|
+
/**
|
|
2743
|
+
* @typedef {object} TemporalTimelike
|
|
2744
|
+
* @property {number} epochMilliseconds - milliseconds since the Unix epoch (present on Temporal.Instant and Temporal.ZonedDateTime)
|
|
2745
|
+
*/
|
|
2746
|
+
|
|
2732
2747
|
/**
|
|
2733
2748
|
* @callback Tick
|
|
2734
|
-
* @param {number|string} tickValue milliseconds
|
|
2749
|
+
* @param {number|string|TemporalDuration} tickValue milliseconds, a string parseable by parseTime, or a Temporal.Duration
|
|
2735
2750
|
* @returns {number} will return the new `now` value
|
|
2736
2751
|
*/
|
|
2737
2752
|
|
|
2738
2753
|
/**
|
|
2739
2754
|
* @callback TickAsync
|
|
2740
|
-
* @param {number|string} tickValue milliseconds
|
|
2755
|
+
* @param {number|string|TemporalDuration} tickValue milliseconds, a string parseable by parseTime, or a Temporal.Duration
|
|
2741
2756
|
* @returns {Promise<number>}
|
|
2742
2757
|
*/
|
|
2743
2758
|
|
|
@@ -2783,13 +2798,13 @@ function requireFakeTimersSrc () {
|
|
|
2783
2798
|
|
|
2784
2799
|
/**
|
|
2785
2800
|
* @callback SetSystemTime
|
|
2786
|
-
* @param {number|Date} [now] initial mocked time, as milliseconds since epoch or a
|
|
2801
|
+
* @param {number|Date|TemporalTimelike} [now] initial mocked time, as milliseconds since epoch, a Date, a Temporal.Instant, or a Temporal.ZonedDateTime
|
|
2787
2802
|
* @returns {void}
|
|
2788
2803
|
*/
|
|
2789
2804
|
|
|
2790
2805
|
/**
|
|
2791
2806
|
* @callback Jump
|
|
2792
|
-
* @param {number|string} tickValue milliseconds
|
|
2807
|
+
* @param {number|string|TemporalDuration} tickValue milliseconds, a human-readable value like "01:11:15", or a Temporal.Duration
|
|
2793
2808
|
* @returns {number}
|
|
2794
2809
|
*/
|
|
2795
2810
|
|
|
@@ -2817,7 +2832,7 @@ function requireFakeTimersSrc () {
|
|
|
2817
2832
|
*/
|
|
2818
2833
|
|
|
2819
2834
|
/**
|
|
2820
|
-
* @typedef {"setTimeout" | "clearTimeout" | "setImmediate" | "clearImmediate" | "setInterval" | "clearInterval" | "Date" | "nextTick" | "hrtime" | "requestAnimationFrame" | "cancelAnimationFrame" | "requestIdleCallback" | "cancelIdleCallback" | "performance" | "queueMicrotask"} FakeMethod
|
|
2835
|
+
* @typedef {"setTimeout" | "clearTimeout" | "setImmediate" | "clearImmediate" | "setInterval" | "clearInterval" | "Date" | "nextTick" | "hrtime" | "requestAnimationFrame" | "cancelAnimationFrame" | "requestIdleCallback" | "cancelIdleCallback" | "performance" | "queueMicrotask" | "Intl" | "Temporal"} FakeMethod
|
|
2821
2836
|
*/
|
|
2822
2837
|
|
|
2823
2838
|
/**
|
|
@@ -2842,6 +2857,7 @@ function requireFakeTimersSrc () {
|
|
|
2842
2857
|
* performance?: any,
|
|
2843
2858
|
* Performance?: any,
|
|
2844
2859
|
* Intl?: any,
|
|
2860
|
+
* Temporal?: any,
|
|
2845
2861
|
* Promise?: typeof Promise,
|
|
2846
2862
|
* Date: typeof Date & { isFake?: boolean, toSource?: () => string, clock?: any }
|
|
2847
2863
|
* }} GlobalObject
|
|
@@ -2873,6 +2889,10 @@ function requireFakeTimersSrc () {
|
|
|
2873
2889
|
* @typedef {Record<string, any> & { clock: Clock }} IntlWithClock
|
|
2874
2890
|
*/
|
|
2875
2891
|
|
|
2892
|
+
/**
|
|
2893
|
+
* @typedef {Record<string, any> & { now: () => number }} PerformanceLike
|
|
2894
|
+
*/
|
|
2895
|
+
|
|
2876
2896
|
/**
|
|
2877
2897
|
* @typedef {object} Timers
|
|
2878
2898
|
* @property {SetTimeout} setTimeout - native `setTimeout`
|
|
@@ -2881,11 +2901,12 @@ function requireFakeTimersSrc () {
|
|
|
2881
2901
|
* @property {ClearInterval} clearInterval - native `clearInterval`
|
|
2882
2902
|
* @property {typeof Date} Date - native `Date`
|
|
2883
2903
|
* @property {typeof Intl} [Intl] - native `Intl`
|
|
2904
|
+
* @property {any} [Temporal] - native `Temporal`
|
|
2884
2905
|
* @property {SetImmediate} [setImmediate] - native `setImmediate`, if available
|
|
2885
2906
|
* @property {ClearImmediate} [clearImmediate] - native `clearImmediate`, if available
|
|
2886
2907
|
* @property {Hrtime} [hrtime] - native `process.hrtime`, if available
|
|
2887
2908
|
* @property {NextTick} [nextTick] - native `process.nextTick`, if available
|
|
2888
|
-
* @property {
|
|
2909
|
+
* @property {PerformanceLike} [performance] - native `performance`, if available
|
|
2889
2910
|
* @property {RequestAnimationFrame} [requestAnimationFrame] - native `requestAnimationFrame`, if available
|
|
2890
2911
|
* @property {QueueMicrotask} [queueMicrotask] - whether `queueMicrotask` exists
|
|
2891
2912
|
* @property {CancelAnimationFrame} [cancelAnimationFrame] - native `cancelAnimationFrame`, if available
|
|
@@ -2926,7 +2947,7 @@ function requireFakeTimersSrc () {
|
|
|
2926
2947
|
|
|
2927
2948
|
/**
|
|
2928
2949
|
* @callback CreateClockCallback
|
|
2929
|
-
* @param {number|Date} [start] initial mocked time, as milliseconds since epoch or a
|
|
2950
|
+
* @param {number|Date|TemporalTimelike} [start] initial mocked time, as milliseconds since epoch, a Date, a Temporal.Instant, or a Temporal.ZonedDateTime
|
|
2930
2951
|
* @param {number} [loopLimit] maximum number of timers run before aborting with an infinite-loop error
|
|
2931
2952
|
* @returns {Clock}
|
|
2932
2953
|
*/
|
|
@@ -2993,13 +3014,14 @@ function requireFakeTimersSrc () {
|
|
|
2993
3014
|
* @property {ClockTickMode} [tickMode] - internal flag
|
|
2994
3015
|
* @property {Timer[]} [jobs] - internal flag
|
|
2995
3016
|
* @property {IntlWithClock} [Intl] - fake Intl object
|
|
3017
|
+
* @property {any} [Temporal] - fake Temporal object
|
|
2996
3018
|
*/
|
|
2997
3019
|
/* eslint-enable jsdoc/reject-any-type */
|
|
2998
3020
|
|
|
2999
3021
|
/**
|
|
3000
3022
|
* Configuration object for the `install` method.
|
|
3001
3023
|
* @typedef {object} Config
|
|
3002
|
-
* @property {number|Date} [now] initial mocked time, as milliseconds since epoch or a
|
|
3024
|
+
* @property {number|Date|TemporalTimelike} [now] initial mocked time, as milliseconds since epoch, a Date, a Temporal.Instant, or a Temporal.ZonedDateTime
|
|
3003
3025
|
* @property {FakeMethod[]} [toFake] method names that should be faked
|
|
3004
3026
|
* @property {FakeMethod[]} [toNotFake] method names that should remain native
|
|
3005
3027
|
* @property {number} [loopLimit] maximum number of timers run before aborting with an infinite-loop error
|
|
@@ -3108,6 +3130,11 @@ function requireFakeTimersSrc () {
|
|
|
3108
3130
|
isPresent.clearImmediate =
|
|
3109
3131
|
_global.clearImmediate && typeof _global.clearImmediate === "function";
|
|
3110
3132
|
isPresent.Intl = _global.Intl && typeof _global.Intl === "object";
|
|
3133
|
+
isPresent.Temporal =
|
|
3134
|
+
_global.Temporal !== null &&
|
|
3135
|
+
typeof _global.Temporal === "object" &&
|
|
3136
|
+
typeof _global.Temporal.Now !== "undefined" &&
|
|
3137
|
+
typeof _global.Temporal.Instant !== "undefined";
|
|
3111
3138
|
|
|
3112
3139
|
if (_global.clearTimeout) {
|
|
3113
3140
|
_global.clearTimeout(timeoutResult);
|
|
@@ -3120,6 +3147,7 @@ function requireFakeTimersSrc () {
|
|
|
3120
3147
|
Object.getOwnPropertyDescriptors(_global.Intl),
|
|
3121
3148
|
)
|
|
3122
3149
|
: undefined;
|
|
3150
|
+
const NativeTemporal = isPresent.Temporal ? _global.Temporal : undefined;
|
|
3123
3151
|
let uniqueTimerId = idCounterStart;
|
|
3124
3152
|
/** @type {number} */
|
|
3125
3153
|
let uniqueTimerOrder = 0;
|
|
@@ -3237,7 +3265,7 @@ function requireFakeTimersSrc () {
|
|
|
3237
3265
|
|
|
3238
3266
|
/**
|
|
3239
3267
|
* Used to grok the `now` parameter to createClock.
|
|
3240
|
-
* @param {Date|number} epoch the system time
|
|
3268
|
+
* @param {Date|number|TemporalTimelike} epoch the system time
|
|
3241
3269
|
* @returns {number}
|
|
3242
3270
|
*/
|
|
3243
3271
|
function getEpoch(epoch) {
|
|
@@ -3247,8 +3275,16 @@ function requireFakeTimersSrc () {
|
|
|
3247
3275
|
if (typeof epoch === "number") {
|
|
3248
3276
|
return epoch;
|
|
3249
3277
|
}
|
|
3250
|
-
if (typeof epoch.getTime === "function") {
|
|
3251
|
-
return epoch.getTime();
|
|
3278
|
+
if (typeof (/** @type {Date} */ (epoch).getTime) === "function") {
|
|
3279
|
+
return /** @type {Date} */ (epoch).getTime();
|
|
3280
|
+
}
|
|
3281
|
+
if (
|
|
3282
|
+
typeof (
|
|
3283
|
+
/** @type {TemporalTimelike} */ (epoch).epochMilliseconds
|
|
3284
|
+
) === "number"
|
|
3285
|
+
) {
|
|
3286
|
+
// Temporal.Instant and Temporal.ZonedDateTime both have epochMilliseconds
|
|
3287
|
+
return /** @type {TemporalTimelike} */ (epoch).epochMilliseconds;
|
|
3252
3288
|
}
|
|
3253
3289
|
throw new TypeError("now should be milliseconds since UNIX epoch");
|
|
3254
3290
|
}
|
|
@@ -3465,6 +3501,56 @@ function requireFakeTimersSrc () {
|
|
|
3465
3501
|
return IntlWithClock;
|
|
3466
3502
|
}
|
|
3467
3503
|
|
|
3504
|
+
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
3505
|
+
function createTemporal(clock, getNanos) {
|
|
3506
|
+
const fakeNow = {
|
|
3507
|
+
instant() {
|
|
3508
|
+
return NativeTemporal.Instant.fromEpochNanoseconds(
|
|
3509
|
+
BigInt(clock.now) * 1_000_000n + BigInt(getNanos()),
|
|
3510
|
+
);
|
|
3511
|
+
},
|
|
3512
|
+
timeZoneId() {
|
|
3513
|
+
return NativeTemporal.Now.timeZoneId();
|
|
3514
|
+
},
|
|
3515
|
+
zonedDateTimeISO(timeZone) {
|
|
3516
|
+
const tz = timeZone ?? NativeTemporal.Now.timeZoneId();
|
|
3517
|
+
return fakeNow.instant().toZonedDateTimeISO(tz);
|
|
3518
|
+
},
|
|
3519
|
+
plainDateTimeISO(timeZone) {
|
|
3520
|
+
return fakeNow.zonedDateTimeISO(timeZone).toPlainDateTime();
|
|
3521
|
+
},
|
|
3522
|
+
plainDateISO(timeZone) {
|
|
3523
|
+
return fakeNow.zonedDateTimeISO(timeZone).toPlainDate();
|
|
3524
|
+
},
|
|
3525
|
+
plainTimeISO(timeZone) {
|
|
3526
|
+
return fakeNow.zonedDateTimeISO(timeZone).toPlainTime();
|
|
3527
|
+
},
|
|
3528
|
+
};
|
|
3529
|
+
|
|
3530
|
+
const TemporalWithClock = Object.create(
|
|
3531
|
+
Object.getPrototypeOf(NativeTemporal),
|
|
3532
|
+
);
|
|
3533
|
+
[
|
|
3534
|
+
...Object.getOwnPropertyNames(NativeTemporal),
|
|
3535
|
+
...Object.getOwnPropertySymbols(NativeTemporal),
|
|
3536
|
+
].forEach((prop) => {
|
|
3537
|
+
Object.defineProperty(
|
|
3538
|
+
TemporalWithClock,
|
|
3539
|
+
prop,
|
|
3540
|
+
Object.getOwnPropertyDescriptor(NativeTemporal, prop),
|
|
3541
|
+
);
|
|
3542
|
+
});
|
|
3543
|
+
// Temporal.Now is writable:false in the spec so we must use defineProperty
|
|
3544
|
+
Object.defineProperty(TemporalWithClock, "Now", {
|
|
3545
|
+
value: fakeNow,
|
|
3546
|
+
writable: true,
|
|
3547
|
+
enumerable: false,
|
|
3548
|
+
configurable: true,
|
|
3549
|
+
});
|
|
3550
|
+
|
|
3551
|
+
return TemporalWithClock;
|
|
3552
|
+
}
|
|
3553
|
+
|
|
3468
3554
|
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
3469
3555
|
function enqueueJob(clock, job) {
|
|
3470
3556
|
// enqueues a microtick-deferred task - ecma262/#sec-enqueuejob
|
|
@@ -4099,85 +4185,6 @@ function requireFakeTimersSrc () {
|
|
|
4099
4185
|
}
|
|
4100
4186
|
}
|
|
4101
4187
|
|
|
4102
|
-
/**
|
|
4103
|
-
* @param {Clock} clock
|
|
4104
|
-
* @returns {Timer[]}
|
|
4105
|
-
*/
|
|
4106
|
-
function uninstall(clock) {
|
|
4107
|
-
let method, i, l;
|
|
4108
|
-
const installedHrTime = "_hrtime";
|
|
4109
|
-
const installedNextTick = "_nextTick";
|
|
4110
|
-
|
|
4111
|
-
for (i = 0, l = clock.methods.length; i < l; i++) {
|
|
4112
|
-
method = clock.methods[i];
|
|
4113
|
-
if (method === "hrtime" && _global.process) {
|
|
4114
|
-
_global.process.hrtime = clock[installedHrTime];
|
|
4115
|
-
} else if (method === "nextTick" && _global.process) {
|
|
4116
|
-
_global.process.nextTick = clock[installedNextTick];
|
|
4117
|
-
} else if (method === "performance") {
|
|
4118
|
-
const originalPerfDescriptor = Object.getOwnPropertyDescriptor(
|
|
4119
|
-
clock,
|
|
4120
|
-
`_${method}`,
|
|
4121
|
-
);
|
|
4122
|
-
if (
|
|
4123
|
-
originalPerfDescriptor &&
|
|
4124
|
-
originalPerfDescriptor.get &&
|
|
4125
|
-
!originalPerfDescriptor.set
|
|
4126
|
-
) {
|
|
4127
|
-
Object.defineProperty(
|
|
4128
|
-
_global,
|
|
4129
|
-
method,
|
|
4130
|
-
originalPerfDescriptor,
|
|
4131
|
-
);
|
|
4132
|
-
} else if (originalPerfDescriptor.configurable) {
|
|
4133
|
-
_global[method] = clock[`_${method}`];
|
|
4134
|
-
}
|
|
4135
|
-
} else {
|
|
4136
|
-
if (clock[method] && clock[method].hasOwnProperty) {
|
|
4137
|
-
_global[method] = clock[`_${method}`];
|
|
4138
|
-
} else {
|
|
4139
|
-
try {
|
|
4140
|
-
delete _global[method];
|
|
4141
|
-
} catch {
|
|
4142
|
-
/* eslint no-empty: "off" */
|
|
4143
|
-
}
|
|
4144
|
-
}
|
|
4145
|
-
}
|
|
4146
|
-
if (clock.timersModuleMethods !== undefined) {
|
|
4147
|
-
for (let j = 0; j < clock.timersModuleMethods.length; j++) {
|
|
4148
|
-
const entry = clock.timersModuleMethods[j];
|
|
4149
|
-
timersModule[entry.methodName] = entry.original;
|
|
4150
|
-
}
|
|
4151
|
-
}
|
|
4152
|
-
if (clock.timersPromisesModuleMethods !== undefined) {
|
|
4153
|
-
for (
|
|
4154
|
-
let j = 0;
|
|
4155
|
-
j < clock.timersPromisesModuleMethods.length;
|
|
4156
|
-
j++
|
|
4157
|
-
) {
|
|
4158
|
-
const entry = clock.timersPromisesModuleMethods[j];
|
|
4159
|
-
timersPromisesModule[entry.methodName] = entry.original;
|
|
4160
|
-
}
|
|
4161
|
-
}
|
|
4162
|
-
}
|
|
4163
|
-
|
|
4164
|
-
clock.setTickMode({ mode: "manual" });
|
|
4165
|
-
|
|
4166
|
-
// Prevent multiple executions which will completely remove these props
|
|
4167
|
-
clock.methods = [];
|
|
4168
|
-
|
|
4169
|
-
for (const [listener, signal] of clock.abortListenerMap.entries()) {
|
|
4170
|
-
signal.removeEventListener("abort", listener);
|
|
4171
|
-
clock.abortListenerMap.delete(listener);
|
|
4172
|
-
}
|
|
4173
|
-
|
|
4174
|
-
// return pending timers, to enable checking what timers remained on uninstall
|
|
4175
|
-
if (!clock.timerHeap) {
|
|
4176
|
-
return [];
|
|
4177
|
-
}
|
|
4178
|
-
return clock.timerHeap.timers.slice();
|
|
4179
|
-
}
|
|
4180
|
-
|
|
4181
4188
|
/**
|
|
4182
4189
|
* @param {object} target the target containing the method to replace
|
|
4183
4190
|
* @param {string} method the keyname of the method on the target
|
|
@@ -4194,6 +4201,8 @@ function requireFakeTimersSrc () {
|
|
|
4194
4201
|
target[method] = clock[method];
|
|
4195
4202
|
} else if (method === "Intl") {
|
|
4196
4203
|
target[method] = clock[method];
|
|
4204
|
+
} else if (method === "Temporal") {
|
|
4205
|
+
target[method] = clock[method];
|
|
4197
4206
|
} else if (method === "performance") {
|
|
4198
4207
|
const originalPerfDescriptor = Object.getOwnPropertyDescriptor(
|
|
4199
4208
|
target,
|
|
@@ -4294,12 +4303,16 @@ function requireFakeTimersSrc () {
|
|
|
4294
4303
|
timers.Intl = NativeIntl;
|
|
4295
4304
|
}
|
|
4296
4305
|
|
|
4306
|
+
if (isPresent.Temporal) {
|
|
4307
|
+
timers.Temporal = NativeTemporal;
|
|
4308
|
+
}
|
|
4309
|
+
|
|
4297
4310
|
const originalSetTimeout = _global.setImmediate || _global.setTimeout;
|
|
4298
4311
|
const originalClearInterval = _global.clearInterval;
|
|
4299
4312
|
const originalSetInterval = _global.setInterval;
|
|
4300
4313
|
|
|
4301
4314
|
/**
|
|
4302
|
-
* @param {Date|number} [start] the system time - non-integer values are floored
|
|
4315
|
+
* @param {Date|number|TemporalTimelike} [start] the system time - non-integer values are floored
|
|
4303
4316
|
* @param {number} [loopLimit] maximum number of timers that will be run when calling runAll()
|
|
4304
4317
|
* @returns {Clock}
|
|
4305
4318
|
*/
|
|
@@ -4312,6 +4325,7 @@ function requireFakeTimersSrc () {
|
|
|
4312
4325
|
loopLimit = loopLimit || 1000;
|
|
4313
4326
|
/** @type {number} */
|
|
4314
4327
|
let nanos = 0;
|
|
4328
|
+
let uninstalled = false;
|
|
4315
4329
|
/** @type {number[]} */
|
|
4316
4330
|
const adjustedSystemTime = [0, 0]; // [millis, nanoremainder]
|
|
4317
4331
|
|
|
@@ -4389,6 +4403,10 @@ function requireFakeTimersSrc () {
|
|
|
4389
4403
|
clock.Intl.clock = clock;
|
|
4390
4404
|
}
|
|
4391
4405
|
|
|
4406
|
+
if (isPresent.Temporal) {
|
|
4407
|
+
clock.Temporal = createTemporal(clock, () => nanos);
|
|
4408
|
+
}
|
|
4409
|
+
|
|
4392
4410
|
/**
|
|
4393
4411
|
* @param {SetTickModeConfig} tickModeConfig - The new configuration for how the clock should tick.
|
|
4394
4412
|
*/
|
|
@@ -4467,7 +4485,9 @@ function requireFakeTimersSrc () {
|
|
|
4467
4485
|
}
|
|
4468
4486
|
clock.setTickMode({ mode: "manual" });
|
|
4469
4487
|
return promise.finally(() => {
|
|
4470
|
-
|
|
4488
|
+
if (!uninstalled) {
|
|
4489
|
+
clock.setTickMode({ mode: "nextAsync" });
|
|
4490
|
+
}
|
|
4471
4491
|
});
|
|
4472
4492
|
}
|
|
4473
4493
|
|
|
@@ -4623,15 +4643,44 @@ function requireFakeTimersSrc () {
|
|
|
4623
4643
|
runJobs(clock);
|
|
4624
4644
|
};
|
|
4625
4645
|
|
|
4646
|
+
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
4647
|
+
function durationToMs(duration) {
|
|
4648
|
+
// relativeTo uses the real system timezone — fake-timers fakes time, not place.
|
|
4649
|
+
// Calendar-unit durations (months, years) will resolve DST/length using the host tz.
|
|
4650
|
+
const relativeTo = NativeTemporal.Instant.fromEpochMilliseconds(
|
|
4651
|
+
clock.now,
|
|
4652
|
+
).toZonedDateTimeISO(NativeTemporal.Now.timeZoneId());
|
|
4653
|
+
return duration.total({ unit: "millisecond", relativeTo });
|
|
4654
|
+
}
|
|
4655
|
+
|
|
4656
|
+
/**
|
|
4657
|
+
* @param {number|string|TemporalDuration} tickValue
|
|
4658
|
+
* @returns {number} milliseconds as a float
|
|
4659
|
+
*/
|
|
4660
|
+
function tickValueToMs(tickValue) {
|
|
4661
|
+
if (typeof tickValue === "number") {
|
|
4662
|
+
return tickValue;
|
|
4663
|
+
}
|
|
4664
|
+
if (
|
|
4665
|
+
isPresent.Temporal &&
|
|
4666
|
+
tickValue !== null &&
|
|
4667
|
+
typeof tickValue === "object" &&
|
|
4668
|
+
typeof (/** @type {TemporalDuration} */ (tickValue).total) ===
|
|
4669
|
+
"function"
|
|
4670
|
+
) {
|
|
4671
|
+
return durationToMs(
|
|
4672
|
+
/** @type {TemporalDuration} */ (tickValue),
|
|
4673
|
+
);
|
|
4674
|
+
}
|
|
4675
|
+
return parseTime(/** @type {string} */ (tickValue));
|
|
4676
|
+
}
|
|
4677
|
+
|
|
4626
4678
|
/**
|
|
4627
|
-
* @param {number|string} tickValue milliseconds
|
|
4679
|
+
* @param {number|string|TemporalDuration} tickValue milliseconds, a string parseable by parseTime, or a Temporal.Duration
|
|
4628
4680
|
* @returns {ClockState} a mutable state object for the tick execution
|
|
4629
4681
|
*/
|
|
4630
4682
|
function createTickState(tickValue) {
|
|
4631
|
-
const msFloat =
|
|
4632
|
-
typeof tickValue === "number"
|
|
4633
|
-
? tickValue
|
|
4634
|
-
: parseTime(tickValue);
|
|
4683
|
+
const msFloat = tickValueToMs(tickValue);
|
|
4635
4684
|
const ms = Math.floor(msFloat);
|
|
4636
4685
|
const remainder = nanoRemainder(msFloat);
|
|
4637
4686
|
let nanosTotal = nanos + remainder;
|
|
@@ -4792,7 +4841,7 @@ function requireFakeTimersSrc () {
|
|
|
4792
4841
|
}
|
|
4793
4842
|
|
|
4794
4843
|
/**
|
|
4795
|
-
* @param {number|string} tickValue milliseconds or a string parseable by parseTime
|
|
4844
|
+
* @param {number|string|TemporalDuration} tickValue milliseconds or a string parseable by parseTime
|
|
4796
4845
|
* @param {boolean} isAsync whether this is an async tick
|
|
4797
4846
|
* @param {FakeTimersFunction} [resolve] promise resolve function
|
|
4798
4847
|
* @param {FakeTimersFunction} [reject] promise reject function
|
|
@@ -4848,7 +4897,7 @@ function requireFakeTimersSrc () {
|
|
|
4848
4897
|
}
|
|
4849
4898
|
|
|
4850
4899
|
/**
|
|
4851
|
-
* @param {string|number} tickValue number of milliseconds
|
|
4900
|
+
* @param {string|number|TemporalDuration} tickValue number of milliseconds, a human-readable value like "01:11:15", or a Temporal.Duration
|
|
4852
4901
|
* @returns {number} will return the new `now` value
|
|
4853
4902
|
*/
|
|
4854
4903
|
clock.tick = function tick(tickValue) {
|
|
@@ -4929,7 +4978,7 @@ function requireFakeTimersSrc () {
|
|
|
4929
4978
|
|
|
4930
4979
|
if (typeof _global.Promise !== "undefined") {
|
|
4931
4980
|
/**
|
|
4932
|
-
* @param {string|number} tickValue number of milliseconds
|
|
4981
|
+
* @param {string|number|TemporalDuration} tickValue number of milliseconds, a human-readable value like "01:11:15", or a Temporal.Duration
|
|
4933
4982
|
* @returns {Promise}
|
|
4934
4983
|
*/
|
|
4935
4984
|
clock.tickAsync = function tickAsync(tickValue) {
|
|
@@ -5055,14 +5104,11 @@ function requireFakeTimersSrc () {
|
|
|
5055
5104
|
};
|
|
5056
5105
|
|
|
5057
5106
|
/**
|
|
5058
|
-
* @param {string|number} tickValue number of milliseconds
|
|
5107
|
+
* @param {string|number|TemporalDuration} tickValue number of milliseconds, a human-readable value like "01:11:15", or a Temporal.Duration
|
|
5059
5108
|
* @returns {number} the new `now` value
|
|
5060
5109
|
*/
|
|
5061
5110
|
clock.jump = function jump(tickValue) {
|
|
5062
|
-
const msFloat =
|
|
5063
|
-
typeof tickValue === "number"
|
|
5064
|
-
? tickValue
|
|
5065
|
-
: parseTime(tickValue);
|
|
5111
|
+
const msFloat = tickValueToMs(tickValue);
|
|
5066
5112
|
const ms = Math.floor(msFloat);
|
|
5067
5113
|
|
|
5068
5114
|
forEachActiveTimer(clock, (timer) => {
|
|
@@ -5087,6 +5133,97 @@ function requireFakeTimersSrc () {
|
|
|
5087
5133
|
clock.hrtime = hrtime;
|
|
5088
5134
|
}
|
|
5089
5135
|
|
|
5136
|
+
/**
|
|
5137
|
+
* @returns {Timer[]}
|
|
5138
|
+
*/
|
|
5139
|
+
clock.uninstall = function () {
|
|
5140
|
+
uninstalled = true;
|
|
5141
|
+
clock.setTickMode({ mode: "manual" });
|
|
5142
|
+
|
|
5143
|
+
if (clock.methods) {
|
|
5144
|
+
const installedHrTime = "_hrtime";
|
|
5145
|
+
const installedNextTick = "_nextTick";
|
|
5146
|
+
let method, i, l;
|
|
5147
|
+
for (i = 0, l = clock.methods.length; i < l; i++) {
|
|
5148
|
+
method = clock.methods[i];
|
|
5149
|
+
if (method === "hrtime" && _global.process) {
|
|
5150
|
+
_global.process.hrtime = clock[installedHrTime];
|
|
5151
|
+
} else if (method === "nextTick" && _global.process) {
|
|
5152
|
+
_global.process.nextTick = clock[installedNextTick];
|
|
5153
|
+
} else if (method === "performance") {
|
|
5154
|
+
const originalPerfDescriptor =
|
|
5155
|
+
Object.getOwnPropertyDescriptor(
|
|
5156
|
+
clock,
|
|
5157
|
+
`_${method}`,
|
|
5158
|
+
);
|
|
5159
|
+
if (
|
|
5160
|
+
originalPerfDescriptor &&
|
|
5161
|
+
originalPerfDescriptor.get &&
|
|
5162
|
+
!originalPerfDescriptor.set
|
|
5163
|
+
) {
|
|
5164
|
+
Object.defineProperty(
|
|
5165
|
+
_global,
|
|
5166
|
+
method,
|
|
5167
|
+
originalPerfDescriptor,
|
|
5168
|
+
);
|
|
5169
|
+
} else if (originalPerfDescriptor.configurable) {
|
|
5170
|
+
_global[method] = clock[`_${method}`];
|
|
5171
|
+
}
|
|
5172
|
+
} else {
|
|
5173
|
+
if (clock[method] && clock[method].hasOwnProperty) {
|
|
5174
|
+
_global[method] = clock[`_${method}`];
|
|
5175
|
+
} else {
|
|
5176
|
+
try {
|
|
5177
|
+
delete _global[method];
|
|
5178
|
+
} catch {
|
|
5179
|
+
/* eslint no-empty: "off" */
|
|
5180
|
+
}
|
|
5181
|
+
}
|
|
5182
|
+
}
|
|
5183
|
+
if (clock.timersModuleMethods !== undefined) {
|
|
5184
|
+
for (
|
|
5185
|
+
let j = 0;
|
|
5186
|
+
j < clock.timersModuleMethods.length;
|
|
5187
|
+
j++
|
|
5188
|
+
) {
|
|
5189
|
+
const entry = clock.timersModuleMethods[j];
|
|
5190
|
+
timersModule[entry.methodName] = entry.original;
|
|
5191
|
+
}
|
|
5192
|
+
}
|
|
5193
|
+
if (clock.timersPromisesModuleMethods !== undefined) {
|
|
5194
|
+
for (
|
|
5195
|
+
let j = 0;
|
|
5196
|
+
j < clock.timersPromisesModuleMethods.length;
|
|
5197
|
+
j++
|
|
5198
|
+
) {
|
|
5199
|
+
const entry = clock.timersPromisesModuleMethods[j];
|
|
5200
|
+
timersPromisesModule[entry.methodName] =
|
|
5201
|
+
entry.original;
|
|
5202
|
+
}
|
|
5203
|
+
}
|
|
5204
|
+
}
|
|
5205
|
+
|
|
5206
|
+
// Prevent multiple executions which will completely remove these props
|
|
5207
|
+
clock.methods = [];
|
|
5208
|
+
}
|
|
5209
|
+
|
|
5210
|
+
if (clock.abortListenerMap) {
|
|
5211
|
+
for (const [
|
|
5212
|
+
listener,
|
|
5213
|
+
signal,
|
|
5214
|
+
] of clock.abortListenerMap.entries()) {
|
|
5215
|
+
signal.removeEventListener("abort", listener);
|
|
5216
|
+
clock.abortListenerMap.delete(listener);
|
|
5217
|
+
}
|
|
5218
|
+
}
|
|
5219
|
+
|
|
5220
|
+
// return pending timers, to enable checking what timers remained on uninstall
|
|
5221
|
+
if (!clock.timerHeap) {
|
|
5222
|
+
return [];
|
|
5223
|
+
}
|
|
5224
|
+
return clock.timerHeap.timers.slice();
|
|
5225
|
+
};
|
|
5226
|
+
|
|
5090
5227
|
return clock;
|
|
5091
5228
|
}
|
|
5092
5229
|
|
|
@@ -5175,10 +5312,6 @@ function requireFakeTimersSrc () {
|
|
|
5175
5312
|
const clock = createClock(config.now, config.loopLimit);
|
|
5176
5313
|
clock.shouldClearNativeTimers = config.shouldClearNativeTimers;
|
|
5177
5314
|
|
|
5178
|
-
clock.uninstall = function () {
|
|
5179
|
-
return uninstall(clock);
|
|
5180
|
-
};
|
|
5181
|
-
|
|
5182
5315
|
clock.abortListenerMap = new Map();
|
|
5183
5316
|
|
|
5184
5317
|
if (hasToFake) {
|
|
@@ -5692,6 +5825,235 @@ class FakeTimers {
|
|
|
5692
5825
|
}
|
|
5693
5826
|
}
|
|
5694
5827
|
|
|
5828
|
+
const whenSymbol = Symbol.for("$$vitest:when");
|
|
5829
|
+
/**
|
|
5830
|
+
* Returns `true` if the given value is a {@linkcode When} chain created by {@linkcode when|vi.when}.
|
|
5831
|
+
*
|
|
5832
|
+
* @param input - The value to check.
|
|
5833
|
+
* @returns `true` if `input` is a {@linkcode When} instance, `false` otherwise.
|
|
5834
|
+
*
|
|
5835
|
+
* @example
|
|
5836
|
+
* const spy = vi.fn()
|
|
5837
|
+
* const w = vi.when(spy).calledWith(1).thenReturn(0)
|
|
5838
|
+
*
|
|
5839
|
+
* expect(isWhenChain(w)).toBe(true)
|
|
5840
|
+
* expect(isWhenChain(spy)).toBe(false)
|
|
5841
|
+
*/
|
|
5842
|
+
function isWhenChain(input) {
|
|
5843
|
+
try {
|
|
5844
|
+
return Reflect.has(input, whenSymbol);
|
|
5845
|
+
} catch {
|
|
5846
|
+
return false;
|
|
5847
|
+
}
|
|
5848
|
+
}
|
|
5849
|
+
/**
|
|
5850
|
+
* Defines conditional behaviors on a Vitest spy based on the arguments it is called with.
|
|
5851
|
+
*
|
|
5852
|
+
* Behaviors are matched using deep equality, last-registered first within each argument set.
|
|
5853
|
+
*
|
|
5854
|
+
* It automatically restores the spy's original implementation when the enclosing block exits if used with the `using` keyword.
|
|
5855
|
+
*
|
|
5856
|
+
* @param spy - A Vitest mock function to attach behaviors to.
|
|
5857
|
+
* @param options - Optional configuration.
|
|
5858
|
+
* @returns A {@linkcode When} instance for registering behaviors.
|
|
5859
|
+
*
|
|
5860
|
+
* @throws {TypeError} If `spy` is not a Vitest mock function.
|
|
5861
|
+
* @throws {Error} If chaining a non-existent method after `calledWith`.
|
|
5862
|
+
* @throws {RangeError} If setting the `times` option on a `then*` method as a negative value or `0`.
|
|
5863
|
+
*
|
|
5864
|
+
* @since 5.0.0
|
|
5865
|
+
* @see {@link https://vitest.dev/api/vi#vi-when}
|
|
5866
|
+
* @see {@link https://vitest.dev/guide/recipes/conditional-mocking}
|
|
5867
|
+
*
|
|
5868
|
+
* @example
|
|
5869
|
+
* // Basic usage
|
|
5870
|
+
* const spy = vi.fn(() => Number.NEGATIVE_INFINITY)
|
|
5871
|
+
* vi.when(spy).calledWith(1).thenReturn(0)
|
|
5872
|
+
*
|
|
5873
|
+
* expect(spy(1)).toBe(0)
|
|
5874
|
+
* expect(spy(2)).toBe(Number.NEGATIVE_INFINITY) // falls through to original implementation
|
|
5875
|
+
*
|
|
5876
|
+
* @example
|
|
5877
|
+
* // Async
|
|
5878
|
+
* const spy = vi.fn()
|
|
5879
|
+
* vi.when(spy).calledWith('user').thenResolve({ id: 1 })
|
|
5880
|
+
*
|
|
5881
|
+
* await expect(spy('user')).resolves.toEqual({ id: 1 })
|
|
5882
|
+
*
|
|
5883
|
+
* @example
|
|
5884
|
+
* // Scoped with `using`
|
|
5885
|
+
* const spy = vi.fn()
|
|
5886
|
+
*
|
|
5887
|
+
* {
|
|
5888
|
+
* using w = vi.when(spy)
|
|
5889
|
+
* .calledWith('darkMode')
|
|
5890
|
+
* .thenReturn(true)
|
|
5891
|
+
*
|
|
5892
|
+
* expect(spy('darkMode')).toBe(true)
|
|
5893
|
+
* }
|
|
5894
|
+
*
|
|
5895
|
+
* // spy's original implementation is restored here
|
|
5896
|
+
* expect(spy('darkMode')).toBe(undefined)
|
|
5897
|
+
*
|
|
5898
|
+
* @example
|
|
5899
|
+
* // Throw on unmatched calls
|
|
5900
|
+
* vi.when(spy, { onUnmatched: 'throw' })
|
|
5901
|
+
* .calledWith(1)
|
|
5902
|
+
* .thenReturn({ id: 1, name: 'Alice' })
|
|
5903
|
+
*
|
|
5904
|
+
* expect(spy(1)).toEqual({ id: 1, name: 'Alice' })
|
|
5905
|
+
* expect(() => spy(2)).toThrow()
|
|
5906
|
+
*/
|
|
5907
|
+
function when(spy, options) {
|
|
5908
|
+
if (!isMockFunction(spy)) throw new TypeError("vi.when: the argument must be a mock function created with `vi.fn()` or `vi.spyOn()`");
|
|
5909
|
+
const behaviors = [];
|
|
5910
|
+
const originalImplementation = spy.getMockImplementation();
|
|
5911
|
+
function findAction(args) {
|
|
5912
|
+
const testers = [...getCustomEqualityTesters(), iterableEquality];
|
|
5913
|
+
for (const behavior of behaviors) if (equals(args, behavior.arguments, testers)) return behavior.actions.findLast((action) => !(action.remaining === 0 && action.called)) ?? null;
|
|
5914
|
+
return null;
|
|
5915
|
+
}
|
|
5916
|
+
spy.mockImplementation(
|
|
5917
|
+
// @ts-expect-error cannot resolve generic args
|
|
5918
|
+
(...args) => {
|
|
5919
|
+
const action = findAction(args);
|
|
5920
|
+
if (action === null) return (typeof options?.onUnmatched === "function" ? options.onUnmatched : options?.onUnmatched === "throw" ? () => {
|
|
5921
|
+
throw new Error(`vi.when: no behavior defined when called with [${args.map((arg) => stringify(arg)).join(", ")}]`);
|
|
5922
|
+
} : originalImplementation)?.(...args);
|
|
5923
|
+
action.remaining -= 1;
|
|
5924
|
+
action.called = true;
|
|
5925
|
+
switch (action.type) {
|
|
5926
|
+
case "return": return action.value;
|
|
5927
|
+
case "throw": throw action.value;
|
|
5928
|
+
case "resolve": return Promise.resolve(action.value);
|
|
5929
|
+
case "reject": return Promise.reject(action.value);
|
|
5930
|
+
}
|
|
5931
|
+
}
|
|
5932
|
+
);
|
|
5933
|
+
function getOrCreateBehavior(args) {
|
|
5934
|
+
const testers = [...getCustomEqualityTesters(), iterableEquality];
|
|
5935
|
+
let behavior = behaviors.find((behavior) => equals(args, behavior.arguments, testers));
|
|
5936
|
+
if (behavior === void 0) {
|
|
5937
|
+
behavior = {
|
|
5938
|
+
arguments: args,
|
|
5939
|
+
actions: []
|
|
5940
|
+
};
|
|
5941
|
+
behaviors.push(behavior);
|
|
5942
|
+
}
|
|
5943
|
+
return behavior;
|
|
5944
|
+
}
|
|
5945
|
+
// @ts-expect-error `Symbol.dispose` has to be assigned conditionally since it's only supported in Node >= 24
|
|
5946
|
+
const output = markWhenChain({
|
|
5947
|
+
calledWith: (...args) => {
|
|
5948
|
+
const behavior = getOrCreateBehavior(args);
|
|
5949
|
+
function appendAction(behavior, type, value, times) {
|
|
5950
|
+
behavior.actions.push({
|
|
5951
|
+
type,
|
|
5952
|
+
value,
|
|
5953
|
+
times,
|
|
5954
|
+
remaining: times,
|
|
5955
|
+
called: false
|
|
5956
|
+
});
|
|
5957
|
+
}
|
|
5958
|
+
const calledWithInstance = markWhenChain({
|
|
5959
|
+
...output,
|
|
5960
|
+
thenThrow: (value, options) => {
|
|
5961
|
+
validateOptions(options);
|
|
5962
|
+
appendAction(behavior, "throw", value, options?.times ?? Number.POSITIVE_INFINITY);
|
|
5963
|
+
return calledWithInstance;
|
|
5964
|
+
},
|
|
5965
|
+
thenThrowOnce: (value) => {
|
|
5966
|
+
appendAction(behavior, "throw", value, 1);
|
|
5967
|
+
return calledWithInstance;
|
|
5968
|
+
},
|
|
5969
|
+
thenReturn: (value, options) => {
|
|
5970
|
+
validateOptions(options);
|
|
5971
|
+
appendAction(behavior, "return", value, options?.times ?? Number.POSITIVE_INFINITY);
|
|
5972
|
+
return calledWithInstance;
|
|
5973
|
+
},
|
|
5974
|
+
thenReturnOnce: (value) => {
|
|
5975
|
+
appendAction(behavior, "return", value, 1);
|
|
5976
|
+
return calledWithInstance;
|
|
5977
|
+
},
|
|
5978
|
+
thenResolve: (value, options) => {
|
|
5979
|
+
validateOptions(options);
|
|
5980
|
+
appendAction(behavior, "resolve", value, options?.times ?? Number.POSITIVE_INFINITY);
|
|
5981
|
+
return calledWithInstance;
|
|
5982
|
+
},
|
|
5983
|
+
thenResolveOnce: (value) => {
|
|
5984
|
+
appendAction(behavior, "resolve", value, 1);
|
|
5985
|
+
return calledWithInstance;
|
|
5986
|
+
},
|
|
5987
|
+
thenReject: (value, options) => {
|
|
5988
|
+
validateOptions(options);
|
|
5989
|
+
appendAction(behavior, "reject", value, options?.times ?? Number.POSITIVE_INFINITY);
|
|
5990
|
+
return calledWithInstance;
|
|
5991
|
+
},
|
|
5992
|
+
thenRejectOnce: (value) => {
|
|
5993
|
+
appendAction(behavior, "reject", value, 1);
|
|
5994
|
+
return calledWithInstance;
|
|
5995
|
+
}
|
|
5996
|
+
});
|
|
5997
|
+
return calledWithInstance;
|
|
5998
|
+
},
|
|
5999
|
+
_getDiagnostics: () => {
|
|
6000
|
+
const pendingBehaviors = behaviors.filter((behavior) => behavior.actions.length === 0 || behavior.actions.some((action) => !hasBeenConsumed(action)));
|
|
6001
|
+
return {
|
|
6002
|
+
isExhausted: behaviors.length !== 0 && pendingBehaviors.length === 0,
|
|
6003
|
+
pendingBehaviors: pendingBehaviors.map((behavior) => `calledWith(${behavior.arguments.map((argument) => stringify(argument)).join(", ")})${behavior.actions.length === 0 ? " → no actions" : `\n${formatActions(behavior.actions)}`}`).join("\n\n")
|
|
6004
|
+
};
|
|
6005
|
+
}
|
|
6006
|
+
});
|
|
6007
|
+
if (Symbol.dispose) output[Symbol.dispose] = () => {
|
|
6008
|
+
spy.mockImplementation(
|
|
6009
|
+
// @ts-expect-error without an original implementation we should fall back to an undefined-returning function as that's what the mocking functions do
|
|
6010
|
+
originalImplementation ?? noop
|
|
6011
|
+
);
|
|
6012
|
+
};
|
|
6013
|
+
return output;
|
|
6014
|
+
}
|
|
6015
|
+
const whenChainMarkerOptions = {};
|
|
6016
|
+
function markWhenChain(input) {
|
|
6017
|
+
Reflect.defineProperty(input, whenSymbol, whenChainMarkerOptions);
|
|
6018
|
+
return input;
|
|
6019
|
+
}
|
|
6020
|
+
function formatActions(actions) {
|
|
6021
|
+
const lines = actions.map((action, index) => {
|
|
6022
|
+
const method = getMethodName(action.type);
|
|
6023
|
+
const left = ` ${getSymbol(action)} ${method}(${stringify(action.value)}${action.times === Number.POSITIVE_INFINITY ? "" : `, { times: ${action.times} }`})`;
|
|
6024
|
+
const unreachable = !hasBeenConsumed(action) && actions.slice(index + 1).some((later) => later.times === Number.POSITIVE_INFINITY);
|
|
6025
|
+
return {
|
|
6026
|
+
left,
|
|
6027
|
+
remaining: getRemainingLabel(action) + (unreachable ? " → unreachable action" : "")
|
|
6028
|
+
};
|
|
6029
|
+
});
|
|
6030
|
+
const maxLeft = Math.max(...lines.map((line) => line.left.length));
|
|
6031
|
+
return lines.map(({ left, remaining }) => `${left.padEnd(maxLeft + 2)}${remaining}`).join("\n");
|
|
6032
|
+
}
|
|
6033
|
+
function getMethodName(type) {
|
|
6034
|
+
switch (type) {
|
|
6035
|
+
case "return": return "thenReturn";
|
|
6036
|
+
case "resolve": return "thenResolve";
|
|
6037
|
+
case "throw": return "thenThrow";
|
|
6038
|
+
case "reject": return "thenReject";
|
|
6039
|
+
default: throw new Error(`vi.when: "${type}" is not a known method`);
|
|
6040
|
+
}
|
|
6041
|
+
}
|
|
6042
|
+
function hasBeenConsumed(action) {
|
|
6043
|
+
return action.remaining === 0 || action.remaining === Number.POSITIVE_INFINITY && action.called;
|
|
6044
|
+
}
|
|
6045
|
+
function getRemainingLabel(action) {
|
|
6046
|
+
if (hasBeenConsumed(action)) return action.remaining === Number.POSITIVE_INFINITY ? "exhausted" : `exhausted (${action.times} of ${action.times})`;
|
|
6047
|
+
return action.remaining === Number.POSITIVE_INFINITY ? "never called" : `${action.remaining} remaining (out of ${action.times})`;
|
|
6048
|
+
}
|
|
6049
|
+
function getSymbol(action) {
|
|
6050
|
+
if (hasBeenConsumed(action)) return "✓";
|
|
6051
|
+
return "✗";
|
|
6052
|
+
}
|
|
6053
|
+
function validateOptions(options) {
|
|
6054
|
+
if (typeof options?.times === "number" && options.times <= 0) throw new RangeError("vi.when: `times` option must be greater than 0");
|
|
6055
|
+
}
|
|
6056
|
+
|
|
5695
6057
|
function copyStackTrace$2(target, source) {
|
|
5696
6058
|
if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
|
|
5697
6059
|
return target;
|
|
@@ -5888,6 +6250,8 @@ function createVitest() {
|
|
|
5888
6250
|
},
|
|
5889
6251
|
spyOn,
|
|
5890
6252
|
fn,
|
|
6253
|
+
when,
|
|
6254
|
+
isWhenChain,
|
|
5891
6255
|
waitFor,
|
|
5892
6256
|
waitUntil,
|
|
5893
6257
|
defineHelper: (fn) => {
|
|
@@ -5977,8 +6341,8 @@ function createVitest() {
|
|
|
5977
6341
|
stubEnv(name, value) {
|
|
5978
6342
|
const env = state().metaEnv;
|
|
5979
6343
|
if (!_stubsEnv.has(name)) _stubsEnv.set(name, env[name]);
|
|
5980
|
-
if (
|
|
5981
|
-
else if (
|
|
6344
|
+
if (value === void 0) delete env[name];
|
|
6345
|
+
else if (_envBooleans.includes(name)) env[name] = value ? "1" : "";
|
|
5982
6346
|
else env[name] = String(value);
|
|
5983
6347
|
return utils;
|
|
5984
6348
|
},
|
|
@@ -6071,7 +6435,7 @@ const unsupported = [
|
|
|
6071
6435
|
* @throws Always throws the provided error with an amended stack trace
|
|
6072
6436
|
*/
|
|
6073
6437
|
function throwWithCause(error, source) {
|
|
6074
|
-
|
|
6438
|
+
error.cause ??= /* @__PURE__ */ new Error("Matcher did not succeed in time.");
|
|
6075
6439
|
throw copyStackTrace(error, source);
|
|
6076
6440
|
}
|
|
6077
6441
|
function createExpectPoll(expect) {
|
|
@@ -6229,6 +6593,15 @@ function raceWith$1(promise, other) {
|
|
|
6229
6593
|
}))]);
|
|
6230
6594
|
}
|
|
6231
6595
|
|
|
6596
|
+
const MockPlugin = (chai, utils) => {
|
|
6597
|
+
utils.addMethod(chai.Assertion.prototype, "toHaveBeenExhausted", wrapAssertion(utils, "toHaveBeenExhausted", function() {
|
|
6598
|
+
const chain = utils.flag(this, "object");
|
|
6599
|
+
if (!isWhenChain(chain)) throw new TypeError(`${utils.inspect(chain)} is not a \`vi.when\` instance`);
|
|
6600
|
+
const diagnostics = chain._getDiagnostics();
|
|
6601
|
+
this.assert(diagnostics.isExhausted, `expected all behaviors to have been exhausted, but some remain:\n\n ${diagnostics.pendingBehaviors.replaceAll(/\n(?!\n)/g, "\n ")}`, "expected at least one behavior to remain un-exhausted, but all were");
|
|
6602
|
+
}));
|
|
6603
|
+
};
|
|
6604
|
+
|
|
6232
6605
|
var naturalCompare$1 = {exports: {}};
|
|
6233
6606
|
|
|
6234
6607
|
var hasRequiredNaturalCompare;
|
|
@@ -6888,7 +7261,7 @@ class SnapshotState {
|
|
|
6888
7261
|
if (!rawSnapshot) receivedSerialized = addExtraLineBreaks(receivedSerialized);
|
|
6889
7262
|
if (rawSnapshot) {
|
|
6890
7263
|
// normalize EOL when snapshot contains CRLF but received is LF
|
|
6891
|
-
if (rawSnapshot.content &&
|
|
7264
|
+
if (rawSnapshot.content && /\r\n/.test(rawSnapshot.content) && !/\r\n/.test(receivedSerialized)) rawSnapshot.content = normalizeNewlines(rawSnapshot.content);
|
|
6892
7265
|
}
|
|
6893
7266
|
const expected = isInline ? inlineSnapshot : rawSnapshot ? rawSnapshot.content : this._snapshotData[key];
|
|
6894
7267
|
const expectedTrimmed = rawSnapshot ? expected : expected?.trim();
|
|
@@ -7481,6 +7854,7 @@ chai.use(JestChaiExpect);
|
|
|
7481
7854
|
chai.use(ChaiStyleAssertions);
|
|
7482
7855
|
chai.use(SnapshotPlugin);
|
|
7483
7856
|
chai.use(JestAsymmetricMatchers);
|
|
7857
|
+
chai.use(MockPlugin);
|
|
7484
7858
|
|
|
7485
7859
|
function createExpect(test) {
|
|
7486
7860
|
const expect = ((value, message) => {
|
|
@@ -7563,30 +7937,74 @@ function inject(key) {
|
|
|
7563
7937
|
}
|
|
7564
7938
|
|
|
7565
7939
|
const now = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
|
|
7940
|
+
/**
|
|
7941
|
+
* The built-in benchmark provider, backed by tinybench. Selected when
|
|
7942
|
+
* `benchmark.provider` is not configured.
|
|
7943
|
+
*/
|
|
7944
|
+
function createDefaultBenchmarkProvider(config) {
|
|
7945
|
+
let benchIdx = 0;
|
|
7946
|
+
return { async run({ test, options, registrations }) {
|
|
7947
|
+
const currentIndex = ++benchIdx;
|
|
7948
|
+
const tinybench = new Bench({
|
|
7949
|
+
signal: test.context.signal,
|
|
7950
|
+
name: `${test.fullTestName} ${currentIndex}`,
|
|
7951
|
+
retainSamples: config.benchmark.retainSamples,
|
|
7952
|
+
...options,
|
|
7953
|
+
now
|
|
7954
|
+
});
|
|
7955
|
+
for (const { name, fn, fnOpts } of registrations) tinybench.add(name, fn, fnOpts);
|
|
7956
|
+
await tinybench.run();
|
|
7957
|
+
const errors = tinybench.tasks.filter((task) => task.result.state === "errored").map((task) => task.result.error);
|
|
7958
|
+
if (errors.length === 1) throw errors[0];
|
|
7959
|
+
if (errors.length > 1) throw new AggregateError(errors, "Some benchmarks failed");
|
|
7960
|
+
return tinybench.tasks.map(toBenchResult);
|
|
7961
|
+
} };
|
|
7962
|
+
}
|
|
7963
|
+
function toBenchResult(task) {
|
|
7964
|
+
const result = task.result;
|
|
7965
|
+
if (result.state !== "completed") throw new Error(`task "${task.name}" did not complete: received "${result.state}"`);
|
|
7966
|
+
return {
|
|
7967
|
+
...result,
|
|
7968
|
+
name: task.name
|
|
7969
|
+
};
|
|
7970
|
+
}
|
|
7971
|
+
|
|
7566
7972
|
const kRegistration = Symbol("registration");
|
|
7567
7973
|
const kFromSource = Symbol("fromSource");
|
|
7568
7974
|
const kPerProject = Symbol("perProject");
|
|
7569
7975
|
const kWriteResult = Symbol("writeResult");
|
|
7570
7976
|
const kFinalize = Symbol("finalize");
|
|
7977
|
+
let cachedProvider;
|
|
7978
|
+
async function loadProviderModule(provider, moduleRunner) {
|
|
7979
|
+
let mod;
|
|
7980
|
+
try {
|
|
7981
|
+
mod = await moduleRunner.import(provider);
|
|
7982
|
+
} catch (error) {
|
|
7983
|
+
throw new Error(`Failed to load benchmark provider from "${provider}".`, { cause: error });
|
|
7984
|
+
}
|
|
7985
|
+
if (mod.default == null) throw new Error(`Benchmark provider loaded from "${provider}" did not have a default export.`);
|
|
7986
|
+
return mod.default;
|
|
7987
|
+
}
|
|
7988
|
+
/**
|
|
7989
|
+
* Resolves the benchmark provider for the current worker, importing a custom
|
|
7990
|
+
* provider module on first use. The result is cached for the lifetime of the
|
|
7991
|
+
* worker so a custom provider is imported at most once.
|
|
7992
|
+
*/
|
|
7993
|
+
function resolveBenchmarkProvider(config, moduleRunner) {
|
|
7994
|
+
if (!cachedProvider) {
|
|
7995
|
+
const provider = config.benchmark.provider;
|
|
7996
|
+
cachedProvider = !provider ? Promise.resolve(createDefaultBenchmarkProvider(config)) : loadProviderModule(provider, moduleRunner);
|
|
7997
|
+
}
|
|
7998
|
+
return cachedProvider;
|
|
7999
|
+
}
|
|
7571
8000
|
function isFromRegistration(reg) {
|
|
7572
8001
|
return kFromSource in reg;
|
|
7573
8002
|
}
|
|
7574
8003
|
function substitutePath(template, projectName) {
|
|
7575
8004
|
return template.replace(/\$\{projectName\}/g, projectName ?? "");
|
|
7576
8005
|
}
|
|
7577
|
-
function createBench(test, config) {
|
|
7578
|
-
let benchIdx = 0;
|
|
8006
|
+
function createBench(test, config, moduleRunner) {
|
|
7579
8007
|
const pending = /* @__PURE__ */ new Set();
|
|
7580
|
-
const createTinybench = (options) => {
|
|
7581
|
-
const currentIndex = ++benchIdx;
|
|
7582
|
-
return new Bench({
|
|
7583
|
-
signal: test.context.signal,
|
|
7584
|
-
name: `${test.fullTestName} ${currentIndex}`,
|
|
7585
|
-
retainSamples: config.benchmark.retainSamples,
|
|
7586
|
-
...options,
|
|
7587
|
-
now
|
|
7588
|
-
});
|
|
7589
|
-
};
|
|
7590
8008
|
const resolveTemplate = (template) => substitutePath(template, config.benchmark.projectName);
|
|
7591
8009
|
const resolveFromSource = async (source) => {
|
|
7592
8010
|
if (typeof source === "function") return source();
|
|
@@ -7604,42 +8022,37 @@ function createBench(test, config) {
|
|
|
7604
8022
|
rank: 0,
|
|
7605
8023
|
fromStore: true
|
|
7606
8024
|
});
|
|
7607
|
-
const createCompareStorage = (
|
|
8025
|
+
const createCompareStorage = (results, fromResults) => {
|
|
7608
8026
|
return { get(name) {
|
|
7609
8027
|
const stored = fromResults?.get(name);
|
|
7610
8028
|
if (stored) return stored;
|
|
7611
|
-
const
|
|
7612
|
-
if (!
|
|
7613
|
-
return
|
|
8029
|
+
const result = results.get(name);
|
|
8030
|
+
if (!result) throw new Error(`task "${name}" was not defined`);
|
|
8031
|
+
return result;
|
|
7614
8032
|
} };
|
|
7615
8033
|
};
|
|
7616
|
-
const serializeBenchmark = (
|
|
7617
|
-
const tasks =
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
totalTime: result.totalTime,
|
|
7627
|
-
rank: 0,
|
|
7628
|
-
...taskMeta?.get(t.name)
|
|
7629
|
-
};
|
|
7630
|
-
});
|
|
8034
|
+
const serializeBenchmark = (results, name, taskMeta, fromTasks) => {
|
|
8035
|
+
const tasks = results.map((result) => ({
|
|
8036
|
+
name: result.name,
|
|
8037
|
+
latency: result.latency,
|
|
8038
|
+
throughput: result.throughput,
|
|
8039
|
+
period: result.period,
|
|
8040
|
+
totalTime: result.totalTime,
|
|
8041
|
+
rank: 0,
|
|
8042
|
+
...taskMeta?.get(result.name)
|
|
8043
|
+
}));
|
|
7631
8044
|
if (fromTasks) tasks.push(...fromTasks);
|
|
7632
8045
|
tasks.sort((a, b) => a.latency.mean - b.latency.mean);
|
|
7633
8046
|
tasks.forEach((task, idx) => {
|
|
7634
8047
|
task.rank = idx + 1;
|
|
7635
8048
|
});
|
|
7636
8049
|
return {
|
|
7637
|
-
name
|
|
8050
|
+
name,
|
|
7638
8051
|
tasks
|
|
7639
8052
|
};
|
|
7640
8053
|
};
|
|
7641
|
-
const recordBenchmark = async (
|
|
7642
|
-
const serializedBenchmark = serializeBenchmark(
|
|
8054
|
+
const recordBenchmark = async (results, name, taskMeta, fromTasks) => {
|
|
8055
|
+
const serializedBenchmark = serializeBenchmark(results, name, taskMeta, fromTasks);
|
|
7643
8056
|
test.benchmarks.push(serializedBenchmark);
|
|
7644
8057
|
await rpc().onTestBenchmark(test.id, serializedBenchmark);
|
|
7645
8058
|
};
|
|
@@ -7653,19 +8066,28 @@ function createBench(test, config) {
|
|
|
7653
8066
|
};
|
|
7654
8067
|
await rpc().writeBenchmarkResult(resolved, data);
|
|
7655
8068
|
};
|
|
7656
|
-
const
|
|
8069
|
+
const groupName = (options) => options?.name ?? test.fullTestName;
|
|
8070
|
+
const runGroup = async (registrations, options) => {
|
|
7657
8071
|
const workerState = getWorkerState();
|
|
7658
8072
|
const getterTracker = workerState.getterTracker;
|
|
7659
8073
|
getterTracker?.resetInvocations();
|
|
7660
8074
|
try {
|
|
7661
|
-
|
|
8075
|
+
const results = await (await resolveBenchmarkProvider(config, moduleRunner)).run({
|
|
8076
|
+
test,
|
|
8077
|
+
config: config.benchmark,
|
|
8078
|
+
registrations,
|
|
8079
|
+
options
|
|
8080
|
+
});
|
|
8081
|
+
const byName = /* @__PURE__ */ new Map();
|
|
8082
|
+
for (const result of results) byName.set(result.name, result);
|
|
8083
|
+
return byName;
|
|
7662
8084
|
} finally {
|
|
7663
8085
|
const excessiveInvocations = config.benchmark.suppressExportGetterWarnings ? void 0 : getterTracker?.getExcessiveInvocations();
|
|
7664
8086
|
if (excessiveInvocations?.length) {
|
|
7665
8087
|
const entries = excessiveInvocations.map(({ moduleId, exportName }) => ` - ${formatModuleId(moduleId, workerState.config.root)} > ${exportName}`).join("\n");
|
|
7666
8088
|
console.warn([
|
|
7667
|
-
|
|
7668
|
-
`Benchmark ${
|
|
8089
|
+
y.yellow(y.bold("Benchmark Warning")),
|
|
8090
|
+
`Benchmark ${y.bold(`"${groupName(options)}"`)} accessed module export getters too many times.`,
|
|
7669
8091
|
"",
|
|
7670
8092
|
"This can make results unreliable because export getters add overhead.",
|
|
7671
8093
|
"See https://vitest.dev/guide/benchmarking#module-runner-overhead",
|
|
@@ -7677,13 +8099,15 @@ function createBench(test, config) {
|
|
|
7677
8099
|
}
|
|
7678
8100
|
};
|
|
7679
8101
|
const runSingle = async (name, fn, fnOpts, options, meta, writeResult) => {
|
|
7680
|
-
const
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
if (
|
|
7686
|
-
|
|
8102
|
+
const result = (await runGroup([{
|
|
8103
|
+
name,
|
|
8104
|
+
fn,
|
|
8105
|
+
fnOpts
|
|
8106
|
+
}], options)).get(name);
|
|
8107
|
+
if (!result) throw new Error(`benchmark provider did not return a result for "${name}"`);
|
|
8108
|
+
await recordBenchmark([result], groupName(options), meta ? new Map([[name, meta]]) : void 0);
|
|
8109
|
+
if (writeResult) await writeResultArtifact(writeResult, result);
|
|
8110
|
+
return result;
|
|
7687
8111
|
};
|
|
7688
8112
|
const runFrom = async (name, source) => {
|
|
7689
8113
|
const data = await resolveFromSource(source);
|
|
@@ -7737,8 +8161,8 @@ function createBench(test, config) {
|
|
|
7737
8161
|
};
|
|
7738
8162
|
bench.compare = async (...args) => {
|
|
7739
8163
|
validateBenchmarkProject(config);
|
|
7740
|
-
// extract optional trailing
|
|
7741
|
-
const lastArg = args
|
|
8164
|
+
// extract optional trailing BenchRunOptions argument
|
|
8165
|
+
const lastArg = args.at(-1);
|
|
7742
8166
|
const benchOptions = lastArg != null && typeof lastArg === "object" && !(kRegistration in lastArg) ? args.pop() : void 0;
|
|
7743
8167
|
const registrations = args;
|
|
7744
8168
|
// Mark every passed-in registration as consumed before validation so a
|
|
@@ -7767,33 +8191,29 @@ function createBench(test, config) {
|
|
|
7767
8191
|
fromTasks.push(taskFromBaseline(reg.name, data));
|
|
7768
8192
|
}
|
|
7769
8193
|
}
|
|
7770
|
-
|
|
7771
|
-
runnable.
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
const errors = tinybench.tasks.filter((task) => task.result.state === "errored").map((task) => task.result.error);
|
|
7778
|
-
if (errors.length > 0) throw new AggregateError(errors, "Some benchmarks failed");
|
|
7779
|
-
}
|
|
7780
|
-
await recordBenchmark(tasks, tinybench.name, taskMeta, fromTasks);
|
|
8194
|
+
let results = /* @__PURE__ */ new Map();
|
|
8195
|
+
if (runnable.length > 0) results = await runGroup(runnable.map((reg) => ({
|
|
8196
|
+
name: reg.name,
|
|
8197
|
+
fn: reg.fn,
|
|
8198
|
+
fnOpts: reg.fnOpts
|
|
8199
|
+
})), benchOptions);
|
|
8200
|
+
await recordBenchmark(Array.from(results.values()), groupName(benchOptions), taskMeta, fromTasks);
|
|
7781
8201
|
// write artifacts for every runnable registration that requested it. We
|
|
7782
8202
|
// do this after recording so a write failure can't be confused with a
|
|
7783
8203
|
// benchmark failure in the reporter output.
|
|
7784
8204
|
await Promise.all(runnable.filter((reg) => reg[kWriteResult] != null).map((reg) => {
|
|
7785
|
-
const
|
|
7786
|
-
return writeResultArtifact(reg[kWriteResult],
|
|
8205
|
+
const result = results.get(reg.name);
|
|
8206
|
+
return writeResultArtifact(reg[kWriteResult], result);
|
|
7787
8207
|
}));
|
|
7788
|
-
return createCompareStorage(
|
|
8208
|
+
return createCompareStorage(results, fromResults);
|
|
7789
8209
|
};
|
|
7790
8210
|
bench[kFinalize] = () => {
|
|
7791
8211
|
if (pending.size === 0) return;
|
|
7792
|
-
const names =
|
|
8212
|
+
const names = Array.from(pending, (reg) => `"${reg.name}"`).join(", ");
|
|
7793
8213
|
pending.clear();
|
|
7794
8214
|
console.warn([
|
|
7795
|
-
|
|
7796
|
-
`Test ${
|
|
8215
|
+
y.yellow(y.bold("Benchmark Warning")),
|
|
8216
|
+
`Test ${y.bold(`"${test.fullTestName}"`)} registered benchmarks that never ran: ${names}.`,
|
|
7797
8217
|
"",
|
|
7798
8218
|
"Call `.run()` on the registration, or pass it to `bench.compare()`.",
|
|
7799
8219
|
"See https://vitest.dev/guide/benchmarking#defining-a-benchmark"
|
|
@@ -7818,8 +8238,8 @@ function normalizeBenchArgs(a, b) {
|
|
|
7818
8238
|
if (typeof b !== "function") throw new TypeError("`bench()` expects a benchmark function. Call `bench(name, fn)` or `bench(name, options, fn)`.");
|
|
7819
8239
|
// Strip vitest-specific fields only when present so we don't allocate a new
|
|
7820
8240
|
// object — preserving referential identity matters: users inspect
|
|
7821
|
-
// `registration.fnOpts` and
|
|
7822
|
-
//
|
|
8241
|
+
// `registration.fnOpts` and the provider sees the same object the caller
|
|
8242
|
+
// passed in.
|
|
7823
8243
|
if (a.writeResult === void 0 && a.perProject === void 0) return {
|
|
7824
8244
|
fn: b,
|
|
7825
8245
|
fnOpts: a,
|
|
@@ -7955,9 +8375,10 @@ class TestRunner {
|
|
|
7955
8375
|
let _bench;
|
|
7956
8376
|
const runnerConfig = this.config;
|
|
7957
8377
|
const benchInstances = this.benchInstances;
|
|
8378
|
+
const moduleRunner = this.moduleRunner;
|
|
7958
8379
|
Object.defineProperty(context, "bench", { get() {
|
|
7959
8380
|
if (!_bench) {
|
|
7960
|
-
_bench = createBench(context.task, runnerConfig);
|
|
8381
|
+
_bench = createBench(context.task, runnerConfig, moduleRunner);
|
|
7961
8382
|
benchInstances.set(context.task, _bench);
|
|
7962
8383
|
}
|
|
7963
8384
|
return _bench;
|
|
@@ -7996,14 +8417,6 @@ class TestRunner {
|
|
|
7996
8417
|
static setTestFn = getFn;
|
|
7997
8418
|
static matchesTags = matchesTags;
|
|
7998
8419
|
static createFileTask = createFileTask;
|
|
7999
|
-
/**
|
|
8000
|
-
* @experimental
|
|
8001
|
-
* A function that runs tinybench tasks.
|
|
8002
|
-
* Can be overriden to run tasks in a special environment.
|
|
8003
|
-
*/
|
|
8004
|
-
static async runBenchmarks(tinybench) {
|
|
8005
|
-
return await tinybench.run();
|
|
8006
|
-
}
|
|
8007
8420
|
}
|
|
8008
8421
|
function clearModuleMocks(config) {
|
|
8009
8422
|
const { clearMocks, mockReset, restoreMocks, unstubEnvs, unstubGlobals } = config;
|