vitest 3.0.0-beta.3 → 3.0.0

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.
Files changed (54) hide show
  1. package/LICENSE.md +1 -315
  2. package/config.d.ts +2 -0
  3. package/dist/browser.d.ts +3 -3
  4. package/dist/browser.js +1 -1
  5. package/dist/chunks/{base.CQ2VEtuH.js → base.CUDzyU2J.js} +2 -2
  6. package/dist/chunks/{cac.e7qW4xLT.js → cac.DZC9WjGM.js} +8 -8
  7. package/dist/chunks/{cli-api.CWDlED-m.js → cli-api.CmJw5Cd_.js} +920 -84
  8. package/dist/chunks/{config.BTPBhmK5.d.ts → config.BRtC-JeT.d.ts} +6 -0
  9. package/dist/chunks/{console.BYGVloWk.js → console.CN7AiMGV.js} +16 -7
  10. package/dist/chunks/{creator.Ot9GlSGw.js → creator.DztqrnyH.js} +1 -1
  11. package/dist/chunks/{execute.2pr0rHgK.js → execute.BMOaRArH.js} +27 -16
  12. package/dist/chunks/global.CnI8_G5V.d.ts +133 -0
  13. package/dist/chunks/{globals.BFncSRNA.js → globals.C5RQxaV3.js} +2 -2
  14. package/dist/chunks/{index.CkWmZCXU.js → index.BQbxGbG9.js} +1 -1
  15. package/dist/chunks/{index.BBoOXW-l.js → index.CUcwvygK.js} +5 -5
  16. package/dist/chunks/{index.DQboAxJm.js → index.D9C26wCk.js} +1 -0
  17. package/dist/chunks/index.TKSL1HjN.js +2460 -0
  18. package/dist/chunks/{reporters.DCiyjXOg.d.ts → reporters.Y8BYiXBN.d.ts} +412 -386
  19. package/dist/chunks/{resolveConfig.C1d7TK-U.js → resolveConfig.CSLLD33d.js} +140 -55
  20. package/dist/chunks/{rpc.C3q9uwRX.js → rpc.TVf73xOu.js} +0 -1
  21. package/dist/chunks/{runBaseTests.qNWRkgHj.js → runBaseTests.C0T_TQwH.js} +9 -7
  22. package/dist/chunks/{setup-common.Cp_bu5q3.js → setup-common.D0zLenuv.js} +1 -1
  23. package/dist/chunks/{RandomSequencer.C6x84bNN.js → typechecker.BJMkWMXo.js} +84 -108
  24. package/dist/chunks/{utils.Coei4Wlj.js → utils.DJWL04yX.js} +9 -20
  25. package/dist/chunks/{vi.S4Fq8wSo.js → vi.Da_PT3Vw.js} +554 -272
  26. package/dist/chunks/{vite.CRSMFy31.d.ts → vite.CQ0dHgkN.d.ts} +1 -1
  27. package/dist/chunks/{vm.DGhTouO3.js → vm.DrFVeTXo.js} +4 -4
  28. package/dist/chunks/{worker.R-PA7DpW.d.ts → worker.B1y96qmv.d.ts} +1 -1
  29. package/dist/chunks/{worker.XbtCXEXv.d.ts → worker.CIpff8Eg.d.ts} +3 -5
  30. package/dist/cli.js +1 -1
  31. package/dist/config.d.ts +4 -4
  32. package/dist/coverage.d.ts +2 -2
  33. package/dist/coverage.js +5 -4
  34. package/dist/execute.d.ts +3 -3
  35. package/dist/execute.js +1 -1
  36. package/dist/index.d.ts +18 -119
  37. package/dist/index.js +2 -2
  38. package/dist/node.d.ts +12 -9
  39. package/dist/node.js +25 -24
  40. package/dist/reporters.d.ts +2 -2
  41. package/dist/reporters.js +4 -10
  42. package/dist/runners.d.ts +2 -1
  43. package/dist/runners.js +9 -16
  44. package/dist/worker.js +1 -1
  45. package/dist/workers/forks.js +2 -2
  46. package/dist/workers/runVmTests.js +8 -6
  47. package/dist/workers/threads.js +2 -2
  48. package/dist/workers/vmForks.js +3 -3
  49. package/dist/workers/vmThreads.js +3 -3
  50. package/dist/workers.d.ts +3 -3
  51. package/dist/workers.js +5 -5
  52. package/package.json +17 -19
  53. package/dist/chunks/index.CzkCSFCy.js +0 -5455
  54. package/dist/chunks/types.BOjykUpq.d.ts +0 -27
@@ -13,7 +13,7 @@ import { spyOn, fn, isMockFunction, mocks } from '@vitest/spy';
13
13
 
14
14
  const unsupported = [
15
15
  // .poll is meant to retry matchers until they succeed, and
16
- // snapshots will always succeed as long as the poll method doesn't thow an error
16
+ // snapshots will always succeed as long as the poll method doesn't throw an error
17
17
  // in this case using the `vi.waitFor` method is more appropriate
18
18
  "matchSnapshot",
19
19
  "toMatchSnapshot",
@@ -66,19 +66,9 @@ function createExpectPoll(expect) {
66
66
  const STACK_TRACE_ERROR = new Error("STACK_TRACE_ERROR");
67
67
  const promise = () => new Promise((resolve, reject) => {
68
68
  let intervalId;
69
+ let timeoutId;
69
70
  let lastError;
70
71
  const { setTimeout, clearTimeout } = getSafeTimers();
71
- const timeoutId = setTimeout(() => {
72
- clearTimeout(intervalId);
73
- reject(
74
- copyStackTrace$1(
75
- new Error(`Matcher did not succeed in ${timeout}ms`, {
76
- cause: lastError
77
- }),
78
- STACK_TRACE_ERROR
79
- )
80
- );
81
- }, timeout);
82
72
  const check = async () => {
83
73
  try {
84
74
  chai$1.util.flag(assertion, "_name", key);
@@ -89,9 +79,26 @@ function createExpectPoll(expect) {
89
79
  clearTimeout(timeoutId);
90
80
  } catch (err) {
91
81
  lastError = err;
92
- intervalId = setTimeout(check, interval);
82
+ if (!chai$1.util.flag(assertion, "_isLastPollAttempt")) {
83
+ intervalId = setTimeout(check, interval);
84
+ }
93
85
  }
94
86
  };
87
+ timeoutId = setTimeout(() => {
88
+ clearTimeout(intervalId);
89
+ chai$1.util.flag(assertion, "_isLastPollAttempt", true);
90
+ const rejectWithCause = (cause) => {
91
+ reject(
92
+ copyStackTrace$1(
93
+ new Error(`Matcher did not succeed in ${timeout}ms`, {
94
+ cause
95
+ }),
96
+ STACK_TRACE_ERROR
97
+ )
98
+ );
99
+ };
100
+ check().then(() => rejectWithCause(lastError)).catch((e) => rejectWithCause(e));
101
+ }, timeout);
95
102
  check();
96
103
  });
97
104
  let awaited = false;
@@ -592,7 +599,6 @@ function requireGlobal () {
592
599
 
593
600
  /**
594
601
  * A reference to the global object
595
- *
596
602
  * @type {object} globalObject
597
603
  */
598
604
  var globalObject;
@@ -623,11 +629,9 @@ function requireThrowsOnProto () {
623
629
  /**
624
630
  * Is true when the environment causes an error to be thrown for accessing the
625
631
  * __proto__ property.
626
- *
627
632
  * This is necessary in order to support `node --disable-proto=throw`.
628
633
  *
629
634
  * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
630
- *
631
635
  * @type {boolean}
632
636
  */
633
637
  let throwsOnProto;
@@ -748,7 +752,6 @@ function requireCalledInOrder () {
748
752
 
749
753
  /**
750
754
  * A Sinon proxy object (fake, spy, stub)
751
- *
752
755
  * @typedef {object} SinonProxy
753
756
  * @property {Function} calledBefore - A method that determines if this proxy was called before another one
754
757
  * @property {string} id - Some id
@@ -757,7 +760,6 @@ function requireCalledInOrder () {
757
760
 
758
761
  /**
759
762
  * Returns true when the spies have been called in the order they were supplied in
760
- *
761
763
  * @param {SinonProxy[] | SinonProxy} spies An array of proxies, or several proxies as arguments
762
764
  * @returns {boolean} true when spies are called in order, false otherwise
763
765
  */
@@ -773,43 +775,6 @@ function requireCalledInOrder () {
773
775
  return calledInOrder_1;
774
776
  }
775
777
 
776
- var functionName;
777
- var hasRequiredFunctionName;
778
-
779
- function requireFunctionName () {
780
- if (hasRequiredFunctionName) return functionName;
781
- hasRequiredFunctionName = 1;
782
-
783
- /**
784
- * Returns a display name for a function
785
- *
786
- * @param {Function} func
787
- * @returns {string}
788
- */
789
- functionName = function functionName(func) {
790
- if (!func) {
791
- return "";
792
- }
793
-
794
- try {
795
- return (
796
- func.displayName ||
797
- func.name ||
798
- // Use function decomposition as a last resort to get function
799
- // name. Does not rely on function decomposition to work - if it
800
- // doesn't debugging will be slightly less informative
801
- // (i.e. toString will say 'spy' rather than 'myFunc').
802
- (String(func).match(/function ([^\s(]+)/) || [])[1]
803
- );
804
- } catch (e) {
805
- // Stringify may fail and we might get an exception, as a last-last
806
- // resort fall back to empty string.
807
- return "";
808
- }
809
- };
810
- return functionName;
811
- }
812
-
813
778
  var className_1;
814
779
  var hasRequiredClassName;
815
780
 
@@ -817,28 +782,14 @@ function requireClassName () {
817
782
  if (hasRequiredClassName) return className_1;
818
783
  hasRequiredClassName = 1;
819
784
 
820
- var functionName = requireFunctionName();
821
-
822
785
  /**
823
786
  * Returns a display name for a value from a constructor
824
- *
825
787
  * @param {object} value A value to examine
826
788
  * @returns {(string|null)} A string or null
827
789
  */
828
790
  function className(value) {
829
- return (
830
- (value.constructor && value.constructor.name) ||
831
- // The next branch is for IE11 support only:
832
- // Because the name property is not set on the prototype
833
- // of the Function object, we finally try to grab the
834
- // name from its definition. This will never be reached
835
- // in node, so we are not able to test this properly.
836
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
837
- (typeof value.constructor === "function" &&
838
- /* istanbul ignore next */
839
- functionName(value.constructor)) ||
840
- null
841
- );
791
+ const name = value.constructor && value.constructor.name;
792
+ return name || null;
842
793
  }
843
794
 
844
795
  className_1 = className;
@@ -859,7 +810,6 @@ function requireDeprecated () {
859
810
  /**
860
811
  * Returns a function that will invoke the supplied function and print a
861
812
  * deprecation warning to the console each time it is called.
862
- *
863
813
  * @param {Function} func
864
814
  * @param {string} msg
865
815
  * @returns {Function}
@@ -878,7 +828,6 @@ function requireDeprecated () {
878
828
  /**
879
829
  * Returns a string which can be supplied to `wrap()` to notify the user that a
880
830
  * particular part of the sinon API has been deprecated.
881
- *
882
831
  * @param {string} packageName
883
832
  * @param {string} funcName
884
833
  * @returns {string}
@@ -889,7 +838,6 @@ function requireDeprecated () {
889
838
 
890
839
  /**
891
840
  * Prints a warning on the console, when it exists
892
- *
893
841
  * @param {string} msg
894
842
  * @returns {undefined}
895
843
  */
@@ -918,7 +866,6 @@ function requireEvery () {
918
866
  /**
919
867
  * Returns true when fn returns true for all members of obj.
920
868
  * This is an every implementation that works for all iterables
921
- *
922
869
  * @param {object} obj
923
870
  * @param {Function} fn
924
871
  * @returns {boolean}
@@ -943,6 +890,42 @@ function requireEvery () {
943
890
  return every;
944
891
  }
945
892
 
893
+ var functionName;
894
+ var hasRequiredFunctionName;
895
+
896
+ function requireFunctionName () {
897
+ if (hasRequiredFunctionName) return functionName;
898
+ hasRequiredFunctionName = 1;
899
+
900
+ /**
901
+ * Returns a display name for a function
902
+ * @param {Function} func
903
+ * @returns {string}
904
+ */
905
+ functionName = function functionName(func) {
906
+ if (!func) {
907
+ return "";
908
+ }
909
+
910
+ try {
911
+ return (
912
+ func.displayName ||
913
+ func.name ||
914
+ // Use function decomposition as a last resort to get function
915
+ // name. Does not rely on function decomposition to work - if it
916
+ // doesn't debugging will be slightly less informative
917
+ // (i.e. toString will say 'spy' rather than 'myFunc').
918
+ (String(func).match(/function ([^\s(]+)/) || [])[1]
919
+ );
920
+ } catch (e) {
921
+ // Stringify may fail and we might get an exception, as a last-last
922
+ // resort fall back to empty string.
923
+ return "";
924
+ }
925
+ };
926
+ return functionName;
927
+ }
928
+
946
929
  var orderByFirstCall_1;
947
930
  var hasRequiredOrderByFirstCall;
948
931
 
@@ -968,14 +951,12 @@ function requireOrderByFirstCall () {
968
951
 
969
952
  /**
970
953
  * A Sinon proxy object (fake, spy, stub)
971
- *
972
954
  * @typedef {object} SinonProxy
973
955
  * @property {Function} getCall - A method that can return the first call
974
956
  */
975
957
 
976
958
  /**
977
959
  * Sorts an array of SinonProxy instances (fake, spy, stub) by their first call
978
- *
979
960
  * @param {SinonProxy[] | SinonProxy} spies
980
961
  * @returns {SinonProxy[]}
981
962
  */
@@ -1480,7 +1461,6 @@ function requireTypeOf () {
1480
1461
 
1481
1462
  /**
1482
1463
  * Returns the lower-case result of running type from type-detect on the value
1483
- *
1484
1464
  * @param {*} value
1485
1465
  * @returns {string}
1486
1466
  */
@@ -1499,7 +1479,6 @@ function requireValueToString () {
1499
1479
 
1500
1480
  /**
1501
1481
  * Returns a string representation of the value
1502
- *
1503
1482
  * @param {*} value
1504
1483
  * @returns {string}
1505
1484
  */
@@ -1544,13 +1523,18 @@ function requireFakeTimersSrc () {
1544
1523
  hasRequiredFakeTimersSrc = 1;
1545
1524
 
1546
1525
  const globalObject = requireLib().global;
1547
- let timersModule;
1526
+ let timersModule, timersPromisesModule;
1548
1527
  if (typeof __vitest_required__ !== 'undefined') {
1549
1528
  try {
1550
1529
  timersModule = __vitest_required__.timers;
1551
1530
  } catch (e) {
1552
1531
  // ignored
1553
1532
  }
1533
+ try {
1534
+ timersPromisesModule = __vitest_required__.timersPromises;
1535
+ } catch (e) {
1536
+ // ignored
1537
+ }
1554
1538
  }
1555
1539
 
1556
1540
  /**
@@ -1561,7 +1545,6 @@ function requireFakeTimersSrc () {
1561
1545
 
1562
1546
  /**
1563
1547
  * Queues a function to be called during a browser's idle periods
1564
- *
1565
1548
  * @callback RequestIdleCallback
1566
1549
  * @param {function(IdleDeadline)} callback
1567
1550
  * @param {{timeout: number}} options - an options object
@@ -1571,14 +1554,14 @@ function requireFakeTimersSrc () {
1571
1554
  /**
1572
1555
  * @callback NextTick
1573
1556
  * @param {VoidVarArgsFunc} callback - the callback to run
1574
- * @param {...*} arguments - optional arguments to call the callback with
1557
+ * @param {...*} args - optional arguments to call the callback with
1575
1558
  * @returns {void}
1576
1559
  */
1577
1560
 
1578
1561
  /**
1579
1562
  * @callback SetImmediate
1580
1563
  * @param {VoidVarArgsFunc} callback - the callback to run
1581
- * @param {...*} arguments - optional arguments to call the callback with
1564
+ * @param {...*} args - optional arguments to call the callback with
1582
1565
  * @returns {NodeImmediate}
1583
1566
  */
1584
1567
 
@@ -1637,12 +1620,13 @@ function requireFakeTimersSrc () {
1637
1620
  * @property {Function[]} methods - the methods that are faked
1638
1621
  * @property {boolean} [shouldClearNativeTimers] inherited from config
1639
1622
  * @property {{methodName:string, original:any}[] | undefined} timersModuleMethods
1623
+ * @property {{methodName:string, original:any}[] | undefined} timersPromisesModuleMethods
1624
+ * @property {Map<function(): void, AbortSignal>} abortListenerMap
1640
1625
  */
1641
1626
  /* eslint-enable jsdoc/require-property-description */
1642
1627
 
1643
1628
  /**
1644
1629
  * Configuration object for the `install` method.
1645
- *
1646
1630
  * @typedef {object} Config
1647
1631
  * @property {number|Date} [now] a number (in milliseconds) or a Date object (default epoch)
1648
1632
  * @property {string[]} [toFake] names of the methods that should be faked.
@@ -1650,12 +1634,12 @@ function requireFakeTimersSrc () {
1650
1634
  * @property {boolean} [shouldAdvanceTime] tells FakeTimers to increment mocked time automatically (default false)
1651
1635
  * @property {number} [advanceTimeDelta] increment mocked time every <<advanceTimeDelta>> ms (default: 20ms)
1652
1636
  * @property {boolean} [shouldClearNativeTimers] forwards clear timer calls to native functions if they are not fakes (default: false)
1637
+ * @property {boolean} [ignoreMissingTimers] default is false, meaning asking to fake timers that are not present will throw an error
1653
1638
  */
1654
1639
 
1655
1640
  /* eslint-disable jsdoc/require-property-description */
1656
1641
  /**
1657
1642
  * The internal structure to describe a scheduled fake timer
1658
- *
1659
1643
  * @typedef {object} Timer
1660
1644
  * @property {Function} func
1661
1645
  * @property {*[]} args
@@ -1669,7 +1653,6 @@ function requireFakeTimersSrc () {
1669
1653
 
1670
1654
  /**
1671
1655
  * A Node timer
1672
- *
1673
1656
  * @typedef {object} NodeImmediate
1674
1657
  * @property {function(): boolean} hasRef
1675
1658
  * @property {function(): NodeImmediate} ref
@@ -1681,7 +1664,6 @@ function requireFakeTimersSrc () {
1681
1664
 
1682
1665
  /**
1683
1666
  * Mocks available features in the specified global namespace.
1684
- *
1685
1667
  * @param {*} _global Namespace to mock (e.g. `window`)
1686
1668
  * @returns {FakeTimers}
1687
1669
  */
@@ -1694,16 +1676,26 @@ function requireFakeTimersSrc () {
1694
1676
  const NOOP_ARRAY = function () {
1695
1677
  return [];
1696
1678
  };
1697
- const timeoutResult = _global.setTimeout(NOOP, 0);
1698
- const addTimerReturnsObject = typeof timeoutResult === "object";
1699
- const hrtimePresent =
1679
+ const isPresent = {};
1680
+ let timeoutResult,
1681
+ addTimerReturnsObject = false;
1682
+
1683
+ if (_global.setTimeout) {
1684
+ isPresent.setTimeout = true;
1685
+ timeoutResult = _global.setTimeout(NOOP, 0);
1686
+ addTimerReturnsObject = typeof timeoutResult === "object";
1687
+ }
1688
+ isPresent.clearTimeout = Boolean(_global.clearTimeout);
1689
+ isPresent.setInterval = Boolean(_global.setInterval);
1690
+ isPresent.clearInterval = Boolean(_global.clearInterval);
1691
+ isPresent.hrtime =
1700
1692
  _global.process && typeof _global.process.hrtime === "function";
1701
- const hrtimeBigintPresent =
1702
- hrtimePresent && typeof _global.process.hrtime.bigint === "function";
1703
- const nextTickPresent =
1693
+ isPresent.hrtimeBigint =
1694
+ isPresent.hrtime && typeof _global.process.hrtime.bigint === "function";
1695
+ isPresent.nextTick =
1704
1696
  _global.process && typeof _global.process.nextTick === "function";
1705
1697
  const utilPromisify = _global.process && _global.__vitest_required__ && _global.__vitest_required__.util.promisify;
1706
- const performancePresent =
1698
+ isPresent.performance =
1707
1699
  _global.performance && typeof _global.performance.now === "function";
1708
1700
  const hasPerformancePrototype =
1709
1701
  _global.Performance &&
@@ -1712,29 +1704,65 @@ function requireFakeTimersSrc () {
1712
1704
  _global.performance &&
1713
1705
  _global.performance.constructor &&
1714
1706
  _global.performance.constructor.prototype;
1715
- const queueMicrotaskPresent = _global.hasOwnProperty("queueMicrotask");
1716
- const requestAnimationFramePresent =
1707
+ isPresent.queueMicrotask = _global.hasOwnProperty("queueMicrotask");
1708
+ isPresent.requestAnimationFrame =
1717
1709
  _global.requestAnimationFrame &&
1718
1710
  typeof _global.requestAnimationFrame === "function";
1719
- const cancelAnimationFramePresent =
1711
+ isPresent.cancelAnimationFrame =
1720
1712
  _global.cancelAnimationFrame &&
1721
1713
  typeof _global.cancelAnimationFrame === "function";
1722
- const requestIdleCallbackPresent =
1714
+ isPresent.requestIdleCallback =
1723
1715
  _global.requestIdleCallback &&
1724
1716
  typeof _global.requestIdleCallback === "function";
1725
- const cancelIdleCallbackPresent =
1717
+ isPresent.cancelIdleCallbackPresent =
1726
1718
  _global.cancelIdleCallback &&
1727
1719
  typeof _global.cancelIdleCallback === "function";
1728
- const setImmediatePresent =
1720
+ isPresent.setImmediate =
1729
1721
  _global.setImmediate && typeof _global.setImmediate === "function";
1730
- const intlPresent = _global.Intl && typeof _global.Intl === "object";
1722
+ isPresent.clearImmediate =
1723
+ _global.clearImmediate && typeof _global.clearImmediate === "function";
1724
+ isPresent.Intl = _global.Intl && typeof _global.Intl === "object";
1731
1725
 
1732
- _global.clearTimeout(timeoutResult);
1726
+ if (_global.clearTimeout) {
1727
+ _global.clearTimeout(timeoutResult);
1728
+ }
1733
1729
 
1734
1730
  const NativeDate = _global.Date;
1735
- const NativeIntl = _global.Intl;
1731
+ const NativeIntl = isPresent.Intl
1732
+ ? Object.defineProperties(
1733
+ Object.create(null),
1734
+ Object.getOwnPropertyDescriptors(_global.Intl),
1735
+ )
1736
+ : undefined;
1736
1737
  let uniqueTimerId = idCounterStart;
1737
1738
 
1739
+ if (NativeDate === undefined) {
1740
+ throw new Error(
1741
+ "The global scope doesn't have a `Date` object" +
1742
+ " (see https://github.com/sinonjs/sinon/issues/1852#issuecomment-419622780)",
1743
+ );
1744
+ }
1745
+ isPresent.Date = true;
1746
+
1747
+ /**
1748
+ * The PerformanceEntry object encapsulates a single performance metric
1749
+ * that is part of the browser's performance timeline.
1750
+ *
1751
+ * This is an object returned by the `mark` and `measure` methods on the Performance prototype
1752
+ */
1753
+ class FakePerformanceEntry {
1754
+ constructor(name, entryType, startTime, duration) {
1755
+ this.name = name;
1756
+ this.entryType = entryType;
1757
+ this.startTime = startTime;
1758
+ this.duration = duration;
1759
+ }
1760
+
1761
+ toJSON() {
1762
+ return JSON.stringify({ ...this });
1763
+ }
1764
+ }
1765
+
1738
1766
  /**
1739
1767
  * @param {number} num
1740
1768
  * @returns {boolean}
@@ -1770,7 +1798,6 @@ function requireFakeTimersSrc () {
1770
1798
  * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
1771
1799
  * number of milliseconds. This is used to support human-readable strings passed
1772
1800
  * to clock.tick()
1773
- *
1774
1801
  * @param {string} str
1775
1802
  * @returns {number}
1776
1803
  */
@@ -1787,7 +1814,7 @@ function requireFakeTimersSrc () {
1787
1814
 
1788
1815
  if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
1789
1816
  throw new Error(
1790
- "tick only understands numbers, 'm:s' and 'h:m:s'. Each part must be two digits"
1817
+ "tick only understands numbers, 'm:s' and 'h:m:s'. Each part must be two digits",
1791
1818
  );
1792
1819
  }
1793
1820
 
@@ -1806,7 +1833,6 @@ function requireFakeTimersSrc () {
1806
1833
 
1807
1834
  /**
1808
1835
  * Get the decimal part of the millisecond value as nanoseconds
1809
- *
1810
1836
  * @param {number} msFloat the number of milliseconds
1811
1837
  * @returns {number} an integer number of nanoseconds in the range [0,1e6)
1812
1838
  *
@@ -1823,7 +1849,6 @@ function requireFakeTimersSrc () {
1823
1849
 
1824
1850
  /**
1825
1851
  * Used to grok the `now` parameter to createClock.
1826
- *
1827
1852
  * @param {Date|number} epoch the system time
1828
1853
  * @returns {number}
1829
1854
  */
@@ -1856,7 +1881,7 @@ function requireFakeTimersSrc () {
1856
1881
  */
1857
1882
  function getInfiniteLoopError(clock, job) {
1858
1883
  const infiniteLoopError = new Error(
1859
- `Aborting after running ${clock.loopLimit} timers, assuming an infinite loop!`
1884
+ `Aborting after running ${clock.loopLimit} timers, assuming an infinite loop!`,
1860
1885
  );
1861
1886
 
1862
1887
  if (!job.error) {
@@ -1866,13 +1891,13 @@ function requireFakeTimersSrc () {
1866
1891
  // pattern never matched in Node
1867
1892
  const computedTargetPattern = /target\.*[<|(|[].*?[>|\]|)]\s*/;
1868
1893
  let clockMethodPattern = new RegExp(
1869
- String(Object.keys(clock).join("|"))
1894
+ String(Object.keys(clock).join("|")),
1870
1895
  );
1871
1896
 
1872
1897
  if (addTimerReturnsObject) {
1873
1898
  // node.js environment
1874
1899
  clockMethodPattern = new RegExp(
1875
- `\\s+at (Object\\.)?(?:${Object.keys(clock).join("|")})\\s+`
1900
+ `\\s+at (Object\\.)?(?:${Object.keys(clock).join("|")})\\s+`,
1876
1901
  );
1877
1902
  }
1878
1903
 
@@ -1919,114 +1944,101 @@ function requireFakeTimersSrc () {
1919
1944
  return infiniteLoopError;
1920
1945
  }
1921
1946
 
1922
- /**
1923
- * @param {Date} target
1924
- * @param {Date} source
1925
- * @returns {Date} the target after modifications
1926
- */
1927
- function mirrorDateProperties(target, source) {
1928
- let prop;
1929
- for (prop in source) {
1930
- if (source.hasOwnProperty(prop)) {
1931
- target[prop] = source[prop];
1947
+ //eslint-disable-next-line jsdoc/require-jsdoc
1948
+ function createDate() {
1949
+ class ClockDate extends NativeDate {
1950
+ /**
1951
+ * @param {number} year
1952
+ * @param {number} month
1953
+ * @param {number} date
1954
+ * @param {number} hour
1955
+ * @param {number} minute
1956
+ * @param {number} second
1957
+ * @param {number} ms
1958
+ * @returns void
1959
+ */
1960
+ // eslint-disable-next-line no-unused-vars
1961
+ constructor(year, month, date, hour, minute, second, ms) {
1962
+ // Defensive and verbose to avoid potential harm in passing
1963
+ // explicit undefined when user does not pass argument
1964
+ if (arguments.length === 0) {
1965
+ super(ClockDate.clock.now);
1966
+ } else {
1967
+ super(...arguments);
1968
+ }
1969
+
1970
+ // ensures identity checks using the constructor prop still works
1971
+ // this should have no other functional effect
1972
+ Object.defineProperty(this, "constructor", {
1973
+ value: NativeDate,
1974
+ enumerable: false,
1975
+ });
1976
+ }
1977
+
1978
+ static [Symbol.hasInstance](instance) {
1979
+ return instance instanceof NativeDate;
1932
1980
  }
1933
1981
  }
1934
1982
 
1935
- // set special now implementation
1936
- if (source.now) {
1937
- target.now = function now() {
1938
- return target.clock.now;
1983
+ ClockDate.isFake = true;
1984
+
1985
+ if (NativeDate.now) {
1986
+ ClockDate.now = function now() {
1987
+ return ClockDate.clock.now;
1939
1988
  };
1940
- } else {
1941
- delete target.now;
1942
1989
  }
1943
1990
 
1944
- // set special toSource implementation
1945
- if (source.toSource) {
1946
- target.toSource = function toSource() {
1947
- return source.toSource();
1991
+ if (NativeDate.toSource) {
1992
+ ClockDate.toSource = function toSource() {
1993
+ return NativeDate.toSource();
1948
1994
  };
1949
- } else {
1950
- delete target.toSource;
1951
1995
  }
1952
1996
 
1953
- // set special toString implementation
1954
- target.toString = function toString() {
1955
- return source.toString();
1997
+ ClockDate.toString = function toString() {
1998
+ return NativeDate.toString();
1956
1999
  };
1957
2000
 
1958
- target.prototype = source.prototype;
1959
- target.parse = source.parse;
1960
- target.UTC = source.UTC;
1961
- target.prototype.toUTCString = source.prototype.toUTCString;
1962
- target.isFake = true;
1963
-
1964
- return target;
1965
- }
1966
-
1967
- //eslint-disable-next-line jsdoc/require-jsdoc
1968
- function createDate() {
2001
+ // noinspection UnnecessaryLocalVariableJS
1969
2002
  /**
1970
- * @param {number} year
1971
- * @param {number} month
1972
- * @param {number} date
1973
- * @param {number} hour
1974
- * @param {number} minute
1975
- * @param {number} second
1976
- * @param {number} ms
1977
- * @returns {Date}
2003
+ * A normal Class constructor cannot be called without `new`, but Date can, so we need
2004
+ * to wrap it in a Proxy in order to ensure this functionality of Date is kept intact
2005
+ * @type {ClockDate}
1978
2006
  */
1979
- function ClockDate(year, month, date, hour, minute, second, ms) {
1980
- // the Date constructor called as a function, ref Ecma-262 Edition 5.1, section 15.9.2.
1981
- // This remains so in the 10th edition of 2019 as well.
1982
- if (!(this instanceof ClockDate)) {
1983
- return new NativeDate(ClockDate.clock.now).toString();
1984
- }
1985
-
1986
- // if Date is called as a constructor with 'new' keyword
1987
- // Defensive and verbose to avoid potential harm in passing
1988
- // explicit undefined when user does not pass argument
1989
- switch (arguments.length) {
1990
- case 0:
1991
- return new NativeDate(ClockDate.clock.now);
1992
- case 1:
1993
- return new NativeDate(year);
1994
- case 2:
1995
- return new NativeDate(year, month);
1996
- case 3:
1997
- return new NativeDate(year, month, date);
1998
- case 4:
1999
- return new NativeDate(year, month, date, hour);
2000
- case 5:
2001
- return new NativeDate(year, month, date, hour, minute);
2002
- case 6:
2003
- return new NativeDate(
2004
- year,
2005
- month,
2006
- date,
2007
- hour,
2008
- minute,
2009
- second
2010
- );
2011
- default:
2012
- return new NativeDate(
2013
- year,
2014
- month,
2015
- date,
2016
- hour,
2017
- minute,
2018
- second,
2019
- ms
2007
+ const ClockDateProxy = new Proxy(ClockDate, {
2008
+ // handler for [[Call]] invocations (i.e. not using `new`)
2009
+ apply() {
2010
+ // the Date constructor called as a function, ref Ecma-262 Edition 5.1, section 15.9.2.
2011
+ // This remains so in the 10th edition of 2019 as well.
2012
+ if (this instanceof ClockDate) {
2013
+ throw new TypeError(
2014
+ "A Proxy should only capture `new` calls with the `construct` handler. This is not supposed to be possible, so check the logic.",
2020
2015
  );
2021
- }
2022
- }
2016
+ }
2017
+
2018
+ return new NativeDate(ClockDate.clock.now).toString();
2019
+ },
2020
+ });
2023
2021
 
2024
- return mirrorDateProperties(ClockDate, NativeDate);
2022
+ return ClockDateProxy;
2025
2023
  }
2026
2024
 
2027
- //eslint-disable-next-line jsdoc/require-jsdoc
2025
+ /**
2026
+ * Mirror Intl by default on our fake implementation
2027
+ *
2028
+ * Most of the properties are the original native ones,
2029
+ * but we need to take control of those that have a
2030
+ * dependency on the current clock.
2031
+ * @returns {object} the partly fake Intl implementation
2032
+ */
2028
2033
  function createIntl() {
2029
- const ClockIntl = { ...NativeIntl };
2034
+ const ClockIntl = {};
2035
+ /*
2036
+ * All properties of Intl are non-enumerable, so we need
2037
+ * to do a bit of work to get them out.
2038
+ */
2039
+ Object.getOwnPropertyNames(NativeIntl).forEach(
2040
+ (property) => (ClockIntl[property] = NativeIntl[property]),
2041
+ );
2030
2042
 
2031
2043
  ClockIntl.DateTimeFormat = function (...args) {
2032
2044
  const realFormatter = new NativeIntl.DateTimeFormat(...args);
@@ -2036,7 +2048,7 @@ function requireFakeTimersSrc () {
2036
2048
  (method) => {
2037
2049
  formatter[method] =
2038
2050
  realFormatter[method].bind(realFormatter);
2039
- }
2051
+ },
2040
2052
  );
2041
2053
 
2042
2054
  ["format", "formatToParts"].forEach((method) => {
@@ -2049,7 +2061,7 @@ function requireFakeTimersSrc () {
2049
2061
  };
2050
2062
 
2051
2063
  ClockIntl.DateTimeFormat.prototype = Object.create(
2052
- NativeIntl.DateTimeFormat.prototype
2064
+ NativeIntl.DateTimeFormat.prototype,
2053
2065
  );
2054
2066
 
2055
2067
  ClockIntl.DateTimeFormat.supportedLocalesOf =
@@ -2102,7 +2114,7 @@ function requireFakeTimersSrc () {
2102
2114
  throw new TypeError(
2103
2115
  `[ERR_INVALID_CALLBACK]: Callback must be a function. Received ${
2104
2116
  timer.func
2105
- } of type ${typeof timer.func}`
2117
+ } of type ${typeof timer.func}`,
2106
2118
  );
2107
2119
  }
2108
2120
  }
@@ -2188,7 +2200,6 @@ function requireFakeTimersSrc () {
2188
2200
  /* eslint consistent-return: "off" */
2189
2201
  /**
2190
2202
  * Timer comparitor
2191
- *
2192
2203
  * @param {Timer} a
2193
2204
  * @param {Timer} b
2194
2205
  * @returns {number}
@@ -2320,7 +2331,6 @@ function requireFakeTimersSrc () {
2320
2331
 
2321
2332
  /**
2322
2333
  * Gets clear handler name for a given timer type
2323
- *
2324
2334
  * @param {string} ttype
2325
2335
  */
2326
2336
  function getClearHandler(ttype) {
@@ -2332,7 +2342,6 @@ function requireFakeTimersSrc () {
2332
2342
 
2333
2343
  /**
2334
2344
  * Gets schedule handler name for a given timer type
2335
- *
2336
2345
  * @param {string} ttype
2337
2346
  */
2338
2347
  function getScheduleHandler(ttype) {
@@ -2385,7 +2394,7 @@ function requireFakeTimersSrc () {
2385
2394
  }
2386
2395
  warnOnce(
2387
2396
  `FakeTimers: ${handlerName} was invoked to clear a native timer instead of one created by this library.` +
2388
- "\nTo automatically clean-up native timers, use `shouldClearNativeTimers`."
2397
+ "\nTo automatically clean-up native timers, use `shouldClearNativeTimers`.",
2389
2398
  );
2390
2399
  }
2391
2400
 
@@ -2402,7 +2411,7 @@ function requireFakeTimersSrc () {
2402
2411
  const clear = getClearHandler(ttype);
2403
2412
  const schedule = getScheduleHandler(timer.type);
2404
2413
  throw new Error(
2405
- `Cannot clear timer: timer created with ${schedule}() but cleared with ${clear}()`
2414
+ `Cannot clear timer: timer created with ${schedule}() but cleared with ${clear}()`,
2406
2415
  );
2407
2416
  }
2408
2417
  }
@@ -2427,7 +2436,7 @@ function requireFakeTimersSrc () {
2427
2436
  } else if (method === "performance") {
2428
2437
  const originalPerfDescriptor = Object.getOwnPropertyDescriptor(
2429
2438
  clock,
2430
- `_${method}`
2439
+ `_${method}`,
2431
2440
  );
2432
2441
  if (
2433
2442
  originalPerfDescriptor &&
@@ -2437,7 +2446,7 @@ function requireFakeTimersSrc () {
2437
2446
  Object.defineProperty(
2438
2447
  _global,
2439
2448
  method,
2440
- originalPerfDescriptor
2449
+ originalPerfDescriptor,
2441
2450
  );
2442
2451
  } else if (originalPerfDescriptor.configurable) {
2443
2452
  _global[method] = clock[`_${method}`];
@@ -2459,6 +2468,16 @@ function requireFakeTimersSrc () {
2459
2468
  timersModule[entry.methodName] = entry.original;
2460
2469
  }
2461
2470
  }
2471
+ if (clock.timersPromisesModuleMethods !== undefined) {
2472
+ for (
2473
+ let j = 0;
2474
+ j < clock.timersPromisesModuleMethods.length;
2475
+ j++
2476
+ ) {
2477
+ const entry = clock.timersPromisesModuleMethods[j];
2478
+ timersPromisesModule[entry.methodName] = entry.original;
2479
+ }
2480
+ }
2462
2481
  }
2463
2482
 
2464
2483
  if (config.shouldAdvanceTime === true) {
@@ -2468,6 +2487,11 @@ function requireFakeTimersSrc () {
2468
2487
  // Prevent multiple executions which will completely remove these props
2469
2488
  clock.methods = [];
2470
2489
 
2490
+ for (const [listener, signal] of clock.abortListenerMap.entries()) {
2491
+ signal.removeEventListener("abort", listener);
2492
+ clock.abortListenerMap.delete(listener);
2493
+ }
2494
+
2471
2495
  // return pending timers, to enable checking what timers remained on uninstall
2472
2496
  if (!clock.timers) {
2473
2497
  return [];
@@ -2485,19 +2509,18 @@ function requireFakeTimersSrc () {
2485
2509
  function hijackMethod(target, method, clock) {
2486
2510
  clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(
2487
2511
  target,
2488
- method
2512
+ method,
2489
2513
  );
2490
2514
  clock[`_${method}`] = target[method];
2491
2515
 
2492
2516
  if (method === "Date") {
2493
- const date = mirrorDateProperties(clock[method], target[method]);
2494
- target[method] = date;
2517
+ target[method] = clock[method];
2495
2518
  } else if (method === "Intl") {
2496
2519
  target[method] = clock[method];
2497
2520
  } else if (method === "performance") {
2498
2521
  const originalPerfDescriptor = Object.getOwnPropertyDescriptor(
2499
2522
  target,
2500
- method
2523
+ method,
2501
2524
  );
2502
2525
  // JSDOM has a read only performance field so we have to save/copy it differently
2503
2526
  if (
@@ -2508,12 +2531,12 @@ function requireFakeTimersSrc () {
2508
2531
  Object.defineProperty(
2509
2532
  clock,
2510
2533
  `_${method}`,
2511
- originalPerfDescriptor
2534
+ originalPerfDescriptor,
2512
2535
  );
2513
2536
 
2514
2537
  const perfDescriptor = Object.getOwnPropertyDescriptor(
2515
2538
  clock,
2516
- method
2539
+ method,
2517
2540
  );
2518
2541
  Object.defineProperty(target, method, perfDescriptor);
2519
2542
  } else {
@@ -2526,7 +2549,7 @@ function requireFakeTimersSrc () {
2526
2549
 
2527
2550
  Object.defineProperties(
2528
2551
  target[method],
2529
- Object.getOwnPropertyDescriptors(clock[method])
2552
+ Object.getOwnPropertyDescriptors(clock[method]),
2530
2553
  );
2531
2554
  }
2532
2555
 
@@ -2570,45 +2593,48 @@ function requireFakeTimersSrc () {
2570
2593
  Date: _global.Date,
2571
2594
  };
2572
2595
 
2573
- if (setImmediatePresent) {
2596
+ if (isPresent.setImmediate) {
2574
2597
  timers.setImmediate = _global.setImmediate;
2598
+ }
2599
+
2600
+ if (isPresent.clearImmediate) {
2575
2601
  timers.clearImmediate = _global.clearImmediate;
2576
2602
  }
2577
2603
 
2578
- if (hrtimePresent) {
2604
+ if (isPresent.hrtime) {
2579
2605
  timers.hrtime = _global.process.hrtime;
2580
2606
  }
2581
2607
 
2582
- if (nextTickPresent) {
2608
+ if (isPresent.nextTick) {
2583
2609
  timers.nextTick = _global.process.nextTick;
2584
2610
  }
2585
2611
 
2586
- if (performancePresent) {
2612
+ if (isPresent.performance) {
2587
2613
  timers.performance = _global.performance;
2588
2614
  }
2589
2615
 
2590
- if (requestAnimationFramePresent) {
2616
+ if (isPresent.requestAnimationFrame) {
2591
2617
  timers.requestAnimationFrame = _global.requestAnimationFrame;
2592
2618
  }
2593
2619
 
2594
- if (queueMicrotaskPresent) {
2595
- timers.queueMicrotask = true;
2620
+ if (isPresent.queueMicrotask) {
2621
+ timers.queueMicrotask = _global.queueMicrotask;
2596
2622
  }
2597
2623
 
2598
- if (cancelAnimationFramePresent) {
2624
+ if (isPresent.cancelAnimationFrame) {
2599
2625
  timers.cancelAnimationFrame = _global.cancelAnimationFrame;
2600
2626
  }
2601
2627
 
2602
- if (requestIdleCallbackPresent) {
2628
+ if (isPresent.requestIdleCallback) {
2603
2629
  timers.requestIdleCallback = _global.requestIdleCallback;
2604
2630
  }
2605
2631
 
2606
- if (cancelIdleCallbackPresent) {
2632
+ if (isPresent.cancelIdleCallback) {
2607
2633
  timers.cancelIdleCallback = _global.cancelIdleCallback;
2608
2634
  }
2609
2635
 
2610
- if (intlPresent) {
2611
- timers.Intl = _global.Intl;
2636
+ if (isPresent.Intl) {
2637
+ timers.Intl = NativeIntl;
2612
2638
  }
2613
2639
 
2614
2640
  const originalSetTimeout = _global.setImmediate || _global.setTimeout;
@@ -2626,13 +2652,6 @@ function requireFakeTimersSrc () {
2626
2652
  let nanos = 0;
2627
2653
  const adjustedSystemTime = [0, 0]; // [millis, nanoremainder]
2628
2654
 
2629
- if (NativeDate === undefined) {
2630
- throw new Error(
2631
- "The global scope doesn't have a `Date` object" +
2632
- " (see https://github.com/sinonjs/sinon/issues/1852#issuecomment-419622780)"
2633
- );
2634
- }
2635
-
2636
2655
  const clock = {
2637
2656
  now: start,
2638
2657
  Date: createDate(),
@@ -2658,7 +2677,7 @@ function requireFakeTimersSrc () {
2658
2677
  if (Array.isArray(prev)) {
2659
2678
  if (prev[1] > 1e9) {
2660
2679
  throw new TypeError(
2661
- "Number of nanoseconds can't exceed a billion"
2680
+ "Number of nanoseconds can't exceed a billion",
2662
2681
  );
2663
2682
  }
2664
2683
 
@@ -2676,27 +2695,36 @@ function requireFakeTimersSrc () {
2676
2695
  return [secsSinceStart, remainderInNanos];
2677
2696
  }
2678
2697
 
2698
+ /**
2699
+ * A high resolution timestamp in milliseconds.
2700
+ * @typedef {number} DOMHighResTimeStamp
2701
+ */
2702
+
2703
+ /**
2704
+ * performance.now()
2705
+ * @returns {DOMHighResTimeStamp}
2706
+ */
2679
2707
  function fakePerformanceNow() {
2680
2708
  const hrt = hrtime();
2681
2709
  const millis = hrt[0] * 1000 + hrt[1] / 1e6;
2682
2710
  return millis;
2683
2711
  }
2684
2712
 
2685
- if (hrtimeBigintPresent) {
2713
+ if (isPresent.hrtimeBigint) {
2686
2714
  hrtime.bigint = function () {
2687
2715
  const parts = hrtime();
2688
2716
  return BigInt(parts[0]) * BigInt(1e9) + BigInt(parts[1]); // eslint-disable-line
2689
2717
  };
2690
2718
  }
2691
2719
 
2692
- if (intlPresent) {
2720
+ if (isPresent.Intl) {
2693
2721
  clock.Intl = createIntl();
2694
2722
  clock.Intl.clock = clock;
2695
2723
  }
2696
2724
 
2697
2725
  clock.requestIdleCallback = function requestIdleCallback(
2698
2726
  func,
2699
- timeout
2727
+ timeout,
2700
2728
  ) {
2701
2729
  let timeToNextIdlePeriod = 0;
2702
2730
 
@@ -2732,7 +2760,7 @@ function requireFakeTimersSrc () {
2732
2760
  clock.setTimeout[utilPromisify.custom] =
2733
2761
  function promisifiedSetTimeout(timeout, arg) {
2734
2762
  return new _global.Promise(function setTimeoutExecutor(
2735
- resolve
2763
+ resolve,
2736
2764
  ) {
2737
2765
  addTimer(clock, {
2738
2766
  func: resolve,
@@ -2774,7 +2802,7 @@ function requireFakeTimersSrc () {
2774
2802
  return clearTimer(clock, timerId, "Interval");
2775
2803
  };
2776
2804
 
2777
- if (setImmediatePresent) {
2805
+ if (isPresent.setImmediate) {
2778
2806
  clock.setImmediate = function setImmediate(func) {
2779
2807
  return addTimer(clock, {
2780
2808
  func: func,
@@ -2793,7 +2821,7 @@ function requireFakeTimersSrc () {
2793
2821
  args: [arg],
2794
2822
  immediate: true,
2795
2823
  });
2796
- }
2824
+ },
2797
2825
  );
2798
2826
  };
2799
2827
  }
@@ -3095,6 +3123,8 @@ function requireFakeTimersSrc () {
3095
3123
  function doRun() {
3096
3124
  originalSetTimeout(function () {
3097
3125
  try {
3126
+ runJobs(clock);
3127
+
3098
3128
  let numTimers;
3099
3129
  if (i < clock.loopLimit) {
3100
3130
  if (!clock.timers) {
@@ -3104,7 +3134,7 @@ function requireFakeTimersSrc () {
3104
3134
  }
3105
3135
 
3106
3136
  numTimers = Object.keys(
3107
- clock.timers
3137
+ clock.timers,
3108
3138
  ).length;
3109
3139
  if (numTimers === 0) {
3110
3140
  resetIsNearInfiniteLimit();
@@ -3150,6 +3180,7 @@ function requireFakeTimersSrc () {
3150
3180
  try {
3151
3181
  const timer = lastTimer(clock);
3152
3182
  if (!timer) {
3183
+ runJobs(clock);
3153
3184
  resolve(clock.now);
3154
3185
  }
3155
3186
 
@@ -3210,12 +3241,12 @@ function requireFakeTimersSrc () {
3210
3241
  clock.tick(ms);
3211
3242
  };
3212
3243
 
3213
- if (performancePresent) {
3244
+ if (isPresent.performance) {
3214
3245
  clock.performance = Object.create(null);
3215
3246
  clock.performance.now = fakePerformanceNow;
3216
3247
  }
3217
3248
 
3218
- if (hrtimePresent) {
3249
+ if (isPresent.hrtime) {
3219
3250
  clock.hrtime = hrtime;
3220
3251
  }
3221
3252
 
@@ -3237,8 +3268,8 @@ function requireFakeTimersSrc () {
3237
3268
  ) {
3238
3269
  throw new TypeError(
3239
3270
  `FakeTimers.install called with ${String(
3240
- config
3241
- )} install requires an object parameter`
3271
+ config,
3272
+ )} install requires an object parameter`,
3242
3273
  );
3243
3274
  }
3244
3275
 
@@ -3246,7 +3277,7 @@ function requireFakeTimersSrc () {
3246
3277
  // Timers are already faked; this is a problem.
3247
3278
  // Make the user reset timers before continuing.
3248
3279
  throw new TypeError(
3249
- "Can't install fake timers twice on the same global object."
3280
+ "Can't install fake timers twice on the same global object.",
3250
3281
  );
3251
3282
  }
3252
3283
 
@@ -3259,7 +3290,21 @@ function requireFakeTimersSrc () {
3259
3290
 
3260
3291
  if (config.target) {
3261
3292
  throw new TypeError(
3262
- "config.target is no longer supported. Use `withGlobal(target)` instead."
3293
+ "config.target is no longer supported. Use `withGlobal(target)` instead.",
3294
+ );
3295
+ }
3296
+
3297
+ /**
3298
+ * @param {string} timer/object the name of the thing that is not present
3299
+ * @param timer
3300
+ */
3301
+ function handleMissingTimer(timer) {
3302
+ if (config.ignoreMissingTimers) {
3303
+ return;
3304
+ }
3305
+
3306
+ throw new ReferenceError(
3307
+ `non-existent timers and/or objects cannot be faked: '${timer}'`,
3263
3308
  );
3264
3309
  }
3265
3310
 
@@ -3271,24 +3316,23 @@ function requireFakeTimersSrc () {
3271
3316
  return uninstall(clock, config);
3272
3317
  };
3273
3318
 
3319
+ clock.abortListenerMap = new Map();
3320
+
3274
3321
  clock.methods = config.toFake || [];
3275
3322
 
3276
3323
  if (clock.methods.length === 0) {
3277
- // do not fake nextTick by default - GitHub#126
3278
- clock.methods = Object.keys(timers).filter(function (key) {
3279
- return key !== "nextTick" && key !== "queueMicrotask";
3280
- });
3324
+ clock.methods = Object.keys(timers);
3281
3325
  }
3282
3326
 
3283
3327
  if (config.shouldAdvanceTime === true) {
3284
3328
  const intervalTick = doIntervalTick.bind(
3285
3329
  null,
3286
3330
  clock,
3287
- config.advanceTimeDelta
3331
+ config.advanceTimeDelta,
3288
3332
  );
3289
3333
  const intervalId = _global.setInterval(
3290
3334
  intervalTick,
3291
- config.advanceTimeDelta
3335
+ config.advanceTimeDelta,
3292
3336
  );
3293
3337
  clock.attachedInterval = intervalId;
3294
3338
  }
@@ -3311,18 +3355,33 @@ function requireFakeTimersSrc () {
3311
3355
  : NOOP;
3312
3356
  }
3313
3357
  });
3358
+ // ensure `mark` returns a value that is valid
3359
+ clock.performance.mark = (name) =>
3360
+ new FakePerformanceEntry(name, "mark", 0, 0);
3361
+ clock.performance.measure = (name) =>
3362
+ new FakePerformanceEntry(name, "measure", 0, 100);
3363
+ // `timeOrigin` should return the time of when the Window session started
3364
+ // (or the Worker was installed)
3365
+ clock.performance.timeOrigin = getEpoch(config.now);
3314
3366
  } else if ((config.toFake || []).includes("performance")) {
3315
- // user explicitly tried to fake performance when not present
3316
- throw new ReferenceError(
3317
- "non-existent performance object cannot be faked"
3318
- );
3367
+ return handleMissingTimer("performance");
3319
3368
  }
3320
3369
  }
3321
3370
  if (_global === globalObject && timersModule) {
3322
3371
  clock.timersModuleMethods = [];
3323
3372
  }
3373
+ if (_global === globalObject && timersPromisesModule) {
3374
+ clock.timersPromisesModuleMethods = [];
3375
+ }
3324
3376
  for (i = 0, l = clock.methods.length; i < l; i++) {
3325
3377
  const nameOfMethodToReplace = clock.methods[i];
3378
+
3379
+ if (!isPresent[nameOfMethodToReplace]) {
3380
+ handleMissingTimer(nameOfMethodToReplace);
3381
+ // eslint-disable-next-line
3382
+ continue;
3383
+ }
3384
+
3326
3385
  if (nameOfMethodToReplace === "hrtime") {
3327
3386
  if (
3328
3387
  _global.process &&
@@ -3352,6 +3411,239 @@ function requireFakeTimersSrc () {
3352
3411
  timersModule[nameOfMethodToReplace] =
3353
3412
  _global[nameOfMethodToReplace];
3354
3413
  }
3414
+ if (clock.timersPromisesModuleMethods !== undefined) {
3415
+ if (nameOfMethodToReplace === "setTimeout") {
3416
+ clock.timersPromisesModuleMethods.push({
3417
+ methodName: "setTimeout",
3418
+ original: timersPromisesModule.setTimeout,
3419
+ });
3420
+
3421
+ timersPromisesModule.setTimeout = (
3422
+ delay,
3423
+ value,
3424
+ options = {},
3425
+ ) =>
3426
+ new Promise((resolve, reject) => {
3427
+ const abort = () => {
3428
+ options.signal.removeEventListener(
3429
+ "abort",
3430
+ abort,
3431
+ );
3432
+ clock.abortListenerMap.delete(abort);
3433
+
3434
+ // This is safe, there is no code path that leads to this function
3435
+ // being invoked before handle has been assigned.
3436
+ // eslint-disable-next-line no-use-before-define
3437
+ clock.clearTimeout(handle);
3438
+ reject(options.signal.reason);
3439
+ };
3440
+
3441
+ const handle = clock.setTimeout(() => {
3442
+ if (options.signal) {
3443
+ options.signal.removeEventListener(
3444
+ "abort",
3445
+ abort,
3446
+ );
3447
+ clock.abortListenerMap.delete(abort);
3448
+ }
3449
+
3450
+ resolve(value);
3451
+ }, delay);
3452
+
3453
+ if (options.signal) {
3454
+ if (options.signal.aborted) {
3455
+ abort();
3456
+ } else {
3457
+ options.signal.addEventListener(
3458
+ "abort",
3459
+ abort,
3460
+ );
3461
+ clock.abortListenerMap.set(
3462
+ abort,
3463
+ options.signal,
3464
+ );
3465
+ }
3466
+ }
3467
+ });
3468
+ } else if (nameOfMethodToReplace === "setImmediate") {
3469
+ clock.timersPromisesModuleMethods.push({
3470
+ methodName: "setImmediate",
3471
+ original: timersPromisesModule.setImmediate,
3472
+ });
3473
+
3474
+ timersPromisesModule.setImmediate = (value, options = {}) =>
3475
+ new Promise((resolve, reject) => {
3476
+ const abort = () => {
3477
+ options.signal.removeEventListener(
3478
+ "abort",
3479
+ abort,
3480
+ );
3481
+ clock.abortListenerMap.delete(abort);
3482
+
3483
+ // This is safe, there is no code path that leads to this function
3484
+ // being invoked before handle has been assigned.
3485
+ // eslint-disable-next-line no-use-before-define
3486
+ clock.clearImmediate(handle);
3487
+ reject(options.signal.reason);
3488
+ };
3489
+
3490
+ const handle = clock.setImmediate(() => {
3491
+ if (options.signal) {
3492
+ options.signal.removeEventListener(
3493
+ "abort",
3494
+ abort,
3495
+ );
3496
+ clock.abortListenerMap.delete(abort);
3497
+ }
3498
+
3499
+ resolve(value);
3500
+ });
3501
+
3502
+ if (options.signal) {
3503
+ if (options.signal.aborted) {
3504
+ abort();
3505
+ } else {
3506
+ options.signal.addEventListener(
3507
+ "abort",
3508
+ abort,
3509
+ );
3510
+ clock.abortListenerMap.set(
3511
+ abort,
3512
+ options.signal,
3513
+ );
3514
+ }
3515
+ }
3516
+ });
3517
+ } else if (nameOfMethodToReplace === "setInterval") {
3518
+ clock.timersPromisesModuleMethods.push({
3519
+ methodName: "setInterval",
3520
+ original: timersPromisesModule.setInterval,
3521
+ });
3522
+
3523
+ timersPromisesModule.setInterval = (
3524
+ delay,
3525
+ value,
3526
+ options = {},
3527
+ ) => ({
3528
+ [Symbol.asyncIterator]: () => {
3529
+ const createResolvable = () => {
3530
+ let resolve, reject;
3531
+ const promise = new Promise((res, rej) => {
3532
+ resolve = res;
3533
+ reject = rej;
3534
+ });
3535
+ promise.resolve = resolve;
3536
+ promise.reject = reject;
3537
+ return promise;
3538
+ };
3539
+
3540
+ let done = false;
3541
+ let hasThrown = false;
3542
+ let returnCall;
3543
+ let nextAvailable = 0;
3544
+ const nextQueue = [];
3545
+
3546
+ const handle = clock.setInterval(() => {
3547
+ if (nextQueue.length > 0) {
3548
+ nextQueue.shift().resolve();
3549
+ } else {
3550
+ nextAvailable++;
3551
+ }
3552
+ }, delay);
3553
+
3554
+ const abort = () => {
3555
+ options.signal.removeEventListener(
3556
+ "abort",
3557
+ abort,
3558
+ );
3559
+ clock.abortListenerMap.delete(abort);
3560
+
3561
+ clock.clearInterval(handle);
3562
+ done = true;
3563
+ for (const resolvable of nextQueue) {
3564
+ resolvable.resolve();
3565
+ }
3566
+ };
3567
+
3568
+ if (options.signal) {
3569
+ if (options.signal.aborted) {
3570
+ done = true;
3571
+ } else {
3572
+ options.signal.addEventListener(
3573
+ "abort",
3574
+ abort,
3575
+ );
3576
+ clock.abortListenerMap.set(
3577
+ abort,
3578
+ options.signal,
3579
+ );
3580
+ }
3581
+ }
3582
+
3583
+ return {
3584
+ next: async () => {
3585
+ if (options.signal?.aborted && !hasThrown) {
3586
+ hasThrown = true;
3587
+ throw options.signal.reason;
3588
+ }
3589
+
3590
+ if (done) {
3591
+ return { done: true, value: undefined };
3592
+ }
3593
+
3594
+ if (nextAvailable > 0) {
3595
+ nextAvailable--;
3596
+ return { done: false, value: value };
3597
+ }
3598
+
3599
+ const resolvable = createResolvable();
3600
+ nextQueue.push(resolvable);
3601
+
3602
+ await resolvable;
3603
+
3604
+ if (returnCall && nextQueue.length === 0) {
3605
+ returnCall.resolve();
3606
+ }
3607
+
3608
+ if (options.signal?.aborted && !hasThrown) {
3609
+ hasThrown = true;
3610
+ throw options.signal.reason;
3611
+ }
3612
+
3613
+ if (done) {
3614
+ return { done: true, value: undefined };
3615
+ }
3616
+
3617
+ return { done: false, value: value };
3618
+ },
3619
+ return: async () => {
3620
+ if (done) {
3621
+ return { done: true, value: undefined };
3622
+ }
3623
+
3624
+ if (nextQueue.length > 0) {
3625
+ returnCall = createResolvable();
3626
+ await returnCall;
3627
+ }
3628
+
3629
+ clock.clearInterval(handle);
3630
+ done = true;
3631
+
3632
+ if (options.signal) {
3633
+ options.signal.removeEventListener(
3634
+ "abort",
3635
+ abort,
3636
+ );
3637
+ clock.abortListenerMap.delete(abort);
3638
+ }
3639
+
3640
+ return { done: true, value: undefined };
3641
+ },
3642
+ };
3643
+ },
3644
+ });
3645
+ }
3646
+ }
3355
3647
  }
3356
3648
 
3357
3649
  return clock;
@@ -3502,21 +3794,11 @@ class FakeTimers {
3502
3794
  "process.nextTick cannot be mocked inside child_process"
3503
3795
  );
3504
3796
  }
3505
- const existingFakedMethods = (this._userConfig?.toFake || toFake).filter(
3506
- (method) => {
3507
- switch (method) {
3508
- case "setImmediate":
3509
- case "clearImmediate":
3510
- return method in this._global && this._global[method];
3511
- default:
3512
- return true;
3513
- }
3514
- }
3515
- );
3516
3797
  this._clock = this._fakeTimers.install({
3517
3798
  now: Date.now(),
3518
3799
  ...this._userConfig,
3519
- toFake: existingFakedMethods
3800
+ toFake: this._userConfig?.toFake || toFake,
3801
+ ignoreMissingTimers: true
3520
3802
  });
3521
3803
  this._fakingTime = true;
3522
3804
  }