vitest 5.0.0-beta.2 → 5.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/chunks/{base.Opc_YHkk.js → base.BEGVMQrS.js} +6 -6
- package/dist/chunks/{browser.d.BUhkKcDl.d.ts → browser.d.BGxB4Xum.d.ts} +5 -26
- package/dist/chunks/{cac.8N4bOkkB.js → cac.CyXAEMkE.js} +26 -33
- package/dist/chunks/{cli-api.B0RFke2g.js → cli-api.DJMXq34b.js} +640 -615
- package/dist/chunks/{config.d.D91DHYaD.d.ts → config.d.DXq1aBpy.d.ts} +93 -89
- package/dist/chunks/{creator.BqL2U_x4.js → creator.D66cVXYh.js} +2 -2
- package/dist/chunks/{defaults.szbHWQun.js → defaults.CUUnbOrq.js} +6 -4
- package/dist/chunks/{env.D4Lgay0q.js → env.BKKtU2WC.js} +2 -1
- package/dist/chunks/global.d.BtKPuz2X.d.ts +194 -0
- package/dist/chunks/{globals.EHmmu0nC.js → globals.BuY-yD0m.js} +2 -1
- package/dist/chunks/{index.D_7-4CaB.js → index.CE58PZNH.js} +1660 -701
- package/dist/chunks/{index.CViWo__T.js → index.CcluKS59.js} +4 -4
- package/dist/chunks/{index.CbgUM9E5.js → index.nQFVd50u.js} +2 -1
- package/dist/chunks/{init-forks.DMge3WTt.js → init-forks.Ce3vGWgL.js} +1 -1
- package/dist/chunks/{init-threads.eIoyCTon.js → init-threads.8e1OLv5v.js} +1 -1
- package/dist/chunks/{init.BVd7SaCA.js → init.6qx-LaHs.js} +31 -3
- package/dist/chunks/{nativeModuleMocker.DKpFw0pk.js → nativeModuleMocker.DDZfQXLs.js} +1 -1
- package/dist/chunks/{plugin.d.cIKZEZ16.d.ts → plugin.d.B7MTG_Fe.d.ts} +103 -88
- package/dist/chunks/{rpc.d.7JZuxZ8u.d.ts → rpc.d.OQ_EZi1Z.d.ts} +18 -2
- package/dist/chunks/{setup-common.Hpq30zVk.js → setup-common.DdEF_hkE.js} +1 -1
- package/dist/chunks/{vm.2okbRRME.js → vm.Bu7mmcZq.js} +2 -2
- package/dist/chunks/{worker.d.Bu1kXGw4.d.ts → worker.d.yR22cs6X.d.ts} +3 -2
- package/dist/cli.js +2 -2
- package/dist/config.cjs +1 -1
- package/dist/config.d.ts +7 -10
- package/dist/config.js +2 -2
- package/dist/index.d.ts +24 -41
- package/dist/index.js +2 -1
- package/dist/module-evaluator.d.ts +4 -1
- package/dist/module-evaluator.js +15 -20
- package/dist/node.d.ts +20 -13
- package/dist/node.js +6 -6
- package/dist/runtime.js +2 -2
- package/dist/worker.d.ts +3 -3
- package/dist/worker.js +7 -6
- package/dist/workers/forks.js +8 -7
- package/dist/workers/runVmTests.js +4 -3
- package/dist/workers/threads.js +8 -7
- package/dist/workers/vmForks.js +4 -4
- package/dist/workers/vmThreads.js +4 -4
- package/package.json +20 -21
- package/dist/chunks/global.d.DhbKSQoV.d.ts +0 -99
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import { TestSyntaxError, getCurrentTest,
|
|
1
|
+
import { TestSyntaxError, getCurrentTest, createTaskCollector, getCurrentSuite, getHooks, getFn, afterAll, afterEach, aroundAll, aroundEach, beforeAll, beforeEach, describe, it, onTestFailed, onTestFinished, recordArtifact, suite, test } from '@vitest/runner';
|
|
2
2
|
import { i as isChildProcess, w as waitForImportsToResolve, r as resetModules, g as getWorkerState } from './utils.BX5Fg8C4.js';
|
|
3
3
|
import { getSafeTimers, delay } from '@vitest/utils/timers';
|
|
4
4
|
import { isMockFunction, fn, spyOn, restoreAllMocks, resetAllMocks, clearAllMocks } from '@vitest/spy';
|
|
5
|
-
import { getType, isObject, noop, assertTypes, ordinal, createSimpleStackTrace, getCallLastIndex
|
|
5
|
+
import { getType, isObject, noop, assertTypes, ordinal, createSimpleStackTrace, getCallLastIndex } from '@vitest/utils/helpers';
|
|
6
6
|
import { positionToOffset, offsetToLineNumber, lineSplitRE } from '@vitest/utils/offset';
|
|
7
7
|
import { parseSingleStack, parseErrorStacktrace } from '@vitest/utils/source-map';
|
|
8
8
|
import { c as commonjsGlobal, g as getDefaultExportFromCjs } from './_commonjsHelpers.D26ty3Ew.js';
|
|
9
9
|
import { R as RealDate, b as resetDate, m as mockDate, r as rpc, V as VitestEvaluatedModules } from './rpc.DFRWVnRh.js';
|
|
10
10
|
import * as chai from 'chai';
|
|
11
11
|
import { use, util } from 'chai';
|
|
12
|
-
import { getNames,
|
|
12
|
+
import { getNames, getTests, getTestName, createChainable, matchesTags } from '@vitest/runner/utils';
|
|
13
13
|
import { processError } from '@vitest/utils/error';
|
|
14
14
|
import { g as getSerializers, a as addSerializer } from './plugins.DrsmdUE2.js';
|
|
15
15
|
import { format } from '@vitest/pretty-format';
|
|
16
16
|
import { printDiffOrStringify, diff } from '@vitest/utils/diff';
|
|
17
17
|
import { stringify, inspect } from '@vitest/utils/display';
|
|
18
18
|
import c from 'tinyrainbow';
|
|
19
|
-
import { normalize } from 'pathe';
|
|
19
|
+
import { isAbsolute, relative, normalize } from 'pathe';
|
|
20
|
+
import { Bench } from 'tinybench';
|
|
20
21
|
import { expectTypeOf } from 'expect-type';
|
|
21
22
|
|
|
22
23
|
const ChaiStyleAssertions = (chai, utils) => {
|
|
@@ -1590,6 +1591,48 @@ const JestExtend = (chai, utils) => {
|
|
|
1590
1591
|
});
|
|
1591
1592
|
};
|
|
1592
1593
|
|
|
1594
|
+
function isBenchResult(value) {
|
|
1595
|
+
return typeof value === "object" && value !== null && "latency" in value && typeof value.latency?.mean === "number";
|
|
1596
|
+
}
|
|
1597
|
+
function formatOps(ops) {
|
|
1598
|
+
return ops.toLocaleString("en-US", {
|
|
1599
|
+
minimumFractionDigits: 2,
|
|
1600
|
+
maximumFractionDigits: 2
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1603
|
+
const benchMatchers = {
|
|
1604
|
+
toBeFasterThan(actual, expected, options) {
|
|
1605
|
+
const { matcherHint, RECEIVED_COLOR, EXPECTED_COLOR } = this.utils;
|
|
1606
|
+
const delta = options?.delta ?? 0;
|
|
1607
|
+
if (!isBenchResult(actual)) throw new TypeError(`${matcherHint(".toBeFasterThan")} expects the actual value to be a benchmark result.`);
|
|
1608
|
+
if (!isBenchResult(expected)) throw new TypeError(`${matcherHint(".toBeFasterThan")} expects the expected value to be a benchmark result.`);
|
|
1609
|
+
const threshold = expected.latency.mean * (1 - delta);
|
|
1610
|
+
const pass = actual.latency.mean < threshold;
|
|
1611
|
+
return {
|
|
1612
|
+
pass,
|
|
1613
|
+
message: () => {
|
|
1614
|
+
const relation = ((actual.latency.mean - expected.latency.mean) / expected.latency.mean * 100).toFixed(2);
|
|
1615
|
+
return pass ? `${matcherHint(".not.toBeFasterThan")}\n\nExpected to not be faster, but was ${Math.abs(Number(relation))}% faster.\n\nReceived: ${RECEIVED_COLOR(formatOps(actual.throughput.mean))} ops/sec\nExpected: ${EXPECTED_COLOR(formatOps(expected.throughput.mean))} ops/sec\n` : `${matcherHint(".toBeFasterThan")}\n\nExpected to be faster${delta > 0 ? ` by at least ${(delta * 100).toFixed(0)}%` : ""}, but was ${Number(relation) > 0 ? `${relation}% slower` : `only ${Math.abs(Number(relation))}% faster`}.\n\nReceived: ${RECEIVED_COLOR(formatOps(actual.throughput.mean))} ops/sec\nExpected: ${EXPECTED_COLOR(formatOps(expected.throughput.mean))} ops/sec\n`;
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1618
|
+
},
|
|
1619
|
+
toBeSlowerThan(actual, expected, options) {
|
|
1620
|
+
const { matcherHint, RECEIVED_COLOR, EXPECTED_COLOR } = this.utils;
|
|
1621
|
+
const delta = options?.delta ?? 0;
|
|
1622
|
+
if (!isBenchResult(actual)) throw new TypeError(`${matcherHint(".toBeSlowerThan")} expects the actual value to be a benchmark result.`);
|
|
1623
|
+
if (!isBenchResult(expected)) throw new TypeError(`${matcherHint(".toBeSlowerThan")} expects the expected value to be a benchmark result.`);
|
|
1624
|
+
const threshold = expected.latency.mean * (1 + delta);
|
|
1625
|
+
const pass = actual.latency.mean > threshold;
|
|
1626
|
+
return {
|
|
1627
|
+
pass,
|
|
1628
|
+
message: () => {
|
|
1629
|
+
const relation = ((actual.latency.mean - expected.latency.mean) / expected.latency.mean * 100).toFixed(2);
|
|
1630
|
+
return pass ? `${matcherHint(".not.toBeSlowerThan")}\n\nExpected to not be slower, but was ${relation}% slower.\n\nReceived: ${RECEIVED_COLOR(formatOps(actual.throughput.mean))} ops/sec\nExpected: ${EXPECTED_COLOR(formatOps(expected.throughput.mean))} ops/sec\n` : `${matcherHint(".toBeSlowerThan")}\n\nExpected to be slower${delta > 0 ? ` by at least ${(delta * 100).toFixed(0)}%` : ""}, but was ${Number(relation) < 0 ? `${Math.abs(Number(relation))}% faster` : `only ${relation}% slower`}.\n\nReceived: ${RECEIVED_COLOR(formatOps(actual.throughput.mean))} ops/sec\nExpected: ${EXPECTED_COLOR(formatOps(expected.throughput.mean))} ops/sec\n`;
|
|
1631
|
+
}
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
|
|
1593
1636
|
var fakeTimersSrc = {};
|
|
1594
1637
|
|
|
1595
1638
|
var global;
|
|
@@ -2529,12 +2572,12 @@ function requireFakeTimersSrc () {
|
|
|
2529
2572
|
if (typeof __vitest_required__ !== 'undefined') {
|
|
2530
2573
|
try {
|
|
2531
2574
|
timersModule = __vitest_required__.timers;
|
|
2532
|
-
} catch
|
|
2575
|
+
} catch {
|
|
2533
2576
|
// ignored
|
|
2534
2577
|
}
|
|
2535
2578
|
try {
|
|
2536
2579
|
timersPromisesModule = __vitest_required__.timersPromises;
|
|
2537
|
-
} catch
|
|
2580
|
+
} catch {
|
|
2538
2581
|
// ignored
|
|
2539
2582
|
}
|
|
2540
2583
|
}
|
|
@@ -2545,18 +2588,18 @@ function requireFakeTimersSrc () {
|
|
|
2545
2588
|
|
|
2546
2589
|
/**
|
|
2547
2590
|
* @typedef {object} NextAsyncTickMode
|
|
2548
|
-
* @property {"nextAsync"} mode
|
|
2591
|
+
* @property {"nextAsync"} mode - runs timers one macrotask at a time
|
|
2549
2592
|
*/
|
|
2550
2593
|
|
|
2551
2594
|
/**
|
|
2552
2595
|
* @typedef {object} ManualTickMode
|
|
2553
|
-
* @property {"manual"} mode
|
|
2596
|
+
* @property {"manual"} mode - advances only when the caller explicitly ticks
|
|
2554
2597
|
*/
|
|
2555
2598
|
|
|
2556
2599
|
/**
|
|
2557
2600
|
* @typedef {object} IntervalTickMode
|
|
2558
|
-
* @property {"interval"} mode
|
|
2559
|
-
* @property {number} [delta]
|
|
2601
|
+
* @property {"interval"} mode - advances automatically on a native interval
|
|
2602
|
+
* @property {number} [delta] - interval duration in milliseconds
|
|
2560
2603
|
*/
|
|
2561
2604
|
|
|
2562
2605
|
/**
|
|
@@ -2564,134 +2607,447 @@ function requireFakeTimersSrc () {
|
|
|
2564
2607
|
*/
|
|
2565
2608
|
|
|
2566
2609
|
/**
|
|
2567
|
-
* @
|
|
2568
|
-
* @
|
|
2569
|
-
* @
|
|
2610
|
+
* @callback FakeTimersFunction
|
|
2611
|
+
* @param {...unknown[]} args
|
|
2612
|
+
* @returns {unknown}
|
|
2570
2613
|
*/
|
|
2571
2614
|
|
|
2572
2615
|
/**
|
|
2573
|
-
*
|
|
2574
|
-
* @callback
|
|
2575
|
-
* @
|
|
2576
|
-
* @param {{timeout: number}} options - an options object
|
|
2577
|
-
* @returns {number} the id
|
|
2616
|
+
* @callback VoidVarArgsFunc
|
|
2617
|
+
* @param {...unknown[]} args - optional arguments to call the callback with
|
|
2618
|
+
* @returns {void}
|
|
2578
2619
|
*/
|
|
2579
2620
|
|
|
2580
2621
|
/**
|
|
2581
2622
|
* @callback NextTick
|
|
2582
2623
|
* @param {VoidVarArgsFunc} callback - the callback to run
|
|
2583
|
-
* @param {
|
|
2624
|
+
* @param {...unknown[]} args - optional arguments to call the callback with
|
|
2584
2625
|
* @returns {void}
|
|
2585
2626
|
*/
|
|
2586
2627
|
|
|
2587
2628
|
/**
|
|
2588
2629
|
* @callback SetImmediate
|
|
2589
2630
|
* @param {VoidVarArgsFunc} callback - the callback to run
|
|
2590
|
-
* @param {
|
|
2631
|
+
* @param {...unknown[]} args - optional arguments to call the callback with
|
|
2591
2632
|
* @returns {NodeImmediate}
|
|
2592
2633
|
*/
|
|
2593
2634
|
|
|
2594
2635
|
/**
|
|
2595
|
-
* @callback
|
|
2596
|
-
* @param {
|
|
2636
|
+
* @callback SetTimeout
|
|
2637
|
+
* @param {VoidVarArgsFunc} callback - the callback to run
|
|
2638
|
+
* @param {number} [delay] - optional delay in milliseconds
|
|
2639
|
+
* @param {...unknown[]} args - optional arguments to call the callback with
|
|
2640
|
+
* @returns {TimerId} - the timeout identifier
|
|
2641
|
+
*/
|
|
2642
|
+
|
|
2643
|
+
/**
|
|
2644
|
+
* @callback ClearTimeout
|
|
2645
|
+
* @param {TimerId} [id] - the timeout identifier to clear
|
|
2646
|
+
* @returns {void}
|
|
2647
|
+
*/
|
|
2648
|
+
|
|
2649
|
+
/**
|
|
2650
|
+
* @callback SetInterval
|
|
2651
|
+
* @param {VoidVarArgsFunc} callback - the callback to run
|
|
2652
|
+
* @param {number} [delay] - optional delay in milliseconds
|
|
2653
|
+
* @param {...unknown[]} args - optional arguments to call the callback with
|
|
2654
|
+
* @returns {TimerId} - the interval identifier
|
|
2655
|
+
*/
|
|
2656
|
+
|
|
2657
|
+
/**
|
|
2658
|
+
* @callback ClearInterval
|
|
2659
|
+
* @param {TimerId} [id] - the interval identifier to clear
|
|
2660
|
+
* @returns {void}
|
|
2661
|
+
*/
|
|
2662
|
+
|
|
2663
|
+
/**
|
|
2664
|
+
* @callback QueueMicrotask
|
|
2665
|
+
* @param {VoidVarArgsFunc} callback - the callback to run
|
|
2666
|
+
* @returns {void}
|
|
2667
|
+
*/
|
|
2668
|
+
|
|
2669
|
+
/**
|
|
2670
|
+
* @callback TimeRemaining
|
|
2671
|
+
* @returns {number}
|
|
2672
|
+
*/
|
|
2673
|
+
|
|
2674
|
+
/**
|
|
2675
|
+
* @typedef {object} IdleDeadline
|
|
2676
|
+
* @property {boolean} didTimeout - whether or not the callback was called before reaching the optional timeout
|
|
2677
|
+
* @property {TimeRemaining} timeRemaining - a floating-point value providing an estimate of the number of milliseconds remaining in the current idle period
|
|
2678
|
+
*/
|
|
2679
|
+
|
|
2680
|
+
/**
|
|
2681
|
+
* @callback RequestIdleCallbackCallback
|
|
2682
|
+
* @param {IdleDeadline} deadline
|
|
2683
|
+
*/
|
|
2684
|
+
|
|
2685
|
+
/**
|
|
2686
|
+
* Queues a function to be called during a browser's idle periods
|
|
2687
|
+
* @callback RequestIdleCallback
|
|
2688
|
+
* @param {RequestIdleCallbackCallback} callback
|
|
2689
|
+
* @param {{timeout?: number}} [options] - an options object
|
|
2690
|
+
* @returns {number} the id
|
|
2691
|
+
*/
|
|
2692
|
+
|
|
2693
|
+
/**
|
|
2694
|
+
* @callback AnimationFrameCallback
|
|
2695
|
+
* @param {number} timestamp
|
|
2696
|
+
*/
|
|
2697
|
+
|
|
2698
|
+
/**
|
|
2699
|
+
* @callback RequestAnimationFrame
|
|
2700
|
+
* @param {AnimationFrameCallback} callback
|
|
2701
|
+
* @returns {TimerId} - the request id
|
|
2702
|
+
*/
|
|
2703
|
+
|
|
2704
|
+
/**
|
|
2705
|
+
* @callback CancelAnimationFrame
|
|
2706
|
+
* @param {TimerId} id - cancels a frame callback
|
|
2707
|
+
* @returns {void}
|
|
2708
|
+
*/
|
|
2709
|
+
|
|
2710
|
+
/**
|
|
2711
|
+
* @callback CancelIdleCallback
|
|
2712
|
+
* @param {TimerId} id - cancels a scheduled idle callback
|
|
2713
|
+
* @returns {void}
|
|
2714
|
+
*/
|
|
2715
|
+
|
|
2716
|
+
/**
|
|
2717
|
+
* @callback ClearImmediate
|
|
2718
|
+
* @param {NodeImmediate} id - faked `clearImmediate`
|
|
2719
|
+
* @returns {void}
|
|
2720
|
+
*/
|
|
2721
|
+
|
|
2722
|
+
/**
|
|
2723
|
+
* @callback CountTimers
|
|
2724
|
+
* @returns {number}
|
|
2725
|
+
*/
|
|
2726
|
+
|
|
2727
|
+
/**
|
|
2728
|
+
* @callback RunMicrotasks
|
|
2729
|
+
* @returns {void}
|
|
2730
|
+
*/
|
|
2731
|
+
|
|
2732
|
+
/**
|
|
2733
|
+
* @callback Tick
|
|
2734
|
+
* @param {number|string} tickValue milliseconds or a string parseable by parseTime
|
|
2735
|
+
* @returns {number} will return the new `now` value
|
|
2736
|
+
*/
|
|
2737
|
+
|
|
2738
|
+
/**
|
|
2739
|
+
* @callback TickAsync
|
|
2740
|
+
* @param {number|string} tickValue milliseconds or a string parseable by parseTime
|
|
2741
|
+
* @returns {Promise<number>}
|
|
2742
|
+
*/
|
|
2743
|
+
|
|
2744
|
+
/**
|
|
2745
|
+
* @callback Next
|
|
2746
|
+
* @returns {number}
|
|
2747
|
+
*/
|
|
2748
|
+
|
|
2749
|
+
/**
|
|
2750
|
+
* @callback NextAsync
|
|
2751
|
+
* @returns {Promise<number>}
|
|
2752
|
+
*/
|
|
2753
|
+
|
|
2754
|
+
/**
|
|
2755
|
+
* @callback RunAll
|
|
2756
|
+
* @returns {number}
|
|
2757
|
+
*/
|
|
2758
|
+
|
|
2759
|
+
/**
|
|
2760
|
+
* @callback RunToFrame
|
|
2761
|
+
* @returns {number}
|
|
2762
|
+
*/
|
|
2763
|
+
|
|
2764
|
+
/**
|
|
2765
|
+
* @callback RunAllAsync
|
|
2766
|
+
* @returns {Promise<number>}
|
|
2767
|
+
*/
|
|
2768
|
+
|
|
2769
|
+
/**
|
|
2770
|
+
* @callback RunToLast
|
|
2771
|
+
* @returns {number}
|
|
2772
|
+
*/
|
|
2773
|
+
|
|
2774
|
+
/**
|
|
2775
|
+
* @callback RunToLastAsync
|
|
2776
|
+
* @returns {Promise<number>}
|
|
2777
|
+
*/
|
|
2778
|
+
|
|
2779
|
+
/**
|
|
2780
|
+
* @callback Reset
|
|
2597
2781
|
* @returns {void}
|
|
2598
2782
|
*/
|
|
2599
2783
|
|
|
2600
2784
|
/**
|
|
2601
|
-
* @
|
|
2602
|
-
* @
|
|
2603
|
-
* @returns {
|
|
2785
|
+
* @callback SetSystemTime
|
|
2786
|
+
* @param {number|Date} [now] initial mocked time, as milliseconds since epoch or a Date
|
|
2787
|
+
* @returns {void}
|
|
2788
|
+
*/
|
|
2789
|
+
|
|
2790
|
+
/**
|
|
2791
|
+
* @callback Jump
|
|
2792
|
+
* @param {number|string} tickValue milliseconds or a human-readable value like "01:11:15"
|
|
2793
|
+
* @returns {number}
|
|
2794
|
+
*/
|
|
2795
|
+
|
|
2796
|
+
/**
|
|
2797
|
+
* @callback Uninstall
|
|
2798
|
+
* @returns {void}
|
|
2799
|
+
*/
|
|
2800
|
+
|
|
2801
|
+
/**
|
|
2802
|
+
* @callback SetTickMode
|
|
2803
|
+
* @param {SetTickModeConfig} tickModeConfig - The new configuration for how the clock should tick.
|
|
2804
|
+
* @returns {void}
|
|
2805
|
+
*/
|
|
2806
|
+
|
|
2807
|
+
/**
|
|
2808
|
+
* @callback Hrtime
|
|
2809
|
+
* @param {Array<number>} [prev]
|
|
2810
|
+
* @returns {Array<number>}
|
|
2811
|
+
*/
|
|
2812
|
+
|
|
2813
|
+
/**
|
|
2814
|
+
* @callback WithGlobal
|
|
2815
|
+
* @param {object} _global Namespace to mock (e.g. `window`)
|
|
2816
|
+
* @returns {FakeTimers}
|
|
2817
|
+
*/
|
|
2818
|
+
|
|
2819
|
+
/**
|
|
2820
|
+
* @typedef {"setTimeout" | "clearTimeout" | "setImmediate" | "clearImmediate" | "setInterval" | "clearInterval" | "Date" | "nextTick" | "hrtime" | "requestAnimationFrame" | "cancelAnimationFrame" | "requestIdleCallback" | "cancelIdleCallback" | "performance" | "queueMicrotask"} FakeMethod
|
|
2821
|
+
*/
|
|
2822
|
+
|
|
2823
|
+
/**
|
|
2824
|
+
* @typedef {number | NodeImmediate | Timer} TimerId
|
|
2825
|
+
*/
|
|
2826
|
+
|
|
2827
|
+
/* eslint-disable jsdoc/reject-any-type */
|
|
2828
|
+
/**
|
|
2829
|
+
* @typedef {Record<string, any> & {
|
|
2830
|
+
* setTimeout?: SetTimeout,
|
|
2831
|
+
* clearTimeout?: ClearTimeout,
|
|
2832
|
+
* setInterval?: SetInterval,
|
|
2833
|
+
* clearInterval?: ClearInterval,
|
|
2834
|
+
* setImmediate?: SetImmediate,
|
|
2835
|
+
* clearImmediate?: ClearImmediate,
|
|
2836
|
+
* queueMicrotask?: QueueMicrotask,
|
|
2837
|
+
* requestAnimationFrame?: RequestAnimationFrame,
|
|
2838
|
+
* cancelAnimationFrame?: CancelAnimationFrame,
|
|
2839
|
+
* requestIdleCallback?: RequestIdleCallback,
|
|
2840
|
+
* cancelIdleCallback?: CancelIdleCallback,
|
|
2841
|
+
* process?: any,
|
|
2842
|
+
* performance?: any,
|
|
2843
|
+
* Performance?: any,
|
|
2844
|
+
* Intl?: any,
|
|
2845
|
+
* Promise?: typeof Promise,
|
|
2846
|
+
* Date: typeof Date & { isFake?: boolean, toSource?: () => string, clock?: any }
|
|
2847
|
+
* }} GlobalObject
|
|
2848
|
+
*/
|
|
2849
|
+
|
|
2850
|
+
/**
|
|
2851
|
+
* @typedef {object} TimerHeap
|
|
2852
|
+
* @property {Timer[]} timers - the heap-ordered timers
|
|
2853
|
+
* @property {() => Timer | undefined} peek - returns the next timer without removing it
|
|
2854
|
+
* @property {(timer: Timer) => void} push - adds a timer to the heap
|
|
2855
|
+
* @property {() => Timer | undefined} pop - removes and returns the next timer
|
|
2856
|
+
* @property {(timer: Timer) => void} remove - removes a specific timer
|
|
2857
|
+
*/
|
|
2858
|
+
|
|
2859
|
+
/**
|
|
2860
|
+
* @typedef {object} ClockTickMode
|
|
2861
|
+
* @property {TickMode} mode - active tick mode
|
|
2862
|
+
* @property {number} counter - increments whenever the mode changes
|
|
2863
|
+
* @property {number} [delta] - interval length in milliseconds
|
|
2864
|
+
*/
|
|
2865
|
+
|
|
2866
|
+
/**
|
|
2867
|
+
* @typedef {object} SetTickModeConfig
|
|
2868
|
+
* @property {TickMode} mode - desired tick mode
|
|
2869
|
+
* @property {number} [delta] - interval length in milliseconds
|
|
2870
|
+
*/
|
|
2871
|
+
|
|
2872
|
+
/**
|
|
2873
|
+
* @typedef {Record<string, any> & { clock: Clock }} IntlWithClock
|
|
2874
|
+
*/
|
|
2875
|
+
|
|
2876
|
+
/**
|
|
2877
|
+
* @typedef {object} Timers
|
|
2878
|
+
* @property {SetTimeout} setTimeout - native `setTimeout`
|
|
2879
|
+
* @property {ClearTimeout} clearTimeout - native `clearTimeout`
|
|
2880
|
+
* @property {SetInterval} setInterval - native `setInterval`
|
|
2881
|
+
* @property {ClearInterval} clearInterval - native `clearInterval`
|
|
2882
|
+
* @property {typeof Date} Date - native `Date`
|
|
2883
|
+
* @property {typeof Intl} [Intl] - native `Intl`
|
|
2884
|
+
* @property {SetImmediate} [setImmediate] - native `setImmediate`, if available
|
|
2885
|
+
* @property {ClearImmediate} [clearImmediate] - native `clearImmediate`, if available
|
|
2886
|
+
* @property {Hrtime} [hrtime] - native `process.hrtime`, if available
|
|
2887
|
+
* @property {NextTick} [nextTick] - native `process.nextTick`, if available
|
|
2888
|
+
* @property {Performance} [performance] - native `performance`, if available
|
|
2889
|
+
* @property {RequestAnimationFrame} [requestAnimationFrame] - native `requestAnimationFrame`, if available
|
|
2890
|
+
* @property {QueueMicrotask} [queueMicrotask] - whether `queueMicrotask` exists
|
|
2891
|
+
* @property {CancelAnimationFrame} [cancelAnimationFrame] - native `cancelAnimationFrame`, if available
|
|
2892
|
+
* @property {RequestIdleCallback} [requestIdleCallback] - native `requestIdleCallback`, if available
|
|
2893
|
+
* @property {CancelIdleCallback} [cancelIdleCallback] - native `cancelIdleCallback`, if available
|
|
2894
|
+
*/
|
|
2895
|
+
|
|
2896
|
+
/**
|
|
2897
|
+
* @typedef {object} ClockState
|
|
2898
|
+
* @property {number} tickFrom - lower bound of the current tick range
|
|
2899
|
+
* @property {number} tickTo - upper bound of the current tick range
|
|
2900
|
+
* @property {number} [previous] - previous timer time used during ticking
|
|
2901
|
+
* @property {number | null} [oldNow] - previous value of `now`
|
|
2902
|
+
* @property {Timer} [timer] - timer currently being processed
|
|
2903
|
+
* @property {unknown} [firstException] - first exception raised while processing timers
|
|
2904
|
+
* @property {number} [nanosTotal] - accumulated nanoseconds from fractional ticks
|
|
2905
|
+
* @property {number} [msFloat] - accumulated fractional milliseconds
|
|
2906
|
+
* @property {number} [ms] - accumulated whole milliseconds
|
|
2907
|
+
*/
|
|
2908
|
+
|
|
2909
|
+
/**
|
|
2910
|
+
* @typedef {object} TimerInitialProps
|
|
2911
|
+
* @property {VoidVarArgsFunc} func - callback or string to execute
|
|
2912
|
+
* @property {unknown[]} [args] - arguments passed to the callback
|
|
2913
|
+
* @property {'Timeout' | 'Interval' | 'Immediate' | 'AnimationFrame' | 'IdleCallback'} [type] - timer kind
|
|
2914
|
+
* @property {number} [delay] - requested delay in milliseconds
|
|
2915
|
+
* @property {number} [callAt] - scheduled execution time
|
|
2916
|
+
* @property {number} [createdAt] - time at which the timer was created
|
|
2917
|
+
* @property {boolean} [immediate] - whether this timer should run before non-immediate timers at the same time
|
|
2918
|
+
* @property {number} [id] - unique timer identifier
|
|
2919
|
+
* @property {Error} [error] - captured stack for loop diagnostics
|
|
2920
|
+
* @property {number} [interval] - interval for repeated timers
|
|
2921
|
+
* @property {boolean} [animation] - whether this is an animation frame timer
|
|
2922
|
+
* @property {boolean} [requestIdleCallback] - whether this is an idle callback timer
|
|
2923
|
+
* @property {number} [order] - execution order for timers at the same time
|
|
2924
|
+
* @property {number} [heapIndex] - index in the timer heap
|
|
2925
|
+
*/
|
|
2926
|
+
|
|
2927
|
+
/**
|
|
2928
|
+
* @callback CreateClockCallback
|
|
2929
|
+
* @param {number|Date} [start] initial mocked time, as milliseconds since epoch or a Date
|
|
2930
|
+
* @param {number} [loopLimit] maximum number of timers run before aborting with an infinite-loop error
|
|
2931
|
+
* @returns {Clock}
|
|
2932
|
+
*/
|
|
2933
|
+
|
|
2934
|
+
/**
|
|
2935
|
+
* @callback InstallCallback
|
|
2936
|
+
* @param {Config} [config] Optional config
|
|
2937
|
+
* @returns {Clock}
|
|
2604
2938
|
*/
|
|
2605
2939
|
|
|
2606
2940
|
/**
|
|
2607
|
-
* @typedef
|
|
2608
|
-
* @property {
|
|
2941
|
+
* @typedef {object} FakeTimers
|
|
2942
|
+
* @property {Timers} timers - the native timer APIs saved for later restoration
|
|
2943
|
+
* @property {CreateClockCallback} createClock - creates a new fake clock
|
|
2944
|
+
* @property {InstallCallback} install - installs the fake timers onto the default global object
|
|
2945
|
+
* @property {WithGlobal} withGlobal - creates a fake-timers instance for a provided global object
|
|
2609
2946
|
*/
|
|
2610
2947
|
|
|
2611
|
-
/* eslint-disable jsdoc/require-property-description */
|
|
2612
2948
|
/**
|
|
2613
2949
|
* @typedef {object} Clock
|
|
2614
|
-
* @property {number} now -
|
|
2615
|
-
* @property {Date} Date -
|
|
2616
|
-
* @property {number} loopLimit -
|
|
2617
|
-
* @property {RequestIdleCallback} requestIdleCallback
|
|
2618
|
-
* @property {
|
|
2619
|
-
* @property {
|
|
2620
|
-
* @property {
|
|
2621
|
-
* @property {NextTick} nextTick
|
|
2622
|
-
* @property {
|
|
2623
|
-
* @property {
|
|
2624
|
-
* @property {
|
|
2625
|
-
* @property {SetImmediate} setImmediate
|
|
2626
|
-
* @property {
|
|
2627
|
-
* @property {
|
|
2628
|
-
* @property {RequestAnimationFrame} requestAnimationFrame
|
|
2629
|
-
* @property {
|
|
2630
|
-
* @property {
|
|
2631
|
-
* @property {
|
|
2632
|
-
* @property {
|
|
2633
|
-
* @property {
|
|
2634
|
-
* @property {
|
|
2635
|
-
* @property {
|
|
2636
|
-
* @property {
|
|
2637
|
-
* @property {
|
|
2638
|
-
* @property {
|
|
2639
|
-
* @property {
|
|
2640
|
-
* @property {
|
|
2641
|
-
* @property {
|
|
2642
|
-
* @property {
|
|
2643
|
-
* @property {
|
|
2644
|
-
* @property {
|
|
2645
|
-
* @property {
|
|
2646
|
-
* @property {
|
|
2647
|
-
* @property {boolean} [shouldClearNativeTimers] inherited from config
|
|
2648
|
-
* @property {{methodName:string, original:
|
|
2649
|
-
* @property {{methodName:string, original:
|
|
2650
|
-
* @property {Map<
|
|
2651
|
-
* @property {
|
|
2950
|
+
* @property {number} now - current mocked time in milliseconds
|
|
2951
|
+
* @property {typeof Date & {clock?: Clock, isFake?: boolean, toSource?: () => string}} Date - fake Date constructor bound to this clock
|
|
2952
|
+
* @property {number} loopLimit - maximum number of timers before assuming an infinite loop
|
|
2953
|
+
* @property {RequestIdleCallback} requestIdleCallback - schedules an idle callback
|
|
2954
|
+
* @property {CancelIdleCallback} cancelIdleCallback - cancels a scheduled idle callback
|
|
2955
|
+
* @property {SetTimeout} setTimeout - faked `setTimeout`
|
|
2956
|
+
* @property {ClearTimeout} clearTimeout - faked `clearTimeout`
|
|
2957
|
+
* @property {NextTick} nextTick - faked `process.nextTick`
|
|
2958
|
+
* @property {QueueMicrotask} queueMicrotask - faked `queueMicrotask`
|
|
2959
|
+
* @property {SetInterval} setInterval - faked `setInterval`
|
|
2960
|
+
* @property {ClearInterval} clearInterval - faked `clearInterval`
|
|
2961
|
+
* @property {SetImmediate} setImmediate - faked `setImmediate`
|
|
2962
|
+
* @property {ClearImmediate} clearImmediate - faked `clearImmediate`
|
|
2963
|
+
* @property {CountTimers} countTimers - counts scheduled timers
|
|
2964
|
+
* @property {RequestAnimationFrame} requestAnimationFrame - schedules a frame callback
|
|
2965
|
+
* @property {CancelAnimationFrame} cancelAnimationFrame - cancels a frame callback
|
|
2966
|
+
* @property {RunMicrotasks} runMicrotasks - drains microtasks
|
|
2967
|
+
* @property {Tick} tick - advances fake time synchronously
|
|
2968
|
+
* @property {TickAsync} tickAsync - advances fake time asynchronously
|
|
2969
|
+
* @property {Next} next - runs the next scheduled timer
|
|
2970
|
+
* @property {NextAsync} nextAsync - runs the next scheduled timer asynchronously
|
|
2971
|
+
* @property {RunAll} runAll - runs all scheduled timers
|
|
2972
|
+
* @property {RunToFrame} runToFrame - runs timers up to the next animation frame
|
|
2973
|
+
* @property {RunAllAsync} runAllAsync - runs all scheduled timers asynchronously
|
|
2974
|
+
* @property {RunToLast} runToLast - runs timers up to the last scheduled timer
|
|
2975
|
+
* @property {RunToLastAsync} runToLastAsync - runs timers up to the last scheduled timer asynchronously
|
|
2976
|
+
* @property {Reset} reset - clears all timers and resets the clock
|
|
2977
|
+
* @property {SetSystemTime} setSystemTime - sets the clock to a specific wall-clock time
|
|
2978
|
+
* @property {Jump} jump - advances time and returns the new `now`
|
|
2979
|
+
* @property {any} performance - fake performance object
|
|
2980
|
+
* @property {Hrtime} hrtime - faked `process.hrtime`
|
|
2981
|
+
* @property {Uninstall} uninstall - restores native timers
|
|
2982
|
+
* @property {string[]} methods - names of faked methods
|
|
2983
|
+
* @property {boolean} [shouldClearNativeTimers] - inherited from config
|
|
2984
|
+
* @property {{methodName:string, original:unknown}[] | undefined} timersModuleMethods - saved Node timers module methods
|
|
2985
|
+
* @property {{methodName:string, original:unknown}[] | undefined} timersPromisesModuleMethods - saved Node timers/promises methods
|
|
2986
|
+
* @property {Map<VoidVarArgsFunc, AbortSignal>} abortListenerMap - active abort listeners
|
|
2987
|
+
* @property {SetTickMode} setTickMode - switches the auto-tick mode
|
|
2988
|
+
* @property {Map<number, Timer>} [timers] - internal timer storage
|
|
2989
|
+
* @property {TimerHeap} [timerHeap] - internal timer heap
|
|
2990
|
+
* @property {boolean} [duringTick] - internal flag
|
|
2991
|
+
* @property {boolean} isNearInfiniteLimit - internal flag indicating the loop limit is nearly reached
|
|
2992
|
+
* @property {TimerId} [attachedInterval] - internal flag
|
|
2993
|
+
* @property {ClockTickMode} [tickMode] - internal flag
|
|
2994
|
+
* @property {Timer[]} [jobs] - internal flag
|
|
2995
|
+
* @property {IntlWithClock} [Intl] - fake Intl object
|
|
2652
2996
|
*/
|
|
2653
|
-
/* eslint-enable jsdoc/
|
|
2997
|
+
/* eslint-enable jsdoc/reject-any-type */
|
|
2654
2998
|
|
|
2655
2999
|
/**
|
|
2656
3000
|
* Configuration object for the `install` method.
|
|
2657
3001
|
* @typedef {object} Config
|
|
2658
|
-
* @property {number|Date} [now]
|
|
2659
|
-
* @property {
|
|
2660
|
-
* @property {
|
|
2661
|
-
* @property {
|
|
2662
|
-
* @property {
|
|
2663
|
-
* @property {
|
|
2664
|
-
* @property {boolean} [
|
|
3002
|
+
* @property {number|Date} [now] initial mocked time, as milliseconds since epoch or a Date
|
|
3003
|
+
* @property {FakeMethod[]} [toFake] method names that should be faked
|
|
3004
|
+
* @property {FakeMethod[]} [toNotFake] method names that should remain native
|
|
3005
|
+
* @property {number} [loopLimit] maximum number of timers run before aborting with an infinite-loop error
|
|
3006
|
+
* @property {boolean} [shouldAdvanceTime] automatically increments mocked time while the clock is installed
|
|
3007
|
+
* @property {number} [advanceTimeDelta] interval in milliseconds used when `shouldAdvanceTime` is enabled
|
|
3008
|
+
* @property {boolean} [shouldClearNativeTimers] forwards clear calls to native methods when the timer is not fake
|
|
3009
|
+
* @property {boolean} [ignoreMissingTimers] suppresses errors when a requested timer is missing from the global object
|
|
3010
|
+
* @property {GlobalObject} [target] global object to install onto
|
|
2665
3011
|
*/
|
|
2666
3012
|
|
|
2667
|
-
/* eslint-disable jsdoc/require-property-description */
|
|
2668
3013
|
/**
|
|
2669
3014
|
* The internal structure to describe a scheduled fake timer
|
|
2670
|
-
* @typedef {
|
|
2671
|
-
* @property {
|
|
2672
|
-
* @property {
|
|
2673
|
-
* @property {number}
|
|
2674
|
-
* @property {number}
|
|
2675
|
-
* @property {
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
3015
|
+
* @typedef {TimerInitialProps} Timer
|
|
3016
|
+
* @property {unknown[]} args - arguments passed to the callback
|
|
3017
|
+
* @property {number} callAt - scheduled execution time
|
|
3018
|
+
* @property {number} createdAt - time at which the timer was created
|
|
3019
|
+
* @property {number} id - unique timer identifier
|
|
3020
|
+
* @property {'Timeout' | 'Interval' | 'Immediate' | 'AnimationFrame' | 'IdleCallback'} type - timer kind
|
|
3021
|
+
*/
|
|
3022
|
+
|
|
3023
|
+
/**
|
|
3024
|
+
* @callback NodeImmediateHasRef
|
|
3025
|
+
* @returns {boolean}
|
|
3026
|
+
*/
|
|
3027
|
+
|
|
3028
|
+
/**
|
|
3029
|
+
* @callback NodeImmediateRef
|
|
3030
|
+
* @returns {NodeImmediate}
|
|
3031
|
+
*/
|
|
3032
|
+
|
|
3033
|
+
/**
|
|
3034
|
+
* @callback NodeImmediateUnref
|
|
3035
|
+
* @returns {NodeImmediate}
|
|
2679
3036
|
*/
|
|
2680
3037
|
|
|
2681
3038
|
/**
|
|
2682
3039
|
* A Node timer
|
|
2683
3040
|
* @typedef {object} NodeImmediate
|
|
2684
|
-
* @property {
|
|
2685
|
-
* @property {
|
|
2686
|
-
* @property {
|
|
3041
|
+
* @property {NodeImmediateHasRef} hasRef - reports whether the timer keeps the event loop alive
|
|
3042
|
+
* @property {NodeImmediateRef} ref - marks the timer as referenced
|
|
3043
|
+
* @property {NodeImmediateUnref} unref - marks the timer as unreferenced
|
|
2687
3044
|
*/
|
|
2688
|
-
/* eslint-enable jsdoc/require-property-description */
|
|
2689
3045
|
|
|
2690
3046
|
/* eslint-disable complexity */
|
|
2691
3047
|
|
|
2692
3048
|
/**
|
|
2693
3049
|
* Mocks available features in the specified global namespace.
|
|
2694
|
-
* @param {
|
|
3050
|
+
* @param {GlobalObject} _global Namespace to mock (e.g. `window`)
|
|
2695
3051
|
* @returns {FakeTimers}
|
|
2696
3052
|
*/
|
|
2697
3053
|
function withGlobal(_global) {
|
|
@@ -2731,7 +3087,10 @@ function requireFakeTimersSrc () {
|
|
|
2731
3087
|
_global.performance &&
|
|
2732
3088
|
_global.performance.constructor &&
|
|
2733
3089
|
_global.performance.constructor.prototype;
|
|
2734
|
-
isPresent.queueMicrotask =
|
|
3090
|
+
isPresent.queueMicrotask = Object.prototype.hasOwnProperty.call(
|
|
3091
|
+
_global,
|
|
3092
|
+
"queueMicrotask",
|
|
3093
|
+
);
|
|
2735
3094
|
isPresent.requestAnimationFrame =
|
|
2736
3095
|
_global.requestAnimationFrame &&
|
|
2737
3096
|
typeof _global.requestAnimationFrame === "function";
|
|
@@ -2741,7 +3100,7 @@ function requireFakeTimersSrc () {
|
|
|
2741
3100
|
isPresent.requestIdleCallback =
|
|
2742
3101
|
_global.requestIdleCallback &&
|
|
2743
3102
|
typeof _global.requestIdleCallback === "function";
|
|
2744
|
-
isPresent.
|
|
3103
|
+
isPresent.cancelIdleCallback =
|
|
2745
3104
|
_global.cancelIdleCallback &&
|
|
2746
3105
|
typeof _global.cancelIdleCallback === "function";
|
|
2747
3106
|
isPresent.setImmediate =
|
|
@@ -2762,6 +3121,8 @@ function requireFakeTimersSrc () {
|
|
|
2762
3121
|
)
|
|
2763
3122
|
: undefined;
|
|
2764
3123
|
let uniqueTimerId = idCounterStart;
|
|
3124
|
+
/** @type {number} */
|
|
3125
|
+
let uniqueTimerOrder = 0;
|
|
2765
3126
|
|
|
2766
3127
|
if (NativeDate === undefined) {
|
|
2767
3128
|
throw new Error(
|
|
@@ -2802,23 +3163,23 @@ function requireFakeTimersSrc () {
|
|
|
2802
3163
|
return isFinite(num);
|
|
2803
3164
|
}
|
|
2804
3165
|
|
|
2805
|
-
let isNearInfiniteLimit = false;
|
|
2806
|
-
|
|
2807
3166
|
/**
|
|
2808
3167
|
* @param {Clock} clock
|
|
2809
3168
|
* @param {number} i
|
|
2810
3169
|
*/
|
|
2811
3170
|
function checkIsNearInfiniteLimit(clock, i) {
|
|
2812
3171
|
if (clock.loopLimit && i === clock.loopLimit - 1) {
|
|
2813
|
-
isNearInfiniteLimit = true;
|
|
3172
|
+
clock.isNearInfiniteLimit = true;
|
|
2814
3173
|
}
|
|
2815
3174
|
}
|
|
2816
3175
|
|
|
2817
3176
|
/**
|
|
2818
|
-
*
|
|
3177
|
+
* @param {Clock} clock
|
|
2819
3178
|
*/
|
|
2820
|
-
function resetIsNearInfiniteLimit() {
|
|
2821
|
-
|
|
3179
|
+
function resetIsNearInfiniteLimit(clock) {
|
|
3180
|
+
if (clock) {
|
|
3181
|
+
clock.isNearInfiniteLimit = false;
|
|
3182
|
+
}
|
|
2822
3183
|
}
|
|
2823
3184
|
|
|
2824
3185
|
/**
|
|
@@ -2883,12 +3244,12 @@ function requireFakeTimersSrc () {
|
|
|
2883
3244
|
if (!epoch) {
|
|
2884
3245
|
return 0;
|
|
2885
3246
|
}
|
|
2886
|
-
if (typeof epoch.getTime === "function") {
|
|
2887
|
-
return epoch.getTime();
|
|
2888
|
-
}
|
|
2889
3247
|
if (typeof epoch === "number") {
|
|
2890
3248
|
return epoch;
|
|
2891
3249
|
}
|
|
3250
|
+
if (typeof epoch.getTime === "function") {
|
|
3251
|
+
return epoch.getTime();
|
|
3252
|
+
}
|
|
2892
3253
|
throw new TypeError("now should be milliseconds since UNIX epoch");
|
|
2893
3254
|
}
|
|
2894
3255
|
|
|
@@ -2905,6 +3266,7 @@ function requireFakeTimersSrc () {
|
|
|
2905
3266
|
/**
|
|
2906
3267
|
* @param {Clock} clock
|
|
2907
3268
|
* @param {Timer} job
|
|
3269
|
+
* @returns {Error}
|
|
2908
3270
|
*/
|
|
2909
3271
|
function getInfiniteLoopError(clock, job) {
|
|
2910
3272
|
const infiniteLoopError = new Error(
|
|
@@ -2964,34 +3326,29 @@ function requireFakeTimersSrc () {
|
|
|
2964
3326
|
Object.defineProperty(infiniteLoopError, "stack", {
|
|
2965
3327
|
value: stack,
|
|
2966
3328
|
});
|
|
2967
|
-
} catch
|
|
3329
|
+
} catch {
|
|
2968
3330
|
// noop
|
|
2969
3331
|
}
|
|
2970
3332
|
|
|
2971
3333
|
return infiniteLoopError;
|
|
2972
3334
|
}
|
|
2973
3335
|
|
|
2974
|
-
|
|
3336
|
+
/**
|
|
3337
|
+
* @returns {typeof Date & { clock: Clock }}
|
|
3338
|
+
*/
|
|
2975
3339
|
function createDate() {
|
|
2976
3340
|
class ClockDate extends NativeDate {
|
|
2977
|
-
/**
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
* @param {number} second
|
|
2984
|
-
* @param {number} ms
|
|
2985
|
-
* @returns void
|
|
2986
|
-
*/
|
|
2987
|
-
// eslint-disable-next-line no-unused-vars
|
|
2988
|
-
constructor(year, month, date, hour, minute, second, ms) {
|
|
2989
|
-
// Defensive and verbose to avoid potential harm in passing
|
|
2990
|
-
// explicit undefined when user does not pass argument
|
|
2991
|
-
if (arguments.length === 0) {
|
|
3341
|
+
/** @type {Clock} */
|
|
3342
|
+
static clock;
|
|
3343
|
+
|
|
3344
|
+
constructor(...args) {
|
|
3345
|
+
// Preserve fake time when Date is called without arguments.
|
|
3346
|
+
if (args.length === 0) {
|
|
2992
3347
|
super(ClockDate.clock.now);
|
|
2993
3348
|
} else {
|
|
2994
|
-
|
|
3349
|
+
// The subclass is intentionally thin for explicit args.
|
|
3350
|
+
// @ts-expect-error Date constructor overloads are intentionally dynamic.
|
|
3351
|
+
super(...args);
|
|
2995
3352
|
}
|
|
2996
3353
|
|
|
2997
3354
|
// ensures identity checks using the constructor prop still works
|
|
@@ -3015,21 +3372,26 @@ function requireFakeTimersSrc () {
|
|
|
3015
3372
|
};
|
|
3016
3373
|
}
|
|
3017
3374
|
|
|
3018
|
-
|
|
3375
|
+
const NativeDateWithToSource =
|
|
3376
|
+
/** @type {typeof Date & { toSource?: () => string }} */ (
|
|
3377
|
+
NativeDate
|
|
3378
|
+
);
|
|
3379
|
+
|
|
3380
|
+
if (NativeDateWithToSource.toSource) {
|
|
3019
3381
|
ClockDate.toSource = function toSource() {
|
|
3020
|
-
return
|
|
3382
|
+
return NativeDateWithToSource.toSource();
|
|
3021
3383
|
};
|
|
3022
3384
|
}
|
|
3023
3385
|
|
|
3024
3386
|
ClockDate.toString = function toString() {
|
|
3025
|
-
return
|
|
3387
|
+
return NativeDateWithToSource.toString();
|
|
3026
3388
|
};
|
|
3027
3389
|
|
|
3028
3390
|
// noinspection UnnecessaryLocalVariableJS
|
|
3029
3391
|
/**
|
|
3030
3392
|
* A normal Class constructor cannot be called without `new`, but Date can, so we need
|
|
3031
3393
|
* to wrap it in a Proxy in order to ensure this functionality of Date is kept intact
|
|
3032
|
-
* @type {ClockDate}
|
|
3394
|
+
* @type {typeof ClockDate}
|
|
3033
3395
|
*/
|
|
3034
3396
|
const ClockDateProxy = new Proxy(ClockDate, {
|
|
3035
3397
|
// handler for [[Call]] invocations (i.e. not using `new`)
|
|
@@ -3046,7 +3408,9 @@ function requireFakeTimersSrc () {
|
|
|
3046
3408
|
},
|
|
3047
3409
|
});
|
|
3048
3410
|
|
|
3049
|
-
return
|
|
3411
|
+
return /** @type {typeof Date & { clock: Clock }} */ (
|
|
3412
|
+
/** @type {unknown} */ (ClockDateProxy)
|
|
3413
|
+
);
|
|
3050
3414
|
}
|
|
3051
3415
|
|
|
3052
3416
|
/**
|
|
@@ -3055,19 +3419,21 @@ function requireFakeTimersSrc () {
|
|
|
3055
3419
|
* Most of the properties are the original native ones,
|
|
3056
3420
|
* but we need to take control of those that have a
|
|
3057
3421
|
* dependency on the current clock.
|
|
3058
|
-
* @
|
|
3422
|
+
* @param {Clock} clock
|
|
3423
|
+
* @returns {IntlWithClock} the partly fake Intl implementation
|
|
3059
3424
|
*/
|
|
3060
|
-
function createIntl() {
|
|
3061
|
-
|
|
3425
|
+
function createIntl(clock) {
|
|
3426
|
+
/** @type {IntlWithClock} */
|
|
3427
|
+
const IntlWithClock = { clock: clock };
|
|
3062
3428
|
/*
|
|
3063
3429
|
* All properties of Intl are non-enumerable, so we need
|
|
3064
3430
|
* to do a bit of work to get them out.
|
|
3065
3431
|
*/
|
|
3066
3432
|
Object.getOwnPropertyNames(NativeIntl).forEach(
|
|
3067
|
-
(property) => (
|
|
3433
|
+
(property) => (IntlWithClock[property] = NativeIntl[property]),
|
|
3068
3434
|
);
|
|
3069
3435
|
|
|
3070
|
-
|
|
3436
|
+
IntlWithClock.DateTimeFormat = function (...args) {
|
|
3071
3437
|
const realFormatter = new NativeIntl.DateTimeFormat(...args);
|
|
3072
3438
|
const formatter = {};
|
|
3073
3439
|
|
|
@@ -3080,21 +3446,23 @@ function requireFakeTimersSrc () {
|
|
|
3080
3446
|
|
|
3081
3447
|
["format", "formatToParts"].forEach((method) => {
|
|
3082
3448
|
formatter[method] = function (date) {
|
|
3083
|
-
return realFormatter[method](
|
|
3449
|
+
return realFormatter[method](
|
|
3450
|
+
date || IntlWithClock.clock.now,
|
|
3451
|
+
);
|
|
3084
3452
|
};
|
|
3085
3453
|
});
|
|
3086
3454
|
|
|
3087
3455
|
return formatter;
|
|
3088
3456
|
};
|
|
3089
3457
|
|
|
3090
|
-
|
|
3458
|
+
IntlWithClock.DateTimeFormat.prototype = Object.create(
|
|
3091
3459
|
NativeIntl.DateTimeFormat.prototype,
|
|
3092
3460
|
);
|
|
3093
3461
|
|
|
3094
|
-
|
|
3462
|
+
IntlWithClock.DateTimeFormat.supportedLocalesOf =
|
|
3095
3463
|
NativeIntl.DateTimeFormat.supportedLocalesOf;
|
|
3096
3464
|
|
|
3097
|
-
return
|
|
3465
|
+
return IntlWithClock;
|
|
3098
3466
|
}
|
|
3099
3467
|
|
|
3100
3468
|
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
@@ -3112,6 +3480,7 @@ function requireFakeTimersSrc () {
|
|
|
3112
3480
|
if (!clock.jobs) {
|
|
3113
3481
|
return;
|
|
3114
3482
|
}
|
|
3483
|
+
const wasNearLimit = clock.isNearInfiniteLimit;
|
|
3115
3484
|
for (let i = 0; i < clock.jobs.length; i++) {
|
|
3116
3485
|
const job = clock.jobs[i];
|
|
3117
3486
|
job.func.apply(null, job.args);
|
|
@@ -3121,38 +3490,275 @@ function requireFakeTimersSrc () {
|
|
|
3121
3490
|
throw getInfiniteLoopError(clock, job);
|
|
3122
3491
|
}
|
|
3123
3492
|
}
|
|
3124
|
-
|
|
3493
|
+
if (!wasNearLimit) {
|
|
3494
|
+
resetIsNearInfiniteLimit(clock);
|
|
3495
|
+
}
|
|
3125
3496
|
clock.jobs = [];
|
|
3126
3497
|
}
|
|
3127
3498
|
|
|
3499
|
+
/**
|
|
3500
|
+
* A compact "soonest timer first" container.
|
|
3501
|
+
*
|
|
3502
|
+
* Think of this as a waiting room for scheduled callbacks where the next
|
|
3503
|
+
* callback to run is always kept at the front of the list. The internal
|
|
3504
|
+
* array is arranged so we can find, add, remove, and reorder timers
|
|
3505
|
+
* efficiently without sorting the whole list every time something changes.
|
|
3506
|
+
*
|
|
3507
|
+
* The important idea is not the data structure name, but the behavior:
|
|
3508
|
+
* the timer that should run next stays near the front, and when one timer
|
|
3509
|
+
* moves, the rest are shifted just enough to keep that promise true.
|
|
3510
|
+
*/
|
|
3511
|
+
class TimerHeap {
|
|
3512
|
+
constructor() {
|
|
3513
|
+
this.timers = [];
|
|
3514
|
+
}
|
|
3515
|
+
|
|
3516
|
+
/**
|
|
3517
|
+
* Look at the next timer without removing it.
|
|
3518
|
+
* This is the timer the clock would run first if time advanced now.
|
|
3519
|
+
* @returns {Timer}
|
|
3520
|
+
*/
|
|
3521
|
+
peek() {
|
|
3522
|
+
return this.timers[0];
|
|
3523
|
+
}
|
|
3524
|
+
|
|
3525
|
+
/**
|
|
3526
|
+
* Add a timer to the waiting room, then move it upward until it is in
|
|
3527
|
+
* the right place relative to the timers it should run before and after.
|
|
3528
|
+
* @param {Timer} timer
|
|
3529
|
+
*/
|
|
3530
|
+
push(timer) {
|
|
3531
|
+
this.timers.push(timer);
|
|
3532
|
+
this.bubbleUp(this.timers.length - 1);
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3535
|
+
/**
|
|
3536
|
+
* Remove and return the next timer to run.
|
|
3537
|
+
*
|
|
3538
|
+
* We pull the front timer out, move the last timer into the empty spot,
|
|
3539
|
+
* and then shift that replacement down until the ordering is correct
|
|
3540
|
+
* again. That avoids rebuilding the whole list from scratch.
|
|
3541
|
+
* @returns {Timer|undefined}
|
|
3542
|
+
*/
|
|
3543
|
+
pop() {
|
|
3544
|
+
if (this.timers.length === 0) {
|
|
3545
|
+
return undefined;
|
|
3546
|
+
}
|
|
3547
|
+
const first = this.timers[0];
|
|
3548
|
+
const last = this.timers.pop();
|
|
3549
|
+
if (this.timers.length > 0) {
|
|
3550
|
+
this.timers[0] = last;
|
|
3551
|
+
last.heapIndex = 0;
|
|
3552
|
+
this.bubbleDown(0);
|
|
3553
|
+
}
|
|
3554
|
+
delete first.heapIndex;
|
|
3555
|
+
return first;
|
|
3556
|
+
}
|
|
3557
|
+
|
|
3558
|
+
/**
|
|
3559
|
+
* Remove a specific timer from the waiting room.
|
|
3560
|
+
*
|
|
3561
|
+
* The heap stores timers in a shape that lets us jump directly to the
|
|
3562
|
+
* timer's current position, replace it with the last timer, and then
|
|
3563
|
+
* move that replacement up or down until the ordering is correct again.
|
|
3564
|
+
* @param {Timer} timer
|
|
3565
|
+
* @returns {boolean}
|
|
3566
|
+
*/
|
|
3567
|
+
remove(timer) {
|
|
3568
|
+
const index = timer.heapIndex;
|
|
3569
|
+
if (index === undefined || this.timers[index] !== timer) {
|
|
3570
|
+
return false;
|
|
3571
|
+
}
|
|
3572
|
+
const last = this.timers.pop();
|
|
3573
|
+
if (timer !== last) {
|
|
3574
|
+
this.timers[index] = last;
|
|
3575
|
+
last.heapIndex = index;
|
|
3576
|
+
if (compareTimers(last, timer) < 0) {
|
|
3577
|
+
this.bubbleUp(index);
|
|
3578
|
+
} else {
|
|
3579
|
+
this.bubbleDown(index);
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
delete timer.heapIndex;
|
|
3583
|
+
return true;
|
|
3584
|
+
}
|
|
3585
|
+
|
|
3586
|
+
/**
|
|
3587
|
+
* Move a timer toward the front until it is no longer "earlier" than
|
|
3588
|
+
* the timer above it.
|
|
3589
|
+
*
|
|
3590
|
+
* Conceptually, this is what happens when something newly scheduled
|
|
3591
|
+
* turns out to belong ahead of its parent in the waiting room. We keep
|
|
3592
|
+
* swapping it upward until it is no longer out of place.
|
|
3593
|
+
* @param {number} index
|
|
3594
|
+
*/
|
|
3595
|
+
bubbleUp(index) {
|
|
3596
|
+
const timer = this.timers[index];
|
|
3597
|
+
let currentIndex = index;
|
|
3598
|
+
while (currentIndex > 0) {
|
|
3599
|
+
const parentIndex = Math.floor((currentIndex - 1) / 2);
|
|
3600
|
+
const parent = this.timers[parentIndex];
|
|
3601
|
+
if (compareTimers(timer, parent) < 0) {
|
|
3602
|
+
this.timers[currentIndex] = parent;
|
|
3603
|
+
parent.heapIndex = currentIndex;
|
|
3604
|
+
currentIndex = parentIndex;
|
|
3605
|
+
} else {
|
|
3606
|
+
break;
|
|
3607
|
+
}
|
|
3608
|
+
}
|
|
3609
|
+
this.timers[currentIndex] = timer;
|
|
3610
|
+
timer.heapIndex = currentIndex;
|
|
3611
|
+
}
|
|
3612
|
+
|
|
3613
|
+
/**
|
|
3614
|
+
* Move a timer away from the front until the timer below it is no
|
|
3615
|
+
* longer supposed to run after it.
|
|
3616
|
+
*
|
|
3617
|
+
* This is the opposite of `bubbleUp`: when a timer at the front is
|
|
3618
|
+
* removed or moved, the replacement may be too far ahead, so we
|
|
3619
|
+
* repeatedly swap it downward with the best child until the waiting
|
|
3620
|
+
* room is ordered again.
|
|
3621
|
+
* @param {number} index
|
|
3622
|
+
*/
|
|
3623
|
+
bubbleDown(index) {
|
|
3624
|
+
const timer = this.timers[index];
|
|
3625
|
+
let currentIndex = index;
|
|
3626
|
+
const halfLength = Math.floor(this.timers.length / 2);
|
|
3627
|
+
while (currentIndex < halfLength) {
|
|
3628
|
+
const leftIndex = currentIndex * 2 + 1;
|
|
3629
|
+
const rightIndex = leftIndex + 1;
|
|
3630
|
+
let bestChildIndex = leftIndex;
|
|
3631
|
+
let bestChild = this.timers[leftIndex];
|
|
3632
|
+
|
|
3633
|
+
if (
|
|
3634
|
+
rightIndex < this.timers.length &&
|
|
3635
|
+
compareTimers(this.timers[rightIndex], bestChild) < 0
|
|
3636
|
+
) {
|
|
3637
|
+
bestChildIndex = rightIndex;
|
|
3638
|
+
bestChild = this.timers[rightIndex];
|
|
3639
|
+
}
|
|
3640
|
+
|
|
3641
|
+
if (compareTimers(bestChild, timer) < 0) {
|
|
3642
|
+
this.timers[currentIndex] = bestChild;
|
|
3643
|
+
bestChild.heapIndex = currentIndex;
|
|
3644
|
+
currentIndex = bestChildIndex;
|
|
3645
|
+
} else {
|
|
3646
|
+
break;
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
this.timers[currentIndex] = timer;
|
|
3650
|
+
timer.heapIndex = currentIndex;
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3654
|
+
/**
|
|
3655
|
+
* Ensure timer storage and heap stay in sync even if a clear path touches
|
|
3656
|
+
* timer state before anything has been scheduled.
|
|
3657
|
+
*
|
|
3658
|
+
* Why do we need two data structures to keep tabs on timers?
|
|
3659
|
+
* 1. Fast ID Lookup (clock.timers): This is a Map from timer IDs to their respective timer objects. It allows clearTimeout(id) and
|
|
3660
|
+
* clearInterval(id) to be $O(1)$ operations. Without this map, finding a specific timer in the heap to remove it would require a linear
|
|
3661
|
+
* $O(n)$ search, which would significantly degrade performance as the number of active timers grows.
|
|
3662
|
+
* 2. Efficient Scheduling (clock.timerHeap): This is a priority queue (min-heap) that keeps timers ordered by their execution time (callAt). It
|
|
3663
|
+
* allows the library to instantly find the next timer to run (peek() in $O(1)$) and efficiently update the schedule when timers are added or
|
|
3664
|
+
* removed ($O(\log n)$).
|
|
3665
|
+
*
|
|
3666
|
+
* In short: clock.timers provides fast access by ID, while clock.timerHeap provides fast access by Time. Removing either one would make common
|
|
3667
|
+
* operations (like clearing or finding the next timer) much slower.
|
|
3668
|
+
* @param {Clock} clock
|
|
3669
|
+
*/
|
|
3670
|
+
function ensureTimerState(clock) {
|
|
3671
|
+
if (!clock.timers) {
|
|
3672
|
+
clock.timers = new Map();
|
|
3673
|
+
clock.timerHeap = new TimerHeap();
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
|
|
3677
|
+
/**
|
|
3678
|
+
* @param {Clock} clock
|
|
3679
|
+
* @param {number} id
|
|
3680
|
+
* @returns {boolean}
|
|
3681
|
+
*/
|
|
3682
|
+
function hasTimer(clock, id) {
|
|
3683
|
+
return clock.timers ? clock.timers.has(id) : false;
|
|
3684
|
+
}
|
|
3685
|
+
|
|
3686
|
+
/**
|
|
3687
|
+
* @param {Clock} clock
|
|
3688
|
+
* @param {number} id
|
|
3689
|
+
* @returns {Timer}
|
|
3690
|
+
*/
|
|
3691
|
+
function getTimer(clock, id) {
|
|
3692
|
+
return clock.timers ? clock.timers.get(id) : undefined;
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3128
3695
|
/**
|
|
3129
3696
|
* @param {Clock} clock
|
|
3130
3697
|
* @param {Timer} timer
|
|
3131
|
-
|
|
3698
|
+
*/
|
|
3699
|
+
function setTimer(clock, timer) {
|
|
3700
|
+
ensureTimerState(clock);
|
|
3701
|
+
clock.timers.set(timer.id, timer);
|
|
3702
|
+
}
|
|
3703
|
+
|
|
3704
|
+
/**
|
|
3705
|
+
* @param {Clock} clock
|
|
3706
|
+
* @param {number} id
|
|
3707
|
+
* @returns {boolean}
|
|
3708
|
+
*/
|
|
3709
|
+
function deleteTimer(clock, id) {
|
|
3710
|
+
return clock.timers ? clock.timers.delete(id) : false;
|
|
3711
|
+
}
|
|
3712
|
+
|
|
3713
|
+
/**
|
|
3714
|
+
* @param {Clock} clock
|
|
3715
|
+
* @param {(timer: Timer) => void} callback
|
|
3716
|
+
*/
|
|
3717
|
+
function forEachActiveTimer(clock, callback) {
|
|
3718
|
+
if (!clock.timers) {
|
|
3719
|
+
return;
|
|
3720
|
+
}
|
|
3721
|
+
|
|
3722
|
+
for (const timer of clock.timers.values()) {
|
|
3723
|
+
callback(timer);
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
|
|
3727
|
+
/**
|
|
3728
|
+
* @param {Clock} clock
|
|
3729
|
+
*/
|
|
3730
|
+
function rebuildTimerHeap(clock) {
|
|
3731
|
+
clock.timerHeap = new TimerHeap();
|
|
3732
|
+
forEachActiveTimer(clock, (timer) => {
|
|
3733
|
+
clock.timerHeap.push(timer);
|
|
3734
|
+
});
|
|
3735
|
+
}
|
|
3736
|
+
|
|
3737
|
+
/**
|
|
3738
|
+
* @param {Clock} clock
|
|
3739
|
+
* @param {TimerInitialProps} timer
|
|
3740
|
+
* @returns {TimerId} id of the created timer
|
|
3132
3741
|
*/
|
|
3133
3742
|
function addTimer(clock, timer) {
|
|
3134
3743
|
if (timer.func === undefined) {
|
|
3135
3744
|
throw new Error("Callback must be provided to timer calls");
|
|
3136
3745
|
}
|
|
3137
3746
|
|
|
3138
|
-
if (
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
} of type ${typeof timer.func}`,
|
|
3145
|
-
);
|
|
3146
|
-
}
|
|
3747
|
+
if (typeof timer.func !== "function") {
|
|
3748
|
+
throw new TypeError(
|
|
3749
|
+
`[ERR_INVALID_CALLBACK]: Callback must be a function. Received ${
|
|
3750
|
+
timer.func
|
|
3751
|
+
} of type ${typeof timer.func}`,
|
|
3752
|
+
);
|
|
3147
3753
|
}
|
|
3148
3754
|
|
|
3149
|
-
if (isNearInfiniteLimit) {
|
|
3755
|
+
if (clock.isNearInfiniteLimit) {
|
|
3150
3756
|
timer.error = new Error();
|
|
3151
3757
|
}
|
|
3152
3758
|
|
|
3153
3759
|
timer.type = timer.immediate ? "Immediate" : "Timeout";
|
|
3154
3760
|
|
|
3155
|
-
if (
|
|
3761
|
+
if (Object.prototype.hasOwnProperty.call(timer, "delay")) {
|
|
3156
3762
|
if (typeof timer.delay !== "number") {
|
|
3157
3763
|
timer.delay = parseInt(timer.delay, 10);
|
|
3158
3764
|
}
|
|
@@ -3164,42 +3770,60 @@ function requireFakeTimersSrc () {
|
|
|
3164
3770
|
timer.delay = Math.max(0, timer.delay);
|
|
3165
3771
|
}
|
|
3166
3772
|
|
|
3167
|
-
if (
|
|
3773
|
+
if (Object.prototype.hasOwnProperty.call(timer, "interval")) {
|
|
3168
3774
|
timer.type = "Interval";
|
|
3169
3775
|
timer.interval = timer.interval > maxTimeout ? 1 : timer.interval;
|
|
3170
3776
|
}
|
|
3171
3777
|
|
|
3172
|
-
if (
|
|
3778
|
+
if (Object.prototype.hasOwnProperty.call(timer, "animation")) {
|
|
3173
3779
|
timer.type = "AnimationFrame";
|
|
3174
3780
|
timer.animation = true;
|
|
3175
3781
|
}
|
|
3176
3782
|
|
|
3177
|
-
if (
|
|
3178
|
-
timer
|
|
3179
|
-
|
|
3783
|
+
if (
|
|
3784
|
+
Object.prototype.hasOwnProperty.call(timer, "requestIdleCallback")
|
|
3785
|
+
) {
|
|
3786
|
+
// mark timer as IdleCallback type if it has no delay, otherwise it'd be of type timeout
|
|
3787
|
+
// this way we are able to sort such that the timer only gets called when there's truly no pending task to run
|
|
3788
|
+
if (!timer.delay) {
|
|
3789
|
+
timer.type = "IdleCallback";
|
|
3790
|
+
}
|
|
3791
|
+
timer.requestIdleCallback = true;
|
|
3180
3792
|
}
|
|
3181
3793
|
|
|
3182
|
-
|
|
3183
|
-
|
|
3794
|
+
ensureTimerState(clock);
|
|
3795
|
+
|
|
3796
|
+
while (hasTimer(clock, uniqueTimerId)) {
|
|
3797
|
+
uniqueTimerId++;
|
|
3798
|
+
if (uniqueTimerId >= Number.MAX_SAFE_INTEGER) {
|
|
3799
|
+
uniqueTimerId = idCounterStart;
|
|
3800
|
+
}
|
|
3184
3801
|
}
|
|
3185
3802
|
|
|
3186
3803
|
timer.id = uniqueTimerId++;
|
|
3804
|
+
if (uniqueTimerId >= Number.MAX_SAFE_INTEGER) {
|
|
3805
|
+
uniqueTimerId = idCounterStart;
|
|
3806
|
+
}
|
|
3807
|
+
|
|
3808
|
+
timer.order = uniqueTimerOrder++;
|
|
3187
3809
|
timer.createdAt = clock.now;
|
|
3188
3810
|
timer.callAt =
|
|
3189
|
-
clock.now +
|
|
3811
|
+
clock.now +
|
|
3812
|
+
(parseInt(String(timer.delay)) || (clock.duringTick ? 1 : 0));
|
|
3190
3813
|
|
|
3191
|
-
clock
|
|
3814
|
+
setTimer(clock, timer);
|
|
3815
|
+
clock.timerHeap.push(timer);
|
|
3192
3816
|
|
|
3193
3817
|
if (addTimerReturnsObject) {
|
|
3194
3818
|
const res = {
|
|
3195
3819
|
refed: true,
|
|
3196
3820
|
ref: function () {
|
|
3197
3821
|
this.refed = true;
|
|
3198
|
-
return
|
|
3822
|
+
return this;
|
|
3199
3823
|
},
|
|
3200
3824
|
unref: function () {
|
|
3201
3825
|
this.refed = false;
|
|
3202
|
-
return
|
|
3826
|
+
return this;
|
|
3203
3827
|
},
|
|
3204
3828
|
hasRef: function () {
|
|
3205
3829
|
return this.refed;
|
|
@@ -3207,12 +3831,15 @@ function requireFakeTimersSrc () {
|
|
|
3207
3831
|
refresh: function () {
|
|
3208
3832
|
timer.callAt =
|
|
3209
3833
|
clock.now +
|
|
3210
|
-
(parseInt(timer.delay) ||
|
|
3834
|
+
(parseInt(String(timer.delay)) ||
|
|
3835
|
+
(clock.duringTick ? 1 : 0));
|
|
3211
3836
|
|
|
3212
|
-
|
|
3213
|
-
|
|
3837
|
+
clock.timerHeap.remove(timer);
|
|
3838
|
+
timer.order = uniqueTimerOrder++;
|
|
3839
|
+
setTimer(clock, timer);
|
|
3840
|
+
clock.timerHeap.push(timer);
|
|
3214
3841
|
|
|
3215
|
-
return
|
|
3842
|
+
return this;
|
|
3216
3843
|
},
|
|
3217
3844
|
[Symbol.toPrimitive]: function () {
|
|
3218
3845
|
return timer.id;
|
|
@@ -3226,12 +3853,20 @@ function requireFakeTimersSrc () {
|
|
|
3226
3853
|
|
|
3227
3854
|
/* eslint consistent-return: "off" */
|
|
3228
3855
|
/**
|
|
3229
|
-
* Timer
|
|
3856
|
+
* Timer comparator
|
|
3230
3857
|
* @param {Timer} a
|
|
3231
3858
|
* @param {Timer} b
|
|
3232
3859
|
* @returns {number}
|
|
3233
3860
|
*/
|
|
3234
3861
|
function compareTimers(a, b) {
|
|
3862
|
+
// Sort IdleCallback timers to the bottom when scheduled for the same time
|
|
3863
|
+
if (a.type === "IdleCallback" && b.type !== "IdleCallback") {
|
|
3864
|
+
return 1;
|
|
3865
|
+
}
|
|
3866
|
+
if (a.type !== "IdleCallback" && b.type === "IdleCallback") {
|
|
3867
|
+
return -1;
|
|
3868
|
+
}
|
|
3869
|
+
|
|
3235
3870
|
// Sort first by absolute timing
|
|
3236
3871
|
if (a.callAt < b.callAt) {
|
|
3237
3872
|
return -1;
|
|
@@ -3248,6 +3883,13 @@ function requireFakeTimersSrc () {
|
|
|
3248
3883
|
return 1;
|
|
3249
3884
|
}
|
|
3250
3885
|
|
|
3886
|
+
if (a.order < b.order) {
|
|
3887
|
+
return -1;
|
|
3888
|
+
}
|
|
3889
|
+
if (a.order > b.order) {
|
|
3890
|
+
return 1;
|
|
3891
|
+
}
|
|
3892
|
+
|
|
3251
3893
|
// Sort next by creation time, earlier-created timers take precedence
|
|
3252
3894
|
if (a.createdAt < b.createdAt) {
|
|
3253
3895
|
return -1;
|
|
@@ -3265,6 +3907,7 @@ function requireFakeTimersSrc () {
|
|
|
3265
3907
|
}
|
|
3266
3908
|
|
|
3267
3909
|
// As timer ids are unique, no fallback `0` is necessary
|
|
3910
|
+
return 0;
|
|
3268
3911
|
}
|
|
3269
3912
|
|
|
3270
3913
|
/**
|
|
@@ -3274,20 +3917,31 @@ function requireFakeTimersSrc () {
|
|
|
3274
3917
|
* @returns {Timer}
|
|
3275
3918
|
*/
|
|
3276
3919
|
function firstTimerInRange(clock, from, to) {
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3920
|
+
if (!clock.timerHeap) {
|
|
3921
|
+
return null;
|
|
3922
|
+
}
|
|
3280
3923
|
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3924
|
+
const timers = clock.timerHeap.timers;
|
|
3925
|
+
if (timers.length === 1 && timers[0].requestIdleCallback) {
|
|
3926
|
+
return timers[0];
|
|
3927
|
+
}
|
|
3284
3928
|
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3929
|
+
const first = clock.timerHeap.peek();
|
|
3930
|
+
if (first && inRange(from, to, first)) {
|
|
3931
|
+
return first;
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3934
|
+
/**
|
|
3935
|
+
* @type {?Timer}
|
|
3936
|
+
*/
|
|
3937
|
+
let timer = null;
|
|
3938
|
+
|
|
3939
|
+
for (let i = 0; i < timers.length; i++) {
|
|
3940
|
+
if (
|
|
3941
|
+
inRange(from, to, timers[i]) &&
|
|
3942
|
+
(!timer || compareTimers(timer, timers[i]) === 1)
|
|
3943
|
+
) {
|
|
3944
|
+
timer = timers[i];
|
|
3291
3945
|
}
|
|
3292
3946
|
}
|
|
3293
3947
|
|
|
@@ -3299,19 +3953,10 @@ function requireFakeTimersSrc () {
|
|
|
3299
3953
|
* @returns {Timer}
|
|
3300
3954
|
*/
|
|
3301
3955
|
function firstTimer(clock) {
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
let id;
|
|
3305
|
-
|
|
3306
|
-
for (id in timers) {
|
|
3307
|
-
if (timers.hasOwnProperty(id)) {
|
|
3308
|
-
if (!timer || compareTimers(timer, timers[id]) === 1) {
|
|
3309
|
-
timer = timers[id];
|
|
3310
|
-
}
|
|
3311
|
-
}
|
|
3956
|
+
if (!clock.timerHeap) {
|
|
3957
|
+
return null;
|
|
3312
3958
|
}
|
|
3313
|
-
|
|
3314
|
-
return timer;
|
|
3959
|
+
return clock.timerHeap.peek() || null;
|
|
3315
3960
|
}
|
|
3316
3961
|
|
|
3317
3962
|
/**
|
|
@@ -3319,15 +3964,15 @@ function requireFakeTimersSrc () {
|
|
|
3319
3964
|
* @returns {Timer}
|
|
3320
3965
|
*/
|
|
3321
3966
|
function lastTimer(clock) {
|
|
3322
|
-
|
|
3967
|
+
if (!clock.timerHeap) {
|
|
3968
|
+
return null;
|
|
3969
|
+
}
|
|
3970
|
+
const timers = clock.timerHeap.timers;
|
|
3323
3971
|
let timer = null;
|
|
3324
|
-
let id;
|
|
3325
3972
|
|
|
3326
|
-
for (
|
|
3327
|
-
if (timers
|
|
3328
|
-
|
|
3329
|
-
timer = timers[id];
|
|
3330
|
-
}
|
|
3973
|
+
for (let i = 0; i < timers.length; i++) {
|
|
3974
|
+
if (!timer || compareTimers(timer, timers[i]) === -1) {
|
|
3975
|
+
timer = timers[i];
|
|
3331
3976
|
}
|
|
3332
3977
|
}
|
|
3333
3978
|
|
|
@@ -3340,25 +3985,27 @@ function requireFakeTimersSrc () {
|
|
|
3340
3985
|
*/
|
|
3341
3986
|
function callTimer(clock, timer) {
|
|
3342
3987
|
if (typeof timer.interval === "number") {
|
|
3343
|
-
clock.
|
|
3988
|
+
clock.timerHeap.remove(timer);
|
|
3989
|
+
timer.callAt += timer.interval;
|
|
3990
|
+
timer.order = uniqueTimerOrder++;
|
|
3991
|
+
if (clock.isNearInfiniteLimit) {
|
|
3992
|
+
timer.error = new Error();
|
|
3993
|
+
}
|
|
3994
|
+
clock.timerHeap.push(timer);
|
|
3344
3995
|
} else {
|
|
3345
|
-
|
|
3996
|
+
deleteTimer(clock, timer.id);
|
|
3997
|
+
clock.timerHeap.remove(timer);
|
|
3346
3998
|
}
|
|
3347
3999
|
|
|
3348
4000
|
if (typeof timer.func === "function") {
|
|
3349
4001
|
timer.func.apply(null, timer.args);
|
|
3350
|
-
} else {
|
|
3351
|
-
/* eslint no-eval: "off" */
|
|
3352
|
-
const eval2 = eval;
|
|
3353
|
-
(function () {
|
|
3354
|
-
eval2(timer.func);
|
|
3355
|
-
})();
|
|
3356
4002
|
}
|
|
3357
4003
|
}
|
|
3358
4004
|
|
|
3359
4005
|
/**
|
|
3360
4006
|
* Gets clear handler name for a given timer type
|
|
3361
4007
|
* @param {string} ttype
|
|
4008
|
+
* @returns {string}
|
|
3362
4009
|
*/
|
|
3363
4010
|
function getClearHandler(ttype) {
|
|
3364
4011
|
if (ttype === "IdleCallback" || ttype === "AnimationFrame") {
|
|
@@ -3370,6 +4017,7 @@ function requireFakeTimersSrc () {
|
|
|
3370
4017
|
/**
|
|
3371
4018
|
* Gets schedule handler name for a given timer type
|
|
3372
4019
|
* @param {string} ttype
|
|
4020
|
+
* @returns {string}
|
|
3373
4021
|
*/
|
|
3374
4022
|
function getScheduleHandler(ttype) {
|
|
3375
4023
|
if (ttype === "IdleCallback" || ttype === "AnimationFrame") {
|
|
@@ -3380,6 +4028,7 @@ function requireFakeTimersSrc () {
|
|
|
3380
4028
|
|
|
3381
4029
|
/**
|
|
3382
4030
|
* Creates an anonymous function to warn only once
|
|
4031
|
+
* @returns {(msg: string) => void}
|
|
3383
4032
|
*/
|
|
3384
4033
|
function createWarnOnce() {
|
|
3385
4034
|
let calls = 0;
|
|
@@ -3392,8 +4041,9 @@ function requireFakeTimersSrc () {
|
|
|
3392
4041
|
|
|
3393
4042
|
/**
|
|
3394
4043
|
* @param {Clock} clock
|
|
3395
|
-
* @param {
|
|
4044
|
+
* @param {TimerId} timerId
|
|
3396
4045
|
* @param {string} ttype
|
|
4046
|
+
* @returns {void}
|
|
3397
4047
|
*/
|
|
3398
4048
|
function clearTimer(clock, timerId, ttype) {
|
|
3399
4049
|
if (!timerId) {
|
|
@@ -3402,10 +4052,6 @@ function requireFakeTimersSrc () {
|
|
|
3402
4052
|
return;
|
|
3403
4053
|
}
|
|
3404
4054
|
|
|
3405
|
-
if (!clock.timers) {
|
|
3406
|
-
clock.timers = {};
|
|
3407
|
-
}
|
|
3408
|
-
|
|
3409
4055
|
// in Node, the ID is stored as the primitive value for `Timeout` objects
|
|
3410
4056
|
// for `Immediate` objects, no ID exists, so it gets coerced to NaN
|
|
3411
4057
|
const id = Number(timerId);
|
|
@@ -3419,21 +4065,30 @@ function requireFakeTimersSrc () {
|
|
|
3419
4065
|
? nativeHandler(timerId)
|
|
3420
4066
|
: undefined;
|
|
3421
4067
|
}
|
|
4068
|
+
|
|
4069
|
+
// Include the stacktrace, excluding the 'error' line
|
|
4070
|
+
const stackTrace = new Error().stack
|
|
4071
|
+
.split("\n")
|
|
4072
|
+
.slice(1)
|
|
4073
|
+
.join("\n");
|
|
4074
|
+
|
|
3422
4075
|
warnOnce(
|
|
3423
4076
|
`FakeTimers: ${handlerName} was invoked to clear a native timer instead of one created by this library.` +
|
|
3424
|
-
"\nTo automatically clean-up native timers, use `shouldClearNativeTimers`."
|
|
4077
|
+
"\nTo automatically clean-up native timers, use `shouldClearNativeTimers`." +
|
|
4078
|
+
`\n${stackTrace}`,
|
|
3425
4079
|
);
|
|
3426
4080
|
}
|
|
3427
4081
|
|
|
3428
|
-
if (clock
|
|
4082
|
+
if (hasTimer(clock, id)) {
|
|
3429
4083
|
// check that the ID matches a timer of the correct type
|
|
3430
|
-
const timer = clock
|
|
4084
|
+
const timer = getTimer(clock, id);
|
|
3431
4085
|
if (
|
|
3432
4086
|
timer.type === ttype ||
|
|
3433
4087
|
(timer.type === "Timeout" && ttype === "Interval") ||
|
|
3434
4088
|
(timer.type === "Interval" && ttype === "Timeout")
|
|
3435
4089
|
) {
|
|
3436
|
-
|
|
4090
|
+
deleteTimer(clock, id);
|
|
4091
|
+
clock.timerHeap.remove(timer);
|
|
3437
4092
|
} else {
|
|
3438
4093
|
const clear = getClearHandler(ttype);
|
|
3439
4094
|
const schedule = getScheduleHandler(timer.type);
|
|
@@ -3478,12 +4133,12 @@ function requireFakeTimersSrc () {
|
|
|
3478
4133
|
_global[method] = clock[`_${method}`];
|
|
3479
4134
|
}
|
|
3480
4135
|
} else {
|
|
3481
|
-
if (
|
|
4136
|
+
if (clock[method] && clock[method].hasOwnProperty) {
|
|
3482
4137
|
_global[method] = clock[`_${method}`];
|
|
3483
4138
|
} else {
|
|
3484
4139
|
try {
|
|
3485
4140
|
delete _global[method];
|
|
3486
|
-
} catch
|
|
4141
|
+
} catch {
|
|
3487
4142
|
/* eslint no-empty: "off" */
|
|
3488
4143
|
}
|
|
3489
4144
|
}
|
|
@@ -3506,7 +4161,7 @@ function requireFakeTimersSrc () {
|
|
|
3506
4161
|
}
|
|
3507
4162
|
}
|
|
3508
4163
|
|
|
3509
|
-
clock.setTickMode("manual");
|
|
4164
|
+
clock.setTickMode({ mode: "manual" });
|
|
3510
4165
|
|
|
3511
4166
|
// Prevent multiple executions which will completely remove these props
|
|
3512
4167
|
clock.methods = [];
|
|
@@ -3517,12 +4172,10 @@ function requireFakeTimersSrc () {
|
|
|
3517
4172
|
}
|
|
3518
4173
|
|
|
3519
4174
|
// return pending timers, to enable checking what timers remained on uninstall
|
|
3520
|
-
if (!clock.
|
|
4175
|
+
if (!clock.timerHeap) {
|
|
3521
4176
|
return [];
|
|
3522
4177
|
}
|
|
3523
|
-
return
|
|
3524
|
-
return clock.timers[key];
|
|
3525
|
-
});
|
|
4178
|
+
return clock.timerHeap.timers.slice();
|
|
3526
4179
|
}
|
|
3527
4180
|
|
|
3528
4181
|
/**
|
|
@@ -3531,7 +4184,7 @@ function requireFakeTimersSrc () {
|
|
|
3531
4184
|
* @param {Clock} clock
|
|
3532
4185
|
*/
|
|
3533
4186
|
function hijackMethod(target, method, clock) {
|
|
3534
|
-
clock[method].
|
|
4187
|
+
clock[method].hasOwnProperty = Object.prototype.hasOwnProperty.call(
|
|
3535
4188
|
target,
|
|
3536
4189
|
method,
|
|
3537
4190
|
);
|
|
@@ -3588,26 +4241,6 @@ function requireFakeTimersSrc () {
|
|
|
3588
4241
|
clock.tick(advanceTimeDelta);
|
|
3589
4242
|
}
|
|
3590
4243
|
|
|
3591
|
-
/**
|
|
3592
|
-
* @typedef {object} Timers
|
|
3593
|
-
* @property {setTimeout} setTimeout
|
|
3594
|
-
* @property {clearTimeout} clearTimeout
|
|
3595
|
-
* @property {setInterval} setInterval
|
|
3596
|
-
* @property {clearInterval} clearInterval
|
|
3597
|
-
* @property {Date} Date
|
|
3598
|
-
* @property {Intl} Intl
|
|
3599
|
-
* @property {SetImmediate=} setImmediate
|
|
3600
|
-
* @property {function(NodeImmediate): void=} clearImmediate
|
|
3601
|
-
* @property {function(number[]):number[]=} hrtime
|
|
3602
|
-
* @property {NextTick=} nextTick
|
|
3603
|
-
* @property {Performance=} performance
|
|
3604
|
-
* @property {RequestAnimationFrame=} requestAnimationFrame
|
|
3605
|
-
* @property {boolean=} queueMicrotask
|
|
3606
|
-
* @property {function(number): void=} cancelAnimationFrame
|
|
3607
|
-
* @property {RequestIdleCallback=} requestIdleCallback
|
|
3608
|
-
* @property {function(number): void=} cancelIdleCallback
|
|
3609
|
-
*/
|
|
3610
|
-
|
|
3611
4244
|
/** @type {Timers} */
|
|
3612
4245
|
const timers = {
|
|
3613
4246
|
setTimeout: _global.setTimeout,
|
|
@@ -3671,30 +4304,37 @@ function requireFakeTimersSrc () {
|
|
|
3671
4304
|
* @returns {Clock}
|
|
3672
4305
|
*/
|
|
3673
4306
|
function createClock(start, loopLimit) {
|
|
4307
|
+
/** @type {number} */
|
|
3674
4308
|
// eslint-disable-next-line no-param-reassign
|
|
3675
4309
|
start = Math.floor(getEpoch(start));
|
|
4310
|
+
const startTimestamp = start;
|
|
3676
4311
|
// eslint-disable-next-line no-param-reassign
|
|
3677
4312
|
loopLimit = loopLimit || 1000;
|
|
4313
|
+
/** @type {number} */
|
|
3678
4314
|
let nanos = 0;
|
|
4315
|
+
/** @type {number[]} */
|
|
3679
4316
|
const adjustedSystemTime = [0, 0]; // [millis, nanoremainder]
|
|
3680
4317
|
|
|
3681
|
-
|
|
4318
|
+
/** @type {Clock} */
|
|
4319
|
+
const clock = /** @type {Clock} */ ({
|
|
3682
4320
|
now: start,
|
|
3683
4321
|
Date: createDate(),
|
|
3684
4322
|
loopLimit: loopLimit,
|
|
4323
|
+
isNearInfiniteLimit: false,
|
|
3685
4324
|
tickMode: { mode: "manual", counter: 0, delta: undefined },
|
|
3686
|
-
};
|
|
4325
|
+
});
|
|
3687
4326
|
|
|
3688
4327
|
clock.Date.clock = clock;
|
|
3689
4328
|
|
|
3690
4329
|
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
3691
4330
|
function getTimeToNextFrame() {
|
|
3692
|
-
return 16 - ((clock.now -
|
|
4331
|
+
return 16 - ((clock.now - startTimestamp) % 16);
|
|
3693
4332
|
}
|
|
3694
4333
|
|
|
3695
4334
|
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
3696
4335
|
function hrtime(prev) {
|
|
3697
|
-
const millisSinceStart =
|
|
4336
|
+
const millisSinceStart =
|
|
4337
|
+
clock.now - adjustedSystemTime[0] - startTimestamp;
|
|
3698
4338
|
const secsSinceStart = Math.floor(millisSinceStart / 1000);
|
|
3699
4339
|
const remainderInNanos =
|
|
3700
4340
|
(millisSinceStart - secsSinceStart * 1e3) * 1e6 +
|
|
@@ -3740,20 +4380,21 @@ function requireFakeTimersSrc () {
|
|
|
3740
4380
|
if (isPresent.hrtimeBigint) {
|
|
3741
4381
|
hrtime.bigint = function () {
|
|
3742
4382
|
const parts = hrtime();
|
|
3743
|
-
return BigInt(parts[0]) * BigInt(1e9) + BigInt(parts[1]);
|
|
4383
|
+
return BigInt(parts[0]) * BigInt(1e9) + BigInt(parts[1]);
|
|
3744
4384
|
};
|
|
3745
4385
|
}
|
|
3746
4386
|
|
|
3747
4387
|
if (isPresent.Intl) {
|
|
3748
|
-
clock.Intl = createIntl();
|
|
4388
|
+
clock.Intl = createIntl(clock);
|
|
3749
4389
|
clock.Intl.clock = clock;
|
|
3750
4390
|
}
|
|
3751
4391
|
|
|
3752
4392
|
/**
|
|
3753
|
-
* @param {
|
|
4393
|
+
* @param {SetTickModeConfig} tickModeConfig - The new configuration for how the clock should tick.
|
|
3754
4394
|
*/
|
|
3755
4395
|
clock.setTickMode = function (tickModeConfig) {
|
|
3756
|
-
const { mode: newMode, delta: newDelta } =
|
|
4396
|
+
const { mode: newMode, delta: newDelta } =
|
|
4397
|
+
/** @type {SetTickModeConfig} */ (tickModeConfig);
|
|
3757
4398
|
const { mode: oldMode, delta: oldDelta } = clock.tickMode;
|
|
3758
4399
|
if (newMode === oldMode && newDelta === oldDelta) {
|
|
3759
4400
|
return;
|
|
@@ -3776,7 +4417,15 @@ function requireFakeTimersSrc () {
|
|
|
3776
4417
|
}
|
|
3777
4418
|
};
|
|
3778
4419
|
|
|
4420
|
+
/**
|
|
4421
|
+
* Keeps advancing the native event loop until the tick mode changes.
|
|
4422
|
+
* @returns {Promise<void>}
|
|
4423
|
+
*/
|
|
3779
4424
|
async function advanceUntilModeChanges() {
|
|
4425
|
+
/**
|
|
4426
|
+
* Waits for one native macrotask and then one microtask turn.
|
|
4427
|
+
* @returns {Promise<void>}
|
|
4428
|
+
*/
|
|
3780
4429
|
async function newMacrotask() {
|
|
3781
4430
|
// MessageChannel ensures that setTimeout is not throttled to 4ms.
|
|
3782
4431
|
// https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#reasons_for_delays_longer_than_specified
|
|
@@ -3784,7 +4433,7 @@ function requireFakeTimersSrc () {
|
|
|
3784
4433
|
const channel = new MessageChannel();
|
|
3785
4434
|
await new Promise((resolve) => {
|
|
3786
4435
|
channel.port1.onmessage = () => {
|
|
3787
|
-
resolve();
|
|
4436
|
+
resolve(undefined);
|
|
3788
4437
|
channel.port1.close();
|
|
3789
4438
|
};
|
|
3790
4439
|
channel.port2.postMessage(undefined);
|
|
@@ -3807,6 +4456,11 @@ function requireFakeTimersSrc () {
|
|
|
3807
4456
|
}
|
|
3808
4457
|
}
|
|
3809
4458
|
|
|
4459
|
+
/**
|
|
4460
|
+
* Temporarily pauses nextAsync auto-ticking while an async operation runs.
|
|
4461
|
+
* @param {Promise<unknown>} promise
|
|
4462
|
+
* @returns {Promise<unknown>}
|
|
4463
|
+
*/
|
|
3810
4464
|
function pauseAutoTickUntilFinished(promise) {
|
|
3811
4465
|
if (clock.tickMode.mode !== "nextAsync") {
|
|
3812
4466
|
return promise;
|
|
@@ -3817,24 +4471,37 @@ function requireFakeTimersSrc () {
|
|
|
3817
4471
|
});
|
|
3818
4472
|
}
|
|
3819
4473
|
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
4474
|
+
/**
|
|
4475
|
+
* Returns the remaining time in the current idle window.
|
|
4476
|
+
* @returns {number}
|
|
4477
|
+
*/
|
|
4478
|
+
function getTimeToNextIdlePeriod() {
|
|
3824
4479
|
let timeToNextIdlePeriod = 0;
|
|
3825
4480
|
|
|
3826
4481
|
if (clock.countTimers() > 0) {
|
|
3827
4482
|
timeToNextIdlePeriod = 50; // const for now
|
|
3828
4483
|
}
|
|
3829
4484
|
|
|
4485
|
+
return timeToNextIdlePeriod;
|
|
4486
|
+
}
|
|
4487
|
+
|
|
4488
|
+
clock.requestIdleCallback = function requestIdleCallback(
|
|
4489
|
+
func,
|
|
4490
|
+
{ timeout } = /** @type {{ timeout?: number }} */ ({}),
|
|
4491
|
+
) {
|
|
4492
|
+
/**
|
|
4493
|
+
* @type {IdleDeadline}
|
|
4494
|
+
*/
|
|
4495
|
+
const idleDeadline = {
|
|
4496
|
+
didTimeout: true,
|
|
4497
|
+
timeRemaining: getTimeToNextIdlePeriod,
|
|
4498
|
+
};
|
|
4499
|
+
|
|
3830
4500
|
const result = addTimer(clock, {
|
|
3831
4501
|
func: func,
|
|
3832
|
-
args:
|
|
3833
|
-
delay:
|
|
3834
|
-
|
|
3835
|
-
? timeToNextIdlePeriod
|
|
3836
|
-
: Math.min(timeout, timeToNextIdlePeriod),
|
|
3837
|
-
idleCallback: true,
|
|
4502
|
+
args: [idleDeadline],
|
|
4503
|
+
delay: timeout,
|
|
4504
|
+
requestIdleCallback: true,
|
|
3838
4505
|
});
|
|
3839
4506
|
|
|
3840
4507
|
return Number(result);
|
|
@@ -3874,7 +4541,7 @@ function requireFakeTimersSrc () {
|
|
|
3874
4541
|
return enqueueJob(clock, {
|
|
3875
4542
|
func: func,
|
|
3876
4543
|
args: Array.prototype.slice.call(arguments, 1),
|
|
3877
|
-
error: isNearInfiniteLimit ? new Error() : null,
|
|
4544
|
+
error: clock.isNearInfiniteLimit ? new Error() : null,
|
|
3878
4545
|
});
|
|
3879
4546
|
};
|
|
3880
4547
|
|
|
@@ -3884,7 +4551,7 @@ function requireFakeTimersSrc () {
|
|
|
3884
4551
|
|
|
3885
4552
|
clock.setInterval = function setInterval(func, timeout) {
|
|
3886
4553
|
// eslint-disable-next-line no-param-reassign
|
|
3887
|
-
timeout = parseInt(timeout, 10);
|
|
4554
|
+
timeout = parseInt(String(timeout), 10);
|
|
3888
4555
|
return addTimer(clock, {
|
|
3889
4556
|
func: func,
|
|
3890
4557
|
args: Array.prototype.slice.call(arguments, 2),
|
|
@@ -3898,13 +4565,15 @@ function requireFakeTimersSrc () {
|
|
|
3898
4565
|
};
|
|
3899
4566
|
|
|
3900
4567
|
if (isPresent.setImmediate) {
|
|
3901
|
-
clock.setImmediate =
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
4568
|
+
clock.setImmediate = /** @type {SetImmediate} */ (
|
|
4569
|
+
function setImmediate(func) {
|
|
4570
|
+
return addTimer(clock, {
|
|
4571
|
+
func: func,
|
|
4572
|
+
args: Array.prototype.slice.call(arguments, 1),
|
|
4573
|
+
immediate: true,
|
|
4574
|
+
});
|
|
4575
|
+
}
|
|
4576
|
+
);
|
|
3908
4577
|
|
|
3909
4578
|
if (typeof _global.Promise !== "undefined" && utilPromisify) {
|
|
3910
4579
|
clock.setImmediate[utilPromisify.custom] =
|
|
@@ -3928,7 +4597,7 @@ function requireFakeTimersSrc () {
|
|
|
3928
4597
|
|
|
3929
4598
|
clock.countTimers = function countTimers() {
|
|
3930
4599
|
return (
|
|
3931
|
-
|
|
4600
|
+
(clock.timerHeap ? clock.timerHeap.timers.length : 0) +
|
|
3932
4601
|
(clock.jobs || []).length
|
|
3933
4602
|
);
|
|
3934
4603
|
};
|
|
@@ -3956,12 +4625,9 @@ function requireFakeTimersSrc () {
|
|
|
3956
4625
|
|
|
3957
4626
|
/**
|
|
3958
4627
|
* @param {number|string} tickValue milliseconds or a string parseable by parseTime
|
|
3959
|
-
* @
|
|
3960
|
-
* @param {Function} resolve
|
|
3961
|
-
* @param {Function} reject
|
|
3962
|
-
* @returns {number|undefined} will return the new `now` value or nothing for async
|
|
4628
|
+
* @returns {ClockState} a mutable state object for the tick execution
|
|
3963
4629
|
*/
|
|
3964
|
-
function
|
|
4630
|
+
function createTickState(tickValue) {
|
|
3965
4631
|
const msFloat =
|
|
3966
4632
|
typeof tickValue === "number"
|
|
3967
4633
|
? tickValue
|
|
@@ -3981,122 +4647,202 @@ function requireFakeTimersSrc () {
|
|
|
3981
4647
|
nanosTotal -= 1e6;
|
|
3982
4648
|
}
|
|
3983
4649
|
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
clock.duringTick = true;
|
|
4650
|
+
return /** @type {ClockState} */ ({
|
|
4651
|
+
msFloat: msFloat,
|
|
4652
|
+
ms: ms,
|
|
4653
|
+
nanosTotal: nanosTotal,
|
|
4654
|
+
tickFrom: clock.now,
|
|
4655
|
+
tickTo: tickTo,
|
|
4656
|
+
previous: clock.now,
|
|
4657
|
+
timer: null,
|
|
4658
|
+
firstException: null,
|
|
4659
|
+
oldNow: null,
|
|
4660
|
+
});
|
|
4661
|
+
}
|
|
3998
4662
|
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4663
|
+
/**
|
|
4664
|
+
* @param {ClockState} state mutable tick state
|
|
4665
|
+
* @param {number} oldNow the clock.now before some action
|
|
4666
|
+
* @param {object} [options] compensation options
|
|
4667
|
+
* @param {boolean} [options.includePrevious] whether to also update state.previous
|
|
4668
|
+
*/
|
|
4669
|
+
function applyClockChangeCompensation(state, oldNow, options) {
|
|
4002
4670
|
if (oldNow !== clock.now) {
|
|
4003
|
-
|
|
4004
|
-
tickFrom +=
|
|
4005
|
-
tickTo +=
|
|
4671
|
+
const difference = clock.now - oldNow;
|
|
4672
|
+
state.tickFrom += difference;
|
|
4673
|
+
state.tickTo += difference;
|
|
4674
|
+
if (options && options.includePrevious) {
|
|
4675
|
+
state.previous += difference;
|
|
4676
|
+
}
|
|
4006
4677
|
}
|
|
4678
|
+
}
|
|
4007
4679
|
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
clock.now = timer.callAt;
|
|
4017
|
-
oldNow = clock.now;
|
|
4018
|
-
try {
|
|
4019
|
-
runJobs(clock);
|
|
4020
|
-
callTimer(clock, timer);
|
|
4021
|
-
} catch (e) {
|
|
4022
|
-
firstException = firstException || e;
|
|
4023
|
-
}
|
|
4024
|
-
|
|
4025
|
-
if (isAsync) {
|
|
4026
|
-
// finish up after native setImmediate callback to allow
|
|
4027
|
-
// all native es6 promises to process their callbacks after
|
|
4028
|
-
// each timer fires.
|
|
4029
|
-
originalSetTimeout(nextPromiseTick);
|
|
4030
|
-
return;
|
|
4031
|
-
}
|
|
4680
|
+
/**
|
|
4681
|
+
* @param {ClockState} state mutable tick state
|
|
4682
|
+
*/
|
|
4683
|
+
function runInitialJobs(state) {
|
|
4684
|
+
state.oldNow = clock.now;
|
|
4685
|
+
runJobs(clock);
|
|
4686
|
+
applyClockChangeCompensation(state, state.oldNow);
|
|
4687
|
+
}
|
|
4032
4688
|
|
|
4033
|
-
|
|
4034
|
-
|
|
4689
|
+
/**
|
|
4690
|
+
* @param {ClockState} state mutable tick state
|
|
4691
|
+
*/
|
|
4692
|
+
function runPostLoopJobs(state) {
|
|
4693
|
+
state.oldNow = clock.now;
|
|
4694
|
+
runJobs(clock);
|
|
4695
|
+
applyClockChangeCompensation(state, state.oldNow);
|
|
4696
|
+
}
|
|
4035
4697
|
|
|
4036
|
-
|
|
4037
|
-
|
|
4698
|
+
/**
|
|
4699
|
+
* @param {ClockState} state mutable tick state
|
|
4700
|
+
*/
|
|
4701
|
+
function selectNextTimerInRange(state) {
|
|
4702
|
+
state.timer = firstTimerInRange(
|
|
4703
|
+
clock,
|
|
4704
|
+
state.previous,
|
|
4705
|
+
state.tickTo,
|
|
4706
|
+
);
|
|
4707
|
+
state.previous = state.tickFrom;
|
|
4708
|
+
}
|
|
4038
4709
|
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4710
|
+
/**
|
|
4711
|
+
* @param {ClockState} state mutable tick state
|
|
4712
|
+
* @param {boolean} isAsync whether this is an async tick
|
|
4713
|
+
* @param {FakeTimersFunction} nextPromiseTick callback for async promise settlement
|
|
4714
|
+
* @param {FakeTimersFunction} compensationCheck callback for clock change compensation
|
|
4715
|
+
* @returns {boolean} whether an early return was triggered (async mode)
|
|
4716
|
+
*/
|
|
4717
|
+
function runTimersInRange(
|
|
4718
|
+
state,
|
|
4719
|
+
isAsync,
|
|
4720
|
+
nextPromiseTick,
|
|
4721
|
+
compensationCheck,
|
|
4722
|
+
) {
|
|
4723
|
+
state.timer = firstTimerInRange(
|
|
4724
|
+
clock,
|
|
4725
|
+
state.tickFrom,
|
|
4726
|
+
state.tickTo,
|
|
4727
|
+
);
|
|
4048
4728
|
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4729
|
+
while (state.timer && state.tickFrom <= state.tickTo) {
|
|
4730
|
+
if (hasTimer(clock, state.timer.id)) {
|
|
4731
|
+
state.tickFrom = state.timer.callAt;
|
|
4732
|
+
clock.now = state.timer.callAt;
|
|
4733
|
+
state.oldNow = clock.now;
|
|
4052
4734
|
try {
|
|
4053
|
-
|
|
4735
|
+
runJobs(clock);
|
|
4736
|
+
callTimer(clock, state.timer);
|
|
4054
4737
|
} catch (e) {
|
|
4055
|
-
firstException = firstException || e;
|
|
4738
|
+
state.firstException = state.firstException || e;
|
|
4739
|
+
}
|
|
4740
|
+
|
|
4741
|
+
if (isAsync) {
|
|
4742
|
+
// finish up after native setImmediate callback to allow
|
|
4743
|
+
// all native es6 promises to process their callbacks after
|
|
4744
|
+
// each timer fires.
|
|
4745
|
+
originalSetTimeout(nextPromiseTick);
|
|
4746
|
+
return true;
|
|
4056
4747
|
}
|
|
4057
|
-
} else {
|
|
4058
|
-
// no timers remaining in the requested range: move the clock all the way to the end
|
|
4059
|
-
clock.now = tickTo;
|
|
4060
4748
|
|
|
4061
|
-
|
|
4062
|
-
nanos = nanosTotal;
|
|
4063
|
-
}
|
|
4064
|
-
if (firstException) {
|
|
4065
|
-
throw firstException;
|
|
4749
|
+
compensationCheck();
|
|
4066
4750
|
}
|
|
4067
4751
|
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4752
|
+
selectNextTimerInRange(state);
|
|
4753
|
+
}
|
|
4754
|
+
return false;
|
|
4755
|
+
}
|
|
4756
|
+
|
|
4757
|
+
/**
|
|
4758
|
+
* @param {ClockState} state mutable tick state
|
|
4759
|
+
* @param {boolean} isAsync whether this is an async tick
|
|
4760
|
+
* @param {FakeTimersFunction} resolve promise resolve function
|
|
4761
|
+
* @returns {number|undefined} the new clock.now or nothing for async
|
|
4762
|
+
*/
|
|
4763
|
+
function finalizeTick(state, isAsync, resolve) {
|
|
4764
|
+
// corner case: during runJobs new timers were scheduled which could be in the range [clock.now, tickTo]
|
|
4765
|
+
state.timer = firstTimerInRange(
|
|
4766
|
+
clock,
|
|
4767
|
+
state.tickFrom,
|
|
4768
|
+
state.tickTo,
|
|
4769
|
+
);
|
|
4770
|
+
if (state.timer) {
|
|
4771
|
+
try {
|
|
4772
|
+
clock.tick(state.tickTo - clock.now); // do it all again - for the remainder of the requested range
|
|
4773
|
+
} catch (e) {
|
|
4774
|
+
state.firstException = state.firstException || e;
|
|
4072
4775
|
}
|
|
4776
|
+
} else {
|
|
4777
|
+
// no timers remaining in the requested range: move the clock all the way to the end
|
|
4778
|
+
clock.now = state.tickTo;
|
|
4779
|
+
|
|
4780
|
+
// update nanos
|
|
4781
|
+
nanos = state.nanosTotal;
|
|
4782
|
+
}
|
|
4783
|
+
if (state.firstException) {
|
|
4784
|
+
throw state.firstException;
|
|
4785
|
+
}
|
|
4786
|
+
|
|
4787
|
+
if (isAsync) {
|
|
4788
|
+
resolve(clock.now);
|
|
4789
|
+
} else {
|
|
4790
|
+
return clock.now;
|
|
4073
4791
|
}
|
|
4792
|
+
}
|
|
4793
|
+
|
|
4794
|
+
/**
|
|
4795
|
+
* @param {number|string} tickValue milliseconds or a string parseable by parseTime
|
|
4796
|
+
* @param {boolean} isAsync whether this is an async tick
|
|
4797
|
+
* @param {FakeTimersFunction} [resolve] promise resolve function
|
|
4798
|
+
* @param {FakeTimersFunction} [reject] promise reject function
|
|
4799
|
+
* @returns {number|undefined} the new clock.now or nothing for async
|
|
4800
|
+
*/
|
|
4801
|
+
function doTick(tickValue, isAsync, resolve, reject) {
|
|
4802
|
+
/** @type {ClockState} */
|
|
4803
|
+
const state = createTickState(tickValue);
|
|
4804
|
+
|
|
4805
|
+
nanos = state.nanosTotal;
|
|
4806
|
+
clock.duringTick = true;
|
|
4807
|
+
|
|
4808
|
+
runInitialJobs(state);
|
|
4809
|
+
|
|
4810
|
+
const compensationCheck = function () {
|
|
4811
|
+
applyClockChangeCompensation(state, state.oldNow, {
|
|
4812
|
+
includePrevious: true,
|
|
4813
|
+
});
|
|
4814
|
+
};
|
|
4074
4815
|
|
|
4075
|
-
nextPromiseTick =
|
|
4816
|
+
const nextPromiseTick =
|
|
4076
4817
|
isAsync &&
|
|
4077
4818
|
function () {
|
|
4078
4819
|
try {
|
|
4079
4820
|
compensationCheck();
|
|
4080
|
-
|
|
4821
|
+
selectNextTimerInRange(state);
|
|
4081
4822
|
doTickInner();
|
|
4082
4823
|
} catch (e) {
|
|
4083
4824
|
reject(e);
|
|
4084
4825
|
}
|
|
4085
4826
|
};
|
|
4086
4827
|
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
if (
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4828
|
+
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
4829
|
+
function doTickInner() {
|
|
4830
|
+
if (
|
|
4831
|
+
runTimersInRange(
|
|
4832
|
+
state,
|
|
4833
|
+
isAsync,
|
|
4834
|
+
nextPromiseTick,
|
|
4835
|
+
compensationCheck,
|
|
4836
|
+
)
|
|
4837
|
+
) {
|
|
4838
|
+
return;
|
|
4093
4839
|
}
|
|
4094
|
-
};
|
|
4095
4840
|
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4841
|
+
runPostLoopJobs(state);
|
|
4842
|
+
clock.duringTick = false;
|
|
4843
|
+
|
|
4844
|
+
return finalizeTick(state, isAsync, resolve);
|
|
4845
|
+
}
|
|
4100
4846
|
|
|
4101
4847
|
return doTickInner();
|
|
4102
4848
|
}
|
|
@@ -4109,26 +4855,6 @@ function requireFakeTimersSrc () {
|
|
|
4109
4855
|
return doTick(tickValue, false);
|
|
4110
4856
|
};
|
|
4111
4857
|
|
|
4112
|
-
if (typeof _global.Promise !== "undefined") {
|
|
4113
|
-
/**
|
|
4114
|
-
* @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
|
|
4115
|
-
* @returns {Promise}
|
|
4116
|
-
*/
|
|
4117
|
-
clock.tickAsync = function tickAsync(tickValue) {
|
|
4118
|
-
return pauseAutoTickUntilFinished(
|
|
4119
|
-
new _global.Promise(function (resolve, reject) {
|
|
4120
|
-
originalSetTimeout(function () {
|
|
4121
|
-
try {
|
|
4122
|
-
doTick(tickValue, true, resolve, reject);
|
|
4123
|
-
} catch (e) {
|
|
4124
|
-
reject(e);
|
|
4125
|
-
}
|
|
4126
|
-
});
|
|
4127
|
-
}),
|
|
4128
|
-
);
|
|
4129
|
-
};
|
|
4130
|
-
}
|
|
4131
|
-
|
|
4132
4858
|
clock.next = function next() {
|
|
4133
4859
|
runJobs(clock);
|
|
4134
4860
|
const timer = firstTimer(clock);
|
|
@@ -4147,61 +4873,40 @@ function requireFakeTimersSrc () {
|
|
|
4147
4873
|
}
|
|
4148
4874
|
};
|
|
4149
4875
|
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
callTimer(clock, timer);
|
|
4167
|
-
} catch (e) {
|
|
4168
|
-
err = e;
|
|
4169
|
-
}
|
|
4170
|
-
clock.duringTick = false;
|
|
4171
|
-
|
|
4172
|
-
originalSetTimeout(function () {
|
|
4173
|
-
if (err) {
|
|
4174
|
-
reject(err);
|
|
4175
|
-
} else {
|
|
4176
|
-
resolve(clock.now);
|
|
4177
|
-
}
|
|
4178
|
-
});
|
|
4179
|
-
} catch (e) {
|
|
4180
|
-
reject(e);
|
|
4181
|
-
}
|
|
4182
|
-
});
|
|
4183
|
-
}),
|
|
4184
|
-
);
|
|
4185
|
-
};
|
|
4876
|
+
/**
|
|
4877
|
+
* @param {(resolve: (value: unknown) => void, reject: (reason?: unknown) => void) => void} callback function to run inside native setTimeout
|
|
4878
|
+
* @returns {Promise}
|
|
4879
|
+
*/
|
|
4880
|
+
function runAsyncWithNativeTimeout(callback) {
|
|
4881
|
+
return pauseAutoTickUntilFinished(
|
|
4882
|
+
new _global.Promise(function (resolve, reject) {
|
|
4883
|
+
originalSetTimeout(function () {
|
|
4884
|
+
try {
|
|
4885
|
+
callback(resolve, reject);
|
|
4886
|
+
} catch (e) {
|
|
4887
|
+
reject(e);
|
|
4888
|
+
}
|
|
4889
|
+
});
|
|
4890
|
+
}),
|
|
4891
|
+
);
|
|
4186
4892
|
}
|
|
4187
4893
|
|
|
4188
4894
|
clock.runAll = function runAll() {
|
|
4189
|
-
let numTimers, i;
|
|
4190
4895
|
runJobs(clock);
|
|
4191
|
-
for (i = 0; i < clock.loopLimit; i++) {
|
|
4896
|
+
for (let i = 0; i < clock.loopLimit; i++) {
|
|
4192
4897
|
if (!clock.timers) {
|
|
4193
|
-
resetIsNearInfiniteLimit();
|
|
4898
|
+
resetIsNearInfiniteLimit(clock);
|
|
4194
4899
|
return clock.now;
|
|
4195
4900
|
}
|
|
4196
4901
|
|
|
4197
|
-
numTimers =
|
|
4902
|
+
const numTimers = clock.timerHeap.timers.length;
|
|
4198
4903
|
if (numTimers === 0) {
|
|
4199
|
-
resetIsNearInfiniteLimit();
|
|
4904
|
+
resetIsNearInfiniteLimit(clock);
|
|
4200
4905
|
return clock.now;
|
|
4201
4906
|
}
|
|
4202
4907
|
|
|
4203
|
-
clock.next();
|
|
4204
4908
|
checkIsNearInfiniteLimit(clock, i);
|
|
4909
|
+
clock.next();
|
|
4205
4910
|
}
|
|
4206
4911
|
|
|
4207
4912
|
const excessJob = firstTimer(clock);
|
|
@@ -4212,60 +4917,6 @@ function requireFakeTimersSrc () {
|
|
|
4212
4917
|
return clock.tick(getTimeToNextFrame());
|
|
4213
4918
|
};
|
|
4214
4919
|
|
|
4215
|
-
if (typeof _global.Promise !== "undefined") {
|
|
4216
|
-
clock.runAllAsync = function runAllAsync() {
|
|
4217
|
-
return pauseAutoTickUntilFinished(
|
|
4218
|
-
new _global.Promise(function (resolve, reject) {
|
|
4219
|
-
let i = 0;
|
|
4220
|
-
/**
|
|
4221
|
-
*
|
|
4222
|
-
*/
|
|
4223
|
-
function doRun() {
|
|
4224
|
-
originalSetTimeout(function () {
|
|
4225
|
-
try {
|
|
4226
|
-
runJobs(clock);
|
|
4227
|
-
|
|
4228
|
-
let numTimers;
|
|
4229
|
-
if (i < clock.loopLimit) {
|
|
4230
|
-
if (!clock.timers) {
|
|
4231
|
-
resetIsNearInfiniteLimit();
|
|
4232
|
-
resolve(clock.now);
|
|
4233
|
-
return;
|
|
4234
|
-
}
|
|
4235
|
-
|
|
4236
|
-
numTimers = Object.keys(
|
|
4237
|
-
clock.timers,
|
|
4238
|
-
).length;
|
|
4239
|
-
if (numTimers === 0) {
|
|
4240
|
-
resetIsNearInfiniteLimit();
|
|
4241
|
-
resolve(clock.now);
|
|
4242
|
-
return;
|
|
4243
|
-
}
|
|
4244
|
-
|
|
4245
|
-
clock.next();
|
|
4246
|
-
|
|
4247
|
-
i++;
|
|
4248
|
-
|
|
4249
|
-
doRun();
|
|
4250
|
-
checkIsNearInfiniteLimit(clock, i);
|
|
4251
|
-
return;
|
|
4252
|
-
}
|
|
4253
|
-
|
|
4254
|
-
const excessJob = firstTimer(clock);
|
|
4255
|
-
reject(
|
|
4256
|
-
getInfiniteLoopError(clock, excessJob),
|
|
4257
|
-
);
|
|
4258
|
-
} catch (e) {
|
|
4259
|
-
reject(e);
|
|
4260
|
-
}
|
|
4261
|
-
});
|
|
4262
|
-
}
|
|
4263
|
-
doRun();
|
|
4264
|
-
}),
|
|
4265
|
-
);
|
|
4266
|
-
};
|
|
4267
|
-
}
|
|
4268
|
-
|
|
4269
4920
|
clock.runToLast = function runToLast() {
|
|
4270
4921
|
const timer = lastTimer(clock);
|
|
4271
4922
|
if (!timer) {
|
|
@@ -4277,32 +4928,110 @@ function requireFakeTimersSrc () {
|
|
|
4277
4928
|
};
|
|
4278
4929
|
|
|
4279
4930
|
if (typeof _global.Promise !== "undefined") {
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
}
|
|
4931
|
+
/**
|
|
4932
|
+
* @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
|
|
4933
|
+
* @returns {Promise}
|
|
4934
|
+
*/
|
|
4935
|
+
clock.tickAsync = function tickAsync(tickValue) {
|
|
4936
|
+
return runAsyncWithNativeTimeout(function (resolve, reject) {
|
|
4937
|
+
doTick(tickValue, true, resolve, reject);
|
|
4938
|
+
});
|
|
4939
|
+
};
|
|
4290
4940
|
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4941
|
+
clock.nextAsync = function nextAsync() {
|
|
4942
|
+
return runAsyncWithNativeTimeout(function (resolve, reject) {
|
|
4943
|
+
const timer = firstTimer(clock);
|
|
4944
|
+
if (!timer) {
|
|
4945
|
+
resolve(clock.now);
|
|
4946
|
+
return;
|
|
4947
|
+
}
|
|
4948
|
+
|
|
4949
|
+
let err;
|
|
4950
|
+
clock.duringTick = true;
|
|
4951
|
+
clock.now = timer.callAt;
|
|
4952
|
+
try {
|
|
4953
|
+
callTimer(clock, timer);
|
|
4954
|
+
} catch (e) {
|
|
4955
|
+
err = e;
|
|
4956
|
+
}
|
|
4957
|
+
clock.duringTick = false;
|
|
4958
|
+
|
|
4959
|
+
originalSetTimeout(function () {
|
|
4960
|
+
if (err) {
|
|
4961
|
+
reject(err);
|
|
4962
|
+
} else {
|
|
4963
|
+
resolve(clock.now);
|
|
4964
|
+
}
|
|
4965
|
+
});
|
|
4966
|
+
});
|
|
4967
|
+
};
|
|
4968
|
+
|
|
4969
|
+
clock.runAllAsync = function runAllAsync() {
|
|
4970
|
+
let i = 0;
|
|
4971
|
+
/**
|
|
4972
|
+
* @param {(value: unknown) => void} resolve promise resolve function
|
|
4973
|
+
* @param {(reason?: unknown) => void} reject promise reject function
|
|
4974
|
+
*/
|
|
4975
|
+
function doRun(resolve, reject) {
|
|
4976
|
+
try {
|
|
4977
|
+
runJobs(clock);
|
|
4978
|
+
|
|
4979
|
+
let numTimers;
|
|
4980
|
+
if (i < clock.loopLimit) {
|
|
4981
|
+
if (!clock.timerHeap) {
|
|
4982
|
+
resetIsNearInfiniteLimit(clock);
|
|
4983
|
+
resolve(clock.now);
|
|
4984
|
+
return;
|
|
4296
4985
|
}
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4986
|
+
|
|
4987
|
+
numTimers = clock.timerHeap.timers.length;
|
|
4988
|
+
if (numTimers === 0) {
|
|
4989
|
+
resetIsNearInfiniteLimit(clock);
|
|
4990
|
+
resolve(clock.now);
|
|
4991
|
+
return;
|
|
4992
|
+
}
|
|
4993
|
+
|
|
4994
|
+
checkIsNearInfiniteLimit(clock, i);
|
|
4995
|
+
clock.next();
|
|
4996
|
+
|
|
4997
|
+
i++;
|
|
4998
|
+
|
|
4999
|
+
originalSetTimeout(function () {
|
|
5000
|
+
doRun(resolve, reject);
|
|
5001
|
+
});
|
|
5002
|
+
return;
|
|
5003
|
+
}
|
|
5004
|
+
|
|
5005
|
+
const excessJob = firstTimer(clock);
|
|
5006
|
+
reject(getInfiniteLoopError(clock, excessJob));
|
|
5007
|
+
} catch (e) {
|
|
5008
|
+
reject(e);
|
|
5009
|
+
}
|
|
5010
|
+
}
|
|
5011
|
+
|
|
5012
|
+
return runAsyncWithNativeTimeout(function (resolve, reject) {
|
|
5013
|
+
doRun(resolve, reject);
|
|
5014
|
+
});
|
|
5015
|
+
};
|
|
5016
|
+
|
|
5017
|
+
clock.runToLastAsync = function runToLastAsync() {
|
|
5018
|
+
return runAsyncWithNativeTimeout(function (resolve) {
|
|
5019
|
+
const timer = lastTimer(clock);
|
|
5020
|
+
if (!timer) {
|
|
5021
|
+
runJobs(clock);
|
|
5022
|
+
resolve(clock.now);
|
|
5023
|
+
return;
|
|
5024
|
+
}
|
|
5025
|
+
|
|
5026
|
+
resolve(clock.tickAsync(timer.callAt - clock.now));
|
|
5027
|
+
});
|
|
4300
5028
|
};
|
|
4301
5029
|
}
|
|
4302
5030
|
|
|
4303
5031
|
clock.reset = function reset() {
|
|
4304
5032
|
nanos = 0;
|
|
4305
|
-
clock.timers =
|
|
5033
|
+
clock.timers = new Map();
|
|
5034
|
+
clock.timerHeap = new TimerHeap();
|
|
4306
5035
|
clock.jobs = [];
|
|
4307
5036
|
clock.now = start;
|
|
4308
5037
|
};
|
|
@@ -4311,7 +5040,6 @@ function requireFakeTimersSrc () {
|
|
|
4311
5040
|
// determine time difference
|
|
4312
5041
|
const newNow = getEpoch(systemTime);
|
|
4313
5042
|
const difference = newNow - clock.now;
|
|
4314
|
-
let id, timer;
|
|
4315
5043
|
|
|
4316
5044
|
adjustedSystemTime[0] = adjustedSystemTime[0] + difference;
|
|
4317
5045
|
adjustedSystemTime[1] = adjustedSystemTime[1] + nanos;
|
|
@@ -4320,18 +5048,15 @@ function requireFakeTimersSrc () {
|
|
|
4320
5048
|
nanos = 0;
|
|
4321
5049
|
|
|
4322
5050
|
// update timers and intervals to keep them stable
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
timer.callAt += difference;
|
|
4328
|
-
}
|
|
4329
|
-
}
|
|
5051
|
+
forEachActiveTimer(clock, (timer) => {
|
|
5052
|
+
timer.createdAt += difference;
|
|
5053
|
+
timer.callAt += difference;
|
|
5054
|
+
});
|
|
4330
5055
|
};
|
|
4331
5056
|
|
|
4332
5057
|
/**
|
|
4333
5058
|
* @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
|
|
4334
|
-
* @returns {number}
|
|
5059
|
+
* @returns {number} the new `now` value
|
|
4335
5060
|
*/
|
|
4336
5061
|
clock.jump = function jump(tickValue) {
|
|
4337
5062
|
const msFloat =
|
|
@@ -4340,12 +5065,17 @@ function requireFakeTimersSrc () {
|
|
|
4340
5065
|
: parseTime(tickValue);
|
|
4341
5066
|
const ms = Math.floor(msFloat);
|
|
4342
5067
|
|
|
4343
|
-
|
|
5068
|
+
forEachActiveTimer(clock, (timer) => {
|
|
4344
5069
|
if (clock.now + ms > timer.callAt) {
|
|
4345
5070
|
timer.callAt = clock.now + ms;
|
|
4346
5071
|
}
|
|
4347
|
-
}
|
|
5072
|
+
});
|
|
5073
|
+
|
|
5074
|
+
// Rebuild heap as order might have changed
|
|
5075
|
+
rebuildTimerHeap(clock);
|
|
5076
|
+
|
|
4348
5077
|
clock.tick(ms);
|
|
5078
|
+
return clock.now;
|
|
4349
5079
|
};
|
|
4350
5080
|
|
|
4351
5081
|
if (isPresent.performance) {
|
|
@@ -4360,6 +5090,11 @@ function requireFakeTimersSrc () {
|
|
|
4360
5090
|
return clock;
|
|
4361
5091
|
}
|
|
4362
5092
|
|
|
5093
|
+
/**
|
|
5094
|
+
* Starts the interval used to advance the clock automatically.
|
|
5095
|
+
* @param {Clock} clock
|
|
5096
|
+
* @param {number} delta
|
|
5097
|
+
*/
|
|
4363
5098
|
function createIntervalTick(clock, delta) {
|
|
4364
5099
|
const intervalTick = doIntervalTick.bind(null, clock, delta);
|
|
4365
5100
|
const intervalId = originalSetInterval(intervalTick, delta);
|
|
@@ -4401,6 +5136,21 @@ function requireFakeTimersSrc () {
|
|
|
4401
5136
|
config.shouldClearNativeTimers =
|
|
4402
5137
|
config.shouldClearNativeTimers || false;
|
|
4403
5138
|
|
|
5139
|
+
const hasToFake = Object.prototype.hasOwnProperty.call(
|
|
5140
|
+
config,
|
|
5141
|
+
"toFake",
|
|
5142
|
+
);
|
|
5143
|
+
const hasToNotFake = Object.prototype.hasOwnProperty.call(
|
|
5144
|
+
config,
|
|
5145
|
+
"toNotFake",
|
|
5146
|
+
);
|
|
5147
|
+
|
|
5148
|
+
if (hasToFake && hasToNotFake) {
|
|
5149
|
+
throw new TypeError(
|
|
5150
|
+
"config.toFake and config.toNotFake cannot be used together",
|
|
5151
|
+
);
|
|
5152
|
+
}
|
|
5153
|
+
|
|
4404
5154
|
if (config.target) {
|
|
4405
5155
|
throw new TypeError(
|
|
4406
5156
|
"config.target is no longer supported. Use `withGlobal(target)` instead.",
|
|
@@ -4408,8 +5158,8 @@ function requireFakeTimersSrc () {
|
|
|
4408
5158
|
}
|
|
4409
5159
|
|
|
4410
5160
|
/**
|
|
4411
|
-
*
|
|
4412
|
-
* @param timer
|
|
5161
|
+
* Handles a missing timer or API name during installation.
|
|
5162
|
+
* @param {string} timer - the name of the missing timer or object
|
|
4413
5163
|
*/
|
|
4414
5164
|
function handleMissingTimer(timer) {
|
|
4415
5165
|
if (config.ignoreMissingTimers) {
|
|
@@ -4431,10 +5181,24 @@ function requireFakeTimersSrc () {
|
|
|
4431
5181
|
|
|
4432
5182
|
clock.abortListenerMap = new Map();
|
|
4433
5183
|
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
5184
|
+
if (hasToFake) {
|
|
5185
|
+
clock.methods = /** @type {FakeMethod[]} */ (config.toFake || []);
|
|
5186
|
+
if (clock.methods.length === 0) {
|
|
5187
|
+
clock.methods = /** @type {FakeMethod[]} */ (
|
|
5188
|
+
Object.keys(timers)
|
|
5189
|
+
);
|
|
5190
|
+
}
|
|
5191
|
+
} else if (hasToNotFake) {
|
|
5192
|
+
const methodsToNotFake = /** @type {string[]} */ (
|
|
5193
|
+
config.toNotFake || []
|
|
5194
|
+
);
|
|
5195
|
+
clock.methods = /** @type {FakeMethod[]} */ (
|
|
5196
|
+
Object.keys(timers).filter(
|
|
5197
|
+
(method) => !methodsToNotFake.includes(method),
|
|
5198
|
+
)
|
|
5199
|
+
);
|
|
5200
|
+
} else {
|
|
5201
|
+
clock.methods = /** @type {FakeMethod[]} */ (Object.keys(timers));
|
|
4438
5202
|
}
|
|
4439
5203
|
|
|
4440
5204
|
if (config.shouldAdvanceTime === true) {
|
|
@@ -4471,7 +5235,7 @@ function requireFakeTimersSrc () {
|
|
|
4471
5235
|
// (or the Worker was installed)
|
|
4472
5236
|
clock.performance.timeOrigin = getEpoch(config.now);
|
|
4473
5237
|
} else if ((config.toFake || []).includes("performance")) {
|
|
4474
|
-
|
|
5238
|
+
handleMissingTimer("performance");
|
|
4475
5239
|
}
|
|
4476
5240
|
}
|
|
4477
5241
|
if (_global === globalObject && timersModule) {
|
|
@@ -4635,10 +5399,13 @@ function requireFakeTimersSrc () {
|
|
|
4635
5399
|
[Symbol.asyncIterator]: () => {
|
|
4636
5400
|
const createResolvable = () => {
|
|
4637
5401
|
let resolve, reject;
|
|
4638
|
-
const promise =
|
|
4639
|
-
resolve
|
|
4640
|
-
|
|
4641
|
-
|
|
5402
|
+
const promise =
|
|
5403
|
+
/** @type {Promise<unknown> & { resolve: (value: unknown) => void; reject: (reason: unknown) => void }} */ (
|
|
5404
|
+
new Promise((res, rej) => {
|
|
5405
|
+
resolve = res;
|
|
5406
|
+
reject = rej;
|
|
5407
|
+
})
|
|
5408
|
+
);
|
|
4642
5409
|
promise.resolve = resolve;
|
|
4643
5410
|
promise.reject = reject;
|
|
4644
5411
|
return promise;
|
|
@@ -4766,22 +5533,13 @@ function requireFakeTimersSrc () {
|
|
|
4766
5533
|
};
|
|
4767
5534
|
}
|
|
4768
5535
|
|
|
4769
|
-
/**
|
|
4770
|
-
* @typedef {object} FakeTimers
|
|
4771
|
-
* @property {Timers} timers
|
|
4772
|
-
* @property {createClock} createClock
|
|
4773
|
-
* @property {Function} install
|
|
4774
|
-
* @property {withGlobal} withGlobal
|
|
4775
|
-
*/
|
|
4776
|
-
|
|
4777
|
-
/* eslint-enable complexity */
|
|
4778
|
-
|
|
4779
5536
|
/** @type {FakeTimers} */
|
|
4780
5537
|
const defaultImplementation = withGlobal(globalObject);
|
|
4781
5538
|
|
|
4782
5539
|
fakeTimersSrc.timers = defaultImplementation.timers;
|
|
4783
5540
|
fakeTimersSrc.createClock = defaultImplementation.createClock;
|
|
4784
5541
|
fakeTimersSrc.install = defaultImplementation.install;
|
|
5542
|
+
/** @type {WithGlobal} */
|
|
4785
5543
|
fakeTimersSrc.withGlobal = withGlobal;
|
|
4786
5544
|
return fakeTimersSrc;
|
|
4787
5545
|
}
|
|
@@ -4872,12 +5630,18 @@ class FakeTimers {
|
|
|
4872
5630
|
this._fakingDate = null;
|
|
4873
5631
|
}
|
|
4874
5632
|
if (this._fakingTime) this._clock.uninstall();
|
|
4875
|
-
|
|
4876
|
-
if (
|
|
5633
|
+
let toFake = this._userConfig?.toFake;
|
|
5634
|
+
if (isChildProcess() && toFake?.includes("nextTick")) throw new Error("process.nextTick cannot be mocked inside child_process");
|
|
5635
|
+
let toNotFake = this._userConfig?.toNotFake;
|
|
5636
|
+
if (toFake === void 0 && toNotFake === void 0)
|
|
5637
|
+
// Do not mock timers internally used by node by default. It can still be mocked through userConfig.
|
|
5638
|
+
toFake = Object.keys(this._fakeTimers.timers).filter((timer) => timer !== "nextTick" && timer !== "queueMicrotask");
|
|
5639
|
+
if (isChildProcess() && toNotFake && !toNotFake.includes("nextTick")) toNotFake = [...toNotFake, "nextTick"];
|
|
4877
5640
|
this._clock = this._fakeTimers.install({
|
|
4878
5641
|
now: fakeDate,
|
|
4879
5642
|
...this._userConfig,
|
|
4880
|
-
toFake
|
|
5643
|
+
...toFake && { toFake },
|
|
5644
|
+
...toNotFake && { toNotFake },
|
|
4881
5645
|
ignoreMissingTimers: true
|
|
4882
5646
|
});
|
|
4883
5647
|
this._fakingTime = true;
|
|
@@ -4928,7 +5692,7 @@ class FakeTimers {
|
|
|
4928
5692
|
}
|
|
4929
5693
|
}
|
|
4930
5694
|
|
|
4931
|
-
function copyStackTrace$
|
|
5695
|
+
function copyStackTrace$2(target, source) {
|
|
4932
5696
|
if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
|
|
4933
5697
|
return target;
|
|
4934
5698
|
}
|
|
@@ -4949,7 +5713,7 @@ function waitFor(callback, options = {}) {
|
|
|
4949
5713
|
const handleTimeout = () => {
|
|
4950
5714
|
if (intervalId) clearInterval(intervalId);
|
|
4951
5715
|
let error = lastError;
|
|
4952
|
-
if (!error) error = copyStackTrace$
|
|
5716
|
+
if (!error) error = copyStackTrace$2(/* @__PURE__ */ new Error("Timed out in waitFor!"), STACK_TRACE_ERROR);
|
|
4953
5717
|
reject(error);
|
|
4954
5718
|
};
|
|
4955
5719
|
const checkCallback = () => {
|
|
@@ -4990,7 +5754,7 @@ function waitUntil(callback, options = {}) {
|
|
|
4990
5754
|
let intervalId;
|
|
4991
5755
|
const onReject = (error) => {
|
|
4992
5756
|
if (intervalId) clearInterval(intervalId);
|
|
4993
|
-
if (!error) error = copyStackTrace$
|
|
5757
|
+
if (!error) error = copyStackTrace$2(/* @__PURE__ */ new Error("Timed out in waitUntil!"), STACK_TRACE_ERROR);
|
|
4994
5758
|
reject(error);
|
|
4995
5759
|
};
|
|
4996
5760
|
const onResolve = (result) => {
|
|
@@ -5129,9 +5893,17 @@ function createVitest() {
|
|
|
5129
5893
|
defineHelper: (fn) => {
|
|
5130
5894
|
return function __VITEST_HELPER__(...args) {
|
|
5131
5895
|
const result = fn.apply(this, args);
|
|
5132
|
-
if (result && typeof result === "object" && typeof result.then === "function")
|
|
5133
|
-
|
|
5134
|
-
|
|
5896
|
+
if (result && typeof result === "object" && typeof result.then === "function") {
|
|
5897
|
+
const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
|
|
5898
|
+
return (async function __VITEST_HELPER__() {
|
|
5899
|
+
try {
|
|
5900
|
+
return await result;
|
|
5901
|
+
} catch (error) {
|
|
5902
|
+
if (error instanceof Error && !error.stack?.includes("__VITEST_HELPER__")) copyStackTrace$1(error, stackTraceError);
|
|
5903
|
+
throw error;
|
|
5904
|
+
}
|
|
5905
|
+
})();
|
|
5906
|
+
}
|
|
5135
5907
|
return result;
|
|
5136
5908
|
};
|
|
5137
5909
|
},
|
|
@@ -5258,6 +6030,10 @@ function getImporter(name) {
|
|
|
5258
6030
|
return stack.includes(` at Object.${name}`) || stack.includes(`${name}@`) || stack.includes(` at ${name} (`);
|
|
5259
6031
|
}) + 1])?.file || "";
|
|
5260
6032
|
}
|
|
6033
|
+
function copyStackTrace$1(target, source) {
|
|
6034
|
+
if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
|
|
6035
|
+
return target;
|
|
6036
|
+
}
|
|
5261
6037
|
|
|
5262
6038
|
// these matchers are not supported because they don't make sense with poll
|
|
5263
6039
|
const unsupported = [
|
|
@@ -5325,7 +6101,9 @@ function createExpectPoll(expect) {
|
|
|
5325
6101
|
const promise = async () => {
|
|
5326
6102
|
chai.util.flag(assertion, "_name", key);
|
|
5327
6103
|
chai.util.flag(assertion, "error", STACK_TRACE_ERROR);
|
|
6104
|
+
const onStart = chai.util.flag(assertion, "_poll.onStart");
|
|
5328
6105
|
const onSettled = chai.util.flag(assertion, "_poll.onSettled");
|
|
6106
|
+
await onStart?.({ assertion });
|
|
5329
6107
|
if (Object.getOwnPropertyDescriptor(assertionFunction, "__vitest_poll_takeover__")?.value) try {
|
|
5330
6108
|
const output = await assertionFunction.call(assertion, ...args);
|
|
5331
6109
|
await onSettled?.({
|
|
@@ -5341,41 +6119,53 @@ function createExpectPoll(expect) {
|
|
|
5341
6119
|
throwWithCause(err, STACK_TRACE_ERROR);
|
|
5342
6120
|
}
|
|
5343
6121
|
const { setTimeout, clearTimeout } = getSafeTimers();
|
|
5344
|
-
let
|
|
5345
|
-
|
|
5346
|
-
const
|
|
5347
|
-
|
|
5348
|
-
|
|
6122
|
+
let timerId;
|
|
6123
|
+
const timeoutController = new AbortController();
|
|
6124
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
6125
|
+
timerId = setTimeout(() => {
|
|
6126
|
+
timeoutController.abort();
|
|
6127
|
+
resolve();
|
|
6128
|
+
}, timeout);
|
|
6129
|
+
});
|
|
6130
|
+
let lastError;
|
|
5349
6131
|
try {
|
|
5350
|
-
while (true) {
|
|
5351
|
-
const
|
|
5352
|
-
if (
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
const obj = await fn();
|
|
5356
|
-
chai.util.flag(assertion, "object", obj);
|
|
5357
|
-
executionPhase = "assertion";
|
|
5358
|
-
const output = await assertionFunction.call(assertion, ...args);
|
|
5359
|
-
await onSettled?.({
|
|
5360
|
-
assertion,
|
|
5361
|
-
status: "pass"
|
|
5362
|
-
});
|
|
5363
|
-
return output;
|
|
5364
|
-
} catch (err) {
|
|
5365
|
-
if (isLastAttempt || executionPhase === "assertion" && chai.util.flag(assertion, "_poll.assert_once")) {
|
|
5366
|
-
await onSettled?.({
|
|
5367
|
-
assertion,
|
|
5368
|
-
status: "fail"
|
|
5369
|
-
});
|
|
5370
|
-
throwWithCause(err, STACK_TRACE_ERROR);
|
|
5371
|
-
}
|
|
5372
|
-
await delay(interval, setTimeout);
|
|
5373
|
-
if (vi.isFakeTimers()) vi.advanceTimersByTime(interval);
|
|
6132
|
+
while (true) try {
|
|
6133
|
+
const fnResult = await raceWith$1(Promise.resolve().then(() => fn({ signal: timeoutController.signal })), timeoutPromise);
|
|
6134
|
+
if (!fnResult.ok) {
|
|
6135
|
+
lastError ??= /* @__PURE__ */ new Error(`expect.poll() function didn't resolve in time.`);
|
|
6136
|
+
break;
|
|
5374
6137
|
}
|
|
6138
|
+
const obj = fnResult.value;
|
|
6139
|
+
chai.util.flag(assertion, "object", obj);
|
|
6140
|
+
const assertionResult = await raceWith$1(Promise.resolve().then(() => assertionFunction.apply(assertion, args)), timeoutPromise);
|
|
6141
|
+
if (!assertionResult.ok) {
|
|
6142
|
+
lastError ??= /* @__PURE__ */ new Error(`expect.poll() assertion didn't resolve in time.`);
|
|
6143
|
+
break;
|
|
6144
|
+
}
|
|
6145
|
+
const output = assertionResult.value;
|
|
6146
|
+
await onSettled?.({
|
|
6147
|
+
assertion,
|
|
6148
|
+
status: "pass"
|
|
6149
|
+
});
|
|
6150
|
+
return output;
|
|
6151
|
+
} catch (err) {
|
|
6152
|
+
lastError = err;
|
|
6153
|
+
// no retry for toMatchScreenshot since
|
|
6154
|
+
// it owns retry/stability after the first element resolution
|
|
6155
|
+
if (key === "toMatchScreenshot") break;
|
|
6156
|
+
if (!(await raceWith$1(delay(interval, setTimeout), timeoutPromise)).ok) break;
|
|
6157
|
+
if (vi.isFakeTimers()) vi.advanceTimersByTime(interval);
|
|
5375
6158
|
}
|
|
5376
6159
|
} finally {
|
|
5377
6160
|
clearTimeout(timerId);
|
|
5378
6161
|
}
|
|
6162
|
+
if (lastError) {
|
|
6163
|
+
await onSettled?.({
|
|
6164
|
+
assertion,
|
|
6165
|
+
status: "fail"
|
|
6166
|
+
});
|
|
6167
|
+
throwWithCause(lastError, STACK_TRACE_ERROR);
|
|
6168
|
+
}
|
|
5379
6169
|
};
|
|
5380
6170
|
let awaited = false;
|
|
5381
6171
|
test.onFinished ??= [];
|
|
@@ -5413,6 +6203,17 @@ function copyStackTrace(target, source) {
|
|
|
5413
6203
|
if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
|
|
5414
6204
|
return target;
|
|
5415
6205
|
}
|
|
6206
|
+
function raceWith$1(promise, other) {
|
|
6207
|
+
const left = promise.then((value) => ({
|
|
6208
|
+
ok: true,
|
|
6209
|
+
value
|
|
6210
|
+
}));
|
|
6211
|
+
if (!other) return left;
|
|
6212
|
+
return Promise.race([left, other.then((value) => ({
|
|
6213
|
+
ok: false,
|
|
6214
|
+
value
|
|
6215
|
+
}))]);
|
|
6216
|
+
}
|
|
5416
6217
|
|
|
5417
6218
|
var naturalCompare$1 = {exports: {}};
|
|
5418
6219
|
|
|
@@ -6303,11 +7104,15 @@ class SnapshotClient {
|
|
|
6303
7104
|
inlineSnapshot
|
|
6304
7105
|
});
|
|
6305
7106
|
const reference = expectedSnapshot.data !== void 0 && snapshotState.snapshotUpdateState !== "all" ? adapter.parseExpected(expectedSnapshot.data) : void 0;
|
|
7107
|
+
const timeoutController = new AbortController();
|
|
6306
7108
|
const stableResult = await getStableSnapshot({
|
|
6307
7109
|
adapter,
|
|
6308
|
-
poll,
|
|
7110
|
+
poll: () => poll({ signal: timeoutController.signal }),
|
|
6309
7111
|
interval,
|
|
6310
|
-
timedOut: timeout > 0 ? new Promise((r) => setTimeout(
|
|
7112
|
+
timedOut: timeout > 0 ? new Promise((r) => setTimeout(() => {
|
|
7113
|
+
timeoutController.abort();
|
|
7114
|
+
r();
|
|
7115
|
+
}, timeout)) : void 0,
|
|
6311
7116
|
match: reference ? (captured) => adapter.match(captured, reference).pass : void 0
|
|
6312
7117
|
});
|
|
6313
7118
|
expectedSnapshot.markAsChecked();
|
|
@@ -6723,6 +7528,7 @@ function createExpect(test) {
|
|
|
6723
7528
|
chai.util.addMethod(expect, "assertions", assertions);
|
|
6724
7529
|
chai.util.addMethod(expect, "hasAssertions", hasAssertions);
|
|
6725
7530
|
expect.extend(customMatchers);
|
|
7531
|
+
expect.extend(benchMatchers);
|
|
6726
7532
|
return expect;
|
|
6727
7533
|
}
|
|
6728
7534
|
const globalExpect = createExpect();
|
|
@@ -6742,140 +7548,280 @@ function inject(key) {
|
|
|
6742
7548
|
return getWorkerState().providedContext[key];
|
|
6743
7549
|
}
|
|
6744
7550
|
|
|
6745
|
-
const
|
|
6746
|
-
const
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
}
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
}
|
|
6778
|
-
|
|
6779
|
-
function createBenchmarkResult(name) {
|
|
6780
|
-
return {
|
|
7551
|
+
const now = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
|
|
7552
|
+
const kRegistration = Symbol("registration");
|
|
7553
|
+
const kFromSource = Symbol("fromSource");
|
|
7554
|
+
const kPerProject = Symbol("perProject");
|
|
7555
|
+
const kWriteResult = Symbol("writeResult");
|
|
7556
|
+
const kFinalize = Symbol("finalize");
|
|
7557
|
+
function isFromRegistration(reg) {
|
|
7558
|
+
return kFromSource in reg;
|
|
7559
|
+
}
|
|
7560
|
+
function substitutePath(template, projectName) {
|
|
7561
|
+
return template.replace(/\$\{projectName\}/g, projectName ?? "");
|
|
7562
|
+
}
|
|
7563
|
+
function createBench(test, config) {
|
|
7564
|
+
let benchIdx = 0;
|
|
7565
|
+
const pending = /* @__PURE__ */ new Set();
|
|
7566
|
+
const createTinybench = (options) => {
|
|
7567
|
+
const currentIndex = ++benchIdx;
|
|
7568
|
+
return new Bench({
|
|
7569
|
+
signal: test.context.signal,
|
|
7570
|
+
name: `${test.fullTestName} ${currentIndex}`,
|
|
7571
|
+
retainSamples: config.benchmark.retainSamples,
|
|
7572
|
+
...options,
|
|
7573
|
+
now
|
|
7574
|
+
});
|
|
7575
|
+
};
|
|
7576
|
+
const resolveTemplate = (template) => substitutePath(template, config.benchmark.projectName);
|
|
7577
|
+
const resolveFromSource = async (source) => {
|
|
7578
|
+
if (typeof source === "function") return source();
|
|
7579
|
+
const resolved = resolveTemplate(source);
|
|
7580
|
+
const data = await rpc().readBenchmarkResult(resolved);
|
|
7581
|
+
if (data == null) throw new Error(`\`bench.from()\` could not find a result file at "${resolved}". Run the source benchmark first to create it.`);
|
|
7582
|
+
return data;
|
|
7583
|
+
};
|
|
7584
|
+
const taskFromBaseline = (name, data) => ({
|
|
6781
7585
|
name,
|
|
7586
|
+
latency: data.latency,
|
|
7587
|
+
throughput: data.throughput,
|
|
7588
|
+
period: data.period,
|
|
7589
|
+
totalTime: data.totalTime,
|
|
6782
7590
|
rank: 0,
|
|
6783
|
-
|
|
6784
|
-
|
|
7591
|
+
fromStore: true
|
|
7592
|
+
});
|
|
7593
|
+
const createCompareStorage = (bench, fromResults) => {
|
|
7594
|
+
return { get(name) {
|
|
7595
|
+
const stored = fromResults?.get(name);
|
|
7596
|
+
if (stored) return stored;
|
|
7597
|
+
const task = bench.getTask(name);
|
|
7598
|
+
if (!task) throw new Error(`task "${name}" was not defined`);
|
|
7599
|
+
return task.result;
|
|
7600
|
+
} };
|
|
6785
7601
|
};
|
|
6786
|
-
|
|
6787
|
-
const
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
7602
|
+
const serializeBenchmark = (tinybenchTasks, name, taskMeta, fromTasks) => {
|
|
7603
|
+
const tasks = tinybenchTasks.map((t) => {
|
|
7604
|
+
const result = t.result;
|
|
7605
|
+
if (result.state === "errored") throw result.error;
|
|
7606
|
+
if (result.state !== "completed") throw new Error(`task "${t.name}" did not complete: received "${result.state}"`);
|
|
7607
|
+
return {
|
|
7608
|
+
name: t.name,
|
|
7609
|
+
latency: result.latency,
|
|
7610
|
+
throughput: result.throughput,
|
|
7611
|
+
period: result.period,
|
|
7612
|
+
totalTime: result.totalTime,
|
|
7613
|
+
rank: 0,
|
|
7614
|
+
...taskMeta?.get(t.name)
|
|
7615
|
+
};
|
|
7616
|
+
});
|
|
7617
|
+
if (fromTasks) tasks.push(...fromTasks);
|
|
7618
|
+
tasks.sort((a, b) => a.latency.mean - b.latency.mean);
|
|
7619
|
+
tasks.forEach((task, idx) => {
|
|
7620
|
+
task.rank = idx + 1;
|
|
7621
|
+
});
|
|
7622
|
+
return {
|
|
7623
|
+
name: name || test.fullTestName,
|
|
7624
|
+
tasks
|
|
7625
|
+
};
|
|
7626
|
+
};
|
|
7627
|
+
const recordBenchmark = async (tinybenchTasks, name, taskMeta, fromTasks) => {
|
|
7628
|
+
const serializedBenchmark = serializeBenchmark(tinybenchTasks, name, taskMeta, fromTasks);
|
|
7629
|
+
test.benchmarks.push(serializedBenchmark);
|
|
7630
|
+
await rpc().onTestBenchmark(test.id, serializedBenchmark);
|
|
7631
|
+
};
|
|
7632
|
+
const writeResultArtifact = async (template, result) => {
|
|
7633
|
+
const resolved = resolveTemplate(template);
|
|
7634
|
+
const data = {
|
|
7635
|
+
latency: result.latency,
|
|
7636
|
+
throughput: result.throughput,
|
|
7637
|
+
period: result.period,
|
|
7638
|
+
totalTime: result.totalTime
|
|
7639
|
+
};
|
|
7640
|
+
await rpc().writeBenchmarkResult(resolved, data);
|
|
7641
|
+
};
|
|
7642
|
+
const runBenchmarks = async (tinybench) => {
|
|
7643
|
+
const workerState = getWorkerState();
|
|
7644
|
+
const getterTracker = workerState.getterTracker;
|
|
7645
|
+
getterTracker?.resetInvocations();
|
|
7646
|
+
try {
|
|
7647
|
+
return await TestRunner.runBenchmarks(tinybench);
|
|
7648
|
+
} finally {
|
|
7649
|
+
const excessiveInvocations = config.benchmark.suppressExportGetterWarnings ? void 0 : getterTracker?.getExcessiveInvocations();
|
|
7650
|
+
if (excessiveInvocations?.length) {
|
|
7651
|
+
const entries = excessiveInvocations.map(({ moduleId, exportName }) => ` - ${formatModuleId(moduleId, workerState.config.root)} > ${exportName}`).join("\n");
|
|
7652
|
+
console.warn([
|
|
7653
|
+
c.yellow(c.bold("Benchmark Warning")),
|
|
7654
|
+
`Benchmark ${c.bold(`"${tinybench.name}"`)} accessed module export getters too many times.`,
|
|
7655
|
+
"",
|
|
7656
|
+
"This can make results unreliable because export getters add overhead.",
|
|
7657
|
+
"See https://vitest.dev/guide/benchmarking#module-runner-overhead",
|
|
7658
|
+
"",
|
|
7659
|
+
"Tracked exports:",
|
|
7660
|
+
entries
|
|
7661
|
+
].join("\n"));
|
|
7662
|
+
}
|
|
7663
|
+
}
|
|
7664
|
+
};
|
|
7665
|
+
const runSingle = async (name, fn, fnOpts, options, meta, writeResult) => {
|
|
7666
|
+
const tinybench = createTinybench(options).add(name, fn, fnOpts);
|
|
7667
|
+
const tasks = await runBenchmarks(tinybench);
|
|
7668
|
+
const task = tinybench.getTask(name);
|
|
7669
|
+
if (task.result.state === "errored") throw task.result.error;
|
|
7670
|
+
await recordBenchmark(tasks, tinybench.name, meta ? new Map([[name, meta]]) : void 0);
|
|
7671
|
+
if (writeResult) await writeResultArtifact(writeResult, task.result);
|
|
7672
|
+
return task.result;
|
|
7673
|
+
};
|
|
7674
|
+
const runFrom = async (name, source) => {
|
|
7675
|
+
const data = await resolveFromSource(source);
|
|
7676
|
+
const benchmark = {
|
|
7677
|
+
name: test.fullTestName,
|
|
7678
|
+
tasks: [{
|
|
7679
|
+
...taskFromBaseline(name, data),
|
|
7680
|
+
rank: 1
|
|
7681
|
+
}]
|
|
6806
7682
|
};
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
}
|
|
7683
|
+
test.benchmarks.push(benchmark);
|
|
7684
|
+
await rpc().onTestBenchmark(test.id, benchmark);
|
|
7685
|
+
return data;
|
|
7686
|
+
};
|
|
7687
|
+
const bench = (nameOrFunction, a, b) => {
|
|
7688
|
+
validateBenchmarkProject(config);
|
|
7689
|
+
const { fn, fnOpts, writeResult, perProject } = normalizeBenchArgs(a, b);
|
|
7690
|
+
const name = typeof nameOrFunction === "function" ? nameOrFunction.name || "<anonymous>" : nameOrFunction;
|
|
7691
|
+
const meta = perProject ? { perProject: true } : void 0;
|
|
7692
|
+
const registration = {
|
|
7693
|
+
[kRegistration]: true,
|
|
7694
|
+
name,
|
|
7695
|
+
fn,
|
|
7696
|
+
fnOpts,
|
|
7697
|
+
run: (options) => {
|
|
7698
|
+
pending.delete(registration);
|
|
7699
|
+
return runSingle(name, fn, fnOpts, options, meta, writeResult);
|
|
7700
|
+
}
|
|
6825
7701
|
};
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
7702
|
+
if (perProject) registration[kPerProject] = true;
|
|
7703
|
+
if (writeResult) registration[kWriteResult] = writeResult;
|
|
7704
|
+
pending.add(registration);
|
|
7705
|
+
return registration;
|
|
7706
|
+
};
|
|
7707
|
+
bench.from = (nameOrFunction, source) => {
|
|
7708
|
+
validateBenchmarkProject(config);
|
|
7709
|
+
if (typeof nameOrFunction !== "string" && typeof nameOrFunction !== "function") throw new TypeError("`bench.from()` requires a name (string or named function) as its first argument.");
|
|
7710
|
+
if (typeof source !== "string" && typeof source !== "function") throw new TypeError("`bench.from()` expects a string path or a function returning the result data as its second argument.");
|
|
7711
|
+
const name = typeof nameOrFunction === "function" ? nameOrFunction.name || "<anonymous>" : nameOrFunction;
|
|
7712
|
+
const registration = {
|
|
7713
|
+
[kRegistration]: true,
|
|
7714
|
+
[kFromSource]: source,
|
|
7715
|
+
name,
|
|
7716
|
+
run: () => {
|
|
7717
|
+
pending.delete(registration);
|
|
7718
|
+
return runFrom(name, source);
|
|
7719
|
+
}
|
|
7720
|
+
};
|
|
7721
|
+
pending.add(registration);
|
|
7722
|
+
return registration;
|
|
7723
|
+
};
|
|
7724
|
+
bench.compare = async (...args) => {
|
|
7725
|
+
validateBenchmarkProject(config);
|
|
7726
|
+
// extract optional trailing BenchCompareOptions argument
|
|
7727
|
+
const lastArg = args[args.length - 1];
|
|
7728
|
+
const benchOptions = lastArg != null && typeof lastArg === "object" && !(kRegistration in lastArg) ? args.pop() : void 0;
|
|
7729
|
+
const registrations = args;
|
|
7730
|
+
// Mark every passed-in registration as consumed before validation so a
|
|
7731
|
+
// throwing `bench.compare()` (wrong arity, wrong shape) doesn't also
|
|
7732
|
+
// trigger the unrun-bench warning — the user's intent was to consume them.
|
|
7733
|
+
for (const reg of registrations) if (reg != null && typeof reg === "object" && kRegistration in reg) pending.delete(reg);
|
|
7734
|
+
if (registrations.length < 2) throw new SyntaxError(`\`bench.compare()\` requires at least 2 benchmarks, received ${registrations.length} instead. ${registrations.length === 1 ? "Consider calling `bench().run()`. " : "Define benchmarks by calling `bench()`. "}See https://vitest.dev/guide/benchmarking#comparing-benchmarks`);
|
|
7735
|
+
for (const reg of registrations) if (reg == null || typeof reg !== "object" || !(kRegistration in reg)) throw new SyntaxError("`bench.compare()` expects every argument to be the return value of `bench` or `bench.from`.");
|
|
7736
|
+
const runnable = [];
|
|
7737
|
+
const fromEntries = [];
|
|
7738
|
+
for (const reg of registrations) if (isFromRegistration(reg)) fromEntries.push(reg);
|
|
7739
|
+
else runnable.push(reg);
|
|
7740
|
+
const taskMeta = /* @__PURE__ */ new Map();
|
|
7741
|
+
for (const reg of runnable) if (reg[kPerProject]) taskMeta.set(reg.name, { perProject: true });
|
|
7742
|
+
const fromResults = /* @__PURE__ */ new Map();
|
|
7743
|
+
const fromTasks = [];
|
|
7744
|
+
if (fromEntries.length > 0) {
|
|
7745
|
+
const resolved = await Promise.all(fromEntries.map(async (reg) => {
|
|
7746
|
+
return {
|
|
7747
|
+
reg,
|
|
7748
|
+
data: await resolveFromSource(reg[kFromSource])
|
|
7749
|
+
};
|
|
7750
|
+
}));
|
|
7751
|
+
for (const { reg, data } of resolved) {
|
|
7752
|
+
fromResults.set(reg.name, data);
|
|
7753
|
+
fromTasks.push(taskFromBaseline(reg.name, data));
|
|
7754
|
+
}
|
|
7755
|
+
}
|
|
7756
|
+
const tinybench = createTinybench(benchOptions);
|
|
7757
|
+
runnable.forEach((reg) => {
|
|
7758
|
+
tinybench.add(reg.name, reg.fn, reg.fnOpts);
|
|
6837
7759
|
});
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
const
|
|
6842
|
-
|
|
6843
|
-
await task.warmup();
|
|
6844
|
-
tasks.push([await new Promise((resolve) => setTimeout(async () => {
|
|
6845
|
-
resolve(await task.run());
|
|
6846
|
-
})), benchmark]);
|
|
7760
|
+
let tasks = [];
|
|
7761
|
+
if (runnable.length > 0) {
|
|
7762
|
+
tasks = await runBenchmarks(tinybench);
|
|
7763
|
+
const errors = tinybench.tasks.filter((task) => task.result.state === "errored").map((task) => task.result.error);
|
|
7764
|
+
if (errors.length > 0) throw new AggregateError(errors, "Some benchmarks failed");
|
|
6847
7765
|
}
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
await
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
7766
|
+
await recordBenchmark(tasks, tinybench.name, taskMeta, fromTasks);
|
|
7767
|
+
// write artifacts for every runnable registration that requested it. We
|
|
7768
|
+
// do this after recording so a write failure can't be confused with a
|
|
7769
|
+
// benchmark failure in the reporter output.
|
|
7770
|
+
await Promise.all(runnable.filter((reg) => reg[kWriteResult] != null).map((reg) => {
|
|
7771
|
+
const task = tinybench.getTask(reg.name);
|
|
7772
|
+
return writeResultArtifact(reg[kWriteResult], task.result);
|
|
7773
|
+
}));
|
|
7774
|
+
return createCompareStorage(tinybench, fromResults);
|
|
7775
|
+
};
|
|
7776
|
+
bench[kFinalize] = () => {
|
|
7777
|
+
if (pending.size === 0) return;
|
|
7778
|
+
const names = [...pending].map((reg) => `"${reg.name}"`).join(", ");
|
|
7779
|
+
pending.clear();
|
|
7780
|
+
console.warn([
|
|
7781
|
+
c.yellow(c.bold("Benchmark Warning")),
|
|
7782
|
+
`Test ${c.bold(`"${test.fullTestName}"`)} registered benchmarks that never ran: ${names}.`,
|
|
7783
|
+
"",
|
|
7784
|
+
"Call `.run()` on the registration, or pass it to `bench.compare()`.",
|
|
7785
|
+
"See https://vitest.dev/guide/benchmarking#defining-a-benchmark"
|
|
7786
|
+
].join("\n"));
|
|
7787
|
+
};
|
|
7788
|
+
return bench;
|
|
6857
7789
|
}
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
}
|
|
6871
|
-
return this.moduleRunner.import(filepath);
|
|
6872
|
-
}
|
|
6873
|
-
async runSuite(suite) {
|
|
6874
|
-
await runBenchmarkSuite(suite, this);
|
|
6875
|
-
}
|
|
6876
|
-
async runTask() {
|
|
6877
|
-
throw new Error("`test()` and `it()` is only available in test mode.");
|
|
7790
|
+
function formatModuleId(moduleId, root) {
|
|
7791
|
+
if (!root || !isAbsolute(moduleId)) return moduleId;
|
|
7792
|
+
return relative(root, moduleId);
|
|
7793
|
+
}
|
|
7794
|
+
function normalizeBenchArgs(a, b) {
|
|
7795
|
+
if (typeof a === "function") {
|
|
7796
|
+
if (b !== void 0) throw new TypeError("`bench()` does not accept options as the third argument. Pass options as the second argument instead: `bench(name, options, fn)`.");
|
|
7797
|
+
return {
|
|
7798
|
+
fn: a,
|
|
7799
|
+
fnOpts: void 0,
|
|
7800
|
+
writeResult: void 0,
|
|
7801
|
+
perProject: false
|
|
7802
|
+
};
|
|
6878
7803
|
}
|
|
7804
|
+
if (typeof b !== "function") throw new TypeError("`bench()` expects a benchmark function. Call `bench(name, fn)` or `bench(name, options, fn)`.");
|
|
7805
|
+
// Strip vitest-specific fields only when present so we don't allocate a new
|
|
7806
|
+
// object — preserving referential identity matters: users inspect
|
|
7807
|
+
// `registration.fnOpts` and tinybench's `add` sees the same object the
|
|
7808
|
+
// caller passed in.
|
|
7809
|
+
if (a.writeResult === void 0 && a.perProject === void 0) return {
|
|
7810
|
+
fn: b,
|
|
7811
|
+
fnOpts: a,
|
|
7812
|
+
writeResult: void 0,
|
|
7813
|
+
perProject: false
|
|
7814
|
+
};
|
|
7815
|
+
const { writeResult, perProject, ...fnOpts } = a;
|
|
7816
|
+
return {
|
|
7817
|
+
fn: b,
|
|
7818
|
+
fnOpts: Object.keys(fnOpts).length > 0 ? fnOpts : void 0,
|
|
7819
|
+
writeResult,
|
|
7820
|
+
perProject: perProject ?? false
|
|
7821
|
+
};
|
|
7822
|
+
}
|
|
7823
|
+
function validateBenchmarkProject(config) {
|
|
7824
|
+
if (!config.benchmark.enabled) throw new Error("Cannot use the `bench` test-context fixture within a regular test run. Benchmarks are inherently flaky, so Vitest runs them in a dedicated project based on the `benchmark.include` pattern (default `**/*.{bench,benchmark}.?(c|m)[jt]s?(x)`). Move this code to a file matched by `benchmark.include`, and make sure `bench` is destructured from the test context (`test('...', async ({ bench }) => { ... })`) — it is not a top-level export of `vitest`. See https://vitest.dev/guide/benchmarking#stability");
|
|
6879
7825
|
}
|
|
6880
7826
|
|
|
6881
7827
|
class TestRunner {
|
|
@@ -6884,7 +7830,11 @@ class TestRunner {
|
|
|
6884
7830
|
moduleRunner;
|
|
6885
7831
|
cancelRun = false;
|
|
6886
7832
|
assertionsErrors = /* @__PURE__ */ new WeakMap();
|
|
7833
|
+
benchInstances = /* @__PURE__ */ new WeakMap();
|
|
6887
7834
|
pool = this.workerState.ctx.pool;
|
|
7835
|
+
/**
|
|
7836
|
+
* @internal
|
|
7837
|
+
*/
|
|
6888
7838
|
_otel;
|
|
6889
7839
|
viteEnvironment;
|
|
6890
7840
|
viteModuleRunner;
|
|
@@ -6910,7 +7860,7 @@ class TestRunner {
|
|
|
6910
7860
|
onCleanupWorkerContext(listener) {
|
|
6911
7861
|
this.workerState.onCleanup(listener);
|
|
6912
7862
|
}
|
|
6913
|
-
onAfterRunFiles() {
|
|
7863
|
+
onAfterRunFiles(_files) {
|
|
6914
7864
|
this.snapshotClient.clear();
|
|
6915
7865
|
this.workerState.current = void 0;
|
|
6916
7866
|
}
|
|
@@ -6957,7 +7907,7 @@ class TestRunner {
|
|
|
6957
7907
|
if (suite.mode !== "skip" && "filepath" in suite) await this.snapshotClient.setup(suite.file.filepath, this.workerState.config.snapshotOptions);
|
|
6958
7908
|
this.workerState.current = suite;
|
|
6959
7909
|
}
|
|
6960
|
-
onBeforeTryTask(test) {
|
|
7910
|
+
onBeforeTryTask(test, _options) {
|
|
6961
7911
|
clearModuleMocks(this.config);
|
|
6962
7912
|
this.snapshotClient.clearTest(test.file.filepath, test.id);
|
|
6963
7913
|
setState({
|
|
@@ -6971,6 +7921,7 @@ class TestRunner {
|
|
|
6971
7921
|
}, globalThis[GLOBAL_EXPECT]);
|
|
6972
7922
|
}
|
|
6973
7923
|
onAfterTryTask(test) {
|
|
7924
|
+
this.benchInstances.get(test)?.[kFinalize]();
|
|
6974
7925
|
const { assertionCalls, expectedAssertionsNumber, expectedAssertionsNumberErrorGen, isExpectingAssertions, isExpectingAssertionsError } = test.context._local ? test.context.expect.getState() : getState(globalThis[GLOBAL_EXPECT]);
|
|
6975
7926
|
if (expectedAssertionsNumber !== null && assertionCalls !== expectedAssertionsNumber) throw expectedAssertionsNumberErrorGen();
|
|
6976
7927
|
if (isExpectingAssertions === true && assertionCalls === 0) throw isExpectingAssertionsError;
|
|
@@ -6987,6 +7938,16 @@ class TestRunner {
|
|
|
6987
7938
|
Object.defineProperty(context, "_local", { get() {
|
|
6988
7939
|
return _expect != null;
|
|
6989
7940
|
} });
|
|
7941
|
+
let _bench;
|
|
7942
|
+
const runnerConfig = this.config;
|
|
7943
|
+
const benchInstances = this.benchInstances;
|
|
7944
|
+
Object.defineProperty(context, "bench", { get() {
|
|
7945
|
+
if (!_bench) {
|
|
7946
|
+
_bench = createBench(context.task, runnerConfig);
|
|
7947
|
+
benchInstances.set(context.task, _bench);
|
|
7948
|
+
}
|
|
7949
|
+
return _bench;
|
|
7950
|
+
} });
|
|
6990
7951
|
return context;
|
|
6991
7952
|
}
|
|
6992
7953
|
getImportDurations() {
|
|
@@ -7021,13 +7982,13 @@ class TestRunner {
|
|
|
7021
7982
|
static setTestFn = getFn;
|
|
7022
7983
|
static matchesTags = matchesTags;
|
|
7023
7984
|
/**
|
|
7024
|
-
* @
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
/**
|
|
7028
|
-
* @deprecated
|
|
7985
|
+
* @experimental
|
|
7986
|
+
* A function that runs tinybench tasks.
|
|
7987
|
+
* Can be overriden to run tasks in a special environment.
|
|
7029
7988
|
*/
|
|
7030
|
-
static
|
|
7989
|
+
static async runBenchmarks(tinybench) {
|
|
7990
|
+
return await tinybench.run();
|
|
7991
|
+
}
|
|
7031
7992
|
}
|
|
7032
7993
|
function clearModuleMocks(config) {
|
|
7033
7994
|
const { clearMocks, mockReset, restoreMocks, unstubEnvs, unstubGlobals } = config;
|
|
@@ -7042,7 +8003,6 @@ const assertType = function assertType() {};
|
|
|
7042
8003
|
|
|
7043
8004
|
var index = /*#__PURE__*/Object.freeze({
|
|
7044
8005
|
__proto__: null,
|
|
7045
|
-
BenchmarkRunner: NodeBenchmarkRunner,
|
|
7046
8006
|
EvaluatedModules: VitestEvaluatedModules,
|
|
7047
8007
|
Snapshots: Snapshots,
|
|
7048
8008
|
TestRunner: TestRunner,
|
|
@@ -7054,7 +8014,6 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
7054
8014
|
assertType: assertType,
|
|
7055
8015
|
beforeAll: beforeAll,
|
|
7056
8016
|
beforeEach: beforeEach,
|
|
7057
|
-
bench: bench,
|
|
7058
8017
|
chai: chai,
|
|
7059
8018
|
createExpect: createExpect,
|
|
7060
8019
|
describe: describe,
|
|
@@ -7072,4 +8031,4 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
7072
8031
|
vitest: vitest
|
|
7073
8032
|
});
|
|
7074
8033
|
|
|
7075
|
-
export {
|
|
8034
|
+
export { Snapshots as S, TestRunner as T, assert as a, assertType as b, createExpect as c, inject as d, vitest as e, globalExpect as g, index as i, should as s, vi as v };
|