Skip to content

Commit

Permalink
fix: getTimerCount not taking immediates and ticks into account (#8139)
Browse files Browse the repository at this point in the history
  • Loading branch information
xixixao authored and SimenB committed Mar 18, 2019
1 parent 4d9f99c commit 8675290
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 27 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
## master

- `[*]` Add documentation and tests related to auto-mocking ([#8086](https://github.com/facebook/jest/pull/8099))

### Features

### Fixes

- `[jest-each]` Fix test function type ([#8145](https://github.com/facebook/jest/pull/8145))
- `[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

- `[*]` Remove flow from code base ([#8061](https://github.com/facebook/jest/pull/8061))
- `[*]` 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

Expand Down
17 changes: 17 additions & 0 deletions packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1165,5 +1165,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);
});
});
});
53 changes: 28 additions & 25 deletions packages/jest-fake-timers/src/jestFakeTimers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default class FakeTimers<TimerRef> {
private _now!: number;
private _ticks!: Array<Tick>;
private _timerAPIs: TimerAPI;
private _timers!: {[key: string]: Timer};
private _timers!: Map<string, Timer>;
private _uuidCounter: number;
private _timerConfig: TimerConfig<TimerRef>;

Expand Down Expand Up @@ -108,9 +108,7 @@ export default class FakeTimers<TimerRef> {
this._immediates.forEach(immediate =>
this._fakeClearImmediate(immediate.uuid),
);
for (const uuid in this._timers) {
delete this._timers[uuid];
}
this._timers.clear();
}

dispose() {
Expand All @@ -124,7 +122,7 @@ export default class FakeTimers<TimerRef> {
this._now = 0;
this._ticks = [];
this._immediates = [];
this._timers = {};
this._timers = new Map();
}

runAllTicks() {
Expand Down Expand Up @@ -227,12 +225,16 @@ export default class FakeTimers<TimerRef> {
}

runOnlyPendingTimers() {
const timers = {...this._timers};
// 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);
Object.keys(timers)
.sort((left, right) => timers[left].expiry - timers[right].expiry)
.forEach(this._runTimerHandle, this);

timerEntries
.sort(([, left], [, right]) => left.expiry - right.expiry)
.forEach(([timerHandle]) => this._runTimerHandle(timerHandle));
}

advanceTimersByTime(msToRun: number) {
Expand All @@ -247,8 +249,11 @@ export default class FakeTimers<TimerRef> {
if (timerHandle === null) {
break;
}

const nextTimerExpiry = this._timers[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
Expand Down Expand Up @@ -333,7 +338,7 @@ export default class FakeTimers<TimerRef> {
getTimerCount() {
this._checkFakeTimers();

return Object.keys(this._timers).length;
return this._timers.size + this._immediates.length + this._ticks.length;
}

private _checkFakeTimers() {
Expand Down Expand Up @@ -374,8 +379,8 @@ export default class FakeTimers<TimerRef> {
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.delete(String(uuid));
}
}

Expand Down Expand Up @@ -444,12 +449,12 @@ export default class FakeTimers<TimerRef> {

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);
}
Expand All @@ -468,34 +473,32 @@ export default class FakeTimers<TimerRef> {

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);
}

private _getNextTimerHandle() {
let nextTimerHandle = null;
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;
Expand All @@ -504,7 +507,7 @@ export default class FakeTimers<TimerRef> {
switch (timer.type) {
case 'timeout':
const callback = timer.callback;
delete this._timers[timerHandle];
this._timers.delete(timerHandle);
callback();
break;

Expand Down

0 comments on commit 8675290

Please sign in to comment.