vitest 5.0.0-beta.2 → 5.0.0-beta.3
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.Bay6B1Dz.js} +4 -4
- package/dist/chunks/{browser.d.BUhkKcDl.d.ts → browser.d.DM1g8UNp.d.ts} +2 -2
- package/dist/chunks/{cac.8N4bOkkB.js → cac.DoK9yX-i.js} +8 -6
- package/dist/chunks/{cli-api.B0RFke2g.js → cli-api.BCY9ylNq.js} +140 -68
- package/dist/chunks/{config.d.D91DHYaD.d.ts → config.d.C0UMwus7.d.ts} +86 -63
- package/dist/chunks/{defaults.szbHWQun.js → defaults.DVfzlTkU.js} +1 -1
- package/dist/chunks/{env.D4Lgay0q.js → env.BKKtU2WC.js} +2 -1
- package/dist/chunks/{global.d.DhbKSQoV.d.ts → global.d.DZbA5YnY.d.ts} +4 -2
- package/dist/chunks/{globals.EHmmu0nC.js → globals.8_qjZdeE.js} +1 -1
- package/dist/chunks/{index.CViWo__T.js → index.PuMGMNHF.js} +2 -2
- package/dist/chunks/{index.D_7-4CaB.js → index.ukHtlBbI.js} +1305 -555
- package/dist/chunks/{init-forks.DMge3WTt.js → init-forks.OoZmDo1g.js} +1 -1
- package/dist/chunks/{init-threads.eIoyCTon.js → init-threads.eSHAowcx.js} +1 -1
- package/dist/chunks/{init.BVd7SaCA.js → init.YjNsCb-_.js} +1 -1
- package/dist/chunks/{plugin.d.cIKZEZ16.d.ts → plugin.d.C00LxKL6.d.ts} +35 -9
- package/dist/chunks/{setup-common.Hpq30zVk.js → setup-common.eQsbxe88.js} +1 -1
- package/dist/chunks/{vm.2okbRRME.js → vm.BE_VOfSs.js} +1 -1
- package/dist/chunks/{worker.d.Bu1kXGw4.d.ts → worker.d.Dv3hDCFf.d.ts} +1 -1
- package/dist/cli.js +2 -2
- package/dist/config.d.ts +6 -7
- package/dist/config.js +2 -2
- package/dist/index.d.ts +8 -8
- package/dist/index.js +1 -1
- package/dist/module-evaluator.js +1 -1
- package/dist/node.d.ts +7 -8
- package/dist/node.js +5 -5
- package/dist/worker.d.ts +2 -2
- package/dist/worker.js +5 -5
- package/dist/workers/forks.js +6 -6
- package/dist/workers/runVmTests.js +3 -3
- package/dist/workers/threads.js +6 -6
- package/dist/workers/vmForks.js +3 -3
- package/dist/workers/vmThreads.js +3 -3
- package/package.json +19 -20
|
@@ -2529,12 +2529,12 @@ function requireFakeTimersSrc () {
|
|
|
2529
2529
|
if (typeof __vitest_required__ !== 'undefined') {
|
|
2530
2530
|
try {
|
|
2531
2531
|
timersModule = __vitest_required__.timers;
|
|
2532
|
-
} catch
|
|
2532
|
+
} catch {
|
|
2533
2533
|
// ignored
|
|
2534
2534
|
}
|
|
2535
2535
|
try {
|
|
2536
2536
|
timersPromisesModule = __vitest_required__.timersPromises;
|
|
2537
|
-
} catch
|
|
2537
|
+
} catch {
|
|
2538
2538
|
// ignored
|
|
2539
2539
|
}
|
|
2540
2540
|
}
|
|
@@ -2545,18 +2545,18 @@ function requireFakeTimersSrc () {
|
|
|
2545
2545
|
|
|
2546
2546
|
/**
|
|
2547
2547
|
* @typedef {object} NextAsyncTickMode
|
|
2548
|
-
* @property {"nextAsync"} mode
|
|
2548
|
+
* @property {"nextAsync"} mode - runs timers one macrotask at a time
|
|
2549
2549
|
*/
|
|
2550
2550
|
|
|
2551
2551
|
/**
|
|
2552
2552
|
* @typedef {object} ManualTickMode
|
|
2553
|
-
* @property {"manual"} mode
|
|
2553
|
+
* @property {"manual"} mode - advances only when the caller explicitly ticks
|
|
2554
2554
|
*/
|
|
2555
2555
|
|
|
2556
2556
|
/**
|
|
2557
2557
|
* @typedef {object} IntervalTickMode
|
|
2558
|
-
* @property {"interval"} mode
|
|
2559
|
-
* @property {number} [delta]
|
|
2558
|
+
* @property {"interval"} mode - advances automatically on a native interval
|
|
2559
|
+
* @property {number} [delta] - interval duration in milliseconds
|
|
2560
2560
|
*/
|
|
2561
2561
|
|
|
2562
2562
|
/**
|
|
@@ -2564,134 +2564,447 @@ function requireFakeTimersSrc () {
|
|
|
2564
2564
|
*/
|
|
2565
2565
|
|
|
2566
2566
|
/**
|
|
2567
|
-
* @
|
|
2568
|
-
* @
|
|
2569
|
-
* @
|
|
2567
|
+
* @callback FakeTimersFunction
|
|
2568
|
+
* @param {...unknown[]} args
|
|
2569
|
+
* @returns {unknown}
|
|
2570
2570
|
*/
|
|
2571
2571
|
|
|
2572
2572
|
/**
|
|
2573
|
-
*
|
|
2574
|
-
* @callback
|
|
2575
|
-
* @
|
|
2576
|
-
* @param {{timeout: number}} options - an options object
|
|
2577
|
-
* @returns {number} the id
|
|
2573
|
+
* @callback VoidVarArgsFunc
|
|
2574
|
+
* @param {...unknown[]} args - optional arguments to call the callback with
|
|
2575
|
+
* @returns {void}
|
|
2578
2576
|
*/
|
|
2579
2577
|
|
|
2580
2578
|
/**
|
|
2581
2579
|
* @callback NextTick
|
|
2582
2580
|
* @param {VoidVarArgsFunc} callback - the callback to run
|
|
2583
|
-
* @param {
|
|
2581
|
+
* @param {...unknown[]} args - optional arguments to call the callback with
|
|
2584
2582
|
* @returns {void}
|
|
2585
2583
|
*/
|
|
2586
2584
|
|
|
2587
2585
|
/**
|
|
2588
2586
|
* @callback SetImmediate
|
|
2589
2587
|
* @param {VoidVarArgsFunc} callback - the callback to run
|
|
2590
|
-
* @param {
|
|
2588
|
+
* @param {...unknown[]} args - optional arguments to call the callback with
|
|
2591
2589
|
* @returns {NodeImmediate}
|
|
2592
2590
|
*/
|
|
2593
2591
|
|
|
2594
2592
|
/**
|
|
2595
|
-
* @callback
|
|
2596
|
-
* @param {
|
|
2593
|
+
* @callback SetTimeout
|
|
2594
|
+
* @param {VoidVarArgsFunc} callback - the callback to run
|
|
2595
|
+
* @param {number} [delay] - optional delay in milliseconds
|
|
2596
|
+
* @param {...unknown[]} args - optional arguments to call the callback with
|
|
2597
|
+
* @returns {TimerId} - the timeout identifier
|
|
2598
|
+
*/
|
|
2599
|
+
|
|
2600
|
+
/**
|
|
2601
|
+
* @callback ClearTimeout
|
|
2602
|
+
* @param {TimerId} [id] - the timeout identifier to clear
|
|
2603
|
+
* @returns {void}
|
|
2604
|
+
*/
|
|
2605
|
+
|
|
2606
|
+
/**
|
|
2607
|
+
* @callback SetInterval
|
|
2608
|
+
* @param {VoidVarArgsFunc} callback - the callback to run
|
|
2609
|
+
* @param {number} [delay] - optional delay in milliseconds
|
|
2610
|
+
* @param {...unknown[]} args - optional arguments to call the callback with
|
|
2611
|
+
* @returns {TimerId} - the interval identifier
|
|
2612
|
+
*/
|
|
2613
|
+
|
|
2614
|
+
/**
|
|
2615
|
+
* @callback ClearInterval
|
|
2616
|
+
* @param {TimerId} [id] - the interval identifier to clear
|
|
2617
|
+
* @returns {void}
|
|
2618
|
+
*/
|
|
2619
|
+
|
|
2620
|
+
/**
|
|
2621
|
+
* @callback QueueMicrotask
|
|
2622
|
+
* @param {VoidVarArgsFunc} callback - the callback to run
|
|
2623
|
+
* @returns {void}
|
|
2624
|
+
*/
|
|
2625
|
+
|
|
2626
|
+
/**
|
|
2627
|
+
* @callback TimeRemaining
|
|
2628
|
+
* @returns {number}
|
|
2629
|
+
*/
|
|
2630
|
+
|
|
2631
|
+
/**
|
|
2632
|
+
* @typedef {object} IdleDeadline
|
|
2633
|
+
* @property {boolean} didTimeout - whether or not the callback was called before reaching the optional timeout
|
|
2634
|
+
* @property {TimeRemaining} timeRemaining - a floating-point value providing an estimate of the number of milliseconds remaining in the current idle period
|
|
2635
|
+
*/
|
|
2636
|
+
|
|
2637
|
+
/**
|
|
2638
|
+
* @callback RequestIdleCallbackCallback
|
|
2639
|
+
* @param {IdleDeadline} deadline
|
|
2640
|
+
*/
|
|
2641
|
+
|
|
2642
|
+
/**
|
|
2643
|
+
* Queues a function to be called during a browser's idle periods
|
|
2644
|
+
* @callback RequestIdleCallback
|
|
2645
|
+
* @param {RequestIdleCallbackCallback} callback
|
|
2646
|
+
* @param {{timeout?: number}} [options] - an options object
|
|
2647
|
+
* @returns {number} the id
|
|
2648
|
+
*/
|
|
2649
|
+
|
|
2650
|
+
/**
|
|
2651
|
+
* @callback AnimationFrameCallback
|
|
2652
|
+
* @param {number} timestamp
|
|
2653
|
+
*/
|
|
2654
|
+
|
|
2655
|
+
/**
|
|
2656
|
+
* @callback RequestAnimationFrame
|
|
2657
|
+
* @param {AnimationFrameCallback} callback
|
|
2658
|
+
* @returns {TimerId} - the request id
|
|
2659
|
+
*/
|
|
2660
|
+
|
|
2661
|
+
/**
|
|
2662
|
+
* @callback CancelAnimationFrame
|
|
2663
|
+
* @param {TimerId} id - cancels a frame callback
|
|
2597
2664
|
* @returns {void}
|
|
2598
2665
|
*/
|
|
2599
2666
|
|
|
2600
2667
|
/**
|
|
2601
|
-
* @
|
|
2602
|
-
* @
|
|
2603
|
-
* @returns {
|
|
2668
|
+
* @callback CancelIdleCallback
|
|
2669
|
+
* @param {TimerId} id - cancels a scheduled idle callback
|
|
2670
|
+
* @returns {void}
|
|
2671
|
+
*/
|
|
2672
|
+
|
|
2673
|
+
/**
|
|
2674
|
+
* @callback ClearImmediate
|
|
2675
|
+
* @param {NodeImmediate} id - faked `clearImmediate`
|
|
2676
|
+
* @returns {void}
|
|
2604
2677
|
*/
|
|
2605
2678
|
|
|
2606
2679
|
/**
|
|
2607
|
-
* @
|
|
2608
|
-
* @
|
|
2680
|
+
* @callback CountTimers
|
|
2681
|
+
* @returns {number}
|
|
2682
|
+
*/
|
|
2683
|
+
|
|
2684
|
+
/**
|
|
2685
|
+
* @callback RunMicrotasks
|
|
2686
|
+
* @returns {void}
|
|
2687
|
+
*/
|
|
2688
|
+
|
|
2689
|
+
/**
|
|
2690
|
+
* @callback Tick
|
|
2691
|
+
* @param {number|string} tickValue milliseconds or a string parseable by parseTime
|
|
2692
|
+
* @returns {number} will return the new `now` value
|
|
2693
|
+
*/
|
|
2694
|
+
|
|
2695
|
+
/**
|
|
2696
|
+
* @callback TickAsync
|
|
2697
|
+
* @param {number|string} tickValue milliseconds or a string parseable by parseTime
|
|
2698
|
+
* @returns {Promise<number>}
|
|
2699
|
+
*/
|
|
2700
|
+
|
|
2701
|
+
/**
|
|
2702
|
+
* @callback Next
|
|
2703
|
+
* @returns {number}
|
|
2704
|
+
*/
|
|
2705
|
+
|
|
2706
|
+
/**
|
|
2707
|
+
* @callback NextAsync
|
|
2708
|
+
* @returns {Promise<number>}
|
|
2709
|
+
*/
|
|
2710
|
+
|
|
2711
|
+
/**
|
|
2712
|
+
* @callback RunAll
|
|
2713
|
+
* @returns {number}
|
|
2714
|
+
*/
|
|
2715
|
+
|
|
2716
|
+
/**
|
|
2717
|
+
* @callback RunToFrame
|
|
2718
|
+
* @returns {number}
|
|
2719
|
+
*/
|
|
2720
|
+
|
|
2721
|
+
/**
|
|
2722
|
+
* @callback RunAllAsync
|
|
2723
|
+
* @returns {Promise<number>}
|
|
2724
|
+
*/
|
|
2725
|
+
|
|
2726
|
+
/**
|
|
2727
|
+
* @callback RunToLast
|
|
2728
|
+
* @returns {number}
|
|
2729
|
+
*/
|
|
2730
|
+
|
|
2731
|
+
/**
|
|
2732
|
+
* @callback RunToLastAsync
|
|
2733
|
+
* @returns {Promise<number>}
|
|
2734
|
+
*/
|
|
2735
|
+
|
|
2736
|
+
/**
|
|
2737
|
+
* @callback Reset
|
|
2738
|
+
* @returns {void}
|
|
2739
|
+
*/
|
|
2740
|
+
|
|
2741
|
+
/**
|
|
2742
|
+
* @callback SetSystemTime
|
|
2743
|
+
* @param {number|Date} [now] initial mocked time, as milliseconds since epoch or a Date
|
|
2744
|
+
* @returns {void}
|
|
2745
|
+
*/
|
|
2746
|
+
|
|
2747
|
+
/**
|
|
2748
|
+
* @callback Jump
|
|
2749
|
+
* @param {number|string} tickValue milliseconds or a human-readable value like "01:11:15"
|
|
2750
|
+
* @returns {number}
|
|
2751
|
+
*/
|
|
2752
|
+
|
|
2753
|
+
/**
|
|
2754
|
+
* @callback Uninstall
|
|
2755
|
+
* @returns {void}
|
|
2756
|
+
*/
|
|
2757
|
+
|
|
2758
|
+
/**
|
|
2759
|
+
* @callback SetTickMode
|
|
2760
|
+
* @param {SetTickModeConfig} tickModeConfig - The new configuration for how the clock should tick.
|
|
2761
|
+
* @returns {void}
|
|
2762
|
+
*/
|
|
2763
|
+
|
|
2764
|
+
/**
|
|
2765
|
+
* @callback Hrtime
|
|
2766
|
+
* @param {Array<number>} [prev]
|
|
2767
|
+
* @returns {Array<number>}
|
|
2768
|
+
*/
|
|
2769
|
+
|
|
2770
|
+
/**
|
|
2771
|
+
* @callback WithGlobal
|
|
2772
|
+
* @param {object} _global Namespace to mock (e.g. `window`)
|
|
2773
|
+
* @returns {FakeTimers}
|
|
2774
|
+
*/
|
|
2775
|
+
|
|
2776
|
+
/**
|
|
2777
|
+
* @typedef {"setTimeout" | "clearTimeout" | "setImmediate" | "clearImmediate" | "setInterval" | "clearInterval" | "Date" | "nextTick" | "hrtime" | "requestAnimationFrame" | "cancelAnimationFrame" | "requestIdleCallback" | "cancelIdleCallback" | "performance" | "queueMicrotask"} FakeMethod
|
|
2778
|
+
*/
|
|
2779
|
+
|
|
2780
|
+
/**
|
|
2781
|
+
* @typedef {number | NodeImmediate | Timer} TimerId
|
|
2782
|
+
*/
|
|
2783
|
+
|
|
2784
|
+
/* eslint-disable jsdoc/reject-any-type */
|
|
2785
|
+
/**
|
|
2786
|
+
* @typedef {Record<string, any> & {
|
|
2787
|
+
* setTimeout?: SetTimeout,
|
|
2788
|
+
* clearTimeout?: ClearTimeout,
|
|
2789
|
+
* setInterval?: SetInterval,
|
|
2790
|
+
* clearInterval?: ClearInterval,
|
|
2791
|
+
* setImmediate?: SetImmediate,
|
|
2792
|
+
* clearImmediate?: ClearImmediate,
|
|
2793
|
+
* queueMicrotask?: QueueMicrotask,
|
|
2794
|
+
* requestAnimationFrame?: RequestAnimationFrame,
|
|
2795
|
+
* cancelAnimationFrame?: CancelAnimationFrame,
|
|
2796
|
+
* requestIdleCallback?: RequestIdleCallback,
|
|
2797
|
+
* cancelIdleCallback?: CancelIdleCallback,
|
|
2798
|
+
* process?: any,
|
|
2799
|
+
* performance?: any,
|
|
2800
|
+
* Performance?: any,
|
|
2801
|
+
* Intl?: any,
|
|
2802
|
+
* Promise?: typeof Promise,
|
|
2803
|
+
* Date: typeof Date & { isFake?: boolean, toSource?: () => string, clock?: any }
|
|
2804
|
+
* }} GlobalObject
|
|
2805
|
+
*/
|
|
2806
|
+
|
|
2807
|
+
/**
|
|
2808
|
+
* @typedef {object} TimerHeap
|
|
2809
|
+
* @property {Timer[]} timers - the heap-ordered timers
|
|
2810
|
+
* @property {() => Timer | undefined} peek - returns the next timer without removing it
|
|
2811
|
+
* @property {(timer: Timer) => void} push - adds a timer to the heap
|
|
2812
|
+
* @property {() => Timer | undefined} pop - removes and returns the next timer
|
|
2813
|
+
* @property {(timer: Timer) => void} remove - removes a specific timer
|
|
2814
|
+
*/
|
|
2815
|
+
|
|
2816
|
+
/**
|
|
2817
|
+
* @typedef {object} ClockTickMode
|
|
2818
|
+
* @property {TickMode} mode - active tick mode
|
|
2819
|
+
* @property {number} counter - increments whenever the mode changes
|
|
2820
|
+
* @property {number} [delta] - interval length in milliseconds
|
|
2821
|
+
*/
|
|
2822
|
+
|
|
2823
|
+
/**
|
|
2824
|
+
* @typedef {object} SetTickModeConfig
|
|
2825
|
+
* @property {TickMode} mode - desired tick mode
|
|
2826
|
+
* @property {number} [delta] - interval length in milliseconds
|
|
2827
|
+
*/
|
|
2828
|
+
|
|
2829
|
+
/**
|
|
2830
|
+
* @typedef {Record<string, any> & { clock: Clock }} IntlWithClock
|
|
2831
|
+
*/
|
|
2832
|
+
|
|
2833
|
+
/**
|
|
2834
|
+
* @typedef {object} Timers
|
|
2835
|
+
* @property {SetTimeout} setTimeout - native `setTimeout`
|
|
2836
|
+
* @property {ClearTimeout} clearTimeout - native `clearTimeout`
|
|
2837
|
+
* @property {SetInterval} setInterval - native `setInterval`
|
|
2838
|
+
* @property {ClearInterval} clearInterval - native `clearInterval`
|
|
2839
|
+
* @property {typeof Date} Date - native `Date`
|
|
2840
|
+
* @property {typeof Intl} [Intl] - native `Intl`
|
|
2841
|
+
* @property {SetImmediate} [setImmediate] - native `setImmediate`, if available
|
|
2842
|
+
* @property {ClearImmediate} [clearImmediate] - native `clearImmediate`, if available
|
|
2843
|
+
* @property {Hrtime} [hrtime] - native `process.hrtime`, if available
|
|
2844
|
+
* @property {NextTick} [nextTick] - native `process.nextTick`, if available
|
|
2845
|
+
* @property {Performance} [performance] - native `performance`, if available
|
|
2846
|
+
* @property {RequestAnimationFrame} [requestAnimationFrame] - native `requestAnimationFrame`, if available
|
|
2847
|
+
* @property {QueueMicrotask} [queueMicrotask] - whether `queueMicrotask` exists
|
|
2848
|
+
* @property {CancelAnimationFrame} [cancelAnimationFrame] - native `cancelAnimationFrame`, if available
|
|
2849
|
+
* @property {RequestIdleCallback} [requestIdleCallback] - native `requestIdleCallback`, if available
|
|
2850
|
+
* @property {CancelIdleCallback} [cancelIdleCallback] - native `cancelIdleCallback`, if available
|
|
2851
|
+
*/
|
|
2852
|
+
|
|
2853
|
+
/**
|
|
2854
|
+
* @typedef {object} ClockState
|
|
2855
|
+
* @property {number} tickFrom - lower bound of the current tick range
|
|
2856
|
+
* @property {number} tickTo - upper bound of the current tick range
|
|
2857
|
+
* @property {number} [previous] - previous timer time used during ticking
|
|
2858
|
+
* @property {number | null} [oldNow] - previous value of `now`
|
|
2859
|
+
* @property {Timer} [timer] - timer currently being processed
|
|
2860
|
+
* @property {unknown} [firstException] - first exception raised while processing timers
|
|
2861
|
+
* @property {number} [nanosTotal] - accumulated nanoseconds from fractional ticks
|
|
2862
|
+
* @property {number} [msFloat] - accumulated fractional milliseconds
|
|
2863
|
+
* @property {number} [ms] - accumulated whole milliseconds
|
|
2864
|
+
*/
|
|
2865
|
+
|
|
2866
|
+
/**
|
|
2867
|
+
* @typedef {object} TimerInitialProps
|
|
2868
|
+
* @property {VoidVarArgsFunc} func - callback or string to execute
|
|
2869
|
+
* @property {unknown[]} [args] - arguments passed to the callback
|
|
2870
|
+
* @property {'Timeout' | 'Interval' | 'Immediate' | 'AnimationFrame' | 'IdleCallback'} [type] - timer kind
|
|
2871
|
+
* @property {number} [delay] - requested delay in milliseconds
|
|
2872
|
+
* @property {number} [callAt] - scheduled execution time
|
|
2873
|
+
* @property {number} [createdAt] - time at which the timer was created
|
|
2874
|
+
* @property {boolean} [immediate] - whether this timer should run before non-immediate timers at the same time
|
|
2875
|
+
* @property {number} [id] - unique timer identifier
|
|
2876
|
+
* @property {Error} [error] - captured stack for loop diagnostics
|
|
2877
|
+
* @property {number} [interval] - interval for repeated timers
|
|
2878
|
+
* @property {boolean} [animation] - whether this is an animation frame timer
|
|
2879
|
+
* @property {boolean} [requestIdleCallback] - whether this is an idle callback timer
|
|
2880
|
+
* @property {number} [order] - execution order for timers at the same time
|
|
2881
|
+
* @property {number} [heapIndex] - index in the timer heap
|
|
2882
|
+
*/
|
|
2883
|
+
|
|
2884
|
+
/**
|
|
2885
|
+
* @callback CreateClockCallback
|
|
2886
|
+
* @param {number|Date} [start] initial mocked time, as milliseconds since epoch or a Date
|
|
2887
|
+
* @param {number} [loopLimit] maximum number of timers run before aborting with an infinite-loop error
|
|
2888
|
+
* @returns {Clock}
|
|
2889
|
+
*/
|
|
2890
|
+
|
|
2891
|
+
/**
|
|
2892
|
+
* @callback InstallCallback
|
|
2893
|
+
* @param {Config} [config] Optional config
|
|
2894
|
+
* @returns {Clock}
|
|
2895
|
+
*/
|
|
2896
|
+
|
|
2897
|
+
/**
|
|
2898
|
+
* @typedef {object} FakeTimers
|
|
2899
|
+
* @property {Timers} timers - the native timer APIs saved for later restoration
|
|
2900
|
+
* @property {CreateClockCallback} createClock - creates a new fake clock
|
|
2901
|
+
* @property {InstallCallback} install - installs the fake timers onto the default global object
|
|
2902
|
+
* @property {WithGlobal} withGlobal - creates a fake-timers instance for a provided global object
|
|
2609
2903
|
*/
|
|
2610
2904
|
|
|
2611
|
-
/* eslint-disable jsdoc/require-property-description */
|
|
2612
2905
|
/**
|
|
2613
2906
|
* @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 {
|
|
2907
|
+
* @property {number} now - current mocked time in milliseconds
|
|
2908
|
+
* @property {typeof Date & {clock?: Clock, isFake?: boolean, toSource?: () => string}} Date - fake Date constructor bound to this clock
|
|
2909
|
+
* @property {number} loopLimit - maximum number of timers before assuming an infinite loop
|
|
2910
|
+
* @property {RequestIdleCallback} requestIdleCallback - schedules an idle callback
|
|
2911
|
+
* @property {CancelIdleCallback} cancelIdleCallback - cancels a scheduled idle callback
|
|
2912
|
+
* @property {SetTimeout} setTimeout - faked `setTimeout`
|
|
2913
|
+
* @property {ClearTimeout} clearTimeout - faked `clearTimeout`
|
|
2914
|
+
* @property {NextTick} nextTick - faked `process.nextTick`
|
|
2915
|
+
* @property {QueueMicrotask} queueMicrotask - faked `queueMicrotask`
|
|
2916
|
+
* @property {SetInterval} setInterval - faked `setInterval`
|
|
2917
|
+
* @property {ClearInterval} clearInterval - faked `clearInterval`
|
|
2918
|
+
* @property {SetImmediate} setImmediate - faked `setImmediate`
|
|
2919
|
+
* @property {ClearImmediate} clearImmediate - faked `clearImmediate`
|
|
2920
|
+
* @property {CountTimers} countTimers - counts scheduled timers
|
|
2921
|
+
* @property {RequestAnimationFrame} requestAnimationFrame - schedules a frame callback
|
|
2922
|
+
* @property {CancelAnimationFrame} cancelAnimationFrame - cancels a frame callback
|
|
2923
|
+
* @property {RunMicrotasks} runMicrotasks - drains microtasks
|
|
2924
|
+
* @property {Tick} tick - advances fake time synchronously
|
|
2925
|
+
* @property {TickAsync} tickAsync - advances fake time asynchronously
|
|
2926
|
+
* @property {Next} next - runs the next scheduled timer
|
|
2927
|
+
* @property {NextAsync} nextAsync - runs the next scheduled timer asynchronously
|
|
2928
|
+
* @property {RunAll} runAll - runs all scheduled timers
|
|
2929
|
+
* @property {RunToFrame} runToFrame - runs timers up to the next animation frame
|
|
2930
|
+
* @property {RunAllAsync} runAllAsync - runs all scheduled timers asynchronously
|
|
2931
|
+
* @property {RunToLast} runToLast - runs timers up to the last scheduled timer
|
|
2932
|
+
* @property {RunToLastAsync} runToLastAsync - runs timers up to the last scheduled timer asynchronously
|
|
2933
|
+
* @property {Reset} reset - clears all timers and resets the clock
|
|
2934
|
+
* @property {SetSystemTime} setSystemTime - sets the clock to a specific wall-clock time
|
|
2935
|
+
* @property {Jump} jump - advances time and returns the new `now`
|
|
2936
|
+
* @property {any} performance - fake performance object
|
|
2937
|
+
* @property {Hrtime} hrtime - faked `process.hrtime`
|
|
2938
|
+
* @property {Uninstall} uninstall - restores native timers
|
|
2939
|
+
* @property {string[]} methods - names of faked methods
|
|
2940
|
+
* @property {boolean} [shouldClearNativeTimers] - inherited from config
|
|
2941
|
+
* @property {{methodName:string, original:unknown}[] | undefined} timersModuleMethods - saved Node timers module methods
|
|
2942
|
+
* @property {{methodName:string, original:unknown}[] | undefined} timersPromisesModuleMethods - saved Node timers/promises methods
|
|
2943
|
+
* @property {Map<VoidVarArgsFunc, AbortSignal>} abortListenerMap - active abort listeners
|
|
2944
|
+
* @property {SetTickMode} setTickMode - switches the auto-tick mode
|
|
2945
|
+
* @property {Map<number, Timer>} [timers] - internal timer storage
|
|
2946
|
+
* @property {TimerHeap} [timerHeap] - internal timer heap
|
|
2947
|
+
* @property {boolean} [duringTick] - internal flag
|
|
2948
|
+
* @property {boolean} isNearInfiniteLimit - internal flag indicating the loop limit is nearly reached
|
|
2949
|
+
* @property {TimerId} [attachedInterval] - internal flag
|
|
2950
|
+
* @property {ClockTickMode} [tickMode] - internal flag
|
|
2951
|
+
* @property {Timer[]} [jobs] - internal flag
|
|
2952
|
+
* @property {IntlWithClock} [Intl] - fake Intl object
|
|
2652
2953
|
*/
|
|
2653
|
-
/* eslint-enable jsdoc/
|
|
2954
|
+
/* eslint-enable jsdoc/reject-any-type */
|
|
2654
2955
|
|
|
2655
2956
|
/**
|
|
2656
2957
|
* Configuration object for the `install` method.
|
|
2657
2958
|
* @typedef {object} Config
|
|
2658
|
-
* @property {number|Date} [now]
|
|
2659
|
-
* @property {
|
|
2660
|
-
* @property {
|
|
2661
|
-
* @property {
|
|
2662
|
-
* @property {
|
|
2663
|
-
* @property {
|
|
2664
|
-
* @property {boolean} [
|
|
2959
|
+
* @property {number|Date} [now] initial mocked time, as milliseconds since epoch or a Date
|
|
2960
|
+
* @property {FakeMethod[]} [toFake] method names that should be faked
|
|
2961
|
+
* @property {FakeMethod[]} [toNotFake] method names that should remain native
|
|
2962
|
+
* @property {number} [loopLimit] maximum number of timers run before aborting with an infinite-loop error
|
|
2963
|
+
* @property {boolean} [shouldAdvanceTime] automatically increments mocked time while the clock is installed
|
|
2964
|
+
* @property {number} [advanceTimeDelta] interval in milliseconds used when `shouldAdvanceTime` is enabled
|
|
2965
|
+
* @property {boolean} [shouldClearNativeTimers] forwards clear calls to native methods when the timer is not fake
|
|
2966
|
+
* @property {boolean} [ignoreMissingTimers] suppresses errors when a requested timer is missing from the global object
|
|
2967
|
+
* @property {GlobalObject} [target] global object to install onto
|
|
2665
2968
|
*/
|
|
2666
2969
|
|
|
2667
|
-
/* eslint-disable jsdoc/require-property-description */
|
|
2668
2970
|
/**
|
|
2669
2971
|
* 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
|
-
|
|
2972
|
+
* @typedef {TimerInitialProps} Timer
|
|
2973
|
+
* @property {unknown[]} args - arguments passed to the callback
|
|
2974
|
+
* @property {number} callAt - scheduled execution time
|
|
2975
|
+
* @property {number} createdAt - time at which the timer was created
|
|
2976
|
+
* @property {number} id - unique timer identifier
|
|
2977
|
+
* @property {'Timeout' | 'Interval' | 'Immediate' | 'AnimationFrame' | 'IdleCallback'} type - timer kind
|
|
2978
|
+
*/
|
|
2979
|
+
|
|
2980
|
+
/**
|
|
2981
|
+
* @callback NodeImmediateHasRef
|
|
2982
|
+
* @returns {boolean}
|
|
2983
|
+
*/
|
|
2984
|
+
|
|
2985
|
+
/**
|
|
2986
|
+
* @callback NodeImmediateRef
|
|
2987
|
+
* @returns {NodeImmediate}
|
|
2988
|
+
*/
|
|
2989
|
+
|
|
2990
|
+
/**
|
|
2991
|
+
* @callback NodeImmediateUnref
|
|
2992
|
+
* @returns {NodeImmediate}
|
|
2679
2993
|
*/
|
|
2680
2994
|
|
|
2681
2995
|
/**
|
|
2682
2996
|
* A Node timer
|
|
2683
2997
|
* @typedef {object} NodeImmediate
|
|
2684
|
-
* @property {
|
|
2685
|
-
* @property {
|
|
2686
|
-
* @property {
|
|
2998
|
+
* @property {NodeImmediateHasRef} hasRef - reports whether the timer keeps the event loop alive
|
|
2999
|
+
* @property {NodeImmediateRef} ref - marks the timer as referenced
|
|
3000
|
+
* @property {NodeImmediateUnref} unref - marks the timer as unreferenced
|
|
2687
3001
|
*/
|
|
2688
|
-
/* eslint-enable jsdoc/require-property-description */
|
|
2689
3002
|
|
|
2690
3003
|
/* eslint-disable complexity */
|
|
2691
3004
|
|
|
2692
3005
|
/**
|
|
2693
3006
|
* Mocks available features in the specified global namespace.
|
|
2694
|
-
* @param {
|
|
3007
|
+
* @param {GlobalObject} _global Namespace to mock (e.g. `window`)
|
|
2695
3008
|
* @returns {FakeTimers}
|
|
2696
3009
|
*/
|
|
2697
3010
|
function withGlobal(_global) {
|
|
@@ -2731,7 +3044,10 @@ function requireFakeTimersSrc () {
|
|
|
2731
3044
|
_global.performance &&
|
|
2732
3045
|
_global.performance.constructor &&
|
|
2733
3046
|
_global.performance.constructor.prototype;
|
|
2734
|
-
isPresent.queueMicrotask =
|
|
3047
|
+
isPresent.queueMicrotask = Object.prototype.hasOwnProperty.call(
|
|
3048
|
+
_global,
|
|
3049
|
+
"queueMicrotask",
|
|
3050
|
+
);
|
|
2735
3051
|
isPresent.requestAnimationFrame =
|
|
2736
3052
|
_global.requestAnimationFrame &&
|
|
2737
3053
|
typeof _global.requestAnimationFrame === "function";
|
|
@@ -2741,7 +3057,7 @@ function requireFakeTimersSrc () {
|
|
|
2741
3057
|
isPresent.requestIdleCallback =
|
|
2742
3058
|
_global.requestIdleCallback &&
|
|
2743
3059
|
typeof _global.requestIdleCallback === "function";
|
|
2744
|
-
isPresent.
|
|
3060
|
+
isPresent.cancelIdleCallback =
|
|
2745
3061
|
_global.cancelIdleCallback &&
|
|
2746
3062
|
typeof _global.cancelIdleCallback === "function";
|
|
2747
3063
|
isPresent.setImmediate =
|
|
@@ -2762,6 +3078,8 @@ function requireFakeTimersSrc () {
|
|
|
2762
3078
|
)
|
|
2763
3079
|
: undefined;
|
|
2764
3080
|
let uniqueTimerId = idCounterStart;
|
|
3081
|
+
/** @type {number} */
|
|
3082
|
+
let uniqueTimerOrder = 0;
|
|
2765
3083
|
|
|
2766
3084
|
if (NativeDate === undefined) {
|
|
2767
3085
|
throw new Error(
|
|
@@ -2802,23 +3120,23 @@ function requireFakeTimersSrc () {
|
|
|
2802
3120
|
return isFinite(num);
|
|
2803
3121
|
}
|
|
2804
3122
|
|
|
2805
|
-
let isNearInfiniteLimit = false;
|
|
2806
|
-
|
|
2807
3123
|
/**
|
|
2808
3124
|
* @param {Clock} clock
|
|
2809
3125
|
* @param {number} i
|
|
2810
3126
|
*/
|
|
2811
3127
|
function checkIsNearInfiniteLimit(clock, i) {
|
|
2812
3128
|
if (clock.loopLimit && i === clock.loopLimit - 1) {
|
|
2813
|
-
isNearInfiniteLimit = true;
|
|
3129
|
+
clock.isNearInfiniteLimit = true;
|
|
2814
3130
|
}
|
|
2815
3131
|
}
|
|
2816
3132
|
|
|
2817
3133
|
/**
|
|
2818
|
-
*
|
|
3134
|
+
* @param {Clock} clock
|
|
2819
3135
|
*/
|
|
2820
|
-
function resetIsNearInfiniteLimit() {
|
|
2821
|
-
|
|
3136
|
+
function resetIsNearInfiniteLimit(clock) {
|
|
3137
|
+
if (clock) {
|
|
3138
|
+
clock.isNearInfiniteLimit = false;
|
|
3139
|
+
}
|
|
2822
3140
|
}
|
|
2823
3141
|
|
|
2824
3142
|
/**
|
|
@@ -2883,12 +3201,12 @@ function requireFakeTimersSrc () {
|
|
|
2883
3201
|
if (!epoch) {
|
|
2884
3202
|
return 0;
|
|
2885
3203
|
}
|
|
2886
|
-
if (typeof epoch.getTime === "function") {
|
|
2887
|
-
return epoch.getTime();
|
|
2888
|
-
}
|
|
2889
3204
|
if (typeof epoch === "number") {
|
|
2890
3205
|
return epoch;
|
|
2891
3206
|
}
|
|
3207
|
+
if (typeof epoch.getTime === "function") {
|
|
3208
|
+
return epoch.getTime();
|
|
3209
|
+
}
|
|
2892
3210
|
throw new TypeError("now should be milliseconds since UNIX epoch");
|
|
2893
3211
|
}
|
|
2894
3212
|
|
|
@@ -2905,6 +3223,7 @@ function requireFakeTimersSrc () {
|
|
|
2905
3223
|
/**
|
|
2906
3224
|
* @param {Clock} clock
|
|
2907
3225
|
* @param {Timer} job
|
|
3226
|
+
* @returns {Error}
|
|
2908
3227
|
*/
|
|
2909
3228
|
function getInfiniteLoopError(clock, job) {
|
|
2910
3229
|
const infiniteLoopError = new Error(
|
|
@@ -2964,34 +3283,29 @@ function requireFakeTimersSrc () {
|
|
|
2964
3283
|
Object.defineProperty(infiniteLoopError, "stack", {
|
|
2965
3284
|
value: stack,
|
|
2966
3285
|
});
|
|
2967
|
-
} catch
|
|
3286
|
+
} catch {
|
|
2968
3287
|
// noop
|
|
2969
3288
|
}
|
|
2970
3289
|
|
|
2971
3290
|
return infiniteLoopError;
|
|
2972
3291
|
}
|
|
2973
3292
|
|
|
2974
|
-
|
|
3293
|
+
/**
|
|
3294
|
+
* @returns {typeof Date & { clock: Clock }}
|
|
3295
|
+
*/
|
|
2975
3296
|
function createDate() {
|
|
2976
3297
|
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) {
|
|
3298
|
+
/** @type {Clock} */
|
|
3299
|
+
static clock;
|
|
3300
|
+
|
|
3301
|
+
constructor(...args) {
|
|
3302
|
+
// Preserve fake time when Date is called without arguments.
|
|
3303
|
+
if (args.length === 0) {
|
|
2992
3304
|
super(ClockDate.clock.now);
|
|
2993
3305
|
} else {
|
|
2994
|
-
|
|
3306
|
+
// The subclass is intentionally thin for explicit args.
|
|
3307
|
+
// @ts-expect-error Date constructor overloads are intentionally dynamic.
|
|
3308
|
+
super(...args);
|
|
2995
3309
|
}
|
|
2996
3310
|
|
|
2997
3311
|
// ensures identity checks using the constructor prop still works
|
|
@@ -3015,21 +3329,26 @@ function requireFakeTimersSrc () {
|
|
|
3015
3329
|
};
|
|
3016
3330
|
}
|
|
3017
3331
|
|
|
3018
|
-
|
|
3332
|
+
const NativeDateWithToSource =
|
|
3333
|
+
/** @type {typeof Date & { toSource?: () => string }} */ (
|
|
3334
|
+
NativeDate
|
|
3335
|
+
);
|
|
3336
|
+
|
|
3337
|
+
if (NativeDateWithToSource.toSource) {
|
|
3019
3338
|
ClockDate.toSource = function toSource() {
|
|
3020
|
-
return
|
|
3339
|
+
return NativeDateWithToSource.toSource();
|
|
3021
3340
|
};
|
|
3022
3341
|
}
|
|
3023
3342
|
|
|
3024
3343
|
ClockDate.toString = function toString() {
|
|
3025
|
-
return
|
|
3344
|
+
return NativeDateWithToSource.toString();
|
|
3026
3345
|
};
|
|
3027
3346
|
|
|
3028
3347
|
// noinspection UnnecessaryLocalVariableJS
|
|
3029
3348
|
/**
|
|
3030
3349
|
* A normal Class constructor cannot be called without `new`, but Date can, so we need
|
|
3031
3350
|
* to wrap it in a Proxy in order to ensure this functionality of Date is kept intact
|
|
3032
|
-
* @type {ClockDate}
|
|
3351
|
+
* @type {typeof ClockDate}
|
|
3033
3352
|
*/
|
|
3034
3353
|
const ClockDateProxy = new Proxy(ClockDate, {
|
|
3035
3354
|
// handler for [[Call]] invocations (i.e. not using `new`)
|
|
@@ -3046,7 +3365,9 @@ function requireFakeTimersSrc () {
|
|
|
3046
3365
|
},
|
|
3047
3366
|
});
|
|
3048
3367
|
|
|
3049
|
-
return
|
|
3368
|
+
return /** @type {typeof Date & { clock: Clock }} */ (
|
|
3369
|
+
/** @type {unknown} */ (ClockDateProxy)
|
|
3370
|
+
);
|
|
3050
3371
|
}
|
|
3051
3372
|
|
|
3052
3373
|
/**
|
|
@@ -3055,19 +3376,21 @@ function requireFakeTimersSrc () {
|
|
|
3055
3376
|
* Most of the properties are the original native ones,
|
|
3056
3377
|
* but we need to take control of those that have a
|
|
3057
3378
|
* dependency on the current clock.
|
|
3058
|
-
* @
|
|
3379
|
+
* @param {Clock} clock
|
|
3380
|
+
* @returns {IntlWithClock} the partly fake Intl implementation
|
|
3059
3381
|
*/
|
|
3060
|
-
function createIntl() {
|
|
3061
|
-
|
|
3382
|
+
function createIntl(clock) {
|
|
3383
|
+
/** @type {IntlWithClock} */
|
|
3384
|
+
const IntlWithClock = { clock: clock };
|
|
3062
3385
|
/*
|
|
3063
3386
|
* All properties of Intl are non-enumerable, so we need
|
|
3064
3387
|
* to do a bit of work to get them out.
|
|
3065
3388
|
*/
|
|
3066
3389
|
Object.getOwnPropertyNames(NativeIntl).forEach(
|
|
3067
|
-
(property) => (
|
|
3390
|
+
(property) => (IntlWithClock[property] = NativeIntl[property]),
|
|
3068
3391
|
);
|
|
3069
3392
|
|
|
3070
|
-
|
|
3393
|
+
IntlWithClock.DateTimeFormat = function (...args) {
|
|
3071
3394
|
const realFormatter = new NativeIntl.DateTimeFormat(...args);
|
|
3072
3395
|
const formatter = {};
|
|
3073
3396
|
|
|
@@ -3080,21 +3403,23 @@ function requireFakeTimersSrc () {
|
|
|
3080
3403
|
|
|
3081
3404
|
["format", "formatToParts"].forEach((method) => {
|
|
3082
3405
|
formatter[method] = function (date) {
|
|
3083
|
-
return realFormatter[method](
|
|
3406
|
+
return realFormatter[method](
|
|
3407
|
+
date || IntlWithClock.clock.now,
|
|
3408
|
+
);
|
|
3084
3409
|
};
|
|
3085
3410
|
});
|
|
3086
3411
|
|
|
3087
3412
|
return formatter;
|
|
3088
3413
|
};
|
|
3089
3414
|
|
|
3090
|
-
|
|
3415
|
+
IntlWithClock.DateTimeFormat.prototype = Object.create(
|
|
3091
3416
|
NativeIntl.DateTimeFormat.prototype,
|
|
3092
3417
|
);
|
|
3093
3418
|
|
|
3094
|
-
|
|
3419
|
+
IntlWithClock.DateTimeFormat.supportedLocalesOf =
|
|
3095
3420
|
NativeIntl.DateTimeFormat.supportedLocalesOf;
|
|
3096
3421
|
|
|
3097
|
-
return
|
|
3422
|
+
return IntlWithClock;
|
|
3098
3423
|
}
|
|
3099
3424
|
|
|
3100
3425
|
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
@@ -3112,6 +3437,7 @@ function requireFakeTimersSrc () {
|
|
|
3112
3437
|
if (!clock.jobs) {
|
|
3113
3438
|
return;
|
|
3114
3439
|
}
|
|
3440
|
+
const wasNearLimit = clock.isNearInfiniteLimit;
|
|
3115
3441
|
for (let i = 0; i < clock.jobs.length; i++) {
|
|
3116
3442
|
const job = clock.jobs[i];
|
|
3117
3443
|
job.func.apply(null, job.args);
|
|
@@ -3121,38 +3447,275 @@ function requireFakeTimersSrc () {
|
|
|
3121
3447
|
throw getInfiniteLoopError(clock, job);
|
|
3122
3448
|
}
|
|
3123
3449
|
}
|
|
3124
|
-
|
|
3450
|
+
if (!wasNearLimit) {
|
|
3451
|
+
resetIsNearInfiniteLimit(clock);
|
|
3452
|
+
}
|
|
3125
3453
|
clock.jobs = [];
|
|
3126
3454
|
}
|
|
3127
3455
|
|
|
3456
|
+
/**
|
|
3457
|
+
* A compact "soonest timer first" container.
|
|
3458
|
+
*
|
|
3459
|
+
* Think of this as a waiting room for scheduled callbacks where the next
|
|
3460
|
+
* callback to run is always kept at the front of the list. The internal
|
|
3461
|
+
* array is arranged so we can find, add, remove, and reorder timers
|
|
3462
|
+
* efficiently without sorting the whole list every time something changes.
|
|
3463
|
+
*
|
|
3464
|
+
* The important idea is not the data structure name, but the behavior:
|
|
3465
|
+
* the timer that should run next stays near the front, and when one timer
|
|
3466
|
+
* moves, the rest are shifted just enough to keep that promise true.
|
|
3467
|
+
*/
|
|
3468
|
+
class TimerHeap {
|
|
3469
|
+
constructor() {
|
|
3470
|
+
this.timers = [];
|
|
3471
|
+
}
|
|
3472
|
+
|
|
3473
|
+
/**
|
|
3474
|
+
* Look at the next timer without removing it.
|
|
3475
|
+
* This is the timer the clock would run first if time advanced now.
|
|
3476
|
+
* @returns {Timer}
|
|
3477
|
+
*/
|
|
3478
|
+
peek() {
|
|
3479
|
+
return this.timers[0];
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3482
|
+
/**
|
|
3483
|
+
* Add a timer to the waiting room, then move it upward until it is in
|
|
3484
|
+
* the right place relative to the timers it should run before and after.
|
|
3485
|
+
* @param {Timer} timer
|
|
3486
|
+
*/
|
|
3487
|
+
push(timer) {
|
|
3488
|
+
this.timers.push(timer);
|
|
3489
|
+
this.bubbleUp(this.timers.length - 1);
|
|
3490
|
+
}
|
|
3491
|
+
|
|
3492
|
+
/**
|
|
3493
|
+
* Remove and return the next timer to run.
|
|
3494
|
+
*
|
|
3495
|
+
* We pull the front timer out, move the last timer into the empty spot,
|
|
3496
|
+
* and then shift that replacement down until the ordering is correct
|
|
3497
|
+
* again. That avoids rebuilding the whole list from scratch.
|
|
3498
|
+
* @returns {Timer|undefined}
|
|
3499
|
+
*/
|
|
3500
|
+
pop() {
|
|
3501
|
+
if (this.timers.length === 0) {
|
|
3502
|
+
return undefined;
|
|
3503
|
+
}
|
|
3504
|
+
const first = this.timers[0];
|
|
3505
|
+
const last = this.timers.pop();
|
|
3506
|
+
if (this.timers.length > 0) {
|
|
3507
|
+
this.timers[0] = last;
|
|
3508
|
+
last.heapIndex = 0;
|
|
3509
|
+
this.bubbleDown(0);
|
|
3510
|
+
}
|
|
3511
|
+
delete first.heapIndex;
|
|
3512
|
+
return first;
|
|
3513
|
+
}
|
|
3514
|
+
|
|
3515
|
+
/**
|
|
3516
|
+
* Remove a specific timer from the waiting room.
|
|
3517
|
+
*
|
|
3518
|
+
* The heap stores timers in a shape that lets us jump directly to the
|
|
3519
|
+
* timer's current position, replace it with the last timer, and then
|
|
3520
|
+
* move that replacement up or down until the ordering is correct again.
|
|
3521
|
+
* @param {Timer} timer
|
|
3522
|
+
* @returns {boolean}
|
|
3523
|
+
*/
|
|
3524
|
+
remove(timer) {
|
|
3525
|
+
const index = timer.heapIndex;
|
|
3526
|
+
if (index === undefined || this.timers[index] !== timer) {
|
|
3527
|
+
return false;
|
|
3528
|
+
}
|
|
3529
|
+
const last = this.timers.pop();
|
|
3530
|
+
if (timer !== last) {
|
|
3531
|
+
this.timers[index] = last;
|
|
3532
|
+
last.heapIndex = index;
|
|
3533
|
+
if (compareTimers(last, timer) < 0) {
|
|
3534
|
+
this.bubbleUp(index);
|
|
3535
|
+
} else {
|
|
3536
|
+
this.bubbleDown(index);
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
delete timer.heapIndex;
|
|
3540
|
+
return true;
|
|
3541
|
+
}
|
|
3542
|
+
|
|
3543
|
+
/**
|
|
3544
|
+
* Move a timer toward the front until it is no longer "earlier" than
|
|
3545
|
+
* the timer above it.
|
|
3546
|
+
*
|
|
3547
|
+
* Conceptually, this is what happens when something newly scheduled
|
|
3548
|
+
* turns out to belong ahead of its parent in the waiting room. We keep
|
|
3549
|
+
* swapping it upward until it is no longer out of place.
|
|
3550
|
+
* @param {number} index
|
|
3551
|
+
*/
|
|
3552
|
+
bubbleUp(index) {
|
|
3553
|
+
const timer = this.timers[index];
|
|
3554
|
+
let currentIndex = index;
|
|
3555
|
+
while (currentIndex > 0) {
|
|
3556
|
+
const parentIndex = Math.floor((currentIndex - 1) / 2);
|
|
3557
|
+
const parent = this.timers[parentIndex];
|
|
3558
|
+
if (compareTimers(timer, parent) < 0) {
|
|
3559
|
+
this.timers[currentIndex] = parent;
|
|
3560
|
+
parent.heapIndex = currentIndex;
|
|
3561
|
+
currentIndex = parentIndex;
|
|
3562
|
+
} else {
|
|
3563
|
+
break;
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
this.timers[currentIndex] = timer;
|
|
3567
|
+
timer.heapIndex = currentIndex;
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3570
|
+
/**
|
|
3571
|
+
* Move a timer away from the front until the timer below it is no
|
|
3572
|
+
* longer supposed to run after it.
|
|
3573
|
+
*
|
|
3574
|
+
* This is the opposite of `bubbleUp`: when a timer at the front is
|
|
3575
|
+
* removed or moved, the replacement may be too far ahead, so we
|
|
3576
|
+
* repeatedly swap it downward with the best child until the waiting
|
|
3577
|
+
* room is ordered again.
|
|
3578
|
+
* @param {number} index
|
|
3579
|
+
*/
|
|
3580
|
+
bubbleDown(index) {
|
|
3581
|
+
const timer = this.timers[index];
|
|
3582
|
+
let currentIndex = index;
|
|
3583
|
+
const halfLength = Math.floor(this.timers.length / 2);
|
|
3584
|
+
while (currentIndex < halfLength) {
|
|
3585
|
+
const leftIndex = currentIndex * 2 + 1;
|
|
3586
|
+
const rightIndex = leftIndex + 1;
|
|
3587
|
+
let bestChildIndex = leftIndex;
|
|
3588
|
+
let bestChild = this.timers[leftIndex];
|
|
3589
|
+
|
|
3590
|
+
if (
|
|
3591
|
+
rightIndex < this.timers.length &&
|
|
3592
|
+
compareTimers(this.timers[rightIndex], bestChild) < 0
|
|
3593
|
+
) {
|
|
3594
|
+
bestChildIndex = rightIndex;
|
|
3595
|
+
bestChild = this.timers[rightIndex];
|
|
3596
|
+
}
|
|
3597
|
+
|
|
3598
|
+
if (compareTimers(bestChild, timer) < 0) {
|
|
3599
|
+
this.timers[currentIndex] = bestChild;
|
|
3600
|
+
bestChild.heapIndex = currentIndex;
|
|
3601
|
+
currentIndex = bestChildIndex;
|
|
3602
|
+
} else {
|
|
3603
|
+
break;
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
this.timers[currentIndex] = timer;
|
|
3607
|
+
timer.heapIndex = currentIndex;
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
|
|
3611
|
+
/**
|
|
3612
|
+
* Ensure timer storage and heap stay in sync even if a clear path touches
|
|
3613
|
+
* timer state before anything has been scheduled.
|
|
3614
|
+
*
|
|
3615
|
+
* Why do we need two data structures to keep tabs on timers?
|
|
3616
|
+
* 1. Fast ID Lookup (clock.timers): This is a Map from timer IDs to their respective timer objects. It allows clearTimeout(id) and
|
|
3617
|
+
* clearInterval(id) to be $O(1)$ operations. Without this map, finding a specific timer in the heap to remove it would require a linear
|
|
3618
|
+
* $O(n)$ search, which would significantly degrade performance as the number of active timers grows.
|
|
3619
|
+
* 2. Efficient Scheduling (clock.timerHeap): This is a priority queue (min-heap) that keeps timers ordered by their execution time (callAt). It
|
|
3620
|
+
* 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
|
|
3621
|
+
* removed ($O(\log n)$).
|
|
3622
|
+
*
|
|
3623
|
+
* In short: clock.timers provides fast access by ID, while clock.timerHeap provides fast access by Time. Removing either one would make common
|
|
3624
|
+
* operations (like clearing or finding the next timer) much slower.
|
|
3625
|
+
* @param {Clock} clock
|
|
3626
|
+
*/
|
|
3627
|
+
function ensureTimerState(clock) {
|
|
3628
|
+
if (!clock.timers) {
|
|
3629
|
+
clock.timers = new Map();
|
|
3630
|
+
clock.timerHeap = new TimerHeap();
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
|
|
3634
|
+
/**
|
|
3635
|
+
* @param {Clock} clock
|
|
3636
|
+
* @param {number} id
|
|
3637
|
+
* @returns {boolean}
|
|
3638
|
+
*/
|
|
3639
|
+
function hasTimer(clock, id) {
|
|
3640
|
+
return clock.timers ? clock.timers.has(id) : false;
|
|
3641
|
+
}
|
|
3642
|
+
|
|
3643
|
+
/**
|
|
3644
|
+
* @param {Clock} clock
|
|
3645
|
+
* @param {number} id
|
|
3646
|
+
* @returns {Timer}
|
|
3647
|
+
*/
|
|
3648
|
+
function getTimer(clock, id) {
|
|
3649
|
+
return clock.timers ? clock.timers.get(id) : undefined;
|
|
3650
|
+
}
|
|
3651
|
+
|
|
3128
3652
|
/**
|
|
3129
3653
|
* @param {Clock} clock
|
|
3130
3654
|
* @param {Timer} timer
|
|
3131
|
-
|
|
3655
|
+
*/
|
|
3656
|
+
function setTimer(clock, timer) {
|
|
3657
|
+
ensureTimerState(clock);
|
|
3658
|
+
clock.timers.set(timer.id, timer);
|
|
3659
|
+
}
|
|
3660
|
+
|
|
3661
|
+
/**
|
|
3662
|
+
* @param {Clock} clock
|
|
3663
|
+
* @param {number} id
|
|
3664
|
+
* @returns {boolean}
|
|
3665
|
+
*/
|
|
3666
|
+
function deleteTimer(clock, id) {
|
|
3667
|
+
return clock.timers ? clock.timers.delete(id) : false;
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3670
|
+
/**
|
|
3671
|
+
* @param {Clock} clock
|
|
3672
|
+
* @param {(timer: Timer) => void} callback
|
|
3673
|
+
*/
|
|
3674
|
+
function forEachActiveTimer(clock, callback) {
|
|
3675
|
+
if (!clock.timers) {
|
|
3676
|
+
return;
|
|
3677
|
+
}
|
|
3678
|
+
|
|
3679
|
+
for (const timer of clock.timers.values()) {
|
|
3680
|
+
callback(timer);
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
|
|
3684
|
+
/**
|
|
3685
|
+
* @param {Clock} clock
|
|
3686
|
+
*/
|
|
3687
|
+
function rebuildTimerHeap(clock) {
|
|
3688
|
+
clock.timerHeap = new TimerHeap();
|
|
3689
|
+
forEachActiveTimer(clock, (timer) => {
|
|
3690
|
+
clock.timerHeap.push(timer);
|
|
3691
|
+
});
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
/**
|
|
3695
|
+
* @param {Clock} clock
|
|
3696
|
+
* @param {TimerInitialProps} timer
|
|
3697
|
+
* @returns {TimerId} id of the created timer
|
|
3132
3698
|
*/
|
|
3133
3699
|
function addTimer(clock, timer) {
|
|
3134
3700
|
if (timer.func === undefined) {
|
|
3135
3701
|
throw new Error("Callback must be provided to timer calls");
|
|
3136
3702
|
}
|
|
3137
3703
|
|
|
3138
|
-
if (
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
} of type ${typeof timer.func}`,
|
|
3145
|
-
);
|
|
3146
|
-
}
|
|
3704
|
+
if (typeof timer.func !== "function") {
|
|
3705
|
+
throw new TypeError(
|
|
3706
|
+
`[ERR_INVALID_CALLBACK]: Callback must be a function. Received ${
|
|
3707
|
+
timer.func
|
|
3708
|
+
} of type ${typeof timer.func}`,
|
|
3709
|
+
);
|
|
3147
3710
|
}
|
|
3148
3711
|
|
|
3149
|
-
if (isNearInfiniteLimit) {
|
|
3712
|
+
if (clock.isNearInfiniteLimit) {
|
|
3150
3713
|
timer.error = new Error();
|
|
3151
3714
|
}
|
|
3152
3715
|
|
|
3153
3716
|
timer.type = timer.immediate ? "Immediate" : "Timeout";
|
|
3154
3717
|
|
|
3155
|
-
if (
|
|
3718
|
+
if (Object.prototype.hasOwnProperty.call(timer, "delay")) {
|
|
3156
3719
|
if (typeof timer.delay !== "number") {
|
|
3157
3720
|
timer.delay = parseInt(timer.delay, 10);
|
|
3158
3721
|
}
|
|
@@ -3164,42 +3727,60 @@ function requireFakeTimersSrc () {
|
|
|
3164
3727
|
timer.delay = Math.max(0, timer.delay);
|
|
3165
3728
|
}
|
|
3166
3729
|
|
|
3167
|
-
if (
|
|
3730
|
+
if (Object.prototype.hasOwnProperty.call(timer, "interval")) {
|
|
3168
3731
|
timer.type = "Interval";
|
|
3169
3732
|
timer.interval = timer.interval > maxTimeout ? 1 : timer.interval;
|
|
3170
3733
|
}
|
|
3171
3734
|
|
|
3172
|
-
if (
|
|
3735
|
+
if (Object.prototype.hasOwnProperty.call(timer, "animation")) {
|
|
3173
3736
|
timer.type = "AnimationFrame";
|
|
3174
3737
|
timer.animation = true;
|
|
3175
3738
|
}
|
|
3176
3739
|
|
|
3177
|
-
if (
|
|
3178
|
-
timer
|
|
3179
|
-
|
|
3740
|
+
if (
|
|
3741
|
+
Object.prototype.hasOwnProperty.call(timer, "requestIdleCallback")
|
|
3742
|
+
) {
|
|
3743
|
+
// mark timer as IdleCallback type if it has no delay, otherwise it'd be of type timeout
|
|
3744
|
+
// this way we are able to sort such that the timer only gets called when there's truly no pending task to run
|
|
3745
|
+
if (!timer.delay) {
|
|
3746
|
+
timer.type = "IdleCallback";
|
|
3747
|
+
}
|
|
3748
|
+
timer.requestIdleCallback = true;
|
|
3180
3749
|
}
|
|
3181
3750
|
|
|
3182
|
-
|
|
3183
|
-
|
|
3751
|
+
ensureTimerState(clock);
|
|
3752
|
+
|
|
3753
|
+
while (hasTimer(clock, uniqueTimerId)) {
|
|
3754
|
+
uniqueTimerId++;
|
|
3755
|
+
if (uniqueTimerId >= Number.MAX_SAFE_INTEGER) {
|
|
3756
|
+
uniqueTimerId = idCounterStart;
|
|
3757
|
+
}
|
|
3184
3758
|
}
|
|
3185
3759
|
|
|
3186
3760
|
timer.id = uniqueTimerId++;
|
|
3761
|
+
if (uniqueTimerId >= Number.MAX_SAFE_INTEGER) {
|
|
3762
|
+
uniqueTimerId = idCounterStart;
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3765
|
+
timer.order = uniqueTimerOrder++;
|
|
3187
3766
|
timer.createdAt = clock.now;
|
|
3188
3767
|
timer.callAt =
|
|
3189
|
-
clock.now +
|
|
3768
|
+
clock.now +
|
|
3769
|
+
(parseInt(String(timer.delay)) || (clock.duringTick ? 1 : 0));
|
|
3190
3770
|
|
|
3191
|
-
clock
|
|
3771
|
+
setTimer(clock, timer);
|
|
3772
|
+
clock.timerHeap.push(timer);
|
|
3192
3773
|
|
|
3193
3774
|
if (addTimerReturnsObject) {
|
|
3194
3775
|
const res = {
|
|
3195
3776
|
refed: true,
|
|
3196
3777
|
ref: function () {
|
|
3197
3778
|
this.refed = true;
|
|
3198
|
-
return
|
|
3779
|
+
return this;
|
|
3199
3780
|
},
|
|
3200
3781
|
unref: function () {
|
|
3201
3782
|
this.refed = false;
|
|
3202
|
-
return
|
|
3783
|
+
return this;
|
|
3203
3784
|
},
|
|
3204
3785
|
hasRef: function () {
|
|
3205
3786
|
return this.refed;
|
|
@@ -3207,12 +3788,15 @@ function requireFakeTimersSrc () {
|
|
|
3207
3788
|
refresh: function () {
|
|
3208
3789
|
timer.callAt =
|
|
3209
3790
|
clock.now +
|
|
3210
|
-
(parseInt(timer.delay) ||
|
|
3791
|
+
(parseInt(String(timer.delay)) ||
|
|
3792
|
+
(clock.duringTick ? 1 : 0));
|
|
3211
3793
|
|
|
3212
|
-
|
|
3213
|
-
|
|
3794
|
+
clock.timerHeap.remove(timer);
|
|
3795
|
+
timer.order = uniqueTimerOrder++;
|
|
3796
|
+
setTimer(clock, timer);
|
|
3797
|
+
clock.timerHeap.push(timer);
|
|
3214
3798
|
|
|
3215
|
-
return
|
|
3799
|
+
return this;
|
|
3216
3800
|
},
|
|
3217
3801
|
[Symbol.toPrimitive]: function () {
|
|
3218
3802
|
return timer.id;
|
|
@@ -3226,12 +3810,20 @@ function requireFakeTimersSrc () {
|
|
|
3226
3810
|
|
|
3227
3811
|
/* eslint consistent-return: "off" */
|
|
3228
3812
|
/**
|
|
3229
|
-
* Timer
|
|
3813
|
+
* Timer comparator
|
|
3230
3814
|
* @param {Timer} a
|
|
3231
3815
|
* @param {Timer} b
|
|
3232
3816
|
* @returns {number}
|
|
3233
3817
|
*/
|
|
3234
3818
|
function compareTimers(a, b) {
|
|
3819
|
+
// Sort IdleCallback timers to the bottom when scheduled for the same time
|
|
3820
|
+
if (a.type === "IdleCallback" && b.type !== "IdleCallback") {
|
|
3821
|
+
return 1;
|
|
3822
|
+
}
|
|
3823
|
+
if (a.type !== "IdleCallback" && b.type === "IdleCallback") {
|
|
3824
|
+
return -1;
|
|
3825
|
+
}
|
|
3826
|
+
|
|
3235
3827
|
// Sort first by absolute timing
|
|
3236
3828
|
if (a.callAt < b.callAt) {
|
|
3237
3829
|
return -1;
|
|
@@ -3248,6 +3840,13 @@ function requireFakeTimersSrc () {
|
|
|
3248
3840
|
return 1;
|
|
3249
3841
|
}
|
|
3250
3842
|
|
|
3843
|
+
if (a.order < b.order) {
|
|
3844
|
+
return -1;
|
|
3845
|
+
}
|
|
3846
|
+
if (a.order > b.order) {
|
|
3847
|
+
return 1;
|
|
3848
|
+
}
|
|
3849
|
+
|
|
3251
3850
|
// Sort next by creation time, earlier-created timers take precedence
|
|
3252
3851
|
if (a.createdAt < b.createdAt) {
|
|
3253
3852
|
return -1;
|
|
@@ -3265,6 +3864,7 @@ function requireFakeTimersSrc () {
|
|
|
3265
3864
|
}
|
|
3266
3865
|
|
|
3267
3866
|
// As timer ids are unique, no fallback `0` is necessary
|
|
3867
|
+
return 0;
|
|
3268
3868
|
}
|
|
3269
3869
|
|
|
3270
3870
|
/**
|
|
@@ -3274,20 +3874,31 @@ function requireFakeTimersSrc () {
|
|
|
3274
3874
|
* @returns {Timer}
|
|
3275
3875
|
*/
|
|
3276
3876
|
function firstTimerInRange(clock, from, to) {
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3877
|
+
if (!clock.timerHeap) {
|
|
3878
|
+
return null;
|
|
3879
|
+
}
|
|
3280
3880
|
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3881
|
+
const timers = clock.timerHeap.timers;
|
|
3882
|
+
if (timers.length === 1 && timers[0].requestIdleCallback) {
|
|
3883
|
+
return timers[0];
|
|
3884
|
+
}
|
|
3284
3885
|
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3886
|
+
const first = clock.timerHeap.peek();
|
|
3887
|
+
if (first && inRange(from, to, first)) {
|
|
3888
|
+
return first;
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3891
|
+
/**
|
|
3892
|
+
* @type {?Timer}
|
|
3893
|
+
*/
|
|
3894
|
+
let timer = null;
|
|
3895
|
+
|
|
3896
|
+
for (let i = 0; i < timers.length; i++) {
|
|
3897
|
+
if (
|
|
3898
|
+
inRange(from, to, timers[i]) &&
|
|
3899
|
+
(!timer || compareTimers(timer, timers[i]) === 1)
|
|
3900
|
+
) {
|
|
3901
|
+
timer = timers[i];
|
|
3291
3902
|
}
|
|
3292
3903
|
}
|
|
3293
3904
|
|
|
@@ -3299,19 +3910,10 @@ function requireFakeTimersSrc () {
|
|
|
3299
3910
|
* @returns {Timer}
|
|
3300
3911
|
*/
|
|
3301
3912
|
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
|
-
}
|
|
3913
|
+
if (!clock.timerHeap) {
|
|
3914
|
+
return null;
|
|
3312
3915
|
}
|
|
3313
|
-
|
|
3314
|
-
return timer;
|
|
3916
|
+
return clock.timerHeap.peek() || null;
|
|
3315
3917
|
}
|
|
3316
3918
|
|
|
3317
3919
|
/**
|
|
@@ -3319,15 +3921,15 @@ function requireFakeTimersSrc () {
|
|
|
3319
3921
|
* @returns {Timer}
|
|
3320
3922
|
*/
|
|
3321
3923
|
function lastTimer(clock) {
|
|
3322
|
-
|
|
3924
|
+
if (!clock.timerHeap) {
|
|
3925
|
+
return null;
|
|
3926
|
+
}
|
|
3927
|
+
const timers = clock.timerHeap.timers;
|
|
3323
3928
|
let timer = null;
|
|
3324
|
-
let id;
|
|
3325
3929
|
|
|
3326
|
-
for (
|
|
3327
|
-
if (timers
|
|
3328
|
-
|
|
3329
|
-
timer = timers[id];
|
|
3330
|
-
}
|
|
3930
|
+
for (let i = 0; i < timers.length; i++) {
|
|
3931
|
+
if (!timer || compareTimers(timer, timers[i]) === -1) {
|
|
3932
|
+
timer = timers[i];
|
|
3331
3933
|
}
|
|
3332
3934
|
}
|
|
3333
3935
|
|
|
@@ -3340,25 +3942,27 @@ function requireFakeTimersSrc () {
|
|
|
3340
3942
|
*/
|
|
3341
3943
|
function callTimer(clock, timer) {
|
|
3342
3944
|
if (typeof timer.interval === "number") {
|
|
3343
|
-
clock.
|
|
3945
|
+
clock.timerHeap.remove(timer);
|
|
3946
|
+
timer.callAt += timer.interval;
|
|
3947
|
+
timer.order = uniqueTimerOrder++;
|
|
3948
|
+
if (clock.isNearInfiniteLimit) {
|
|
3949
|
+
timer.error = new Error();
|
|
3950
|
+
}
|
|
3951
|
+
clock.timerHeap.push(timer);
|
|
3344
3952
|
} else {
|
|
3345
|
-
|
|
3953
|
+
deleteTimer(clock, timer.id);
|
|
3954
|
+
clock.timerHeap.remove(timer);
|
|
3346
3955
|
}
|
|
3347
3956
|
|
|
3348
3957
|
if (typeof timer.func === "function") {
|
|
3349
3958
|
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
3959
|
}
|
|
3357
3960
|
}
|
|
3358
3961
|
|
|
3359
3962
|
/**
|
|
3360
3963
|
* Gets clear handler name for a given timer type
|
|
3361
3964
|
* @param {string} ttype
|
|
3965
|
+
* @returns {string}
|
|
3362
3966
|
*/
|
|
3363
3967
|
function getClearHandler(ttype) {
|
|
3364
3968
|
if (ttype === "IdleCallback" || ttype === "AnimationFrame") {
|
|
@@ -3370,6 +3974,7 @@ function requireFakeTimersSrc () {
|
|
|
3370
3974
|
/**
|
|
3371
3975
|
* Gets schedule handler name for a given timer type
|
|
3372
3976
|
* @param {string} ttype
|
|
3977
|
+
* @returns {string}
|
|
3373
3978
|
*/
|
|
3374
3979
|
function getScheduleHandler(ttype) {
|
|
3375
3980
|
if (ttype === "IdleCallback" || ttype === "AnimationFrame") {
|
|
@@ -3380,6 +3985,7 @@ function requireFakeTimersSrc () {
|
|
|
3380
3985
|
|
|
3381
3986
|
/**
|
|
3382
3987
|
* Creates an anonymous function to warn only once
|
|
3988
|
+
* @returns {(msg: string) => void}
|
|
3383
3989
|
*/
|
|
3384
3990
|
function createWarnOnce() {
|
|
3385
3991
|
let calls = 0;
|
|
@@ -3392,8 +3998,9 @@ function requireFakeTimersSrc () {
|
|
|
3392
3998
|
|
|
3393
3999
|
/**
|
|
3394
4000
|
* @param {Clock} clock
|
|
3395
|
-
* @param {
|
|
4001
|
+
* @param {TimerId} timerId
|
|
3396
4002
|
* @param {string} ttype
|
|
4003
|
+
* @returns {void}
|
|
3397
4004
|
*/
|
|
3398
4005
|
function clearTimer(clock, timerId, ttype) {
|
|
3399
4006
|
if (!timerId) {
|
|
@@ -3402,10 +4009,6 @@ function requireFakeTimersSrc () {
|
|
|
3402
4009
|
return;
|
|
3403
4010
|
}
|
|
3404
4011
|
|
|
3405
|
-
if (!clock.timers) {
|
|
3406
|
-
clock.timers = {};
|
|
3407
|
-
}
|
|
3408
|
-
|
|
3409
4012
|
// in Node, the ID is stored as the primitive value for `Timeout` objects
|
|
3410
4013
|
// for `Immediate` objects, no ID exists, so it gets coerced to NaN
|
|
3411
4014
|
const id = Number(timerId);
|
|
@@ -3419,21 +4022,30 @@ function requireFakeTimersSrc () {
|
|
|
3419
4022
|
? nativeHandler(timerId)
|
|
3420
4023
|
: undefined;
|
|
3421
4024
|
}
|
|
4025
|
+
|
|
4026
|
+
// Include the stacktrace, excluding the 'error' line
|
|
4027
|
+
const stackTrace = new Error().stack
|
|
4028
|
+
.split("\n")
|
|
4029
|
+
.slice(1)
|
|
4030
|
+
.join("\n");
|
|
4031
|
+
|
|
3422
4032
|
warnOnce(
|
|
3423
4033
|
`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`."
|
|
4034
|
+
"\nTo automatically clean-up native timers, use `shouldClearNativeTimers`." +
|
|
4035
|
+
`\n${stackTrace}`,
|
|
3425
4036
|
);
|
|
3426
4037
|
}
|
|
3427
4038
|
|
|
3428
|
-
if (clock
|
|
4039
|
+
if (hasTimer(clock, id)) {
|
|
3429
4040
|
// check that the ID matches a timer of the correct type
|
|
3430
|
-
const timer = clock
|
|
4041
|
+
const timer = getTimer(clock, id);
|
|
3431
4042
|
if (
|
|
3432
4043
|
timer.type === ttype ||
|
|
3433
4044
|
(timer.type === "Timeout" && ttype === "Interval") ||
|
|
3434
4045
|
(timer.type === "Interval" && ttype === "Timeout")
|
|
3435
4046
|
) {
|
|
3436
|
-
|
|
4047
|
+
deleteTimer(clock, id);
|
|
4048
|
+
clock.timerHeap.remove(timer);
|
|
3437
4049
|
} else {
|
|
3438
4050
|
const clear = getClearHandler(ttype);
|
|
3439
4051
|
const schedule = getScheduleHandler(timer.type);
|
|
@@ -3478,12 +4090,12 @@ function requireFakeTimersSrc () {
|
|
|
3478
4090
|
_global[method] = clock[`_${method}`];
|
|
3479
4091
|
}
|
|
3480
4092
|
} else {
|
|
3481
|
-
if (
|
|
4093
|
+
if (clock[method] && clock[method].hasOwnProperty) {
|
|
3482
4094
|
_global[method] = clock[`_${method}`];
|
|
3483
4095
|
} else {
|
|
3484
4096
|
try {
|
|
3485
4097
|
delete _global[method];
|
|
3486
|
-
} catch
|
|
4098
|
+
} catch {
|
|
3487
4099
|
/* eslint no-empty: "off" */
|
|
3488
4100
|
}
|
|
3489
4101
|
}
|
|
@@ -3506,7 +4118,7 @@ function requireFakeTimersSrc () {
|
|
|
3506
4118
|
}
|
|
3507
4119
|
}
|
|
3508
4120
|
|
|
3509
|
-
clock.setTickMode("manual");
|
|
4121
|
+
clock.setTickMode({ mode: "manual" });
|
|
3510
4122
|
|
|
3511
4123
|
// Prevent multiple executions which will completely remove these props
|
|
3512
4124
|
clock.methods = [];
|
|
@@ -3517,12 +4129,10 @@ function requireFakeTimersSrc () {
|
|
|
3517
4129
|
}
|
|
3518
4130
|
|
|
3519
4131
|
// return pending timers, to enable checking what timers remained on uninstall
|
|
3520
|
-
if (!clock.
|
|
4132
|
+
if (!clock.timerHeap) {
|
|
3521
4133
|
return [];
|
|
3522
4134
|
}
|
|
3523
|
-
return
|
|
3524
|
-
return clock.timers[key];
|
|
3525
|
-
});
|
|
4135
|
+
return clock.timerHeap.timers.slice();
|
|
3526
4136
|
}
|
|
3527
4137
|
|
|
3528
4138
|
/**
|
|
@@ -3531,7 +4141,7 @@ function requireFakeTimersSrc () {
|
|
|
3531
4141
|
* @param {Clock} clock
|
|
3532
4142
|
*/
|
|
3533
4143
|
function hijackMethod(target, method, clock) {
|
|
3534
|
-
clock[method].
|
|
4144
|
+
clock[method].hasOwnProperty = Object.prototype.hasOwnProperty.call(
|
|
3535
4145
|
target,
|
|
3536
4146
|
method,
|
|
3537
4147
|
);
|
|
@@ -3588,26 +4198,6 @@ function requireFakeTimersSrc () {
|
|
|
3588
4198
|
clock.tick(advanceTimeDelta);
|
|
3589
4199
|
}
|
|
3590
4200
|
|
|
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
4201
|
/** @type {Timers} */
|
|
3612
4202
|
const timers = {
|
|
3613
4203
|
setTimeout: _global.setTimeout,
|
|
@@ -3671,30 +4261,37 @@ function requireFakeTimersSrc () {
|
|
|
3671
4261
|
* @returns {Clock}
|
|
3672
4262
|
*/
|
|
3673
4263
|
function createClock(start, loopLimit) {
|
|
4264
|
+
/** @type {number} */
|
|
3674
4265
|
// eslint-disable-next-line no-param-reassign
|
|
3675
4266
|
start = Math.floor(getEpoch(start));
|
|
4267
|
+
const startTimestamp = start;
|
|
3676
4268
|
// eslint-disable-next-line no-param-reassign
|
|
3677
4269
|
loopLimit = loopLimit || 1000;
|
|
4270
|
+
/** @type {number} */
|
|
3678
4271
|
let nanos = 0;
|
|
4272
|
+
/** @type {number[]} */
|
|
3679
4273
|
const adjustedSystemTime = [0, 0]; // [millis, nanoremainder]
|
|
3680
4274
|
|
|
3681
|
-
|
|
4275
|
+
/** @type {Clock} */
|
|
4276
|
+
const clock = /** @type {Clock} */ ({
|
|
3682
4277
|
now: start,
|
|
3683
4278
|
Date: createDate(),
|
|
3684
4279
|
loopLimit: loopLimit,
|
|
4280
|
+
isNearInfiniteLimit: false,
|
|
3685
4281
|
tickMode: { mode: "manual", counter: 0, delta: undefined },
|
|
3686
|
-
};
|
|
4282
|
+
});
|
|
3687
4283
|
|
|
3688
4284
|
clock.Date.clock = clock;
|
|
3689
4285
|
|
|
3690
4286
|
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
3691
4287
|
function getTimeToNextFrame() {
|
|
3692
|
-
return 16 - ((clock.now -
|
|
4288
|
+
return 16 - ((clock.now - startTimestamp) % 16);
|
|
3693
4289
|
}
|
|
3694
4290
|
|
|
3695
4291
|
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
3696
4292
|
function hrtime(prev) {
|
|
3697
|
-
const millisSinceStart =
|
|
4293
|
+
const millisSinceStart =
|
|
4294
|
+
clock.now - adjustedSystemTime[0] - startTimestamp;
|
|
3698
4295
|
const secsSinceStart = Math.floor(millisSinceStart / 1000);
|
|
3699
4296
|
const remainderInNanos =
|
|
3700
4297
|
(millisSinceStart - secsSinceStart * 1e3) * 1e6 +
|
|
@@ -3740,20 +4337,21 @@ function requireFakeTimersSrc () {
|
|
|
3740
4337
|
if (isPresent.hrtimeBigint) {
|
|
3741
4338
|
hrtime.bigint = function () {
|
|
3742
4339
|
const parts = hrtime();
|
|
3743
|
-
return BigInt(parts[0]) * BigInt(1e9) + BigInt(parts[1]);
|
|
4340
|
+
return BigInt(parts[0]) * BigInt(1e9) + BigInt(parts[1]);
|
|
3744
4341
|
};
|
|
3745
4342
|
}
|
|
3746
4343
|
|
|
3747
4344
|
if (isPresent.Intl) {
|
|
3748
|
-
clock.Intl = createIntl();
|
|
4345
|
+
clock.Intl = createIntl(clock);
|
|
3749
4346
|
clock.Intl.clock = clock;
|
|
3750
4347
|
}
|
|
3751
4348
|
|
|
3752
4349
|
/**
|
|
3753
|
-
* @param {
|
|
4350
|
+
* @param {SetTickModeConfig} tickModeConfig - The new configuration for how the clock should tick.
|
|
3754
4351
|
*/
|
|
3755
4352
|
clock.setTickMode = function (tickModeConfig) {
|
|
3756
|
-
const { mode: newMode, delta: newDelta } =
|
|
4353
|
+
const { mode: newMode, delta: newDelta } =
|
|
4354
|
+
/** @type {SetTickModeConfig} */ (tickModeConfig);
|
|
3757
4355
|
const { mode: oldMode, delta: oldDelta } = clock.tickMode;
|
|
3758
4356
|
if (newMode === oldMode && newDelta === oldDelta) {
|
|
3759
4357
|
return;
|
|
@@ -3776,7 +4374,15 @@ function requireFakeTimersSrc () {
|
|
|
3776
4374
|
}
|
|
3777
4375
|
};
|
|
3778
4376
|
|
|
4377
|
+
/**
|
|
4378
|
+
* Keeps advancing the native event loop until the tick mode changes.
|
|
4379
|
+
* @returns {Promise<void>}
|
|
4380
|
+
*/
|
|
3779
4381
|
async function advanceUntilModeChanges() {
|
|
4382
|
+
/**
|
|
4383
|
+
* Waits for one native macrotask and then one microtask turn.
|
|
4384
|
+
* @returns {Promise<void>}
|
|
4385
|
+
*/
|
|
3780
4386
|
async function newMacrotask() {
|
|
3781
4387
|
// MessageChannel ensures that setTimeout is not throttled to 4ms.
|
|
3782
4388
|
// https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#reasons_for_delays_longer_than_specified
|
|
@@ -3784,7 +4390,7 @@ function requireFakeTimersSrc () {
|
|
|
3784
4390
|
const channel = new MessageChannel();
|
|
3785
4391
|
await new Promise((resolve) => {
|
|
3786
4392
|
channel.port1.onmessage = () => {
|
|
3787
|
-
resolve();
|
|
4393
|
+
resolve(undefined);
|
|
3788
4394
|
channel.port1.close();
|
|
3789
4395
|
};
|
|
3790
4396
|
channel.port2.postMessage(undefined);
|
|
@@ -3807,6 +4413,11 @@ function requireFakeTimersSrc () {
|
|
|
3807
4413
|
}
|
|
3808
4414
|
}
|
|
3809
4415
|
|
|
4416
|
+
/**
|
|
4417
|
+
* Temporarily pauses nextAsync auto-ticking while an async operation runs.
|
|
4418
|
+
* @param {Promise<unknown>} promise
|
|
4419
|
+
* @returns {Promise<unknown>}
|
|
4420
|
+
*/
|
|
3810
4421
|
function pauseAutoTickUntilFinished(promise) {
|
|
3811
4422
|
if (clock.tickMode.mode !== "nextAsync") {
|
|
3812
4423
|
return promise;
|
|
@@ -3817,24 +4428,37 @@ function requireFakeTimersSrc () {
|
|
|
3817
4428
|
});
|
|
3818
4429
|
}
|
|
3819
4430
|
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
4431
|
+
/**
|
|
4432
|
+
* Returns the remaining time in the current idle window.
|
|
4433
|
+
* @returns {number}
|
|
4434
|
+
*/
|
|
4435
|
+
function getTimeToNextIdlePeriod() {
|
|
3824
4436
|
let timeToNextIdlePeriod = 0;
|
|
3825
4437
|
|
|
3826
4438
|
if (clock.countTimers() > 0) {
|
|
3827
4439
|
timeToNextIdlePeriod = 50; // const for now
|
|
3828
4440
|
}
|
|
3829
4441
|
|
|
4442
|
+
return timeToNextIdlePeriod;
|
|
4443
|
+
}
|
|
4444
|
+
|
|
4445
|
+
clock.requestIdleCallback = function requestIdleCallback(
|
|
4446
|
+
func,
|
|
4447
|
+
{ timeout } = /** @type {{ timeout?: number }} */ ({}),
|
|
4448
|
+
) {
|
|
4449
|
+
/**
|
|
4450
|
+
* @type {IdleDeadline}
|
|
4451
|
+
*/
|
|
4452
|
+
const idleDeadline = {
|
|
4453
|
+
didTimeout: true,
|
|
4454
|
+
timeRemaining: getTimeToNextIdlePeriod,
|
|
4455
|
+
};
|
|
4456
|
+
|
|
3830
4457
|
const result = addTimer(clock, {
|
|
3831
4458
|
func: func,
|
|
3832
|
-
args:
|
|
3833
|
-
delay:
|
|
3834
|
-
|
|
3835
|
-
? timeToNextIdlePeriod
|
|
3836
|
-
: Math.min(timeout, timeToNextIdlePeriod),
|
|
3837
|
-
idleCallback: true,
|
|
4459
|
+
args: [idleDeadline],
|
|
4460
|
+
delay: timeout,
|
|
4461
|
+
requestIdleCallback: true,
|
|
3838
4462
|
});
|
|
3839
4463
|
|
|
3840
4464
|
return Number(result);
|
|
@@ -3874,7 +4498,7 @@ function requireFakeTimersSrc () {
|
|
|
3874
4498
|
return enqueueJob(clock, {
|
|
3875
4499
|
func: func,
|
|
3876
4500
|
args: Array.prototype.slice.call(arguments, 1),
|
|
3877
|
-
error: isNearInfiniteLimit ? new Error() : null,
|
|
4501
|
+
error: clock.isNearInfiniteLimit ? new Error() : null,
|
|
3878
4502
|
});
|
|
3879
4503
|
};
|
|
3880
4504
|
|
|
@@ -3884,7 +4508,7 @@ function requireFakeTimersSrc () {
|
|
|
3884
4508
|
|
|
3885
4509
|
clock.setInterval = function setInterval(func, timeout) {
|
|
3886
4510
|
// eslint-disable-next-line no-param-reassign
|
|
3887
|
-
timeout = parseInt(timeout, 10);
|
|
4511
|
+
timeout = parseInt(String(timeout), 10);
|
|
3888
4512
|
return addTimer(clock, {
|
|
3889
4513
|
func: func,
|
|
3890
4514
|
args: Array.prototype.slice.call(arguments, 2),
|
|
@@ -3898,13 +4522,15 @@ function requireFakeTimersSrc () {
|
|
|
3898
4522
|
};
|
|
3899
4523
|
|
|
3900
4524
|
if (isPresent.setImmediate) {
|
|
3901
|
-
clock.setImmediate =
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
4525
|
+
clock.setImmediate = /** @type {SetImmediate} */ (
|
|
4526
|
+
function setImmediate(func) {
|
|
4527
|
+
return addTimer(clock, {
|
|
4528
|
+
func: func,
|
|
4529
|
+
args: Array.prototype.slice.call(arguments, 1),
|
|
4530
|
+
immediate: true,
|
|
4531
|
+
});
|
|
4532
|
+
}
|
|
4533
|
+
);
|
|
3908
4534
|
|
|
3909
4535
|
if (typeof _global.Promise !== "undefined" && utilPromisify) {
|
|
3910
4536
|
clock.setImmediate[utilPromisify.custom] =
|
|
@@ -3928,7 +4554,7 @@ function requireFakeTimersSrc () {
|
|
|
3928
4554
|
|
|
3929
4555
|
clock.countTimers = function countTimers() {
|
|
3930
4556
|
return (
|
|
3931
|
-
|
|
4557
|
+
(clock.timerHeap ? clock.timerHeap.timers.length : 0) +
|
|
3932
4558
|
(clock.jobs || []).length
|
|
3933
4559
|
);
|
|
3934
4560
|
};
|
|
@@ -3956,12 +4582,9 @@ function requireFakeTimersSrc () {
|
|
|
3956
4582
|
|
|
3957
4583
|
/**
|
|
3958
4584
|
* @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
|
|
4585
|
+
* @returns {ClockState} a mutable state object for the tick execution
|
|
3963
4586
|
*/
|
|
3964
|
-
function
|
|
4587
|
+
function createTickState(tickValue) {
|
|
3965
4588
|
const msFloat =
|
|
3966
4589
|
typeof tickValue === "number"
|
|
3967
4590
|
? tickValue
|
|
@@ -3981,122 +4604,202 @@ function requireFakeTimersSrc () {
|
|
|
3981
4604
|
nanosTotal -= 1e6;
|
|
3982
4605
|
}
|
|
3983
4606
|
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
clock.duringTick = true;
|
|
4607
|
+
return /** @type {ClockState} */ ({
|
|
4608
|
+
msFloat: msFloat,
|
|
4609
|
+
ms: ms,
|
|
4610
|
+
nanosTotal: nanosTotal,
|
|
4611
|
+
tickFrom: clock.now,
|
|
4612
|
+
tickTo: tickTo,
|
|
4613
|
+
previous: clock.now,
|
|
4614
|
+
timer: null,
|
|
4615
|
+
firstException: null,
|
|
4616
|
+
oldNow: null,
|
|
4617
|
+
});
|
|
4618
|
+
}
|
|
3998
4619
|
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4620
|
+
/**
|
|
4621
|
+
* @param {ClockState} state mutable tick state
|
|
4622
|
+
* @param {number} oldNow the clock.now before some action
|
|
4623
|
+
* @param {object} [options] compensation options
|
|
4624
|
+
* @param {boolean} [options.includePrevious] whether to also update state.previous
|
|
4625
|
+
*/
|
|
4626
|
+
function applyClockChangeCompensation(state, oldNow, options) {
|
|
4002
4627
|
if (oldNow !== clock.now) {
|
|
4003
|
-
|
|
4004
|
-
tickFrom +=
|
|
4005
|
-
tickTo +=
|
|
4628
|
+
const difference = clock.now - oldNow;
|
|
4629
|
+
state.tickFrom += difference;
|
|
4630
|
+
state.tickTo += difference;
|
|
4631
|
+
if (options && options.includePrevious) {
|
|
4632
|
+
state.previous += difference;
|
|
4633
|
+
}
|
|
4006
4634
|
}
|
|
4635
|
+
}
|
|
4007
4636
|
|
|
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
|
-
}
|
|
4637
|
+
/**
|
|
4638
|
+
* @param {ClockState} state mutable tick state
|
|
4639
|
+
*/
|
|
4640
|
+
function runInitialJobs(state) {
|
|
4641
|
+
state.oldNow = clock.now;
|
|
4642
|
+
runJobs(clock);
|
|
4643
|
+
applyClockChangeCompensation(state, state.oldNow);
|
|
4644
|
+
}
|
|
4032
4645
|
|
|
4033
|
-
|
|
4034
|
-
|
|
4646
|
+
/**
|
|
4647
|
+
* @param {ClockState} state mutable tick state
|
|
4648
|
+
*/
|
|
4649
|
+
function runPostLoopJobs(state) {
|
|
4650
|
+
state.oldNow = clock.now;
|
|
4651
|
+
runJobs(clock);
|
|
4652
|
+
applyClockChangeCompensation(state, state.oldNow);
|
|
4653
|
+
}
|
|
4035
4654
|
|
|
4036
|
-
|
|
4037
|
-
|
|
4655
|
+
/**
|
|
4656
|
+
* @param {ClockState} state mutable tick state
|
|
4657
|
+
*/
|
|
4658
|
+
function selectNextTimerInRange(state) {
|
|
4659
|
+
state.timer = firstTimerInRange(
|
|
4660
|
+
clock,
|
|
4661
|
+
state.previous,
|
|
4662
|
+
state.tickTo,
|
|
4663
|
+
);
|
|
4664
|
+
state.previous = state.tickFrom;
|
|
4665
|
+
}
|
|
4038
4666
|
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4667
|
+
/**
|
|
4668
|
+
* @param {ClockState} state mutable tick state
|
|
4669
|
+
* @param {boolean} isAsync whether this is an async tick
|
|
4670
|
+
* @param {FakeTimersFunction} nextPromiseTick callback for async promise settlement
|
|
4671
|
+
* @param {FakeTimersFunction} compensationCheck callback for clock change compensation
|
|
4672
|
+
* @returns {boolean} whether an early return was triggered (async mode)
|
|
4673
|
+
*/
|
|
4674
|
+
function runTimersInRange(
|
|
4675
|
+
state,
|
|
4676
|
+
isAsync,
|
|
4677
|
+
nextPromiseTick,
|
|
4678
|
+
compensationCheck,
|
|
4679
|
+
) {
|
|
4680
|
+
state.timer = firstTimerInRange(
|
|
4681
|
+
clock,
|
|
4682
|
+
state.tickFrom,
|
|
4683
|
+
state.tickTo,
|
|
4684
|
+
);
|
|
4048
4685
|
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4686
|
+
while (state.timer && state.tickFrom <= state.tickTo) {
|
|
4687
|
+
if (hasTimer(clock, state.timer.id)) {
|
|
4688
|
+
state.tickFrom = state.timer.callAt;
|
|
4689
|
+
clock.now = state.timer.callAt;
|
|
4690
|
+
state.oldNow = clock.now;
|
|
4052
4691
|
try {
|
|
4053
|
-
|
|
4692
|
+
runJobs(clock);
|
|
4693
|
+
callTimer(clock, state.timer);
|
|
4054
4694
|
} catch (e) {
|
|
4055
|
-
firstException = firstException || e;
|
|
4695
|
+
state.firstException = state.firstException || e;
|
|
4056
4696
|
}
|
|
4057
|
-
} else {
|
|
4058
|
-
// no timers remaining in the requested range: move the clock all the way to the end
|
|
4059
|
-
clock.now = tickTo;
|
|
4060
4697
|
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4698
|
+
if (isAsync) {
|
|
4699
|
+
// finish up after native setImmediate callback to allow
|
|
4700
|
+
// all native es6 promises to process their callbacks after
|
|
4701
|
+
// each timer fires.
|
|
4702
|
+
originalSetTimeout(nextPromiseTick);
|
|
4703
|
+
return true;
|
|
4704
|
+
}
|
|
4705
|
+
|
|
4706
|
+
compensationCheck();
|
|
4066
4707
|
}
|
|
4067
4708
|
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4709
|
+
selectNextTimerInRange(state);
|
|
4710
|
+
}
|
|
4711
|
+
return false;
|
|
4712
|
+
}
|
|
4713
|
+
|
|
4714
|
+
/**
|
|
4715
|
+
* @param {ClockState} state mutable tick state
|
|
4716
|
+
* @param {boolean} isAsync whether this is an async tick
|
|
4717
|
+
* @param {FakeTimersFunction} resolve promise resolve function
|
|
4718
|
+
* @returns {number|undefined} the new clock.now or nothing for async
|
|
4719
|
+
*/
|
|
4720
|
+
function finalizeTick(state, isAsync, resolve) {
|
|
4721
|
+
// corner case: during runJobs new timers were scheduled which could be in the range [clock.now, tickTo]
|
|
4722
|
+
state.timer = firstTimerInRange(
|
|
4723
|
+
clock,
|
|
4724
|
+
state.tickFrom,
|
|
4725
|
+
state.tickTo,
|
|
4726
|
+
);
|
|
4727
|
+
if (state.timer) {
|
|
4728
|
+
try {
|
|
4729
|
+
clock.tick(state.tickTo - clock.now); // do it all again - for the remainder of the requested range
|
|
4730
|
+
} catch (e) {
|
|
4731
|
+
state.firstException = state.firstException || e;
|
|
4072
4732
|
}
|
|
4733
|
+
} else {
|
|
4734
|
+
// no timers remaining in the requested range: move the clock all the way to the end
|
|
4735
|
+
clock.now = state.tickTo;
|
|
4736
|
+
|
|
4737
|
+
// update nanos
|
|
4738
|
+
nanos = state.nanosTotal;
|
|
4739
|
+
}
|
|
4740
|
+
if (state.firstException) {
|
|
4741
|
+
throw state.firstException;
|
|
4073
4742
|
}
|
|
4074
4743
|
|
|
4075
|
-
|
|
4744
|
+
if (isAsync) {
|
|
4745
|
+
resolve(clock.now);
|
|
4746
|
+
} else {
|
|
4747
|
+
return clock.now;
|
|
4748
|
+
}
|
|
4749
|
+
}
|
|
4750
|
+
|
|
4751
|
+
/**
|
|
4752
|
+
* @param {number|string} tickValue milliseconds or a string parseable by parseTime
|
|
4753
|
+
* @param {boolean} isAsync whether this is an async tick
|
|
4754
|
+
* @param {FakeTimersFunction} [resolve] promise resolve function
|
|
4755
|
+
* @param {FakeTimersFunction} [reject] promise reject function
|
|
4756
|
+
* @returns {number|undefined} the new clock.now or nothing for async
|
|
4757
|
+
*/
|
|
4758
|
+
function doTick(tickValue, isAsync, resolve, reject) {
|
|
4759
|
+
/** @type {ClockState} */
|
|
4760
|
+
const state = createTickState(tickValue);
|
|
4761
|
+
|
|
4762
|
+
nanos = state.nanosTotal;
|
|
4763
|
+
clock.duringTick = true;
|
|
4764
|
+
|
|
4765
|
+
runInitialJobs(state);
|
|
4766
|
+
|
|
4767
|
+
const compensationCheck = function () {
|
|
4768
|
+
applyClockChangeCompensation(state, state.oldNow, {
|
|
4769
|
+
includePrevious: true,
|
|
4770
|
+
});
|
|
4771
|
+
};
|
|
4772
|
+
|
|
4773
|
+
const nextPromiseTick =
|
|
4076
4774
|
isAsync &&
|
|
4077
4775
|
function () {
|
|
4078
4776
|
try {
|
|
4079
4777
|
compensationCheck();
|
|
4080
|
-
|
|
4778
|
+
selectNextTimerInRange(state);
|
|
4081
4779
|
doTickInner();
|
|
4082
4780
|
} catch (e) {
|
|
4083
4781
|
reject(e);
|
|
4084
4782
|
}
|
|
4085
4783
|
};
|
|
4086
4784
|
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
if (
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4785
|
+
//eslint-disable-next-line jsdoc/require-jsdoc
|
|
4786
|
+
function doTickInner() {
|
|
4787
|
+
if (
|
|
4788
|
+
runTimersInRange(
|
|
4789
|
+
state,
|
|
4790
|
+
isAsync,
|
|
4791
|
+
nextPromiseTick,
|
|
4792
|
+
compensationCheck,
|
|
4793
|
+
)
|
|
4794
|
+
) {
|
|
4795
|
+
return;
|
|
4093
4796
|
}
|
|
4094
|
-
};
|
|
4095
4797
|
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4798
|
+
runPostLoopJobs(state);
|
|
4799
|
+
clock.duringTick = false;
|
|
4800
|
+
|
|
4801
|
+
return finalizeTick(state, isAsync, resolve);
|
|
4802
|
+
}
|
|
4100
4803
|
|
|
4101
4804
|
return doTickInner();
|
|
4102
4805
|
}
|
|
@@ -4109,26 +4812,6 @@ function requireFakeTimersSrc () {
|
|
|
4109
4812
|
return doTick(tickValue, false);
|
|
4110
4813
|
};
|
|
4111
4814
|
|
|
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
4815
|
clock.next = function next() {
|
|
4133
4816
|
runJobs(clock);
|
|
4134
4817
|
const timer = firstTimer(clock);
|
|
@@ -4147,61 +4830,40 @@ function requireFakeTimersSrc () {
|
|
|
4147
4830
|
}
|
|
4148
4831
|
};
|
|
4149
4832
|
|
|
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
|
-
};
|
|
4833
|
+
/**
|
|
4834
|
+
* @param {(resolve: (value: unknown) => void, reject: (reason?: unknown) => void) => void} callback function to run inside native setTimeout
|
|
4835
|
+
* @returns {Promise}
|
|
4836
|
+
*/
|
|
4837
|
+
function runAsyncWithNativeTimeout(callback) {
|
|
4838
|
+
return pauseAutoTickUntilFinished(
|
|
4839
|
+
new _global.Promise(function (resolve, reject) {
|
|
4840
|
+
originalSetTimeout(function () {
|
|
4841
|
+
try {
|
|
4842
|
+
callback(resolve, reject);
|
|
4843
|
+
} catch (e) {
|
|
4844
|
+
reject(e);
|
|
4845
|
+
}
|
|
4846
|
+
});
|
|
4847
|
+
}),
|
|
4848
|
+
);
|
|
4186
4849
|
}
|
|
4187
4850
|
|
|
4188
4851
|
clock.runAll = function runAll() {
|
|
4189
|
-
let numTimers, i;
|
|
4190
4852
|
runJobs(clock);
|
|
4191
|
-
for (i = 0; i < clock.loopLimit; i++) {
|
|
4853
|
+
for (let i = 0; i < clock.loopLimit; i++) {
|
|
4192
4854
|
if (!clock.timers) {
|
|
4193
|
-
resetIsNearInfiniteLimit();
|
|
4855
|
+
resetIsNearInfiniteLimit(clock);
|
|
4194
4856
|
return clock.now;
|
|
4195
4857
|
}
|
|
4196
4858
|
|
|
4197
|
-
numTimers =
|
|
4859
|
+
const numTimers = clock.timerHeap.timers.length;
|
|
4198
4860
|
if (numTimers === 0) {
|
|
4199
|
-
resetIsNearInfiniteLimit();
|
|
4861
|
+
resetIsNearInfiniteLimit(clock);
|
|
4200
4862
|
return clock.now;
|
|
4201
4863
|
}
|
|
4202
4864
|
|
|
4203
|
-
clock.next();
|
|
4204
4865
|
checkIsNearInfiniteLimit(clock, i);
|
|
4866
|
+
clock.next();
|
|
4205
4867
|
}
|
|
4206
4868
|
|
|
4207
4869
|
const excessJob = firstTimer(clock);
|
|
@@ -4212,60 +4874,6 @@ function requireFakeTimersSrc () {
|
|
|
4212
4874
|
return clock.tick(getTimeToNextFrame());
|
|
4213
4875
|
};
|
|
4214
4876
|
|
|
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
4877
|
clock.runToLast = function runToLast() {
|
|
4270
4878
|
const timer = lastTimer(clock);
|
|
4271
4879
|
if (!timer) {
|
|
@@ -4277,32 +4885,110 @@ function requireFakeTimersSrc () {
|
|
|
4277
4885
|
};
|
|
4278
4886
|
|
|
4279
4887
|
if (typeof _global.Promise !== "undefined") {
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
}
|
|
4888
|
+
/**
|
|
4889
|
+
* @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
|
|
4890
|
+
* @returns {Promise}
|
|
4891
|
+
*/
|
|
4892
|
+
clock.tickAsync = function tickAsync(tickValue) {
|
|
4893
|
+
return runAsyncWithNativeTimeout(function (resolve, reject) {
|
|
4894
|
+
doTick(tickValue, true, resolve, reject);
|
|
4895
|
+
});
|
|
4896
|
+
};
|
|
4290
4897
|
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4898
|
+
clock.nextAsync = function nextAsync() {
|
|
4899
|
+
return runAsyncWithNativeTimeout(function (resolve, reject) {
|
|
4900
|
+
const timer = firstTimer(clock);
|
|
4901
|
+
if (!timer) {
|
|
4902
|
+
resolve(clock.now);
|
|
4903
|
+
return;
|
|
4904
|
+
}
|
|
4905
|
+
|
|
4906
|
+
let err;
|
|
4907
|
+
clock.duringTick = true;
|
|
4908
|
+
clock.now = timer.callAt;
|
|
4909
|
+
try {
|
|
4910
|
+
callTimer(clock, timer);
|
|
4911
|
+
} catch (e) {
|
|
4912
|
+
err = e;
|
|
4913
|
+
}
|
|
4914
|
+
clock.duringTick = false;
|
|
4915
|
+
|
|
4916
|
+
originalSetTimeout(function () {
|
|
4917
|
+
if (err) {
|
|
4918
|
+
reject(err);
|
|
4919
|
+
} else {
|
|
4920
|
+
resolve(clock.now);
|
|
4921
|
+
}
|
|
4922
|
+
});
|
|
4923
|
+
});
|
|
4924
|
+
};
|
|
4925
|
+
|
|
4926
|
+
clock.runAllAsync = function runAllAsync() {
|
|
4927
|
+
let i = 0;
|
|
4928
|
+
/**
|
|
4929
|
+
* @param {(value: unknown) => void} resolve promise resolve function
|
|
4930
|
+
* @param {(reason?: unknown) => void} reject promise reject function
|
|
4931
|
+
*/
|
|
4932
|
+
function doRun(resolve, reject) {
|
|
4933
|
+
try {
|
|
4934
|
+
runJobs(clock);
|
|
4935
|
+
|
|
4936
|
+
let numTimers;
|
|
4937
|
+
if (i < clock.loopLimit) {
|
|
4938
|
+
if (!clock.timerHeap) {
|
|
4939
|
+
resetIsNearInfiniteLimit(clock);
|
|
4940
|
+
resolve(clock.now);
|
|
4941
|
+
return;
|
|
4296
4942
|
}
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4943
|
+
|
|
4944
|
+
numTimers = clock.timerHeap.timers.length;
|
|
4945
|
+
if (numTimers === 0) {
|
|
4946
|
+
resetIsNearInfiniteLimit(clock);
|
|
4947
|
+
resolve(clock.now);
|
|
4948
|
+
return;
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4951
|
+
checkIsNearInfiniteLimit(clock, i);
|
|
4952
|
+
clock.next();
|
|
4953
|
+
|
|
4954
|
+
i++;
|
|
4955
|
+
|
|
4956
|
+
originalSetTimeout(function () {
|
|
4957
|
+
doRun(resolve, reject);
|
|
4958
|
+
});
|
|
4959
|
+
return;
|
|
4960
|
+
}
|
|
4961
|
+
|
|
4962
|
+
const excessJob = firstTimer(clock);
|
|
4963
|
+
reject(getInfiniteLoopError(clock, excessJob));
|
|
4964
|
+
} catch (e) {
|
|
4965
|
+
reject(e);
|
|
4966
|
+
}
|
|
4967
|
+
}
|
|
4968
|
+
|
|
4969
|
+
return runAsyncWithNativeTimeout(function (resolve, reject) {
|
|
4970
|
+
doRun(resolve, reject);
|
|
4971
|
+
});
|
|
4972
|
+
};
|
|
4973
|
+
|
|
4974
|
+
clock.runToLastAsync = function runToLastAsync() {
|
|
4975
|
+
return runAsyncWithNativeTimeout(function (resolve) {
|
|
4976
|
+
const timer = lastTimer(clock);
|
|
4977
|
+
if (!timer) {
|
|
4978
|
+
runJobs(clock);
|
|
4979
|
+
resolve(clock.now);
|
|
4980
|
+
return;
|
|
4981
|
+
}
|
|
4982
|
+
|
|
4983
|
+
resolve(clock.tickAsync(timer.callAt - clock.now));
|
|
4984
|
+
});
|
|
4300
4985
|
};
|
|
4301
4986
|
}
|
|
4302
4987
|
|
|
4303
4988
|
clock.reset = function reset() {
|
|
4304
4989
|
nanos = 0;
|
|
4305
|
-
clock.timers =
|
|
4990
|
+
clock.timers = new Map();
|
|
4991
|
+
clock.timerHeap = new TimerHeap();
|
|
4306
4992
|
clock.jobs = [];
|
|
4307
4993
|
clock.now = start;
|
|
4308
4994
|
};
|
|
@@ -4311,7 +4997,6 @@ function requireFakeTimersSrc () {
|
|
|
4311
4997
|
// determine time difference
|
|
4312
4998
|
const newNow = getEpoch(systemTime);
|
|
4313
4999
|
const difference = newNow - clock.now;
|
|
4314
|
-
let id, timer;
|
|
4315
5000
|
|
|
4316
5001
|
adjustedSystemTime[0] = adjustedSystemTime[0] + difference;
|
|
4317
5002
|
adjustedSystemTime[1] = adjustedSystemTime[1] + nanos;
|
|
@@ -4320,18 +5005,15 @@ function requireFakeTimersSrc () {
|
|
|
4320
5005
|
nanos = 0;
|
|
4321
5006
|
|
|
4322
5007
|
// update timers and intervals to keep them stable
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
timer.callAt += difference;
|
|
4328
|
-
}
|
|
4329
|
-
}
|
|
5008
|
+
forEachActiveTimer(clock, (timer) => {
|
|
5009
|
+
timer.createdAt += difference;
|
|
5010
|
+
timer.callAt += difference;
|
|
5011
|
+
});
|
|
4330
5012
|
};
|
|
4331
5013
|
|
|
4332
5014
|
/**
|
|
4333
5015
|
* @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
|
|
4334
|
-
* @returns {number}
|
|
5016
|
+
* @returns {number} the new `now` value
|
|
4335
5017
|
*/
|
|
4336
5018
|
clock.jump = function jump(tickValue) {
|
|
4337
5019
|
const msFloat =
|
|
@@ -4340,12 +5022,17 @@ function requireFakeTimersSrc () {
|
|
|
4340
5022
|
: parseTime(tickValue);
|
|
4341
5023
|
const ms = Math.floor(msFloat);
|
|
4342
5024
|
|
|
4343
|
-
|
|
5025
|
+
forEachActiveTimer(clock, (timer) => {
|
|
4344
5026
|
if (clock.now + ms > timer.callAt) {
|
|
4345
5027
|
timer.callAt = clock.now + ms;
|
|
4346
5028
|
}
|
|
4347
|
-
}
|
|
5029
|
+
});
|
|
5030
|
+
|
|
5031
|
+
// Rebuild heap as order might have changed
|
|
5032
|
+
rebuildTimerHeap(clock);
|
|
5033
|
+
|
|
4348
5034
|
clock.tick(ms);
|
|
5035
|
+
return clock.now;
|
|
4349
5036
|
};
|
|
4350
5037
|
|
|
4351
5038
|
if (isPresent.performance) {
|
|
@@ -4360,6 +5047,11 @@ function requireFakeTimersSrc () {
|
|
|
4360
5047
|
return clock;
|
|
4361
5048
|
}
|
|
4362
5049
|
|
|
5050
|
+
/**
|
|
5051
|
+
* Starts the interval used to advance the clock automatically.
|
|
5052
|
+
* @param {Clock} clock
|
|
5053
|
+
* @param {number} delta
|
|
5054
|
+
*/
|
|
4363
5055
|
function createIntervalTick(clock, delta) {
|
|
4364
5056
|
const intervalTick = doIntervalTick.bind(null, clock, delta);
|
|
4365
5057
|
const intervalId = originalSetInterval(intervalTick, delta);
|
|
@@ -4401,6 +5093,21 @@ function requireFakeTimersSrc () {
|
|
|
4401
5093
|
config.shouldClearNativeTimers =
|
|
4402
5094
|
config.shouldClearNativeTimers || false;
|
|
4403
5095
|
|
|
5096
|
+
const hasToFake = Object.prototype.hasOwnProperty.call(
|
|
5097
|
+
config,
|
|
5098
|
+
"toFake",
|
|
5099
|
+
);
|
|
5100
|
+
const hasToNotFake = Object.prototype.hasOwnProperty.call(
|
|
5101
|
+
config,
|
|
5102
|
+
"toNotFake",
|
|
5103
|
+
);
|
|
5104
|
+
|
|
5105
|
+
if (hasToFake && hasToNotFake) {
|
|
5106
|
+
throw new TypeError(
|
|
5107
|
+
"config.toFake and config.toNotFake cannot be used together",
|
|
5108
|
+
);
|
|
5109
|
+
}
|
|
5110
|
+
|
|
4404
5111
|
if (config.target) {
|
|
4405
5112
|
throw new TypeError(
|
|
4406
5113
|
"config.target is no longer supported. Use `withGlobal(target)` instead.",
|
|
@@ -4408,8 +5115,8 @@ function requireFakeTimersSrc () {
|
|
|
4408
5115
|
}
|
|
4409
5116
|
|
|
4410
5117
|
/**
|
|
4411
|
-
*
|
|
4412
|
-
* @param timer
|
|
5118
|
+
* Handles a missing timer or API name during installation.
|
|
5119
|
+
* @param {string} timer - the name of the missing timer or object
|
|
4413
5120
|
*/
|
|
4414
5121
|
function handleMissingTimer(timer) {
|
|
4415
5122
|
if (config.ignoreMissingTimers) {
|
|
@@ -4431,10 +5138,24 @@ function requireFakeTimersSrc () {
|
|
|
4431
5138
|
|
|
4432
5139
|
clock.abortListenerMap = new Map();
|
|
4433
5140
|
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
5141
|
+
if (hasToFake) {
|
|
5142
|
+
clock.methods = /** @type {FakeMethod[]} */ (config.toFake || []);
|
|
5143
|
+
if (clock.methods.length === 0) {
|
|
5144
|
+
clock.methods = /** @type {FakeMethod[]} */ (
|
|
5145
|
+
Object.keys(timers)
|
|
5146
|
+
);
|
|
5147
|
+
}
|
|
5148
|
+
} else if (hasToNotFake) {
|
|
5149
|
+
const methodsToNotFake = /** @type {string[]} */ (
|
|
5150
|
+
config.toNotFake || []
|
|
5151
|
+
);
|
|
5152
|
+
clock.methods = /** @type {FakeMethod[]} */ (
|
|
5153
|
+
Object.keys(timers).filter(
|
|
5154
|
+
(method) => !methodsToNotFake.includes(method),
|
|
5155
|
+
)
|
|
5156
|
+
);
|
|
5157
|
+
} else {
|
|
5158
|
+
clock.methods = /** @type {FakeMethod[]} */ (Object.keys(timers));
|
|
4438
5159
|
}
|
|
4439
5160
|
|
|
4440
5161
|
if (config.shouldAdvanceTime === true) {
|
|
@@ -4471,7 +5192,7 @@ function requireFakeTimersSrc () {
|
|
|
4471
5192
|
// (or the Worker was installed)
|
|
4472
5193
|
clock.performance.timeOrigin = getEpoch(config.now);
|
|
4473
5194
|
} else if ((config.toFake || []).includes("performance")) {
|
|
4474
|
-
|
|
5195
|
+
handleMissingTimer("performance");
|
|
4475
5196
|
}
|
|
4476
5197
|
}
|
|
4477
5198
|
if (_global === globalObject && timersModule) {
|
|
@@ -4635,10 +5356,13 @@ function requireFakeTimersSrc () {
|
|
|
4635
5356
|
[Symbol.asyncIterator]: () => {
|
|
4636
5357
|
const createResolvable = () => {
|
|
4637
5358
|
let resolve, reject;
|
|
4638
|
-
const promise =
|
|
4639
|
-
resolve
|
|
4640
|
-
|
|
4641
|
-
|
|
5359
|
+
const promise =
|
|
5360
|
+
/** @type {Promise<unknown> & { resolve: (value: unknown) => void; reject: (reason: unknown) => void }} */ (
|
|
5361
|
+
new Promise((res, rej) => {
|
|
5362
|
+
resolve = res;
|
|
5363
|
+
reject = rej;
|
|
5364
|
+
})
|
|
5365
|
+
);
|
|
4642
5366
|
promise.resolve = resolve;
|
|
4643
5367
|
promise.reject = reject;
|
|
4644
5368
|
return promise;
|
|
@@ -4766,22 +5490,13 @@ function requireFakeTimersSrc () {
|
|
|
4766
5490
|
};
|
|
4767
5491
|
}
|
|
4768
5492
|
|
|
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
5493
|
/** @type {FakeTimers} */
|
|
4780
5494
|
const defaultImplementation = withGlobal(globalObject);
|
|
4781
5495
|
|
|
4782
5496
|
fakeTimersSrc.timers = defaultImplementation.timers;
|
|
4783
5497
|
fakeTimersSrc.createClock = defaultImplementation.createClock;
|
|
4784
5498
|
fakeTimersSrc.install = defaultImplementation.install;
|
|
5499
|
+
/** @type {WithGlobal} */
|
|
4785
5500
|
fakeTimersSrc.withGlobal = withGlobal;
|
|
4786
5501
|
return fakeTimersSrc;
|
|
4787
5502
|
}
|
|
@@ -4872,12 +5587,18 @@ class FakeTimers {
|
|
|
4872
5587
|
this._fakingDate = null;
|
|
4873
5588
|
}
|
|
4874
5589
|
if (this._fakingTime) this._clock.uninstall();
|
|
4875
|
-
|
|
4876
|
-
if (
|
|
5590
|
+
let toFake = this._userConfig?.toFake;
|
|
5591
|
+
if (isChildProcess() && toFake?.includes("nextTick")) throw new Error("process.nextTick cannot be mocked inside child_process");
|
|
5592
|
+
let toNotFake = this._userConfig?.toNotFake;
|
|
5593
|
+
if (toFake === void 0 && toNotFake === void 0)
|
|
5594
|
+
// Do not mock timers internally used by node by default. It can still be mocked through userConfig.
|
|
5595
|
+
toFake = Object.keys(this._fakeTimers.timers).filter((timer) => timer !== "nextTick" && timer !== "queueMicrotask");
|
|
5596
|
+
if (isChildProcess() && toNotFake && !toNotFake.includes("nextTick")) toNotFake = [...toNotFake, "nextTick"];
|
|
4877
5597
|
this._clock = this._fakeTimers.install({
|
|
4878
5598
|
now: fakeDate,
|
|
4879
5599
|
...this._userConfig,
|
|
4880
|
-
toFake
|
|
5600
|
+
...toFake && { toFake },
|
|
5601
|
+
...toNotFake && { toNotFake },
|
|
4881
5602
|
ignoreMissingTimers: true
|
|
4882
5603
|
});
|
|
4883
5604
|
this._fakingTime = true;
|
|
@@ -5325,7 +6046,9 @@ function createExpectPoll(expect) {
|
|
|
5325
6046
|
const promise = async () => {
|
|
5326
6047
|
chai.util.flag(assertion, "_name", key);
|
|
5327
6048
|
chai.util.flag(assertion, "error", STACK_TRACE_ERROR);
|
|
6049
|
+
const onStart = chai.util.flag(assertion, "_poll.onStart");
|
|
5328
6050
|
const onSettled = chai.util.flag(assertion, "_poll.onSettled");
|
|
6051
|
+
await onStart?.({ assertion });
|
|
5329
6052
|
if (Object.getOwnPropertyDescriptor(assertionFunction, "__vitest_poll_takeover__")?.value) try {
|
|
5330
6053
|
const output = await assertionFunction.call(assertion, ...args);
|
|
5331
6054
|
await onSettled?.({
|
|
@@ -5341,41 +6064,53 @@ function createExpectPoll(expect) {
|
|
|
5341
6064
|
throwWithCause(err, STACK_TRACE_ERROR);
|
|
5342
6065
|
}
|
|
5343
6066
|
const { setTimeout, clearTimeout } = getSafeTimers();
|
|
5344
|
-
let
|
|
5345
|
-
|
|
5346
|
-
const
|
|
5347
|
-
|
|
5348
|
-
|
|
6067
|
+
let timerId;
|
|
6068
|
+
const timeoutController = new AbortController();
|
|
6069
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
6070
|
+
timerId = setTimeout(() => {
|
|
6071
|
+
timeoutController.abort();
|
|
6072
|
+
resolve();
|
|
6073
|
+
}, timeout);
|
|
6074
|
+
});
|
|
6075
|
+
let lastError;
|
|
5349
6076
|
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);
|
|
6077
|
+
while (true) try {
|
|
6078
|
+
const fnResult = await raceWith$1(Promise.resolve().then(() => fn({ signal: timeoutController.signal })), timeoutPromise);
|
|
6079
|
+
if (!fnResult.ok) {
|
|
6080
|
+
lastError ??= /* @__PURE__ */ new Error(`expect.poll() function didn't resolve in time.`);
|
|
6081
|
+
break;
|
|
5374
6082
|
}
|
|
6083
|
+
const obj = fnResult.value;
|
|
6084
|
+
chai.util.flag(assertion, "object", obj);
|
|
6085
|
+
const assertionResult = await raceWith$1(Promise.resolve().then(() => assertionFunction.apply(assertion, args)), timeoutPromise);
|
|
6086
|
+
if (!assertionResult.ok) {
|
|
6087
|
+
lastError ??= /* @__PURE__ */ new Error(`expect.poll() assertion didn't resolve in time.`);
|
|
6088
|
+
break;
|
|
6089
|
+
}
|
|
6090
|
+
const output = assertionResult.value;
|
|
6091
|
+
await onSettled?.({
|
|
6092
|
+
assertion,
|
|
6093
|
+
status: "pass"
|
|
6094
|
+
});
|
|
6095
|
+
return output;
|
|
6096
|
+
} catch (err) {
|
|
6097
|
+
lastError = err;
|
|
6098
|
+
// no retry for toMatchScreenshot since
|
|
6099
|
+
// it owns retry/stability after the first element resolution
|
|
6100
|
+
if (key === "toMatchScreenshot") break;
|
|
6101
|
+
if (!(await raceWith$1(delay(interval, setTimeout), timeoutPromise)).ok) break;
|
|
6102
|
+
if (vi.isFakeTimers()) vi.advanceTimersByTime(interval);
|
|
5375
6103
|
}
|
|
5376
6104
|
} finally {
|
|
5377
6105
|
clearTimeout(timerId);
|
|
5378
6106
|
}
|
|
6107
|
+
if (lastError) {
|
|
6108
|
+
await onSettled?.({
|
|
6109
|
+
assertion,
|
|
6110
|
+
status: "fail"
|
|
6111
|
+
});
|
|
6112
|
+
throwWithCause(lastError, STACK_TRACE_ERROR);
|
|
6113
|
+
}
|
|
5379
6114
|
};
|
|
5380
6115
|
let awaited = false;
|
|
5381
6116
|
test.onFinished ??= [];
|
|
@@ -5413,6 +6148,17 @@ function copyStackTrace(target, source) {
|
|
|
5413
6148
|
if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
|
|
5414
6149
|
return target;
|
|
5415
6150
|
}
|
|
6151
|
+
function raceWith$1(promise, other) {
|
|
6152
|
+
const left = promise.then((value) => ({
|
|
6153
|
+
ok: true,
|
|
6154
|
+
value
|
|
6155
|
+
}));
|
|
6156
|
+
if (!other) return left;
|
|
6157
|
+
return Promise.race([left, other.then((value) => ({
|
|
6158
|
+
ok: false,
|
|
6159
|
+
value
|
|
6160
|
+
}))]);
|
|
6161
|
+
}
|
|
5416
6162
|
|
|
5417
6163
|
var naturalCompare$1 = {exports: {}};
|
|
5418
6164
|
|
|
@@ -6303,11 +7049,15 @@ class SnapshotClient {
|
|
|
6303
7049
|
inlineSnapshot
|
|
6304
7050
|
});
|
|
6305
7051
|
const reference = expectedSnapshot.data !== void 0 && snapshotState.snapshotUpdateState !== "all" ? adapter.parseExpected(expectedSnapshot.data) : void 0;
|
|
7052
|
+
const timeoutController = new AbortController();
|
|
6306
7053
|
const stableResult = await getStableSnapshot({
|
|
6307
7054
|
adapter,
|
|
6308
|
-
poll,
|
|
7055
|
+
poll: () => poll({ signal: timeoutController.signal }),
|
|
6309
7056
|
interval,
|
|
6310
|
-
timedOut: timeout > 0 ? new Promise((r) => setTimeout(
|
|
7057
|
+
timedOut: timeout > 0 ? new Promise((r) => setTimeout(() => {
|
|
7058
|
+
timeoutController.abort();
|
|
7059
|
+
r();
|
|
7060
|
+
}, timeout)) : void 0,
|
|
6311
7061
|
match: reference ? (captured) => adapter.match(captured, reference).pass : void 0
|
|
6312
7062
|
});
|
|
6313
7063
|
expectedSnapshot.markAsChecked();
|