123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- 'use strict';
- Object.defineProperty(exports, '__esModule', {
- value: true
- });
- var _jestMessageUtil;
- function _load_jestMessageUtil() {
- return (_jestMessageUtil = require('jest-message-util'));
- }
- var _set_global;
- function _load_set_global() {
- return (_set_global = _interopRequireDefault(require('./set_global')));
- }
- function _interopRequireDefault(obj) {
- return obj && obj.__esModule ? obj : {default: obj};
- }
- /**
- * We don't know the type of arguments for a callback ahead of time which is why
- * we are disabling the flowtype/no-weak-types rule here.
- */
- /* eslint-disable flowtype/no-weak-types */
- /* eslint-enable flowtype/no-weak-types */
- const MS_IN_A_YEAR = 31536000000;
- /**
- * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- *
- */
- class FakeTimers {
- constructor(_ref) {
- let global = _ref.global,
- moduleMocker = _ref.moduleMocker,
- timerConfig = _ref.timerConfig,
- config = _ref.config,
- maxLoops = _ref.maxLoops;
- this._global = global;
- this._timerConfig = timerConfig;
- this._config = config;
- this._maxLoops = maxLoops || 100000;
- this._uuidCounter = 1;
- this._moduleMocker = moduleMocker;
- // Store original timer APIs for future reference
- this._timerAPIs = {
- clearImmediate: global.clearImmediate,
- clearInterval: global.clearInterval,
- clearTimeout: global.clearTimeout,
- nextTick: global.process && global.process.nextTick,
- setImmediate: global.setImmediate,
- setInterval: global.setInterval,
- setTimeout: global.setTimeout
- };
- this.reset();
- this._createMocks();
- // These globally-accessible function are now deprecated!
- // They will go away very soon, so do not use them!
- // Instead, use the versions available on the `jest` object
- global.mockRunTicksRepeatedly = this.runAllTicks.bind(this);
- global.mockRunTimersOnce = this.runOnlyPendingTimers.bind(this);
- global.mockAdvanceTimersByTime = this.advanceTimersByTime.bind(this);
- global.mockRunTimersRepeatedly = this.runAllTimers.bind(this);
- global.mockClearTimers = this.clearAllTimers.bind(this);
- global.mockGetTimersCount = () => Object.keys(this._timers).length;
- }
- clearAllTimers() {
- this._immediates.forEach(immediate =>
- this._fakeClearImmediate(immediate.uuid)
- );
- for (const uuid in this._timers) {
- delete this._timers[uuid];
- }
- }
- dispose() {
- this._disposed = true;
- this.clearAllTimers();
- }
- reset() {
- this._cancelledTicks = {};
- this._cancelledImmediates = {};
- this._now = 0;
- this._ticks = [];
- this._immediates = [];
- this._timers = {};
- }
- runAllTicks() {
- this._checkFakeTimers();
- // Only run a generous number of ticks and then bail.
- // This is just to help avoid recursive loops
- let i;
- for (i = 0; i < this._maxLoops; i++) {
- const tick = this._ticks.shift();
- if (tick === undefined) {
- break;
- }
- if (!this._cancelledTicks.hasOwnProperty(tick.uuid)) {
- // Callback may throw, so update the map prior calling.
- this._cancelledTicks[tick.uuid] = true;
- tick.callback();
- }
- }
- if (i === this._maxLoops) {
- throw new Error(
- 'Ran ' +
- this._maxLoops +
- ' ticks, and there are still more! ' +
- "Assuming we've hit an infinite recursion and bailing out..."
- );
- }
- }
- runAllImmediates() {
- this._checkFakeTimers();
- // Only run a generous number of immediates and then bail.
- let i;
- for (i = 0; i < this._maxLoops; i++) {
- const immediate = this._immediates.shift();
- if (immediate === undefined) {
- break;
- }
- this._runImmediate(immediate);
- }
- if (i === this._maxLoops) {
- throw new Error(
- 'Ran ' +
- this._maxLoops +
- ' immediates, and there are still more! Assuming ' +
- "we've hit an infinite recursion and bailing out..."
- );
- }
- }
- _runImmediate(immediate) {
- if (!this._cancelledImmediates.hasOwnProperty(immediate.uuid)) {
- // Callback may throw, so update the map prior calling.
- this._cancelledImmediates[immediate.uuid] = true;
- immediate.callback();
- }
- }
- runAllTimers() {
- this._checkFakeTimers();
- this.runAllTicks();
- this.runAllImmediates();
- // Only run a generous number of timers and then bail.
- // This is just to help avoid recursive loops
- let i;
- for (i = 0; i < this._maxLoops; i++) {
- const nextTimerHandle = this._getNextTimerHandle();
- // If there are no more timer handles, stop!
- if (nextTimerHandle === null) {
- break;
- }
- this._runTimerHandle(nextTimerHandle);
- // Some of the immediate calls could be enqueued
- // during the previous handling of the timers, we should
- // run them as well.
- if (this._immediates.length) {
- this.runAllImmediates();
- }
- if (this._ticks.length) {
- this.runAllTicks();
- }
- }
- if (i === this._maxLoops) {
- throw new Error(
- 'Ran ' +
- this._maxLoops +
- ' timers, and there are still more! ' +
- "Assuming we've hit an infinite recursion and bailing out..."
- );
- }
- }
- runOnlyPendingTimers() {
- const timers = Object.assign({}, this._timers);
- this._checkFakeTimers();
- this._immediates.forEach(this._runImmediate, this);
- Object.keys(timers)
- .sort((left, right) => timers[left].expiry - timers[right].expiry)
- .forEach(this._runTimerHandle, this);
- }
- advanceTimersByTime(msToRun) {
- this._checkFakeTimers();
- // Only run a generous number of timers and then bail.
- // This is just to help avoid recursive loops
- let i;
- for (i = 0; i < this._maxLoops; i++) {
- const timerHandle = this._getNextTimerHandle();
- // If there are no more timer handles, stop!
- if (timerHandle === null) {
- break;
- }
- const nextTimerExpiry = this._timers[timerHandle].expiry;
- if (this._now + msToRun < nextTimerExpiry) {
- // There are no timers between now and the target we're running to, so
- // adjust our time cursor and quit
- this._now += msToRun;
- break;
- } else {
- msToRun -= nextTimerExpiry - this._now;
- this._now = nextTimerExpiry;
- this._runTimerHandle(timerHandle);
- }
- }
- if (i === this._maxLoops) {
- throw new Error(
- 'Ran ' +
- this._maxLoops +
- ' timers, and there are still more! ' +
- "Assuming we've hit an infinite recursion and bailing out..."
- );
- }
- }
- runWithRealTimers(cb) {
- const prevClearImmediate = this._global.clearImmediate;
- const prevClearInterval = this._global.clearInterval;
- const prevClearTimeout = this._global.clearTimeout;
- const prevNextTick = this._global.process.nextTick;
- const prevSetImmediate = this._global.setImmediate;
- const prevSetInterval = this._global.setInterval;
- const prevSetTimeout = this._global.setTimeout;
- this.useRealTimers();
- let cbErr = null;
- let errThrown = false;
- try {
- cb();
- } catch (e) {
- errThrown = true;
- cbErr = e;
- }
- this._global.clearImmediate = prevClearImmediate;
- this._global.clearInterval = prevClearInterval;
- this._global.clearTimeout = prevClearTimeout;
- this._global.process.nextTick = prevNextTick;
- this._global.setImmediate = prevSetImmediate;
- this._global.setInterval = prevSetInterval;
- this._global.setTimeout = prevSetTimeout;
- if (errThrown) {
- throw cbErr;
- }
- }
- useRealTimers() {
- const global = this._global;
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'clearImmediate',
- this._timerAPIs.clearImmediate
- );
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'clearInterval',
- this._timerAPIs.clearInterval
- );
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'clearTimeout',
- this._timerAPIs.clearTimeout
- );
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'setImmediate',
- this._timerAPIs.setImmediate
- );
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'setInterval',
- this._timerAPIs.setInterval
- );
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'setTimeout',
- this._timerAPIs.setTimeout
- );
- global.process.nextTick = this._timerAPIs.nextTick;
- }
- useFakeTimers() {
- this._createMocks();
- const global = this._global;
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'clearImmediate',
- this._fakeTimerAPIs.clearImmediate
- );
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'clearInterval',
- this._fakeTimerAPIs.clearInterval
- );
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'clearTimeout',
- this._fakeTimerAPIs.clearTimeout
- );
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'setImmediate',
- this._fakeTimerAPIs.setImmediate
- );
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'setInterval',
- this._fakeTimerAPIs.setInterval
- );
- (0, (_set_global || _load_set_global()).default)(
- global,
- 'setTimeout',
- this._fakeTimerAPIs.setTimeout
- );
- global.process.nextTick = this._fakeTimerAPIs.nextTick;
- }
- _checkFakeTimers() {
- if (this._global.setTimeout !== this._fakeTimerAPIs.setTimeout) {
- this._global.console.warn(
- `A function to advance timers was called but the timers API is not ` +
- `mocked with fake timers. Call \`jest.useFakeTimers()\` in this ` +
- `test or enable fake timers globally by setting ` +
- `\`"timers": "fake"\` in ` +
- `the configuration file. This warning is likely a result of a ` +
- `default configuration change in Jest 15.\n\n` +
- `Release Blog Post: https://jestjs.io/blog/2016/09/01/jest-15.html\n` +
- `Stack Trace:\n` +
- (0, (_jestMessageUtil || _load_jestMessageUtil()).formatStackTrace)(
- new Error().stack,
- this._config,
- {
- noStackTrace: false
- }
- )
- );
- }
- }
- _createMocks() {
- const fn = impl => this._moduleMocker.fn().mockImplementation(impl);
- this._fakeTimerAPIs = {
- clearImmediate: fn(this._fakeClearImmediate.bind(this)),
- clearInterval: fn(this._fakeClearTimer.bind(this)),
- clearTimeout: fn(this._fakeClearTimer.bind(this)),
- nextTick: fn(this._fakeNextTick.bind(this)),
- setImmediate: fn(this._fakeSetImmediate.bind(this)),
- setInterval: fn(this._fakeSetInterval.bind(this)),
- setTimeout: fn(this._fakeSetTimeout.bind(this))
- };
- }
- _fakeClearTimer(timerRef) {
- const uuid = this._timerConfig.refToId(timerRef);
- if (uuid && this._timers.hasOwnProperty(uuid)) {
- delete this._timers[String(uuid)];
- }
- }
- _fakeClearImmediate(uuid) {
- this._cancelledImmediates[uuid] = true;
- }
- _fakeNextTick(callback) {
- if (this._disposed) {
- return;
- }
- const args = [];
- for (let ii = 1, ll = arguments.length; ii < ll; ii++) {
- args.push(arguments[ii]);
- }
- const uuid = String(this._uuidCounter++);
- this._ticks.push({
- callback: () => callback.apply(null, args),
- uuid: uuid
- });
- const cancelledTicks = this._cancelledTicks;
- this._timerAPIs.nextTick(() => {
- if (!cancelledTicks.hasOwnProperty(uuid)) {
- // Callback may throw, so update the map prior calling.
- cancelledTicks[uuid] = true;
- callback.apply(null, args);
- }
- });
- }
- _fakeSetImmediate(callback) {
- if (this._disposed) {
- return null;
- }
- const args = [];
- for (let ii = 1, ll = arguments.length; ii < ll; ii++) {
- args.push(arguments[ii]);
- }
- const uuid = this._uuidCounter++;
- this._immediates.push({
- callback: () => callback.apply(null, args),
- uuid: String(uuid)
- });
- const cancelledImmediates = this._cancelledImmediates;
- this._timerAPIs.setImmediate(() => {
- if (!cancelledImmediates.hasOwnProperty(uuid)) {
- // Callback may throw, so update the map prior calling.
- cancelledImmediates[String(uuid)] = true;
- callback.apply(null, args);
- }
- });
- return uuid;
- }
- _fakeSetInterval(callback, intervalDelay) {
- if (this._disposed) {
- return null;
- }
- if (intervalDelay == null) {
- intervalDelay = 0;
- }
- const args = [];
- for (let ii = 2, ll = arguments.length; ii < ll; ii++) {
- args.push(arguments[ii]);
- }
- const uuid = this._uuidCounter++;
- this._timers[String(uuid)] = {
- callback: () => callback.apply(null, args),
- expiry: this._now + intervalDelay,
- interval: intervalDelay,
- type: 'interval'
- };
- return this._timerConfig.idToRef(uuid);
- }
- _fakeSetTimeout(callback, delay) {
- if (this._disposed) {
- return null;
- }
- // eslint-disable-next-line no-bitwise
- delay = Number(delay) | 0;
- const args = [];
- for (let ii = 2, ll = arguments.length; ii < ll; ii++) {
- args.push(arguments[ii]);
- }
- const uuid = this._uuidCounter++;
- this._timers[String(uuid)] = {
- callback: () => callback.apply(null, args),
- expiry: this._now + delay,
- interval: null,
- type: 'timeout'
- };
- return this._timerConfig.idToRef(uuid);
- }
- _getNextTimerHandle() {
- let nextTimerHandle = null;
- let uuid;
- let soonestTime = MS_IN_A_YEAR;
- let timer;
- for (uuid in this._timers) {
- timer = this._timers[uuid];
- if (timer.expiry < soonestTime) {
- soonestTime = timer.expiry;
- nextTimerHandle = uuid;
- }
- }
- return nextTimerHandle;
- }
- _runTimerHandle(timerHandle) {
- const timer = this._timers[timerHandle];
- if (!timer) {
- return;
- }
- switch (timer.type) {
- case 'timeout':
- const callback = timer.callback;
- delete this._timers[timerHandle];
- callback();
- break;
- case 'interval':
- timer.expiry = this._now + timer.interval;
- timer.callback();
- break;
- default:
- throw new Error('Unexpected timer type: ' + timer.type);
- }
- }
- }
- exports.default = FakeTimers;
|