source: frontend/node_modules/@sinonjs/fake-timers/src/fake-timers-src.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 13 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 55.2 KB
Line 
1"use strict";
2
3const globalObject = require("@sinonjs/commons").global;
4
5/**
6 * @typedef {object} IdleDeadline
7 * @property {boolean} didTimeout - whether or not the callback was called before reaching the optional timeout
8 * @property {function():number} timeRemaining - a floating-point value providing an estimate of the number of milliseconds remaining in the current idle period
9 */
10
11/**
12 * Queues a function to be called during a browser's idle periods
13 *
14 * @callback RequestIdleCallback
15 * @param {function(IdleDeadline)} callback
16 * @param {{timeout: number}} options - an options object
17 * @returns {number} the id
18 */
19
20/**
21 * @callback NextTick
22 * @param {VoidVarArgsFunc} callback - the callback to run
23 * @param {...*} arguments - optional arguments to call the callback with
24 * @returns {void}
25 */
26
27/**
28 * @callback SetImmediate
29 * @param {VoidVarArgsFunc} callback - the callback to run
30 * @param {...*} arguments - optional arguments to call the callback with
31 * @returns {NodeImmediate}
32 */
33
34/**
35 * @callback VoidVarArgsFunc
36 * @param {...*} callback - the callback to run
37 * @returns {void}
38 */
39
40/**
41 * @typedef RequestAnimationFrame
42 * @property {function(number):void} requestAnimationFrame
43 * @returns {number} - the id
44 */
45
46/**
47 * @typedef Performance
48 * @property {function(): number} now
49 */
50
51/* eslint-disable jsdoc/require-property-description */
52/**
53 * @typedef {object} Clock
54 * @property {number} now - the current time
55 * @property {Date} Date - the Date constructor
56 * @property {number} loopLimit - the maximum number of timers before assuming an infinite loop
57 * @property {RequestIdleCallback} requestIdleCallback
58 * @property {function(number):void} cancelIdleCallback
59 * @property {setTimeout} setTimeout
60 * @property {clearTimeout} clearTimeout
61 * @property {NextTick} nextTick
62 * @property {queueMicrotask} queueMicrotask
63 * @property {setInterval} setInterval
64 * @property {clearInterval} clearInterval
65 * @property {SetImmediate} setImmediate
66 * @property {function(NodeImmediate):void} clearImmediate
67 * @property {function():number} countTimers
68 * @property {RequestAnimationFrame} requestAnimationFrame
69 * @property {function(number):void} cancelAnimationFrame
70 * @property {function():void} runMicrotasks
71 * @property {function(string | number): number} tick
72 * @property {function(string | number): Promise<number>} tickAsync
73 * @property {function(): number} next
74 * @property {function(): Promise<number>} nextAsync
75 * @property {function(): number} runAll
76 * @property {function(): number} runToFrame
77 * @property {function(): Promise<number>} runAllAsync
78 * @property {function(): number} runToLast
79 * @property {function(): Promise<number>} runToLastAsync
80 * @property {function(): void} reset
81 * @property {function(number | Date): void} setSystemTime
82 * @property {Performance} performance
83 * @property {function(number[]): number[]} hrtime - process.hrtime (legacy)
84 * @property {function(): void} uninstall Uninstall the clock.
85 * @property {Function[]} methods - the methods that are faked
86 * @property {boolean} [shouldClearNativeTimers] inherited from config
87 */
88/* eslint-enable jsdoc/require-property-description */
89
90/**
91 * Configuration object for the `install` method.
92 *
93 * @typedef {object} Config
94 * @property {number|Date} [now] a number (in milliseconds) or a Date object (default epoch)
95 * @property {string[]} [toFake] names of the methods that should be faked.
96 * @property {number} [loopLimit] the maximum number of timers that will be run when calling runAll()
97 * @property {boolean} [shouldAdvanceTime] tells FakeTimers to increment mocked time automatically (default false)
98 * @property {number} [advanceTimeDelta] increment mocked time every <<advanceTimeDelta>> ms (default: 20ms)
99 * @property {boolean} [shouldClearNativeTimers] forwards clear timer calls to native functions if they are not fakes (default: false)
100 */
101
102/* eslint-disable jsdoc/require-property-description */
103/**
104 * The internal structure to describe a scheduled fake timer
105 *
106 * @typedef {object} Timer
107 * @property {Function} func
108 * @property {*[]} args
109 * @property {number} delay
110 * @property {number} callAt
111 * @property {number} createdAt
112 * @property {boolean} immediate
113 * @property {number} id
114 * @property {Error} [error]
115 */
116
117/**
118 * A Node timer
119 *
120 * @typedef {object} NodeImmediate
121 * @property {function(): boolean} hasRef
122 * @property {function(): NodeImmediate} ref
123 * @property {function(): NodeImmediate} unref
124 */
125/* eslint-enable jsdoc/require-property-description */
126
127/* eslint-disable complexity */
128
129/**
130 * Mocks available features in the specified global namespace.
131 *
132 * @param {*} _global Namespace to mock (e.g. `window`)
133 * @returns {FakeTimers}
134 */
135function withGlobal(_global) {
136 const userAgent = _global.navigator && _global.navigator.userAgent;
137 const isRunningInIE = userAgent && userAgent.indexOf("MSIE ") > -1;
138 const maxTimeout = Math.pow(2, 31) - 1; //see https://heycam.github.io/webidl/#abstract-opdef-converttoint
139 const idCounterStart = 1e12; // arbitrarily large number to avoid collisions with native timer IDs
140 const NOOP = function () {
141 return undefined;
142 };
143 const NOOP_ARRAY = function () {
144 return [];
145 };
146 const timeoutResult = _global.setTimeout(NOOP, 0);
147 const addTimerReturnsObject = typeof timeoutResult === "object";
148 const hrtimePresent =
149 _global.process && typeof _global.process.hrtime === "function";
150 const hrtimeBigintPresent =
151 hrtimePresent && typeof _global.process.hrtime.bigint === "function";
152 const nextTickPresent =
153 _global.process && typeof _global.process.nextTick === "function";
154 const utilPromisify = _global.process && require("util").promisify;
155 const performancePresent =
156 _global.performance && typeof _global.performance.now === "function";
157 const hasPerformancePrototype =
158 _global.Performance &&
159 (typeof _global.Performance).match(/^(function|object)$/);
160 const queueMicrotaskPresent = _global.hasOwnProperty("queueMicrotask");
161 const requestAnimationFramePresent =
162 _global.requestAnimationFrame &&
163 typeof _global.requestAnimationFrame === "function";
164 const cancelAnimationFramePresent =
165 _global.cancelAnimationFrame &&
166 typeof _global.cancelAnimationFrame === "function";
167 const requestIdleCallbackPresent =
168 _global.requestIdleCallback &&
169 typeof _global.requestIdleCallback === "function";
170 const cancelIdleCallbackPresent =
171 _global.cancelIdleCallback &&
172 typeof _global.cancelIdleCallback === "function";
173 const setImmediatePresent =
174 _global.setImmediate && typeof _global.setImmediate === "function";
175
176 // Make properties writable in IE, as per
177 // https://www.adequatelygood.com/Replacing-setTimeout-Globally.html
178 /* eslint-disable no-self-assign */
179 if (isRunningInIE) {
180 _global.setTimeout = _global.setTimeout;
181 _global.clearTimeout = _global.clearTimeout;
182 _global.setInterval = _global.setInterval;
183 _global.clearInterval = _global.clearInterval;
184 _global.Date = _global.Date;
185 }
186
187 // setImmediate is not a standard function
188 // avoid adding the prop to the window object if not present
189 if (setImmediatePresent) {
190 _global.setImmediate = _global.setImmediate;
191 _global.clearImmediate = _global.clearImmediate;
192 }
193 /* eslint-enable no-self-assign */
194
195 _global.clearTimeout(timeoutResult);
196
197 const NativeDate = _global.Date;
198 let uniqueTimerId = idCounterStart;
199
200 /**
201 * @param {number} num
202 * @returns {boolean}
203 */
204 function isNumberFinite(num) {
205 if (Number.isFinite) {
206 return Number.isFinite(num);
207 }
208
209 return isFinite(num);
210 }
211
212 let isNearInfiniteLimit = false;
213
214 /**
215 * @param {Clock} clock
216 * @param {number} i
217 */
218 function checkIsNearInfiniteLimit(clock, i) {
219 if (clock.loopLimit && i === clock.loopLimit - 1) {
220 isNearInfiniteLimit = true;
221 }
222 }
223
224 /**
225 *
226 */
227 function resetIsNearInfiniteLimit() {
228 isNearInfiniteLimit = false;
229 }
230
231 /**
232 * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
233 * number of milliseconds. This is used to support human-readable strings passed
234 * to clock.tick()
235 *
236 * @param {string} str
237 * @returns {number}
238 */
239 function parseTime(str) {
240 if (!str) {
241 return 0;
242 }
243
244 const strings = str.split(":");
245 const l = strings.length;
246 let i = l;
247 let ms = 0;
248 let parsed;
249
250 if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
251 throw new Error(
252 "tick only understands numbers, 'm:s' and 'h:m:s'. Each part must be two digits"
253 );
254 }
255
256 while (i--) {
257 parsed = parseInt(strings[i], 10);
258
259 if (parsed >= 60) {
260 throw new Error(`Invalid time ${str}`);
261 }
262
263 ms += parsed * Math.pow(60, l - i - 1);
264 }
265
266 return ms * 1000;
267 }
268
269 /**
270 * Get the decimal part of the millisecond value as nanoseconds
271 *
272 * @param {number} msFloat the number of milliseconds
273 * @returns {number} an integer number of nanoseconds in the range [0,1e6)
274 *
275 * Example: nanoRemainer(123.456789) -> 456789
276 */
277 function nanoRemainder(msFloat) {
278 const modulo = 1e6;
279 const remainder = (msFloat * 1e6) % modulo;
280 const positiveRemainder =
281 remainder < 0 ? remainder + modulo : remainder;
282
283 return Math.floor(positiveRemainder);
284 }
285
286 /**
287 * Used to grok the `now` parameter to createClock.
288 *
289 * @param {Date|number} epoch the system time
290 * @returns {number}
291 */
292 function getEpoch(epoch) {
293 if (!epoch) {
294 return 0;
295 }
296 if (typeof epoch.getTime === "function") {
297 return epoch.getTime();
298 }
299 if (typeof epoch === "number") {
300 return epoch;
301 }
302 throw new TypeError("now should be milliseconds since UNIX epoch");
303 }
304
305 /**
306 * @param {number} from
307 * @param {number} to
308 * @param {Timer} timer
309 * @returns {boolean}
310 */
311 function inRange(from, to, timer) {
312 return timer && timer.callAt >= from && timer.callAt <= to;
313 }
314
315 /**
316 * @param {Clock} clock
317 * @param {Timer} job
318 */
319 function getInfiniteLoopError(clock, job) {
320 const infiniteLoopError = new Error(
321 `Aborting after running ${clock.loopLimit} timers, assuming an infinite loop!`
322 );
323
324 if (!job.error) {
325 return infiniteLoopError;
326 }
327
328 // pattern never matched in Node
329 const computedTargetPattern = /target\.*[<|(|[].*?[>|\]|)]\s*/;
330 let clockMethodPattern = new RegExp(
331 String(Object.keys(clock).join("|"))
332 );
333
334 if (addTimerReturnsObject) {
335 // node.js environment
336 clockMethodPattern = new RegExp(
337 `\\s+at (Object\\.)?(?:${Object.keys(clock).join("|")})\\s+`
338 );
339 }
340
341 let matchedLineIndex = -1;
342 job.error.stack.split("\n").some(function (line, i) {
343 // If we've matched a computed target line (e.g. setTimeout) then we
344 // don't need to look any further. Return true to stop iterating.
345 const matchedComputedTarget = line.match(computedTargetPattern);
346 /* istanbul ignore if */
347 if (matchedComputedTarget) {
348 matchedLineIndex = i;
349 return true;
350 }
351
352 // If we've matched a clock method line, then there may still be
353 // others further down the trace. Return false to keep iterating.
354 const matchedClockMethod = line.match(clockMethodPattern);
355 if (matchedClockMethod) {
356 matchedLineIndex = i;
357 return false;
358 }
359
360 // If we haven't matched anything on this line, but we matched
361 // previously and set the matched line index, then we can stop.
362 // If we haven't matched previously, then we should keep iterating.
363 return matchedLineIndex >= 0;
364 });
365
366 const stack = `${infiniteLoopError}\n${job.type || "Microtask"} - ${
367 job.func.name || "anonymous"
368 }\n${job.error.stack
369 .split("\n")
370 .slice(matchedLineIndex + 1)
371 .join("\n")}`;
372
373 try {
374 Object.defineProperty(infiniteLoopError, "stack", {
375 value: stack,
376 });
377 } catch (e) {
378 // noop
379 }
380
381 return infiniteLoopError;
382 }
383
384 /**
385 * @param {Date} target
386 * @param {Date} source
387 * @returns {Date} the target after modifications
388 */
389 function mirrorDateProperties(target, source) {
390 let prop;
391 for (prop in source) {
392 if (source.hasOwnProperty(prop)) {
393 target[prop] = source[prop];
394 }
395 }
396
397 // set special now implementation
398 if (source.now) {
399 target.now = function now() {
400 return target.clock.now;
401 };
402 } else {
403 delete target.now;
404 }
405
406 // set special toSource implementation
407 if (source.toSource) {
408 target.toSource = function toSource() {
409 return source.toSource();
410 };
411 } else {
412 delete target.toSource;
413 }
414
415 // set special toString implementation
416 target.toString = function toString() {
417 return source.toString();
418 };
419
420 target.prototype = source.prototype;
421 target.parse = source.parse;
422 target.UTC = source.UTC;
423 target.prototype.toUTCString = source.prototype.toUTCString;
424
425 return target;
426 }
427
428 //eslint-disable-next-line jsdoc/require-jsdoc
429 function createDate() {
430 /**
431 * @param {number} year
432 * @param {number} month
433 * @param {number} date
434 * @param {number} hour
435 * @param {number} minute
436 * @param {number} second
437 * @param {number} ms
438 *
439 * @returns {Date}
440 */
441 function ClockDate(year, month, date, hour, minute, second, ms) {
442 // the Date constructor called as a function, ref Ecma-262 Edition 5.1, section 15.9.2.
443 // This remains so in the 10th edition of 2019 as well.
444 if (!(this instanceof ClockDate)) {
445 return new NativeDate(ClockDate.clock.now).toString();
446 }
447
448 // if Date is called as a constructor with 'new' keyword
449 // Defensive and verbose to avoid potential harm in passing
450 // explicit undefined when user does not pass argument
451 switch (arguments.length) {
452 case 0:
453 return new NativeDate(ClockDate.clock.now);
454 case 1:
455 return new NativeDate(year);
456 case 2:
457 return new NativeDate(year, month);
458 case 3:
459 return new NativeDate(year, month, date);
460 case 4:
461 return new NativeDate(year, month, date, hour);
462 case 5:
463 return new NativeDate(year, month, date, hour, minute);
464 case 6:
465 return new NativeDate(
466 year,
467 month,
468 date,
469 hour,
470 minute,
471 second
472 );
473 default:
474 return new NativeDate(
475 year,
476 month,
477 date,
478 hour,
479 minute,
480 second,
481 ms
482 );
483 }
484 }
485
486 return mirrorDateProperties(ClockDate, NativeDate);
487 }
488
489 //eslint-disable-next-line jsdoc/require-jsdoc
490 function enqueueJob(clock, job) {
491 // enqueues a microtick-deferred task - ecma262/#sec-enqueuejob
492 if (!clock.jobs) {
493 clock.jobs = [];
494 }
495 clock.jobs.push(job);
496 }
497
498 //eslint-disable-next-line jsdoc/require-jsdoc
499 function runJobs(clock) {
500 // runs all microtick-deferred tasks - ecma262/#sec-runjobs
501 if (!clock.jobs) {
502 return;
503 }
504 for (let i = 0; i < clock.jobs.length; i++) {
505 const job = clock.jobs[i];
506 job.func.apply(null, job.args);
507
508 checkIsNearInfiniteLimit(clock, i);
509 if (clock.loopLimit && i > clock.loopLimit) {
510 throw getInfiniteLoopError(clock, job);
511 }
512 }
513 resetIsNearInfiniteLimit();
514 clock.jobs = [];
515 }
516
517 /**
518 * @param {Clock} clock
519 * @param {Timer} timer
520 * @returns {number} id of the created timer
521 */
522 function addTimer(clock, timer) {
523 if (timer.func === undefined) {
524 throw new Error("Callback must be provided to timer calls");
525 }
526
527 if (addTimerReturnsObject) {
528 // Node.js environment
529 if (typeof timer.func !== "function") {
530 throw new TypeError(
531 `[ERR_INVALID_CALLBACK]: Callback must be a function. Received ${
532 timer.func
533 } of type ${typeof timer.func}`
534 );
535 }
536 }
537
538 if (isNearInfiniteLimit) {
539 timer.error = new Error();
540 }
541
542 timer.type = timer.immediate ? "Immediate" : "Timeout";
543
544 if (timer.hasOwnProperty("delay")) {
545 if (typeof timer.delay !== "number") {
546 timer.delay = parseInt(timer.delay, 10);
547 }
548
549 if (!isNumberFinite(timer.delay)) {
550 timer.delay = 0;
551 }
552 timer.delay = timer.delay > maxTimeout ? 1 : timer.delay;
553 timer.delay = Math.max(0, timer.delay);
554 }
555
556 if (timer.hasOwnProperty("interval")) {
557 timer.type = "Interval";
558 timer.interval = timer.interval > maxTimeout ? 1 : timer.interval;
559 }
560
561 if (timer.hasOwnProperty("animation")) {
562 timer.type = "AnimationFrame";
563 timer.animation = true;
564 }
565
566 if (timer.hasOwnProperty("idleCallback")) {
567 timer.type = "IdleCallback";
568 timer.idleCallback = true;
569 }
570
571 if (!clock.timers) {
572 clock.timers = {};
573 }
574
575 timer.id = uniqueTimerId++;
576 timer.createdAt = clock.now;
577 timer.callAt =
578 clock.now + (parseInt(timer.delay) || (clock.duringTick ? 1 : 0));
579
580 clock.timers[timer.id] = timer;
581
582 if (addTimerReturnsObject) {
583 const res = {
584 ref: function () {
585 return res;
586 },
587 unref: function () {
588 return res;
589 },
590 refresh: function () {
591 clearTimeout(timer.id);
592 const args = [timer.func, timer.delay].concat(timer.args);
593 return setTimeout.apply(null, args);
594 },
595 [Symbol.toPrimitive]: function () {
596 return timer.id;
597 },
598 };
599 return res;
600 }
601
602 return timer.id;
603 }
604
605 /* eslint consistent-return: "off" */
606 /**
607 * Timer comparitor
608 *
609 * @param {Timer} a
610 * @param {Timer} b
611 * @returns {number}
612 */
613 function compareTimers(a, b) {
614 // Sort first by absolute timing
615 if (a.callAt < b.callAt) {
616 return -1;
617 }
618 if (a.callAt > b.callAt) {
619 return 1;
620 }
621
622 // Sort next by immediate, immediate timers take precedence
623 if (a.immediate && !b.immediate) {
624 return -1;
625 }
626 if (!a.immediate && b.immediate) {
627 return 1;
628 }
629
630 // Sort next by creation time, earlier-created timers take precedence
631 if (a.createdAt < b.createdAt) {
632 return -1;
633 }
634 if (a.createdAt > b.createdAt) {
635 return 1;
636 }
637
638 // Sort next by id, lower-id timers take precedence
639 if (a.id < b.id) {
640 return -1;
641 }
642 if (a.id > b.id) {
643 return 1;
644 }
645
646 // As timer ids are unique, no fallback `0` is necessary
647 }
648
649 /**
650 * @param {Clock} clock
651 * @param {number} from
652 * @param {number} to
653 *
654 * @returns {Timer}
655 */
656 function firstTimerInRange(clock, from, to) {
657 const timers = clock.timers;
658 let timer = null;
659 let id, isInRange;
660
661 for (id in timers) {
662 if (timers.hasOwnProperty(id)) {
663 isInRange = inRange(from, to, timers[id]);
664
665 if (
666 isInRange &&
667 (!timer || compareTimers(timer, timers[id]) === 1)
668 ) {
669 timer = timers[id];
670 }
671 }
672 }
673
674 return timer;
675 }
676
677 /**
678 * @param {Clock} clock
679 * @returns {Timer}
680 */
681 function firstTimer(clock) {
682 const timers = clock.timers;
683 let timer = null;
684 let id;
685
686 for (id in timers) {
687 if (timers.hasOwnProperty(id)) {
688 if (!timer || compareTimers(timer, timers[id]) === 1) {
689 timer = timers[id];
690 }
691 }
692 }
693
694 return timer;
695 }
696
697 /**
698 * @param {Clock} clock
699 * @returns {Timer}
700 */
701 function lastTimer(clock) {
702 const timers = clock.timers;
703 let timer = null;
704 let id;
705
706 for (id in timers) {
707 if (timers.hasOwnProperty(id)) {
708 if (!timer || compareTimers(timer, timers[id]) === -1) {
709 timer = timers[id];
710 }
711 }
712 }
713
714 return timer;
715 }
716
717 /**
718 * @param {Clock} clock
719 * @param {Timer} timer
720 */
721 function callTimer(clock, timer) {
722 if (typeof timer.interval === "number") {
723 clock.timers[timer.id].callAt += timer.interval;
724 } else {
725 delete clock.timers[timer.id];
726 }
727
728 if (typeof timer.func === "function") {
729 timer.func.apply(null, timer.args);
730 } else {
731 /* eslint no-eval: "off" */
732 const eval2 = eval;
733 (function () {
734 eval2(timer.func);
735 })();
736 }
737 }
738
739 /**
740 * Gets clear handler name for a given timer type
741 * @param {string} ttype
742 */
743 function getClearHandler(ttype) {
744 if (ttype === "IdleCallback" || ttype === "AnimationFrame") {
745 return `cancel${ttype}`;
746 }
747 return `clear${ttype}`;
748 }
749
750 /**
751 * Gets schedule handler name for a given timer type
752 * @param {string} ttype
753 */
754 function getScheduleHandler(ttype) {
755 if (ttype === "IdleCallback" || ttype === "AnimationFrame") {
756 return `request${ttype}`;
757 }
758 return `set${ttype}`;
759 }
760
761 /**
762 * Creates an anonymous function to warn only once
763 */
764 function createWarnOnce() {
765 let calls = 0;
766 return function (msg) {
767 // eslint-disable-next-line
768 !calls++ && console.warn(msg);
769 };
770 }
771 const warnOnce = createWarnOnce();
772
773 /**
774 * @param {Clock} clock
775 * @param {number} timerId
776 * @param {string} ttype
777 */
778 function clearTimer(clock, timerId, ttype) {
779 if (!timerId) {
780 // null appears to be allowed in most browsers, and appears to be
781 // relied upon by some libraries, like Bootstrap carousel
782 return;
783 }
784
785 if (!clock.timers) {
786 clock.timers = {};
787 }
788
789 // in Node, the ID is stored as the primitive value for `Timeout` objects
790 // for `Immediate` objects, no ID exists, so it gets coerced to NaN
791 const id = Number(timerId);
792
793 if (Number.isNaN(id) || id < idCounterStart) {
794 const handlerName = getClearHandler(ttype);
795
796 if (clock.shouldClearNativeTimers === true) {
797 const nativeHandler = clock[`_${handlerName}`];
798 return typeof nativeHandler === "function"
799 ? nativeHandler(timerId)
800 : undefined;
801 }
802 warnOnce(
803 `FakeTimers: ${handlerName} was invoked to clear a native timer instead of one created by this library.` +
804 "\nTo automatically clean-up native timers, use `shouldClearNativeTimers`."
805 );
806 }
807
808 if (clock.timers.hasOwnProperty(id)) {
809 // check that the ID matches a timer of the correct type
810 const timer = clock.timers[id];
811 if (
812 timer.type === ttype ||
813 (timer.type === "Timeout" && ttype === "Interval") ||
814 (timer.type === "Interval" && ttype === "Timeout")
815 ) {
816 delete clock.timers[id];
817 } else {
818 const clear = getClearHandler(ttype);
819 const schedule = getScheduleHandler(timer.type);
820 throw new Error(
821 `Cannot clear timer: timer created with ${schedule}() but cleared with ${clear}()`
822 );
823 }
824 }
825 }
826
827 /**
828 * @param {Clock} clock
829 * @param {Config} config
830 * @returns {Timer[]}
831 */
832 function uninstall(clock, config) {
833 let method, i, l;
834 const installedHrTime = "_hrtime";
835 const installedNextTick = "_nextTick";
836
837 for (i = 0, l = clock.methods.length; i < l; i++) {
838 method = clock.methods[i];
839 if (method === "hrtime" && _global.process) {
840 _global.process.hrtime = clock[installedHrTime];
841 } else if (method === "nextTick" && _global.process) {
842 _global.process.nextTick = clock[installedNextTick];
843 } else if (method === "performance") {
844 const originalPerfDescriptor = Object.getOwnPropertyDescriptor(
845 clock,
846 `_${method}`
847 );
848 if (
849 originalPerfDescriptor &&
850 originalPerfDescriptor.get &&
851 !originalPerfDescriptor.set
852 ) {
853 Object.defineProperty(
854 _global,
855 method,
856 originalPerfDescriptor
857 );
858 } else if (originalPerfDescriptor.configurable) {
859 _global[method] = clock[`_${method}`];
860 }
861 } else {
862 if (_global[method] && _global[method].hadOwnProperty) {
863 _global[method] = clock[`_${method}`];
864 } else {
865 try {
866 delete _global[method];
867 } catch (ignore) {
868 /* eslint no-empty: "off" */
869 }
870 }
871 }
872 }
873
874 if (config.shouldAdvanceTime === true) {
875 _global.clearInterval(clock.attachedInterval);
876 }
877
878 // Prevent multiple executions which will completely remove these props
879 clock.methods = [];
880
881 // return pending timers, to enable checking what timers remained on uninstall
882 if (!clock.timers) {
883 return [];
884 }
885 return Object.keys(clock.timers).map(function mapper(key) {
886 return clock.timers[key];
887 });
888 }
889
890 /**
891 * @param {object} target the target containing the method to replace
892 * @param {string} method the keyname of the method on the target
893 * @param {Clock} clock
894 */
895 function hijackMethod(target, method, clock) {
896 clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(
897 target,
898 method
899 );
900 clock[`_${method}`] = target[method];
901
902 if (method === "Date") {
903 const date = mirrorDateProperties(clock[method], target[method]);
904 target[method] = date;
905 } else if (method === "performance") {
906 const originalPerfDescriptor = Object.getOwnPropertyDescriptor(
907 target,
908 method
909 );
910 // JSDOM has a read only performance field so we have to save/copy it differently
911 if (
912 originalPerfDescriptor &&
913 originalPerfDescriptor.get &&
914 !originalPerfDescriptor.set
915 ) {
916 Object.defineProperty(
917 clock,
918 `_${method}`,
919 originalPerfDescriptor
920 );
921
922 const perfDescriptor = Object.getOwnPropertyDescriptor(
923 clock,
924 method
925 );
926 Object.defineProperty(target, method, perfDescriptor);
927 } else {
928 target[method] = clock[method];
929 }
930 } else {
931 target[method] = function () {
932 return clock[method].apply(clock, arguments);
933 };
934
935 Object.defineProperties(
936 target[method],
937 Object.getOwnPropertyDescriptors(clock[method])
938 );
939 }
940
941 target[method].clock = clock;
942 }
943
944 /**
945 * @param {Clock} clock
946 * @param {number} advanceTimeDelta
947 */
948 function doIntervalTick(clock, advanceTimeDelta) {
949 clock.tick(advanceTimeDelta);
950 }
951
952 /**
953 * @typedef {object} Timers
954 * @property {setTimeout} setTimeout
955 * @property {clearTimeout} clearTimeout
956 * @property {setInterval} setInterval
957 * @property {clearInterval} clearInterval
958 * @property {Date} Date
959 * @property {SetImmediate=} setImmediate
960 * @property {function(NodeImmediate): void=} clearImmediate
961 * @property {function(number[]):number[]=} hrtime
962 * @property {NextTick=} nextTick
963 * @property {Performance=} performance
964 * @property {RequestAnimationFrame=} requestAnimationFrame
965 * @property {boolean=} queueMicrotask
966 * @property {function(number): void=} cancelAnimationFrame
967 * @property {RequestIdleCallback=} requestIdleCallback
968 * @property {function(number): void=} cancelIdleCallback
969 */
970
971 /** @type {Timers} */
972 const timers = {
973 setTimeout: _global.setTimeout,
974 clearTimeout: _global.clearTimeout,
975 setInterval: _global.setInterval,
976 clearInterval: _global.clearInterval,
977 Date: _global.Date,
978 };
979
980 if (setImmediatePresent) {
981 timers.setImmediate = _global.setImmediate;
982 timers.clearImmediate = _global.clearImmediate;
983 }
984
985 if (hrtimePresent) {
986 timers.hrtime = _global.process.hrtime;
987 }
988
989 if (nextTickPresent) {
990 timers.nextTick = _global.process.nextTick;
991 }
992
993 if (performancePresent) {
994 timers.performance = _global.performance;
995 }
996
997 if (requestAnimationFramePresent) {
998 timers.requestAnimationFrame = _global.requestAnimationFrame;
999 }
1000
1001 if (queueMicrotaskPresent) {
1002 timers.queueMicrotask = true;
1003 }
1004
1005 if (cancelAnimationFramePresent) {
1006 timers.cancelAnimationFrame = _global.cancelAnimationFrame;
1007 }
1008
1009 if (requestIdleCallbackPresent) {
1010 timers.requestIdleCallback = _global.requestIdleCallback;
1011 }
1012
1013 if (cancelIdleCallbackPresent) {
1014 timers.cancelIdleCallback = _global.cancelIdleCallback;
1015 }
1016
1017 const originalSetTimeout = _global.setImmediate || _global.setTimeout;
1018
1019 /**
1020 * @param {Date|number} [start] the system time - non-integer values are floored
1021 * @param {number} [loopLimit] maximum number of timers that will be run when calling runAll()
1022 * @returns {Clock}
1023 */
1024 function createClock(start, loopLimit) {
1025 // eslint-disable-next-line no-param-reassign
1026 start = Math.floor(getEpoch(start));
1027 // eslint-disable-next-line no-param-reassign
1028 loopLimit = loopLimit || 1000;
1029 let nanos = 0;
1030 const adjustedSystemTime = [0, 0]; // [millis, nanoremainder]
1031
1032 if (NativeDate === undefined) {
1033 throw new Error(
1034 "The global scope doesn't have a `Date` object" +
1035 " (see https://github.com/sinonjs/sinon/issues/1852#issuecomment-419622780)"
1036 );
1037 }
1038
1039 const clock = {
1040 now: start,
1041 Date: createDate(),
1042 loopLimit: loopLimit,
1043 };
1044
1045 clock.Date.clock = clock;
1046
1047 //eslint-disable-next-line jsdoc/require-jsdoc
1048 function getTimeToNextFrame() {
1049 return 16 - ((clock.now - start) % 16);
1050 }
1051
1052 //eslint-disable-next-line jsdoc/require-jsdoc
1053 function hrtime(prev) {
1054 const millisSinceStart = clock.now - adjustedSystemTime[0] - start;
1055 const secsSinceStart = Math.floor(millisSinceStart / 1000);
1056 const remainderInNanos =
1057 (millisSinceStart - secsSinceStart * 1e3) * 1e6 +
1058 nanos -
1059 adjustedSystemTime[1];
1060
1061 if (Array.isArray(prev)) {
1062 if (prev[1] > 1e9) {
1063 throw new TypeError(
1064 "Number of nanoseconds can't exceed a billion"
1065 );
1066 }
1067
1068 const oldSecs = prev[0];
1069 let nanoDiff = remainderInNanos - prev[1];
1070 let secDiff = secsSinceStart - oldSecs;
1071
1072 if (nanoDiff < 0) {
1073 nanoDiff += 1e9;
1074 secDiff -= 1;
1075 }
1076
1077 return [secDiff, nanoDiff];
1078 }
1079 return [secsSinceStart, remainderInNanos];
1080 }
1081
1082 if (hrtimeBigintPresent) {
1083 hrtime.bigint = function () {
1084 const parts = hrtime();
1085 return BigInt(parts[0]) * BigInt(1e9) + BigInt(parts[1]); // eslint-disable-line
1086 };
1087 }
1088
1089 clock.requestIdleCallback = function requestIdleCallback(
1090 func,
1091 timeout
1092 ) {
1093 let timeToNextIdlePeriod = 0;
1094
1095 if (clock.countTimers() > 0) {
1096 timeToNextIdlePeriod = 50; // const for now
1097 }
1098
1099 const result = addTimer(clock, {
1100 func: func,
1101 args: Array.prototype.slice.call(arguments, 2),
1102 delay:
1103 typeof timeout === "undefined"
1104 ? timeToNextIdlePeriod
1105 : Math.min(timeout, timeToNextIdlePeriod),
1106 idleCallback: true,
1107 });
1108
1109 return Number(result);
1110 };
1111
1112 clock.cancelIdleCallback = function cancelIdleCallback(timerId) {
1113 return clearTimer(clock, timerId, "IdleCallback");
1114 };
1115
1116 clock.setTimeout = function setTimeout(func, timeout) {
1117 return addTimer(clock, {
1118 func: func,
1119 args: Array.prototype.slice.call(arguments, 2),
1120 delay: timeout,
1121 });
1122 };
1123 if (typeof _global.Promise !== "undefined" && utilPromisify) {
1124 clock.setTimeout[
1125 utilPromisify.custom
1126 ] = function promisifiedSetTimeout(timeout, arg) {
1127 return new _global.Promise(function setTimeoutExecutor(
1128 resolve
1129 ) {
1130 addTimer(clock, {
1131 func: resolve,
1132 args: [arg],
1133 delay: timeout,
1134 });
1135 });
1136 };
1137 }
1138
1139 clock.clearTimeout = function clearTimeout(timerId) {
1140 return clearTimer(clock, timerId, "Timeout");
1141 };
1142
1143 clock.nextTick = function nextTick(func) {
1144 return enqueueJob(clock, {
1145 func: func,
1146 args: Array.prototype.slice.call(arguments, 1),
1147 error: isNearInfiniteLimit ? new Error() : null,
1148 });
1149 };
1150
1151 clock.queueMicrotask = function queueMicrotask(func) {
1152 return clock.nextTick(func); // explicitly drop additional arguments
1153 };
1154
1155 clock.setInterval = function setInterval(func, timeout) {
1156 // eslint-disable-next-line no-param-reassign
1157 timeout = parseInt(timeout, 10);
1158 return addTimer(clock, {
1159 func: func,
1160 args: Array.prototype.slice.call(arguments, 2),
1161 delay: timeout,
1162 interval: timeout,
1163 });
1164 };
1165
1166 clock.clearInterval = function clearInterval(timerId) {
1167 return clearTimer(clock, timerId, "Interval");
1168 };
1169
1170 if (setImmediatePresent) {
1171 clock.setImmediate = function setImmediate(func) {
1172 return addTimer(clock, {
1173 func: func,
1174 args: Array.prototype.slice.call(arguments, 1),
1175 immediate: true,
1176 });
1177 };
1178
1179 if (typeof _global.Promise !== "undefined" && utilPromisify) {
1180 clock.setImmediate[
1181 utilPromisify.custom
1182 ] = function promisifiedSetImmediate(arg) {
1183 return new _global.Promise(function setImmediateExecutor(
1184 resolve
1185 ) {
1186 addTimer(clock, {
1187 func: resolve,
1188 args: [arg],
1189 immediate: true,
1190 });
1191 });
1192 };
1193 }
1194
1195 clock.clearImmediate = function clearImmediate(timerId) {
1196 return clearTimer(clock, timerId, "Immediate");
1197 };
1198 }
1199
1200 clock.countTimers = function countTimers() {
1201 return (
1202 Object.keys(clock.timers || {}).length +
1203 (clock.jobs || []).length
1204 );
1205 };
1206
1207 clock.requestAnimationFrame = function requestAnimationFrame(func) {
1208 const result = addTimer(clock, {
1209 func: func,
1210 delay: getTimeToNextFrame(),
1211 args: [clock.now + getTimeToNextFrame()],
1212 animation: true,
1213 });
1214
1215 return Number(result);
1216 };
1217
1218 clock.cancelAnimationFrame = function cancelAnimationFrame(timerId) {
1219 return clearTimer(clock, timerId, "AnimationFrame");
1220 };
1221
1222 clock.runMicrotasks = function runMicrotasks() {
1223 runJobs(clock);
1224 };
1225
1226 /**
1227 * @param {number|string} tickValue milliseconds or a string parseable by parseTime
1228 * @param {boolean} isAsync
1229 * @param {Function} resolve
1230 * @param {Function} reject
1231 * @returns {number|undefined} will return the new `now` value or nothing for async
1232 */
1233 function doTick(tickValue, isAsync, resolve, reject) {
1234 const msFloat =
1235 typeof tickValue === "number"
1236 ? tickValue
1237 : parseTime(tickValue);
1238 const ms = Math.floor(msFloat);
1239 const remainder = nanoRemainder(msFloat);
1240 let nanosTotal = nanos + remainder;
1241 let tickTo = clock.now + ms;
1242
1243 if (msFloat < 0) {
1244 throw new TypeError("Negative ticks are not supported");
1245 }
1246
1247 // adjust for positive overflow
1248 if (nanosTotal >= 1e6) {
1249 tickTo += 1;
1250 nanosTotal -= 1e6;
1251 }
1252
1253 nanos = nanosTotal;
1254 let tickFrom = clock.now;
1255 let previous = clock.now;
1256 // ESLint fails to detect this correctly
1257 /* eslint-disable prefer-const */
1258 let timer,
1259 firstException,
1260 oldNow,
1261 nextPromiseTick,
1262 compensationCheck,
1263 postTimerCall;
1264 /* eslint-enable prefer-const */
1265
1266 clock.duringTick = true;
1267
1268 // perform microtasks
1269 oldNow = clock.now;
1270 runJobs(clock);
1271 if (oldNow !== clock.now) {
1272 // compensate for any setSystemTime() call during microtask callback
1273 tickFrom += clock.now - oldNow;
1274 tickTo += clock.now - oldNow;
1275 }
1276
1277 //eslint-disable-next-line jsdoc/require-jsdoc
1278 function doTickInner() {
1279 // perform each timer in the requested range
1280 timer = firstTimerInRange(clock, tickFrom, tickTo);
1281 // eslint-disable-next-line no-unmodified-loop-condition
1282 while (timer && tickFrom <= tickTo) {
1283 if (clock.timers[timer.id]) {
1284 tickFrom = timer.callAt;
1285 clock.now = timer.callAt;
1286 oldNow = clock.now;
1287 try {
1288 runJobs(clock);
1289 callTimer(clock, timer);
1290 } catch (e) {
1291 firstException = firstException || e;
1292 }
1293
1294 if (isAsync) {
1295 // finish up after native setImmediate callback to allow
1296 // all native es6 promises to process their callbacks after
1297 // each timer fires.
1298 originalSetTimeout(nextPromiseTick);
1299 return;
1300 }
1301
1302 compensationCheck();
1303 }
1304
1305 postTimerCall();
1306 }
1307
1308 // perform process.nextTick()s again
1309 oldNow = clock.now;
1310 runJobs(clock);
1311 if (oldNow !== clock.now) {
1312 // compensate for any setSystemTime() call during process.nextTick() callback
1313 tickFrom += clock.now - oldNow;
1314 tickTo += clock.now - oldNow;
1315 }
1316 clock.duringTick = false;
1317
1318 // corner case: during runJobs new timers were scheduled which could be in the range [clock.now, tickTo]
1319 timer = firstTimerInRange(clock, tickFrom, tickTo);
1320 if (timer) {
1321 try {
1322 clock.tick(tickTo - clock.now); // do it all again - for the remainder of the requested range
1323 } catch (e) {
1324 firstException = firstException || e;
1325 }
1326 } else {
1327 // no timers remaining in the requested range: move the clock all the way to the end
1328 clock.now = tickTo;
1329
1330 // update nanos
1331 nanos = nanosTotal;
1332 }
1333 if (firstException) {
1334 throw firstException;
1335 }
1336
1337 if (isAsync) {
1338 resolve(clock.now);
1339 } else {
1340 return clock.now;
1341 }
1342 }
1343
1344 nextPromiseTick =
1345 isAsync &&
1346 function () {
1347 try {
1348 compensationCheck();
1349 postTimerCall();
1350 doTickInner();
1351 } catch (e) {
1352 reject(e);
1353 }
1354 };
1355
1356 compensationCheck = function () {
1357 // compensate for any setSystemTime() call during timer callback
1358 if (oldNow !== clock.now) {
1359 tickFrom += clock.now - oldNow;
1360 tickTo += clock.now - oldNow;
1361 previous += clock.now - oldNow;
1362 }
1363 };
1364
1365 postTimerCall = function () {
1366 timer = firstTimerInRange(clock, previous, tickTo);
1367 previous = tickFrom;
1368 };
1369
1370 return doTickInner();
1371 }
1372
1373 /**
1374 * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
1375 * @returns {number} will return the new `now` value
1376 */
1377 clock.tick = function tick(tickValue) {
1378 return doTick(tickValue, false);
1379 };
1380
1381 if (typeof _global.Promise !== "undefined") {
1382 /**
1383 * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"
1384 * @returns {Promise}
1385 */
1386 clock.tickAsync = function tickAsync(tickValue) {
1387 return new _global.Promise(function (resolve, reject) {
1388 originalSetTimeout(function () {
1389 try {
1390 doTick(tickValue, true, resolve, reject);
1391 } catch (e) {
1392 reject(e);
1393 }
1394 });
1395 });
1396 };
1397 }
1398
1399 clock.next = function next() {
1400 runJobs(clock);
1401 const timer = firstTimer(clock);
1402 if (!timer) {
1403 return clock.now;
1404 }
1405
1406 clock.duringTick = true;
1407 try {
1408 clock.now = timer.callAt;
1409 callTimer(clock, timer);
1410 runJobs(clock);
1411 return clock.now;
1412 } finally {
1413 clock.duringTick = false;
1414 }
1415 };
1416
1417 if (typeof _global.Promise !== "undefined") {
1418 clock.nextAsync = function nextAsync() {
1419 return new _global.Promise(function (resolve, reject) {
1420 originalSetTimeout(function () {
1421 try {
1422 const timer = firstTimer(clock);
1423 if (!timer) {
1424 resolve(clock.now);
1425 return;
1426 }
1427
1428 let err;
1429 clock.duringTick = true;
1430 clock.now = timer.callAt;
1431 try {
1432 callTimer(clock, timer);
1433 } catch (e) {
1434 err = e;
1435 }
1436 clock.duringTick = false;
1437
1438 originalSetTimeout(function () {
1439 if (err) {
1440 reject(err);
1441 } else {
1442 resolve(clock.now);
1443 }
1444 });
1445 } catch (e) {
1446 reject(e);
1447 }
1448 });
1449 });
1450 };
1451 }
1452
1453 clock.runAll = function runAll() {
1454 let numTimers, i;
1455 runJobs(clock);
1456 for (i = 0; i < clock.loopLimit; i++) {
1457 if (!clock.timers) {
1458 resetIsNearInfiniteLimit();
1459 return clock.now;
1460 }
1461
1462 numTimers = Object.keys(clock.timers).length;
1463 if (numTimers === 0) {
1464 resetIsNearInfiniteLimit();
1465 return clock.now;
1466 }
1467
1468 clock.next();
1469 checkIsNearInfiniteLimit(clock, i);
1470 }
1471
1472 const excessJob = firstTimer(clock);
1473 throw getInfiniteLoopError(clock, excessJob);
1474 };
1475
1476 clock.runToFrame = function runToFrame() {
1477 return clock.tick(getTimeToNextFrame());
1478 };
1479
1480 if (typeof _global.Promise !== "undefined") {
1481 clock.runAllAsync = function runAllAsync() {
1482 return new _global.Promise(function (resolve, reject) {
1483 let i = 0;
1484 /**
1485 *
1486 */
1487 function doRun() {
1488 originalSetTimeout(function () {
1489 try {
1490 let numTimers;
1491 if (i < clock.loopLimit) {
1492 if (!clock.timers) {
1493 resetIsNearInfiniteLimit();
1494 resolve(clock.now);
1495 return;
1496 }
1497
1498 numTimers = Object.keys(clock.timers)
1499 .length;
1500 if (numTimers === 0) {
1501 resetIsNearInfiniteLimit();
1502 resolve(clock.now);
1503 return;
1504 }
1505
1506 clock.next();
1507
1508 i++;
1509
1510 doRun();
1511 checkIsNearInfiniteLimit(clock, i);
1512 return;
1513 }
1514
1515 const excessJob = firstTimer(clock);
1516 reject(getInfiniteLoopError(clock, excessJob));
1517 } catch (e) {
1518 reject(e);
1519 }
1520 });
1521 }
1522 doRun();
1523 });
1524 };
1525 }
1526
1527 clock.runToLast = function runToLast() {
1528 const timer = lastTimer(clock);
1529 if (!timer) {
1530 runJobs(clock);
1531 return clock.now;
1532 }
1533
1534 return clock.tick(timer.callAt - clock.now);
1535 };
1536
1537 if (typeof _global.Promise !== "undefined") {
1538 clock.runToLastAsync = function runToLastAsync() {
1539 return new _global.Promise(function (resolve, reject) {
1540 originalSetTimeout(function () {
1541 try {
1542 const timer = lastTimer(clock);
1543 if (!timer) {
1544 resolve(clock.now);
1545 }
1546
1547 resolve(clock.tickAsync(timer.callAt));
1548 } catch (e) {
1549 reject(e);
1550 }
1551 });
1552 });
1553 };
1554 }
1555
1556 clock.reset = function reset() {
1557 nanos = 0;
1558 clock.timers = {};
1559 clock.jobs = [];
1560 clock.now = start;
1561 };
1562
1563 clock.setSystemTime = function setSystemTime(systemTime) {
1564 // determine time difference
1565 const newNow = getEpoch(systemTime);
1566 const difference = newNow - clock.now;
1567 let id, timer;
1568
1569 adjustedSystemTime[0] = adjustedSystemTime[0] + difference;
1570 adjustedSystemTime[1] = adjustedSystemTime[1] + nanos;
1571 // update 'system clock'
1572 clock.now = newNow;
1573 nanos = 0;
1574
1575 // update timers and intervals to keep them stable
1576 for (id in clock.timers) {
1577 if (clock.timers.hasOwnProperty(id)) {
1578 timer = clock.timers[id];
1579 timer.createdAt += difference;
1580 timer.callAt += difference;
1581 }
1582 }
1583 };
1584
1585 if (performancePresent) {
1586 clock.performance = Object.create(null);
1587
1588 if (hasPerformancePrototype) {
1589 const proto = _global.Performance.prototype;
1590
1591 Object.getOwnPropertyNames(proto).forEach(function (name) {
1592 if (name.indexOf("getEntries") === 0) {
1593 // match expected return type for getEntries functions
1594 clock.performance[name] = NOOP_ARRAY;
1595 } else {
1596 clock.performance[name] = NOOP;
1597 }
1598 });
1599 }
1600
1601 clock.performance.now = function FakeTimersNow() {
1602 const hrt = hrtime();
1603 const millis = hrt[0] * 1000 + hrt[1] / 1e6;
1604 return millis;
1605 };
1606 }
1607
1608 if (hrtimePresent) {
1609 clock.hrtime = hrtime;
1610 }
1611
1612 return clock;
1613 }
1614
1615 /* eslint-disable complexity */
1616
1617 /**
1618 * @param {Config=} [config] Optional config
1619 * @returns {Clock}
1620 */
1621 function install(config) {
1622 if (
1623 arguments.length > 1 ||
1624 config instanceof Date ||
1625 Array.isArray(config) ||
1626 typeof config === "number"
1627 ) {
1628 throw new TypeError(
1629 `FakeTimers.install called with ${String(
1630 config
1631 )} install requires an object parameter`
1632 );
1633 }
1634
1635 // eslint-disable-next-line no-param-reassign
1636 config = typeof config !== "undefined" ? config : {};
1637 config.shouldAdvanceTime = config.shouldAdvanceTime || false;
1638 config.advanceTimeDelta = config.advanceTimeDelta || 20;
1639 config.shouldClearNativeTimers =
1640 config.shouldClearNativeTimers || false;
1641
1642 if (config.target) {
1643 throw new TypeError(
1644 "config.target is no longer supported. Use `withGlobal(target)` instead."
1645 );
1646 }
1647
1648 let i, l;
1649 const clock = createClock(config.now, config.loopLimit);
1650 clock.shouldClearNativeTimers = config.shouldClearNativeTimers;
1651
1652 clock.uninstall = function () {
1653 return uninstall(clock, config);
1654 };
1655
1656 clock.methods = config.toFake || [];
1657
1658 if (clock.methods.length === 0) {
1659 // do not fake nextTick by default - GitHub#126
1660 clock.methods = Object.keys(timers).filter(function (key) {
1661 return key !== "nextTick" && key !== "queueMicrotask";
1662 });
1663 }
1664
1665 if (config.shouldAdvanceTime === true) {
1666 const intervalTick = doIntervalTick.bind(
1667 null,
1668 clock,
1669 config.advanceTimeDelta
1670 );
1671 const intervalId = _global.setInterval(
1672 intervalTick,
1673 config.advanceTimeDelta
1674 );
1675 clock.attachedInterval = intervalId;
1676 }
1677
1678 for (i = 0, l = clock.methods.length; i < l; i++) {
1679 const nameOfMethodToReplace = clock.methods[i];
1680 if (nameOfMethodToReplace === "hrtime") {
1681 if (
1682 _global.process &&
1683 typeof _global.process.hrtime === "function"
1684 ) {
1685 hijackMethod(_global.process, nameOfMethodToReplace, clock);
1686 }
1687 } else if (nameOfMethodToReplace === "nextTick") {
1688 if (
1689 _global.process &&
1690 typeof _global.process.nextTick === "function"
1691 ) {
1692 hijackMethod(_global.process, nameOfMethodToReplace, clock);
1693 }
1694 } else {
1695 hijackMethod(_global, nameOfMethodToReplace, clock);
1696 }
1697 }
1698
1699 return clock;
1700 }
1701
1702 /* eslint-enable complexity */
1703
1704 return {
1705 timers: timers,
1706 createClock: createClock,
1707 install: install,
1708 withGlobal: withGlobal,
1709 };
1710}
1711
1712/**
1713 * @typedef {object} FakeTimers
1714 * @property {Timers} timers
1715 * @property {createClock} createClock
1716 * @property {Function} install
1717 * @property {withGlobal} withGlobal
1718 */
1719
1720/* eslint-enable complexity */
1721
1722/** @type {FakeTimers} */
1723const defaultImplementation = withGlobal(globalObject);
1724
1725exports.timers = defaultImplementation.timers;
1726exports.createClock = defaultImplementation.createClock;
1727exports.install = defaultImplementation.install;
1728exports.withGlobal = withGlobal;
Note: See TracBrowser for help on using the repository browser.