vitest 5.0.0-beta.4 → 5.0.0-beta.6
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 +0 -17
- package/dist/browser.d.ts +8 -6
- package/dist/browser.js +5 -3
- package/dist/chunks/artifact.BNnEI1sJ.js +2770 -0
- package/dist/chunks/{base.BEGVMQrS.js → base.BKfXyFN7.js} +12 -12
- package/dist/chunks/browser.d.DoM6vBOs.d.ts +64 -0
- package/dist/chunks/{cac.CyXAEMkE.js → cac.DKrA6qEB.js} +15 -7
- package/dist/chunks/{cli-api.DJMXq34b.js → cli-api.cZcvaUFI.js} +491 -852
- package/dist/chunks/config.d.CKWK3nld.d.ts +2920 -0
- package/dist/chunks/{console.B3IRP8fX.js → console.DjVIMaXT.js} +4 -4
- package/dist/chunks/{coverage.d.g2xbl2sP.d.ts → coverage.d.CCNrKR65.d.ts} +2 -0
- package/dist/chunks/{creator.D66cVXYh.js → creator.C4nK7Krt.js} +19 -4
- package/dist/chunks/{defaults.CUUnbOrq.js → defaults.B_pFOTYy.js} +1 -1
- package/dist/chunks/{globals.BuY-yD0m.js → globals.CzUA1xn8.js} +12 -12
- package/dist/chunks/{index.CcluKS59.js → index.B4UTDegh.js} +6 -6
- package/dist/chunks/{nativeModuleRunner.BOeMnHl4.js → index.CesbTg1C.js} +3 -34
- package/dist/chunks/{index.CE58PZNH.js → index.D6NDM5O1.js} +515 -121
- package/dist/chunks/{index.nQFVd50u.js → index.DNRmy2jU.js} +32 -10
- package/dist/chunks/{index.og1WyBLx.js → index.Djaij2xr.js} +660 -58
- package/dist/chunks/{init-forks.Ce3vGWgL.js → init-forks.BG4bCDny.js} +1 -1
- package/dist/chunks/{init-threads.8e1OLv5v.js → init-threads.DLtIP5Qq.js} +1 -1
- package/dist/chunks/{init.6qx-LaHs.js → init.DTAQFCjl.js} +10 -6
- package/dist/chunks/{nativeModuleMocker.DDZfQXLs.js → nativeModuleMocker.BKtCThoO.js} +2 -3
- package/dist/chunks/nativeModuleRunner.WlMdOB52.js +36 -0
- package/dist/chunks/{node.CwFbQqI1.js → node.C9I1sbE9.js} +1 -2
- package/dist/chunks/{plugin.d.B7MTG_Fe.d.ts → plugin.d.Bpge8Jye.d.ts} +94 -37
- package/dist/chunks/{rpc.DFRWVnRh.js → rpc.DZEh5xnQ.js} +1 -1
- package/dist/chunks/{rpc.d.OQ_EZi1Z.d.ts → rpc.d.C6-dGZ2f.d.ts} +1 -2
- package/dist/chunks/{setup-common.DdEF_hkE.js → setup-common.ZNdeu5wa.js} +2 -2
- package/dist/chunks/{global.d.BtKPuz2X.d.ts → task-utils.d.mMDXJF_I.d.ts} +30 -89
- package/dist/chunks/{utils.BX5Fg8C4.js → utils.DYj33du9.js} +1 -17
- package/dist/chunks/{vm.Bu7mmcZq.js → vm.CeHWcIrU.js} +4 -4
- package/dist/chunks/{worker.d.yR22cs6X.d.ts → worker.d.JES7ffPK.d.ts} +3 -3
- package/dist/cli.js +1 -1
- package/dist/config.cjs +1 -1
- package/dist/config.d.ts +12 -13
- package/dist/config.js +1 -1
- package/dist/index.d.ts +416 -21
- package/dist/index.js +9 -9
- package/dist/module-evaluator.d.ts +7 -4
- package/dist/module-evaluator.js +7 -0
- package/dist/node.d.ts +31 -18
- package/dist/node.js +22 -16
- package/dist/runtime.d.ts +9 -3
- package/dist/runtime.js +4 -5
- package/dist/task-utils.js +296 -0
- package/dist/worker.d.ts +7 -6
- package/dist/worker.js +15 -14
- package/dist/workers/forks.js +16 -15
- package/dist/workers/runVmTests.js +10 -10
- package/dist/workers/threads.js +16 -15
- package/dist/workers/vmForks.js +8 -8
- package/dist/workers/vmThreads.js +8 -8
- package/package.json +18 -19
- package/dist/chunks/browser.d.BGxB4Xum.d.ts +0 -878
- package/dist/chunks/config.d.DXq1aBpy.d.ts +0 -244
- package/dist/chunks/environment.d-DOJxxZV9.d.DOJxxZV9.d.ts +0 -17
- package/dist/chunks/general.d.DFAHgpC2.d.ts +0 -247
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { TestSyntaxError, getCurrentTest, createTaskCollector, getCurrentSuite, getHooks, getFn, afterAll, afterEach, aroundAll, aroundEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, recordArtifact, suite, test } from '
|
|
2
|
-
import { i as isChildProcess,
|
|
1
|
+
import { T as TestSyntaxError, g as getCurrentTest, c as createTaskCollector, a as getCurrentSuite, b as createChainable, d as getHooks, e as getFn, m as matchesTags, f as afterAll, h as afterEach, i as aroundAll, j as aroundEach, k as beforeAll, l as beforeEach, n as describe, o as it, q as onTestFailed, r as onTestFinished, t as recordArtifact, u as suite, v as test } from './artifact.BNnEI1sJ.js';
|
|
2
|
+
import { i as isChildProcess, r as resetModules, g as getWorkerState } from './utils.DYj33du9.js';
|
|
3
3
|
import { getSafeTimers, delay } from '@vitest/utils/timers';
|
|
4
4
|
import { isMockFunction, fn, spyOn, restoreAllMocks, resetAllMocks, clearAllMocks } from '@vitest/spy';
|
|
5
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
|
-
import { R as RealDate, b as resetDate, m as mockDate, r as rpc, V as VitestEvaluatedModules } from './rpc.
|
|
9
|
+
import { R as RealDate, b as resetDate, m as mockDate, r as rpc, V as VitestEvaluatedModules } from './rpc.DZEh5xnQ.js';
|
|
10
|
+
import { stringify, inspect } from '@vitest/utils/display';
|
|
11
|
+
import { printDiffOrStringify, diff } from '@vitest/utils/diff';
|
|
12
|
+
import c from 'tinyrainbow';
|
|
10
13
|
import * as chai from 'chai';
|
|
11
14
|
import { use, util } from 'chai';
|
|
12
|
-
import { getNames, getTests, getTestName, createChainable, matchesTags } from '@vitest/runner/utils';
|
|
13
15
|
import { processError } from '@vitest/utils/error';
|
|
16
|
+
import { getNames, getTests, getTestName, createFileTask } from '../task-utils.js';
|
|
14
17
|
import { g as getSerializers, a as addSerializer } from './plugins.DrsmdUE2.js';
|
|
15
18
|
import { format } from '@vitest/pretty-format';
|
|
16
|
-
import { printDiffOrStringify, diff } from '@vitest/utils/diff';
|
|
17
|
-
import { stringify, inspect } from '@vitest/utils/display';
|
|
18
|
-
import c from 'tinyrainbow';
|
|
19
19
|
import { isAbsolute, relative, normalize } from 'pathe';
|
|
20
20
|
import { Bench } from 'tinybench';
|
|
21
21
|
import { expectTypeOf } from 'expect-type';
|
|
@@ -342,7 +342,7 @@ function isA(typeName, value) {
|
|
|
342
342
|
function isDomNode(obj) {
|
|
343
343
|
return obj !== null && typeof obj === "object" && "nodeType" in obj && typeof obj.nodeType === "number" && "nodeName" in obj && typeof obj.nodeName === "string" && "isEqualNode" in obj && typeof obj.isEqualNode === "function";
|
|
344
344
|
}
|
|
345
|
-
// SENTINEL constants are from https://github.com/
|
|
345
|
+
// SENTINEL constants are from https://github.com/immutable-js/immutable-js
|
|
346
346
|
const IS_KEYED_SENTINEL = "@@__IMMUTABLE_KEYED__@@";
|
|
347
347
|
const IS_SET_SENTINEL = "@@__IMMUTABLE_SET__@@";
|
|
348
348
|
const IS_LIST_SENTINEL = "@@__IMMUTABLE_LIST__@@";
|
|
@@ -2729,15 +2729,35 @@ function requireFakeTimersSrc () {
|
|
|
2729
2729
|
* @returns {void}
|
|
2730
2730
|
*/
|
|
2731
2731
|
|
|
2732
|
+
/**
|
|
2733
|
+
* @typedef {object} TemporalDuration
|
|
2734
|
+
* @property {number} years - years component
|
|
2735
|
+
* @property {number} months - months component
|
|
2736
|
+
* @property {number} weeks - weeks component
|
|
2737
|
+
* @property {number} days - days component
|
|
2738
|
+
* @property {number} hours - hours component
|
|
2739
|
+
* @property {number} minutes - minutes component
|
|
2740
|
+
* @property {number} seconds - seconds component
|
|
2741
|
+
* @property {number} milliseconds - milliseconds component
|
|
2742
|
+
* @property {number} microseconds - microseconds component
|
|
2743
|
+
* @property {number} nanoseconds - nanoseconds component
|
|
2744
|
+
* @property {(options: {unit: string, relativeTo?: unknown}) => number} total - converts to a single unit
|
|
2745
|
+
*/
|
|
2746
|
+
|
|
2747
|
+
/**
|
|
2748
|
+
* @typedef {object} TemporalTimelike
|
|
2749
|
+
* @property {number} epochMilliseconds - milliseconds since the Unix epoch (present on Temporal.Instant and Temporal.ZonedDateTime)
|
|
2750
|
+
*/
|
|
2751
|
+
|
|
2732
2752
|
/**
|
|
2733
2753
|
* @callback Tick
|
|
2734
|
-
* @param {number|string} tickValue milliseconds
|
|
2754
|
+
* @param {number|string|TemporalDuration} tickValue milliseconds, a string parseable by parseTime, or a Temporal.Duration
|
|
2735
2755
|
* @returns {number} will return the new `now` value
|
|
2736
2756
|
*/
|
|
2737
2757
|
|
|
2738
2758
|
/**
|
|
2739
2759
|
* @callback TickAsync
|
|
2740
|
-
* @param {number|string} tickValue milliseconds
|
|
2760
|
+
* @param {number|string|TemporalDuration} tickValue milliseconds, a string parseable by parseTime, or a Temporal.Duration
|
|
2741
2761
|
* @returns {Promise<number>}
|
|
2742
2762
|
*/
|
|
2743
2763
|
|
|
@@ -2783,13 +2803,13 @@ function requireFakeTimersSrc () {
|
|
|
2783
2803
|
|
|
2784
2804
|
/**
|
|
2785
2805
|
* @callback SetSystemTime
|
|
2786
|
-
* @param {number|Date} [now] initial mocked time, as milliseconds since epoch or a
|
|
2806
|
+
* @param {number|Date|TemporalTimelike} [now] initial mocked time, as milliseconds since epoch, a Date, a Temporal.Instant, or a Temporal.ZonedDateTime
|
|
2787
2807
|
* @returns {void}
|
|
2788
2808
|
*/
|
|
2789
2809
|
|
|
2790
2810
|
/**
|
|
2791
2811
|
* @callback Jump
|
|
2792
|
-
* @param {number|string} tickValue milliseconds
|
|
2812
|
+
* @param {number|string|TemporalDuration} tickValue milliseconds, a human-readable value like "01:11:15", or a Temporal.Duration
|
|
2793
2813
|
* @returns {number}
|
|
2794
2814
|
*/
|
|
2795
2815
|
|
|
@@ -2817,7 +2837,7 @@ function requireFakeTimersSrc () {
|
|
|
2817
2837
|
*/
|
|
2818
2838
|
|
|
2819
2839
|
/**
|
|
2820
|
-
* @typedef {"setTimeout" | "clearTimeout" | "setImmediate" | "clearImmediate" | "setInterval" | "clearInterval" | "Date" | "nextTick" | "hrtime" | "requestAnimationFrame" | "cancelAnimationFrame" | "requestIdleCallback" | "cancelIdleCallback" | "performance" | "queueMicrotask"} FakeMethod
|
|
2840
|
+
* @typedef {"setTimeout" | "clearTimeout" | "setImmediate" | "clearImmediate" | "setInterval" | "clearInterval" | "Date" | "nextTick" | "hrtime" | "requestAnimationFrame" | "cancelAnimationFrame" | "requestIdleCallback" | "cancelIdleCallback" | "performance" | "queueMicrotask" | "Intl" | "Temporal"} FakeMethod
|
|
2821
2841
|
*/
|
|
2822
2842
|
|
|
2823
2843
|
/**
|
|
@@ -2842,6 +2862,7 @@ function requireFakeTimersSrc () {
|
|
|
2842
2862
|
* performance?: any,
|
|
2843
2863
|
* Performance?: any,
|
|
2844
2864
|
* Intl?: any,
|
|
2865
|
+
* Temporal?: any,
|
|
2845
2866
|
* Promise?: typeof Promise,
|
|
2846
2867
|
* Date: typeof Date & { isFake?: boolean, toSource?: () => string, clock?: any }
|
|
2847
2868
|
* }} GlobalObject
|
|
@@ -2873,6 +2894,10 @@ function requireFakeTimersSrc () {
|
|
|
2873
2894
|
* @typedef {Record<string, any> & { clock: Clock }} IntlWithClock
|
|
2874
2895
|
*/
|
|
2875
2896
|
|
|
2897
|
+
/**
|
|
2898
|
+
* @typedef {Record<string, any> & { now: () => number }} PerformanceLike
|
|
2899
|
+
*/
|
|
2900
|
+
|
|
2876
2901
|
/**
|
|
2877
2902
|
* @typedef {object} Timers
|
|
2878
2903
|
* @property {SetTimeout} setTimeout - native `setTimeout`
|
|
@@ -2881,11 +2906,12 @@ function requireFakeTimersSrc () {
|
|
|
2881
2906
|
* @property {ClearInterval} clearInterval - native `clearInterval`
|
|
2882
2907
|
* @property {typeof Date} Date - native `Date`
|
|
2883
2908
|
* @property {typeof Intl} [Intl] - native `Intl`
|
|
2909
|
+
* @property {any} [Temporal] - native `Temporal`
|
|
2884
2910
|
* @property {SetImmediate} [setImmediate] - native `setImmediate`, if available
|
|
2885
2911
|
* @property {ClearImmediate} [clearImmediate] - native `clearImmediate`, if available
|
|
2886
2912
|
* @property {Hrtime} [hrtime] - native `process.hrtime`, if available
|
|
2887
2913
|
* @property {NextTick} [nextTick] - native `process.nextTick`, if available
|
|
2888
|
-
* @property {
|
|
2914
|
+
* @property {PerformanceLike} [performance] - native `performance`, if available
|
|
2889
2915
|
* @property {RequestAnimationFrame} [requestAnimationFrame] - native `requestAnimationFrame`, if available
|
|
2890
2916
|
* @property {QueueMicrotask} [queueMicrotask] - whether `queueMicrotask` exists
|
|
2891
2917
|
* @property {CancelAnimationFrame} [cancelAnimationFrame] - native `cancelAnimationFrame`, if available
|
|
@@ -2926,7 +2952,7 @@ function requireFakeTimersSrc () {
|
|
|
2926
2952
|
|
|
2927
2953
|
/**
|
|
2928
2954
|
* @callback CreateClockCallback
|
|
2929
|
-
* @param {number|Date} [start] initial mocked time, as milliseconds since epoch or a
|
|
2955
|
+
* @param {number|Date|TemporalTimelike} [start] initial mocked time, as milliseconds since epoch, a Date, a Temporal.Instant, or a Temporal.ZonedDateTime
|
|
2930
2956
|
* @param {number} [loopLimit] maximum number of timers run before aborting with an infinite-loop error
|
|
2931
2957
|
* @returns {Clock}
|
|
2932
2958
|
*/
|
|
@@ -2993,13 +3019,14 @@ function requireFakeTimersSrc () {
|
|
|
2993
3019
|
* @property {ClockTickMode} [tickMode] - internal flag
|
|
2994
3020
|
* @property {Timer[]} [jobs] - internal flag
|
|
2995
3021
|
* @property {IntlWithClock} [Intl] - fake Intl object
|
|
3022
|
+
* @property {any} [Temporal] - fake Temporal object
|
|
2996
3023
|
*/
|
|
2997
3024
|
/* eslint-enable jsdoc/reject-any-type */
|
|
2998
3025
|
|
|
2999
3026
|
/**
|
|
3000
3027
|
* Configuration object for the `install` method.
|
|
3001
3028
|
* @typedef {object} Config
|
|
3002
|
-
* @property {number|Date} [now] initial mocked time, as milliseconds since epoch or a
|
|
3029
|
+
* @property {number|Date|TemporalTimelike} [now] initial mocked time, as milliseconds since epoch, a Date, a Temporal.Instant, or a Temporal.ZonedDateTime
|
|
3003
3030
|
* @property {FakeMethod[]} [toFake] method names that should be faked
|
|
3004
3031
|
* @property {FakeMethod[]} [toNotFake] method names that should remain native
|
|
3005
3032
|
* @property {number} [loopLimit] maximum number of timers run before aborting with an infinite-loop error
|
|
@@ -3108,6 +3135,11 @@ function requireFakeTimersSrc () {
|
|
|
3108
3135
|
isPresent.clearImmediate =
|
|
3109
3136
|
_global.clearImmediate && typeof _global.clearImmediate === "function";
|
|
3110
3137
|
isPresent.Intl = _global.Intl && typeof _global.Intl === "object";
|
|
3138
|
+
isPresent.Temporal =
|
|
3139
|
+
_global.Temporal !== null &&
|
|
3140
|
+
typeof _global.Temporal === "object" &&
|
|
3141
|
+
typeof _global.Temporal.Now !== "undefined" &&
|
|
3142
|
+
typeof _global.Temporal.Instant !== "undefined";
|
|
3111
3143
|
|
|
3112
3144
|
if (_global.clearTimeout) {
|
|
3113
3145
|
_global.clearTimeout(timeoutResult);
|
|
@@ -3120,6 +3152,7 @@ function requireFakeTimersSrc () {
|
|
|
3120
3152
|
Object.getOwnPropertyDescriptors(_global.Intl),
|
|
3121
3153
|
)
|
|
3122
3154
|
: undefined;
|
|
3155
|
+
const NativeTemporal = isPresent.Temporal ? _global.Temporal : undefined;
|
|
3123
3156
|
let uniqueTimerId = idCounterStart;
|
|
3124
3157
|
/** @type {number} */
|
|
3125
3158
|
let uniqueTimerOrder = 0;
|
|
@@ -3237,7 +3270,7 @@ function requireFakeTimersSrc () {
|
|
|
3237
3270
|
|
|
3238
3271
|
/**
|
|
3239
3272
|
* Used to grok the `now` parameter to createClock.
|
|
3240
|
-
* @param {Date|number} epoch the system time
|
|
3273
|
+
* @param {Date|number|TemporalTimelike} epoch the system time
|
|
3241
3274
|
* @returns {number}
|
|
3242
3275
|
*/
|
|
3243
3276
|
function getEpoch(epoch) {
|
|
@@ -3247,8 +3280,16 @@ function requireFakeTimersSrc () {
|
|
|
3247
3280
|
if (typeof epoch === "number") {
|
|
3248
3281
|
return epoch;
|
|
3249
3282
|
}
|
|
3250
|
-
if (typeof epoch.getTime === "function") {
|
|
3251
|
-
return epoch.getTime();
|
|
3283
|
+
if (typeof (/** @type {Date} */ (epoch).getTime) === "function") {
|
|
3284
|
+
return /** @type {Date} */ (epoch).getTime();
|
|
3285
|
+
}
|
|
3286
|
+
if (
|
|
3287
|
+
typeof (
|
|
3288
|
+
/** @type {TemporalTimelike} */ (epoch).epochMilliseconds
|
|
3289
|
+
) === "number"
|
|
3290
|
+
) {
|
|
3291
|
+
// Temporal.Instant and Temporal.ZonedDateTime both have epochMilliseconds
|
|
3292
|
+
return /** @type {TemporalTimelike} */ (epoch).epochMilliseconds;
|
|
3252
3293
|
}
|
|
3253
3294
|
throw new TypeError("now should be milliseconds since UNIX epoch");
|
|
3254
3295
|
}
|
|
@@ -3465,6 +3506,56 @@ function requireFakeTimersSrc () {
|
|
|
3465
3506
|
return IntlWithClock;
|
|
3466
3507
|
}
|
|
3467
3508
|
|
|
3509
|
+
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
3510
|
+
function createTemporal(clock, getNanos) {
|
|
3511
|
+
const fakeNow = {
|
|
3512
|
+
instant() {
|
|
3513
|
+
return NativeTemporal.Instant.fromEpochNanoseconds(
|
|
3514
|
+
BigInt(clock.now) * 1_000_000n + BigInt(getNanos()),
|
|
3515
|
+
);
|
|
3516
|
+
},
|
|
3517
|
+
timeZoneId() {
|
|
3518
|
+
return NativeTemporal.Now.timeZoneId();
|
|
3519
|
+
},
|
|
3520
|
+
zonedDateTimeISO(timeZone) {
|
|
3521
|
+
const tz = timeZone ?? NativeTemporal.Now.timeZoneId();
|
|
3522
|
+
return fakeNow.instant().toZonedDateTimeISO(tz);
|
|
3523
|
+
},
|
|
3524
|
+
plainDateTimeISO(timeZone) {
|
|
3525
|
+
return fakeNow.zonedDateTimeISO(timeZone).toPlainDateTime();
|
|
3526
|
+
},
|
|
3527
|
+
plainDateISO(timeZone) {
|
|
3528
|
+
return fakeNow.zonedDateTimeISO(timeZone).toPlainDate();
|
|
3529
|
+
},
|
|
3530
|
+
plainTimeISO(timeZone) {
|
|
3531
|
+
return fakeNow.zonedDateTimeISO(timeZone).toPlainTime();
|
|
3532
|
+
},
|
|
3533
|
+
};
|
|
3534
|
+
|
|
3535
|
+
const TemporalWithClock = Object.create(
|
|
3536
|
+
Object.getPrototypeOf(NativeTemporal),
|
|
3537
|
+
);
|
|
3538
|
+
[
|
|
3539
|
+
...Object.getOwnPropertyNames(NativeTemporal),
|
|
3540
|
+
...Object.getOwnPropertySymbols(NativeTemporal),
|
|
3541
|
+
].forEach((prop) => {
|
|
3542
|
+
Object.defineProperty(
|
|
3543
|
+
TemporalWithClock,
|
|
3544
|
+
prop,
|
|
3545
|
+
Object.getOwnPropertyDescriptor(NativeTemporal, prop),
|
|
3546
|
+
);
|
|
3547
|
+
});
|
|
3548
|
+
// Temporal.Now is writable:false in the spec so we must use defineProperty
|
|
3549
|
+
Object.defineProperty(TemporalWithClock, "Now", {
|
|
3550
|
+
value: fakeNow,
|
|
3551
|
+
writable: true,
|
|
3552
|
+
enumerable: false,
|
|
3553
|
+
configurable: true,
|
|
3554
|
+
});
|
|
3555
|
+
|
|
3556
|
+
return TemporalWithClock;
|
|
3557
|
+
}
|
|
3558
|
+
|
|
3468
3559
|
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
3469
3560
|
function enqueueJob(clock, job) {
|
|
3470
3561
|
// enqueues a microtick-deferred task - ecma262/#sec-enqueuejob
|
|
@@ -4099,85 +4190,6 @@ function requireFakeTimersSrc () {
|
|
|
4099
4190
|
}
|
|
4100
4191
|
}
|
|
4101
4192
|
|
|
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
4193
|
/**
|
|
4182
4194
|
* @param {object} target the target containing the method to replace
|
|
4183
4195
|
* @param {string} method the keyname of the method on the target
|
|
@@ -4194,6 +4206,8 @@ function requireFakeTimersSrc () {
|
|
|
4194
4206
|
target[method] = clock[method];
|
|
4195
4207
|
} else if (method === "Intl") {
|
|
4196
4208
|
target[method] = clock[method];
|
|
4209
|
+
} else if (method === "Temporal") {
|
|
4210
|
+
target[method] = clock[method];
|
|
4197
4211
|
} else if (method === "performance") {
|
|
4198
4212
|
const originalPerfDescriptor = Object.getOwnPropertyDescriptor(
|
|
4199
4213
|
target,
|
|
@@ -4294,12 +4308,16 @@ function requireFakeTimersSrc () {
|
|
|
4294
4308
|
timers.Intl = NativeIntl;
|
|
4295
4309
|
}
|
|
4296
4310
|
|
|
4311
|
+
if (isPresent.Temporal) {
|
|
4312
|
+
timers.Temporal = NativeTemporal;
|
|
4313
|
+
}
|
|
4314
|
+
|
|
4297
4315
|
const originalSetTimeout = _global.setImmediate || _global.setTimeout;
|
|
4298
4316
|
const originalClearInterval = _global.clearInterval;
|
|
4299
4317
|
const originalSetInterval = _global.setInterval;
|
|
4300
4318
|
|
|
4301
4319
|
/**
|
|
4302
|
-
* @param {Date|number} [start] the system time - non-integer values are floored
|
|
4320
|
+
* @param {Date|number|TemporalTimelike} [start] the system time - non-integer values are floored
|
|
4303
4321
|
* @param {number} [loopLimit] maximum number of timers that will be run when calling runAll()
|
|
4304
4322
|
* @returns {Clock}
|
|
4305
4323
|
*/
|
|
@@ -4312,6 +4330,7 @@ function requireFakeTimersSrc () {
|
|
|
4312
4330
|
loopLimit = loopLimit || 1000;
|
|
4313
4331
|
/** @type {number} */
|
|
4314
4332
|
let nanos = 0;
|
|
4333
|
+
let uninstalled = false;
|
|
4315
4334
|
/** @type {number[]} */
|
|
4316
4335
|
const adjustedSystemTime = [0, 0]; // [millis, nanoremainder]
|
|
4317
4336
|
|
|
@@ -4389,6 +4408,10 @@ function requireFakeTimersSrc () {
|
|
|
4389
4408
|
clock.Intl.clock = clock;
|
|
4390
4409
|
}
|
|
4391
4410
|
|
|
4411
|
+
if (isPresent.Temporal) {
|
|
4412
|
+
clock.Temporal = createTemporal(clock, () => nanos);
|
|
4413
|
+
}
|
|
4414
|
+
|
|
4392
4415
|
/**
|
|
4393
4416
|
* @param {SetTickModeConfig} tickModeConfig - The new configuration for how the clock should tick.
|
|
4394
4417
|
*/
|
|
@@ -4467,7 +4490,9 @@ function requireFakeTimersSrc () {
|
|
|
4467
4490
|
}
|
|
4468
4491
|
clock.setTickMode({ mode: "manual" });
|
|
4469
4492
|
return promise.finally(() => {
|
|
4470
|
-
|
|
4493
|
+
if (!uninstalled) {
|
|
4494
|
+
clock.setTickMode({ mode: "nextAsync" });
|
|
4495
|
+
}
|
|
4471
4496
|
});
|
|
4472
4497
|
}
|
|
4473
4498
|
|
|
@@ -4623,15 +4648,44 @@ function requireFakeTimersSrc () {
|
|
|
4623
4648
|
runJobs(clock);
|
|
4624
4649
|
};
|
|
4625
4650
|
|
|
4651
|
+
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
4652
|
+
function durationToMs(duration) {
|
|
4653
|
+
// relativeTo uses the real system timezone — fake-timers fakes time, not place.
|
|
4654
|
+
// Calendar-unit durations (months, years) will resolve DST/length using the host tz.
|
|
4655
|
+
const relativeTo = NativeTemporal.Instant.fromEpochMilliseconds(
|
|
4656
|
+
clock.now,
|
|
4657
|
+
).toZonedDateTimeISO(NativeTemporal.Now.timeZoneId());
|
|
4658
|
+
return duration.total({ unit: "millisecond", relativeTo });
|
|
4659
|
+
}
|
|
4660
|
+
|
|
4626
4661
|
/**
|
|
4627
|
-
* @param {number|string} tickValue
|
|
4662
|
+
* @param {number|string|TemporalDuration} tickValue
|
|
4663
|
+
* @returns {number} milliseconds as a float
|
|
4664
|
+
*/
|
|
4665
|
+
function tickValueToMs(tickValue) {
|
|
4666
|
+
if (typeof tickValue === "number") {
|
|
4667
|
+
return tickValue;
|
|
4668
|
+
}
|
|
4669
|
+
if (
|
|
4670
|
+
isPresent.Temporal &&
|
|
4671
|
+
tickValue !== null &&
|
|
4672
|
+
typeof tickValue === "object" &&
|
|
4673
|
+
typeof (/** @type {TemporalDuration} */ (tickValue).total) ===
|
|
4674
|
+
"function"
|
|
4675
|
+
) {
|
|
4676
|
+
return durationToMs(
|
|
4677
|
+
/** @type {TemporalDuration} */ (tickValue),
|
|
4678
|
+
);
|
|
4679
|
+
}
|
|
4680
|
+
return parseTime(/** @type {string} */ (tickValue));
|
|
4681
|
+
}
|
|
4682
|
+
|
|
4683
|
+
/**
|
|
4684
|
+
* @param {number|string|TemporalDuration} tickValue milliseconds, a string parseable by parseTime, or a Temporal.Duration
|
|
4628
4685
|
* @returns {ClockState} a mutable state object for the tick execution
|
|
4629
4686
|
*/
|
|
4630
4687
|
function createTickState(tickValue) {
|
|
4631
|
-
const msFloat =
|
|
4632
|
-
typeof tickValue === "number"
|
|
4633
|
-
? tickValue
|
|
4634
|
-
: parseTime(tickValue);
|
|
4688
|
+
const msFloat = tickValueToMs(tickValue);
|
|
4635
4689
|
const ms = Math.floor(msFloat);
|
|
4636
4690
|
const remainder = nanoRemainder(msFloat);
|
|
4637
4691
|
let nanosTotal = nanos + remainder;
|
|
@@ -4792,7 +4846,7 @@ function requireFakeTimersSrc () {
|
|
|
4792
4846
|
}
|
|
4793
4847
|
|
|
4794
4848
|
/**
|
|
4795
|
-
* @param {number|string} tickValue milliseconds or a string parseable by parseTime
|
|
4849
|
+
* @param {number|string|TemporalDuration} tickValue milliseconds or a string parseable by parseTime
|
|
4796
4850
|
* @param {boolean} isAsync whether this is an async tick
|
|
4797
4851
|
* @param {FakeTimersFunction} [resolve] promise resolve function
|
|
4798
4852
|
* @param {FakeTimersFunction} [reject] promise reject function
|
|
@@ -4848,7 +4902,7 @@ function requireFakeTimersSrc () {
|
|
|
4848
4902
|
}
|
|
4849
4903
|
|
|
4850
4904
|
/**
|
|
4851
|
-
* @param {string|number} tickValue number of milliseconds
|
|
4905
|
+
* @param {string|number|TemporalDuration} tickValue number of milliseconds, a human-readable value like "01:11:15", or a Temporal.Duration
|
|
4852
4906
|
* @returns {number} will return the new `now` value
|
|
4853
4907
|
*/
|
|
4854
4908
|
clock.tick = function tick(tickValue) {
|
|
@@ -4929,7 +4983,7 @@ function requireFakeTimersSrc () {
|
|
|
4929
4983
|
|
|
4930
4984
|
if (typeof _global.Promise !== "undefined") {
|
|
4931
4985
|
/**
|
|
4932
|
-
* @param {string|number} tickValue number of milliseconds
|
|
4986
|
+
* @param {string|number|TemporalDuration} tickValue number of milliseconds, a human-readable value like "01:11:15", or a Temporal.Duration
|
|
4933
4987
|
* @returns {Promise}
|
|
4934
4988
|
*/
|
|
4935
4989
|
clock.tickAsync = function tickAsync(tickValue) {
|
|
@@ -5055,14 +5109,11 @@ function requireFakeTimersSrc () {
|
|
|
5055
5109
|
};
|
|
5056
5110
|
|
|
5057
5111
|
/**
|
|
5058
|
-
* @param {string|number} tickValue number of milliseconds
|
|
5112
|
+
* @param {string|number|TemporalDuration} tickValue number of milliseconds, a human-readable value like "01:11:15", or a Temporal.Duration
|
|
5059
5113
|
* @returns {number} the new `now` value
|
|
5060
5114
|
*/
|
|
5061
5115
|
clock.jump = function jump(tickValue) {
|
|
5062
|
-
const msFloat =
|
|
5063
|
-
typeof tickValue === "number"
|
|
5064
|
-
? tickValue
|
|
5065
|
-
: parseTime(tickValue);
|
|
5116
|
+
const msFloat = tickValueToMs(tickValue);
|
|
5066
5117
|
const ms = Math.floor(msFloat);
|
|
5067
5118
|
|
|
5068
5119
|
forEachActiveTimer(clock, (timer) => {
|
|
@@ -5087,6 +5138,97 @@ function requireFakeTimersSrc () {
|
|
|
5087
5138
|
clock.hrtime = hrtime;
|
|
5088
5139
|
}
|
|
5089
5140
|
|
|
5141
|
+
/**
|
|
5142
|
+
* @returns {Timer[]}
|
|
5143
|
+
*/
|
|
5144
|
+
clock.uninstall = function () {
|
|
5145
|
+
uninstalled = true;
|
|
5146
|
+
clock.setTickMode({ mode: "manual" });
|
|
5147
|
+
|
|
5148
|
+
if (clock.methods) {
|
|
5149
|
+
const installedHrTime = "_hrtime";
|
|
5150
|
+
const installedNextTick = "_nextTick";
|
|
5151
|
+
let method, i, l;
|
|
5152
|
+
for (i = 0, l = clock.methods.length; i < l; i++) {
|
|
5153
|
+
method = clock.methods[i];
|
|
5154
|
+
if (method === "hrtime" && _global.process) {
|
|
5155
|
+
_global.process.hrtime = clock[installedHrTime];
|
|
5156
|
+
} else if (method === "nextTick" && _global.process) {
|
|
5157
|
+
_global.process.nextTick = clock[installedNextTick];
|
|
5158
|
+
} else if (method === "performance") {
|
|
5159
|
+
const originalPerfDescriptor =
|
|
5160
|
+
Object.getOwnPropertyDescriptor(
|
|
5161
|
+
clock,
|
|
5162
|
+
`_${method}`,
|
|
5163
|
+
);
|
|
5164
|
+
if (
|
|
5165
|
+
originalPerfDescriptor &&
|
|
5166
|
+
originalPerfDescriptor.get &&
|
|
5167
|
+
!originalPerfDescriptor.set
|
|
5168
|
+
) {
|
|
5169
|
+
Object.defineProperty(
|
|
5170
|
+
_global,
|
|
5171
|
+
method,
|
|
5172
|
+
originalPerfDescriptor,
|
|
5173
|
+
);
|
|
5174
|
+
} else if (originalPerfDescriptor.configurable) {
|
|
5175
|
+
_global[method] = clock[`_${method}`];
|
|
5176
|
+
}
|
|
5177
|
+
} else {
|
|
5178
|
+
if (clock[method] && clock[method].hasOwnProperty) {
|
|
5179
|
+
_global[method] = clock[`_${method}`];
|
|
5180
|
+
} else {
|
|
5181
|
+
try {
|
|
5182
|
+
delete _global[method];
|
|
5183
|
+
} catch {
|
|
5184
|
+
/* eslint no-empty: "off" */
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
}
|
|
5188
|
+
if (clock.timersModuleMethods !== undefined) {
|
|
5189
|
+
for (
|
|
5190
|
+
let j = 0;
|
|
5191
|
+
j < clock.timersModuleMethods.length;
|
|
5192
|
+
j++
|
|
5193
|
+
) {
|
|
5194
|
+
const entry = clock.timersModuleMethods[j];
|
|
5195
|
+
timersModule[entry.methodName] = entry.original;
|
|
5196
|
+
}
|
|
5197
|
+
}
|
|
5198
|
+
if (clock.timersPromisesModuleMethods !== undefined) {
|
|
5199
|
+
for (
|
|
5200
|
+
let j = 0;
|
|
5201
|
+
j < clock.timersPromisesModuleMethods.length;
|
|
5202
|
+
j++
|
|
5203
|
+
) {
|
|
5204
|
+
const entry = clock.timersPromisesModuleMethods[j];
|
|
5205
|
+
timersPromisesModule[entry.methodName] =
|
|
5206
|
+
entry.original;
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
5209
|
+
}
|
|
5210
|
+
|
|
5211
|
+
// Prevent multiple executions which will completely remove these props
|
|
5212
|
+
clock.methods = [];
|
|
5213
|
+
}
|
|
5214
|
+
|
|
5215
|
+
if (clock.abortListenerMap) {
|
|
5216
|
+
for (const [
|
|
5217
|
+
listener,
|
|
5218
|
+
signal,
|
|
5219
|
+
] of clock.abortListenerMap.entries()) {
|
|
5220
|
+
signal.removeEventListener("abort", listener);
|
|
5221
|
+
clock.abortListenerMap.delete(listener);
|
|
5222
|
+
}
|
|
5223
|
+
}
|
|
5224
|
+
|
|
5225
|
+
// return pending timers, to enable checking what timers remained on uninstall
|
|
5226
|
+
if (!clock.timerHeap) {
|
|
5227
|
+
return [];
|
|
5228
|
+
}
|
|
5229
|
+
return clock.timerHeap.timers.slice();
|
|
5230
|
+
};
|
|
5231
|
+
|
|
5090
5232
|
return clock;
|
|
5091
5233
|
}
|
|
5092
5234
|
|
|
@@ -5175,10 +5317,6 @@ function requireFakeTimersSrc () {
|
|
|
5175
5317
|
const clock = createClock(config.now, config.loopLimit);
|
|
5176
5318
|
clock.shouldClearNativeTimers = config.shouldClearNativeTimers;
|
|
5177
5319
|
|
|
5178
|
-
clock.uninstall = function () {
|
|
5179
|
-
return uninstall(clock);
|
|
5180
|
-
};
|
|
5181
|
-
|
|
5182
5320
|
clock.abortListenerMap = new Map();
|
|
5183
5321
|
|
|
5184
5322
|
if (hasToFake) {
|
|
@@ -5692,6 +5830,235 @@ class FakeTimers {
|
|
|
5692
5830
|
}
|
|
5693
5831
|
}
|
|
5694
5832
|
|
|
5833
|
+
const whenSymbol = Symbol.for("$$vitest:when");
|
|
5834
|
+
/**
|
|
5835
|
+
* Returns `true` if the given value is a {@linkcode When} chain created by {@linkcode when|vi.when}.
|
|
5836
|
+
*
|
|
5837
|
+
* @param input - The value to check.
|
|
5838
|
+
* @returns `true` if `input` is a {@linkcode When} instance, `false` otherwise.
|
|
5839
|
+
*
|
|
5840
|
+
* @example
|
|
5841
|
+
* const spy = vi.fn()
|
|
5842
|
+
* const w = vi.when(spy).calledWith(1).thenReturn(0)
|
|
5843
|
+
*
|
|
5844
|
+
* expect(isWhenChain(w)).toBe(true)
|
|
5845
|
+
* expect(isWhenChain(spy)).toBe(false)
|
|
5846
|
+
*/
|
|
5847
|
+
function isWhenChain(input) {
|
|
5848
|
+
try {
|
|
5849
|
+
return Reflect.has(input, whenSymbol);
|
|
5850
|
+
} catch {
|
|
5851
|
+
return false;
|
|
5852
|
+
}
|
|
5853
|
+
}
|
|
5854
|
+
/**
|
|
5855
|
+
* Defines conditional behaviors on a Vitest spy based on the arguments it is called with.
|
|
5856
|
+
*
|
|
5857
|
+
* Behaviors are matched using deep equality, last-registered first within each argument set.
|
|
5858
|
+
*
|
|
5859
|
+
* It automatically restores the spy's original implementation when the enclosing block exits if used with the `using` keyword.
|
|
5860
|
+
*
|
|
5861
|
+
* @param spy - A Vitest mock function to attach behaviors to.
|
|
5862
|
+
* @param options - Optional configuration.
|
|
5863
|
+
* @returns A {@linkcode When} instance for registering behaviors.
|
|
5864
|
+
*
|
|
5865
|
+
* @throws {TypeError} If `spy` is not a Vitest mock function.
|
|
5866
|
+
* @throws {Error} If chaining a non-existent method after `calledWith`.
|
|
5867
|
+
* @throws {RangeError} If setting the `times` option on a `then*` method as a negative value or `0`.
|
|
5868
|
+
*
|
|
5869
|
+
* @since 5.0.0
|
|
5870
|
+
* @see {@link https://vitest.dev/api/vi#vi-when}
|
|
5871
|
+
* @see {@link https://vitest.dev/guide/recipes/conditional-mocking}
|
|
5872
|
+
*
|
|
5873
|
+
* @example
|
|
5874
|
+
* // Basic usage
|
|
5875
|
+
* const spy = vi.fn(() => Number.NEGATIVE_INFINITY)
|
|
5876
|
+
* vi.when(spy).calledWith(1).thenReturn(0)
|
|
5877
|
+
*
|
|
5878
|
+
* expect(spy(1)).toBe(0)
|
|
5879
|
+
* expect(spy(2)).toBe(Number.NEGATIVE_INFINITY) // falls through to original implementation
|
|
5880
|
+
*
|
|
5881
|
+
* @example
|
|
5882
|
+
* // Async
|
|
5883
|
+
* const spy = vi.fn()
|
|
5884
|
+
* vi.when(spy).calledWith('user').thenResolve({ id: 1 })
|
|
5885
|
+
*
|
|
5886
|
+
* await expect(spy('user')).resolves.toEqual({ id: 1 })
|
|
5887
|
+
*
|
|
5888
|
+
* @example
|
|
5889
|
+
* // Scoped with `using`
|
|
5890
|
+
* const spy = vi.fn()
|
|
5891
|
+
*
|
|
5892
|
+
* {
|
|
5893
|
+
* using w = vi.when(spy)
|
|
5894
|
+
* .calledWith('darkMode')
|
|
5895
|
+
* .thenReturn(true)
|
|
5896
|
+
*
|
|
5897
|
+
* expect(spy('darkMode')).toBe(true)
|
|
5898
|
+
* }
|
|
5899
|
+
*
|
|
5900
|
+
* // spy's original implementation is restored here
|
|
5901
|
+
* expect(spy('darkMode')).toBe(undefined)
|
|
5902
|
+
*
|
|
5903
|
+
* @example
|
|
5904
|
+
* // Throw on unmatched calls
|
|
5905
|
+
* vi.when(spy, { onUnmatched: 'throw' })
|
|
5906
|
+
* .calledWith(1)
|
|
5907
|
+
* .thenReturn({ id: 1, name: 'Alice' })
|
|
5908
|
+
*
|
|
5909
|
+
* expect(spy(1)).toEqual({ id: 1, name: 'Alice' })
|
|
5910
|
+
* expect(() => spy(2)).toThrow()
|
|
5911
|
+
*/
|
|
5912
|
+
function when(spy, options) {
|
|
5913
|
+
if (!isMockFunction(spy)) throw new TypeError("vi.when: the argument must be a mock function created with `vi.fn()` or `vi.spyOn()`");
|
|
5914
|
+
const behaviors = [];
|
|
5915
|
+
const originalImplementation = spy.getMockImplementation();
|
|
5916
|
+
function findAction(args) {
|
|
5917
|
+
const testers = [...getCustomEqualityTesters(), iterableEquality];
|
|
5918
|
+
for (const behavior of behaviors) if (equals(args, behavior.arguments, testers)) return behavior.actions.findLast((action) => !(action.remaining === 0 && action.called)) ?? null;
|
|
5919
|
+
return null;
|
|
5920
|
+
}
|
|
5921
|
+
spy.mockImplementation(
|
|
5922
|
+
// @ts-expect-error cannot resolve generic args
|
|
5923
|
+
(...args) => {
|
|
5924
|
+
const action = findAction(args);
|
|
5925
|
+
if (action === null) return (typeof options?.onUnmatched === "function" ? options.onUnmatched : options?.onUnmatched === "throw" ? () => {
|
|
5926
|
+
throw new Error(`vi.when: no behavior defined when called with [${args.map((arg) => stringify(arg)).join(", ")}]`);
|
|
5927
|
+
} : originalImplementation)?.(...args);
|
|
5928
|
+
action.remaining -= 1;
|
|
5929
|
+
action.called = true;
|
|
5930
|
+
switch (action.type) {
|
|
5931
|
+
case "return": return action.value;
|
|
5932
|
+
case "throw": throw action.value;
|
|
5933
|
+
case "resolve": return Promise.resolve(action.value);
|
|
5934
|
+
case "reject": return Promise.reject(action.value);
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
);
|
|
5938
|
+
function getOrCreateBehavior(args) {
|
|
5939
|
+
const testers = [...getCustomEqualityTesters(), iterableEquality];
|
|
5940
|
+
let behavior = behaviors.find((behavior) => equals(args, behavior.arguments, testers));
|
|
5941
|
+
if (behavior === void 0) {
|
|
5942
|
+
behavior = {
|
|
5943
|
+
arguments: args,
|
|
5944
|
+
actions: []
|
|
5945
|
+
};
|
|
5946
|
+
behaviors.push(behavior);
|
|
5947
|
+
}
|
|
5948
|
+
return behavior;
|
|
5949
|
+
}
|
|
5950
|
+
// @ts-expect-error `Symbol.dispose` has to be assigned conditionally since it's only supported in Node >= 24
|
|
5951
|
+
const output = markWhenChain({
|
|
5952
|
+
calledWith: (...args) => {
|
|
5953
|
+
const behavior = getOrCreateBehavior(args);
|
|
5954
|
+
function appendAction(behavior, type, value, times) {
|
|
5955
|
+
behavior.actions.push({
|
|
5956
|
+
type,
|
|
5957
|
+
value,
|
|
5958
|
+
times,
|
|
5959
|
+
remaining: times,
|
|
5960
|
+
called: false
|
|
5961
|
+
});
|
|
5962
|
+
}
|
|
5963
|
+
const calledWithInstance = markWhenChain({
|
|
5964
|
+
...output,
|
|
5965
|
+
thenThrow: (value, options) => {
|
|
5966
|
+
validateOptions(options);
|
|
5967
|
+
appendAction(behavior, "throw", value, options?.times ?? Number.POSITIVE_INFINITY);
|
|
5968
|
+
return calledWithInstance;
|
|
5969
|
+
},
|
|
5970
|
+
thenThrowOnce: (value) => {
|
|
5971
|
+
appendAction(behavior, "throw", value, 1);
|
|
5972
|
+
return calledWithInstance;
|
|
5973
|
+
},
|
|
5974
|
+
thenReturn: (value, options) => {
|
|
5975
|
+
validateOptions(options);
|
|
5976
|
+
appendAction(behavior, "return", value, options?.times ?? Number.POSITIVE_INFINITY);
|
|
5977
|
+
return calledWithInstance;
|
|
5978
|
+
},
|
|
5979
|
+
thenReturnOnce: (value) => {
|
|
5980
|
+
appendAction(behavior, "return", value, 1);
|
|
5981
|
+
return calledWithInstance;
|
|
5982
|
+
},
|
|
5983
|
+
thenResolve: (value, options) => {
|
|
5984
|
+
validateOptions(options);
|
|
5985
|
+
appendAction(behavior, "resolve", value, options?.times ?? Number.POSITIVE_INFINITY);
|
|
5986
|
+
return calledWithInstance;
|
|
5987
|
+
},
|
|
5988
|
+
thenResolveOnce: (value) => {
|
|
5989
|
+
appendAction(behavior, "resolve", value, 1);
|
|
5990
|
+
return calledWithInstance;
|
|
5991
|
+
},
|
|
5992
|
+
thenReject: (value, options) => {
|
|
5993
|
+
validateOptions(options);
|
|
5994
|
+
appendAction(behavior, "reject", value, options?.times ?? Number.POSITIVE_INFINITY);
|
|
5995
|
+
return calledWithInstance;
|
|
5996
|
+
},
|
|
5997
|
+
thenRejectOnce: (value) => {
|
|
5998
|
+
appendAction(behavior, "reject", value, 1);
|
|
5999
|
+
return calledWithInstance;
|
|
6000
|
+
}
|
|
6001
|
+
});
|
|
6002
|
+
return calledWithInstance;
|
|
6003
|
+
},
|
|
6004
|
+
_getDiagnostics: () => {
|
|
6005
|
+
const pendingBehaviors = behaviors.filter((behavior) => behavior.actions.length === 0 || behavior.actions.some((action) => !hasBeenConsumed(action)));
|
|
6006
|
+
return {
|
|
6007
|
+
isExhausted: behaviors.length !== 0 && pendingBehaviors.length === 0,
|
|
6008
|
+
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")
|
|
6009
|
+
};
|
|
6010
|
+
}
|
|
6011
|
+
});
|
|
6012
|
+
if (Symbol.dispose) output[Symbol.dispose] = () => {
|
|
6013
|
+
spy.mockImplementation(
|
|
6014
|
+
// @ts-expect-error without an original implementation we should fall back to an undefined-returning function as that's what the mocking functions do
|
|
6015
|
+
originalImplementation ?? noop
|
|
6016
|
+
);
|
|
6017
|
+
};
|
|
6018
|
+
return output;
|
|
6019
|
+
}
|
|
6020
|
+
const whenChainMarkerOptions = {};
|
|
6021
|
+
function markWhenChain(input) {
|
|
6022
|
+
Reflect.defineProperty(input, whenSymbol, whenChainMarkerOptions);
|
|
6023
|
+
return input;
|
|
6024
|
+
}
|
|
6025
|
+
function formatActions(actions) {
|
|
6026
|
+
const lines = actions.map((action, index) => {
|
|
6027
|
+
const method = getMethodName(action.type);
|
|
6028
|
+
const left = ` ${getSymbol(action)} ${method}(${stringify(action.value)}${action.times === Number.POSITIVE_INFINITY ? "" : `, { times: ${action.times} }`})`;
|
|
6029
|
+
const unreachable = !hasBeenConsumed(action) && actions.slice(index + 1).some((later) => later.times === Number.POSITIVE_INFINITY);
|
|
6030
|
+
return {
|
|
6031
|
+
left,
|
|
6032
|
+
remaining: getRemainingLabel(action) + (unreachable ? " → unreachable action" : "")
|
|
6033
|
+
};
|
|
6034
|
+
});
|
|
6035
|
+
const maxLeft = Math.max(...lines.map((line) => line.left.length));
|
|
6036
|
+
return lines.map(({ left, remaining }) => `${left.padEnd(maxLeft + 2)}${remaining}`).join("\n");
|
|
6037
|
+
}
|
|
6038
|
+
function getMethodName(type) {
|
|
6039
|
+
switch (type) {
|
|
6040
|
+
case "return": return "thenReturn";
|
|
6041
|
+
case "resolve": return "thenResolve";
|
|
6042
|
+
case "throw": return "thenThrow";
|
|
6043
|
+
case "reject": return "thenReject";
|
|
6044
|
+
default: throw new Error(`vi.when: "${type}" is not a known method`);
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6047
|
+
function hasBeenConsumed(action) {
|
|
6048
|
+
return action.remaining === 0 || action.remaining === Number.POSITIVE_INFINITY && action.called;
|
|
6049
|
+
}
|
|
6050
|
+
function getRemainingLabel(action) {
|
|
6051
|
+
if (hasBeenConsumed(action)) return action.remaining === Number.POSITIVE_INFINITY ? "exhausted" : `exhausted (${action.times} of ${action.times})`;
|
|
6052
|
+
return action.remaining === Number.POSITIVE_INFINITY ? "never called" : `${action.remaining} remaining (out of ${action.times})`;
|
|
6053
|
+
}
|
|
6054
|
+
function getSymbol(action) {
|
|
6055
|
+
if (hasBeenConsumed(action)) return "✓";
|
|
6056
|
+
return "✗";
|
|
6057
|
+
}
|
|
6058
|
+
function validateOptions(options) {
|
|
6059
|
+
if (typeof options?.times === "number" && options.times <= 0) throw new RangeError("vi.when: `times` option must be greater than 0");
|
|
6060
|
+
}
|
|
6061
|
+
|
|
5695
6062
|
function copyStackTrace$2(target, source) {
|
|
5696
6063
|
if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
|
|
5697
6064
|
return target;
|
|
@@ -5888,6 +6255,8 @@ function createVitest() {
|
|
|
5888
6255
|
},
|
|
5889
6256
|
spyOn,
|
|
5890
6257
|
fn,
|
|
6258
|
+
when,
|
|
6259
|
+
isWhenChain,
|
|
5891
6260
|
waitFor,
|
|
5892
6261
|
waitUntil,
|
|
5893
6262
|
defineHelper: (fn) => {
|
|
@@ -6034,6 +6403,20 @@ function copyStackTrace$1(target, source) {
|
|
|
6034
6403
|
if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
|
|
6035
6404
|
return target;
|
|
6036
6405
|
}
|
|
6406
|
+
function waitNextTick() {
|
|
6407
|
+
const { setTimeout } = getSafeTimers();
|
|
6408
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
6409
|
+
}
|
|
6410
|
+
async function waitForImportsToResolve() {
|
|
6411
|
+
await waitNextTick();
|
|
6412
|
+
const state = getWorkerState();
|
|
6413
|
+
const promises = [];
|
|
6414
|
+
const resolvingCount = state.resolvingModules.size;
|
|
6415
|
+
for (const [_, mod] of state.evaluatedModules.idToModuleMap) if (mod.promise && !mod.evaluated) promises.push(mod.promise);
|
|
6416
|
+
if (!promises.length && !resolvingCount) return;
|
|
6417
|
+
await Promise.allSettled(promises);
|
|
6418
|
+
await waitForImportsToResolve();
|
|
6419
|
+
}
|
|
6037
6420
|
|
|
6038
6421
|
// these matchers are not supported because they don't make sense with poll
|
|
6039
6422
|
const unsupported = [
|
|
@@ -6057,7 +6440,7 @@ const unsupported = [
|
|
|
6057
6440
|
* @throws Always throws the provided error with an amended stack trace
|
|
6058
6441
|
*/
|
|
6059
6442
|
function throwWithCause(error, source) {
|
|
6060
|
-
|
|
6443
|
+
error.cause ??= /* @__PURE__ */ new Error("Matcher did not succeed in time.");
|
|
6061
6444
|
throw copyStackTrace(error, source);
|
|
6062
6445
|
}
|
|
6063
6446
|
function createExpectPoll(expect) {
|
|
@@ -6215,6 +6598,15 @@ function raceWith$1(promise, other) {
|
|
|
6215
6598
|
}))]);
|
|
6216
6599
|
}
|
|
6217
6600
|
|
|
6601
|
+
const MockPlugin = (chai, utils) => {
|
|
6602
|
+
utils.addMethod(chai.Assertion.prototype, "toHaveBeenExhausted", wrapAssertion(utils, "toHaveBeenExhausted", function() {
|
|
6603
|
+
const chain = utils.flag(this, "object");
|
|
6604
|
+
if (!isWhenChain(chain)) throw new TypeError(`${utils.inspect(chain)} is not a \`vi.when\` instance`);
|
|
6605
|
+
const diagnostics = chain._getDiagnostics();
|
|
6606
|
+
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");
|
|
6607
|
+
}));
|
|
6608
|
+
};
|
|
6609
|
+
|
|
6218
6610
|
var naturalCompare$1 = {exports: {}};
|
|
6219
6611
|
|
|
6220
6612
|
var hasRequiredNaturalCompare;
|
|
@@ -6874,7 +7266,7 @@ class SnapshotState {
|
|
|
6874
7266
|
if (!rawSnapshot) receivedSerialized = addExtraLineBreaks(receivedSerialized);
|
|
6875
7267
|
if (rawSnapshot) {
|
|
6876
7268
|
// normalize EOL when snapshot contains CRLF but received is LF
|
|
6877
|
-
if (rawSnapshot.content &&
|
|
7269
|
+
if (rawSnapshot.content && /\r\n/.test(rawSnapshot.content) && !/\r\n/.test(receivedSerialized)) rawSnapshot.content = normalizeNewlines(rawSnapshot.content);
|
|
6878
7270
|
}
|
|
6879
7271
|
const expected = isInline ? inlineSnapshot : rawSnapshot ? rawSnapshot.content : this._snapshotData[key];
|
|
6880
7272
|
const expectedTrimmed = rawSnapshot ? expected : expected?.trim();
|
|
@@ -7467,6 +7859,7 @@ chai.use(JestChaiExpect);
|
|
|
7467
7859
|
chai.use(ChaiStyleAssertions);
|
|
7468
7860
|
chai.use(SnapshotPlugin);
|
|
7469
7861
|
chai.use(JestAsymmetricMatchers);
|
|
7862
|
+
chai.use(MockPlugin);
|
|
7470
7863
|
|
|
7471
7864
|
function createExpect(test) {
|
|
7472
7865
|
const expect = ((value, message) => {
|
|
@@ -7724,7 +8117,7 @@ function createBench(test, config) {
|
|
|
7724
8117
|
bench.compare = async (...args) => {
|
|
7725
8118
|
validateBenchmarkProject(config);
|
|
7726
8119
|
// extract optional trailing BenchCompareOptions argument
|
|
7727
|
-
const lastArg = args
|
|
8120
|
+
const lastArg = args.at(-1);
|
|
7728
8121
|
const benchOptions = lastArg != null && typeof lastArg === "object" && !(kRegistration in lastArg) ? args.pop() : void 0;
|
|
7729
8122
|
const registrations = args;
|
|
7730
8123
|
// Mark every passed-in registration as consumed before validation so a
|
|
@@ -7775,7 +8168,7 @@ function createBench(test, config) {
|
|
|
7775
8168
|
};
|
|
7776
8169
|
bench[kFinalize] = () => {
|
|
7777
8170
|
if (pending.size === 0) return;
|
|
7778
|
-
const names =
|
|
8171
|
+
const names = Array.from(pending, (reg) => `"${reg.name}"`).join(", ");
|
|
7779
8172
|
pending.clear();
|
|
7780
8173
|
console.warn([
|
|
7781
8174
|
c.yellow(c.bold("Benchmark Warning")),
|
|
@@ -7981,6 +8374,7 @@ class TestRunner {
|
|
|
7981
8374
|
static setSuiteHooks = getHooks;
|
|
7982
8375
|
static setTestFn = getFn;
|
|
7983
8376
|
static matchesTags = matchesTags;
|
|
8377
|
+
static createFileTask = createFileTask;
|
|
7984
8378
|
/**
|
|
7985
8379
|
* @experimental
|
|
7986
8380
|
* A function that runs tinybench tasks.
|