From 07837df8795c3198943c388675fd4b1637059f9c Mon Sep 17 00:00:00 2001 From: xixixao Date: Sun, 17 Mar 2019 15:20:43 +0000 Subject: [PATCH 1/5] Move timers from Object to Map --- .../jest-fake-timers/src/jestFakeTimers.ts | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/packages/jest-fake-timers/src/jestFakeTimers.ts b/packages/jest-fake-timers/src/jestFakeTimers.ts index 9dca4a0ac1d2..4ffbde6fe737 100644 --- a/packages/jest-fake-timers/src/jestFakeTimers.ts +++ b/packages/jest-fake-timers/src/jestFakeTimers.ts @@ -65,7 +65,7 @@ export default class FakeTimers { private _now!: number; private _ticks!: Array; private _timerAPIs: TimerAPI; - private _timers!: {[key: string]: Timer}; + private _timers!: Map; private _uuidCounter: number; private _timerConfig: TimerConfig; @@ -108,9 +108,7 @@ export default class FakeTimers { this._immediates.forEach(immediate => this._fakeClearImmediate(immediate.uuid), ); - for (const uuid in this._timers) { - delete this._timers[uuid]; - } + this._timers.clear(); } dispose() { @@ -124,7 +122,7 @@ export default class FakeTimers { this._now = 0; this._ticks = []; this._immediates = []; - this._timers = {}; + this._timers = new Map(); } runAllTicks() { @@ -227,11 +225,13 @@ export default class FakeTimers { } runOnlyPendingTimers() { - const timers = {...this._timers}; this._checkFakeTimers(); this._immediates.forEach(this._runImmediate, this); - Object.keys(timers) - .sort((left, right) => timers[left].expiry - timers[right].expiry) + Array.from(this._timers.keys()) + .sort( + (left, right) => + this._timers.get(left).expiry - this._timers.get(right).expiry + ) .forEach(this._runTimerHandle, this); } @@ -248,7 +248,7 @@ export default class FakeTimers { break; } - const nextTimerExpiry = this._timers[timerHandle].expiry; + const nextTimerExpiry = this._timers.get(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 @@ -333,7 +333,7 @@ export default class FakeTimers { getTimerCount() { this._checkFakeTimers(); - return Object.keys(this._timers).length; + return this._timers.size; } private _checkFakeTimers() { @@ -374,8 +374,8 @@ export default class FakeTimers { private _fakeClearTimer(timerRef: TimerRef) { const uuid = this._timerConfig.refToId(timerRef); - if (uuid && this._timers.hasOwnProperty(uuid)) { - delete this._timers[String(uuid)]; + if (uuid && this._timers.has(uuid)) { + this._timers.delete(String(uuid)); } } @@ -444,12 +444,12 @@ export default class FakeTimers { const uuid = this._uuidCounter++; - this._timers[String(uuid)] = { + this._timers.set(String(uuid), { callback: () => callback.apply(null, args), expiry: this._now + intervalDelay, interval: intervalDelay, type: 'interval', - }; + }); return this._timerConfig.idToRef(uuid); } @@ -468,12 +468,12 @@ export default class FakeTimers { const uuid = this._uuidCounter++; - this._timers[String(uuid)] = { + this._timers.set(String(uuid), { callback: () => callback.apply(null, args), expiry: this._now + delay, interval: undefined, type: 'timeout', - }; + }); return this._timerConfig.idToRef(uuid); } @@ -483,19 +483,18 @@ export default class FakeTimers { let uuid; let soonestTime = MS_IN_A_YEAR; let timer; - for (uuid in this._timers) { - timer = this._timers[uuid]; + this._timers.forEach((timer, uuid) => { if (timer.expiry < soonestTime) { soonestTime = timer.expiry; nextTimerHandle = uuid; } - } + }); return nextTimerHandle; } private _runTimerHandle(timerHandle: TimerID) { - const timer = this._timers[timerHandle]; + const timer = this._timers.get(timerHandle); if (!timer) { return; @@ -504,7 +503,7 @@ export default class FakeTimers { switch (timer.type) { case 'timeout': const callback = timer.callback; - delete this._timers[timerHandle]; + this._timers.delete(timerHandle); callback(); break; From 76916e2b1cd40a257841340584ea3bf53fe8915e Mon Sep 17 00:00:00 2001 From: xixixao Date: Sun, 17 Mar 2019 15:24:19 +0000 Subject: [PATCH 2/5] Fix getTimerCount method --- .../src/__tests__/jestFakeTimers.test.ts | 18 ++++++++++++++++++ .../jest-fake-timers/src/jestFakeTimers.ts | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts b/packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts index ac0d7ad149d1..521f93c59eab 100644 --- a/packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts +++ b/packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts @@ -1166,4 +1166,22 @@ describe('FakeTimers', () => { expect(timers.getTimerCount()).toEqual(0); }); }); + + it('includes immediates and ticks', () => { + const timers = new FakeTimers({ + config, + global, + moduleMocker, + timerConfig, + }); + + timers.useFakeTimers(); + + global.setTimeout(() => {}, 0); + global.setImmediate(() => {}); + process.nextTick(() => {}); + + expect(timers.getTimerCount()).toEqual(3); + }); + }); }); diff --git a/packages/jest-fake-timers/src/jestFakeTimers.ts b/packages/jest-fake-timers/src/jestFakeTimers.ts index 4ffbde6fe737..d78055080b36 100644 --- a/packages/jest-fake-timers/src/jestFakeTimers.ts +++ b/packages/jest-fake-timers/src/jestFakeTimers.ts @@ -333,7 +333,7 @@ export default class FakeTimers { getTimerCount() { this._checkFakeTimers(); - return this._timers.size; + return this._timers.size + this._immediates.length + this._ticks.length; } private _checkFakeTimers() { From f81de5c77d7415922239b6bc2cd4ec0060bea2b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Mon, 18 Mar 2019 13:43:41 +0000 Subject: [PATCH 3/5] fix map-based implementation --- .../src/__tests__/jestFakeTimers.test.ts | 3 +-- .../jest-fake-timers/src/jestFakeTimers.ts | 23 ++++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts b/packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts index 521f93c59eab..483d2a7ca5a5 100644 --- a/packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts +++ b/packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts @@ -1165,9 +1165,8 @@ describe('FakeTimers', () => { expect(timers.getTimerCount()).toEqual(0); }); - }); - it('includes immediates and ticks', () => { + it('includes immediates and ticks', () => { const timers = new FakeTimers({ config, global, diff --git a/packages/jest-fake-timers/src/jestFakeTimers.ts b/packages/jest-fake-timers/src/jestFakeTimers.ts index d78055080b36..9009f55181fc 100644 --- a/packages/jest-fake-timers/src/jestFakeTimers.ts +++ b/packages/jest-fake-timers/src/jestFakeTimers.ts @@ -225,14 +225,13 @@ export default class FakeTimers { } runOnlyPendingTimers() { + const timerEntries = Array.from(this._timers.entries()); this._checkFakeTimers(); this._immediates.forEach(this._runImmediate, this); - Array.from(this._timers.keys()) - .sort( - (left, right) => - this._timers.get(left).expiry - this._timers.get(right).expiry - ) - .forEach(this._runTimerHandle, this); + + timerEntries + .sort(([, left], [, right]) => left.expiry - right.expiry) + .forEach(([timerHandle]) => this._runTimerHandle(timerHandle)); } advanceTimersByTime(msToRun: number) { @@ -247,8 +246,11 @@ export default class FakeTimers { if (timerHandle === null) { break; } - - const nextTimerExpiry = this._timers.get(timerHandle).expiry; + const timerValue = this._timers.get(timerHandle); + if (timerValue === undefined) { + break; + } + const nextTimerExpiry = timerValue.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 @@ -374,7 +376,7 @@ export default class FakeTimers { private _fakeClearTimer(timerRef: TimerRef) { const uuid = this._timerConfig.refToId(timerRef); - if (uuid && this._timers.has(uuid)) { + if (uuid) { this._timers.delete(String(uuid)); } } @@ -480,9 +482,8 @@ export default class FakeTimers { private _getNextTimerHandle() { let nextTimerHandle = null; - let uuid; let soonestTime = MS_IN_A_YEAR; - let timer; + this._timers.forEach((timer, uuid) => { if (timer.expiry < soonestTime) { soonestTime = timer.expiry; From 44f18921331fe9133b16b49fe7c95d7029e1698d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Mon, 18 Mar 2019 13:52:29 +0000 Subject: [PATCH 4/5] add a comment --- packages/jest-fake-timers/src/jestFakeTimers.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/jest-fake-timers/src/jestFakeTimers.ts b/packages/jest-fake-timers/src/jestFakeTimers.ts index 9009f55181fc..a8ed4b4509e7 100644 --- a/packages/jest-fake-timers/src/jestFakeTimers.ts +++ b/packages/jest-fake-timers/src/jestFakeTimers.ts @@ -225,6 +225,9 @@ export default class FakeTimers { } runOnlyPendingTimers() { + // We need to hold the current shape of `this._timers` because existing + // timers can add new ones to the map and hence would run more than necessary. + // See https://github.com/facebook/jest/pull/4608 for details const timerEntries = Array.from(this._timers.entries()); this._checkFakeTimers(); this._immediates.forEach(this._runImmediate, this); From 1a35a0bda23e0d363a93e808ba1a56ab3d6559aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Mon, 18 Mar 2019 14:28:36 +0000 Subject: [PATCH 5/5] add changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1718e470eb1..b0bd2c3fbdb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,11 @@ ## master -- `[*]` Add documentation and tests related to auto-mocking ([#8086](https://github.com/facebook/jest/pull/8099)) - ### Features ### Fixes - `[pretty-format]` Print `BigInt` as a readable number instead of `{}` [#8138](https://github.com/facebook/jest/pull/8138) +- `[jest-fake-timers]` `getTimerCount` not taking immediates and ticks into account ([#8139](https://github.com/facebook/jest/pull/8139)) ### Chore & Maintenance @@ -14,6 +13,7 @@ - `[*]` Use property initializer syntax in Jest codebase [#8117](https://github.com/facebook/jest/pull/8117) - `[docs]` Improve description of optional arguments in ExpectAPI.md [#8126](https://github.com/facebook/jest/pull/8126) - `[*]` Move @types/node to the root package.json [#8129](https://github.com/facebook/jest/pull/8129) +- `[*]` Add documentation and tests related to auto-mocking ([#8086](https://github.com/facebook/jest/pull/8099)) ### Performance