feat(zone.js): add jest fakeTimers support (#39016)
Close #38851, support `jest` fakeTimers APIs' integration with `fakeAsync()`. After enable this feature, calling `jest.useFakeTimers()` will make all test run into `fakeAsync()` automatically. ``` beforeEach(() => { jest.useFakeTimers('modern'); }); afterEach(() => { jest.useRealTimers(); }); test('should run into fakeAsync() automatically', () => { const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); expect(fakeAsyncZoneSpec).toBeTruthy(); }); ``` Also there are mappings between `jest` and `zone` APIs. - `jest.runAllTicks()` will call `flushMicrotasks()`. - `jest.runAllTimers()` will call `flush()`. - `jest.advanceTimersByTime()` will call `tick()` - `jest.runOnlyPendingTimers()` will call `flushOnlyPendingTimers()` - `jest.advanceTimersToNextTimer()` will call `tickToNext()` - `jest.clearAllTimers()` will call `removeAllTimers()` - `jest.getTimerCount()` will call `getTimerCount()` PR Close #39016
This commit is contained in:

committed by
Joey Perrott

parent
a48c8edd83
commit
82d54fe8c3
@ -92,6 +92,10 @@ class Scheduler {
|
||||
this._currentRealTime = realTime;
|
||||
}
|
||||
|
||||
getRealSystemTime() {
|
||||
return OriginalDate.now();
|
||||
}
|
||||
|
||||
scheduleFunction(cb: Function, delay: number, options?: {
|
||||
args?: any[],
|
||||
isPeriodic?: boolean,
|
||||
@ -145,6 +149,27 @@ class Scheduler {
|
||||
}
|
||||
}
|
||||
|
||||
removeAll(): void {
|
||||
this._schedulerQueue = [];
|
||||
}
|
||||
|
||||
getTimerCount(): number {
|
||||
return this._schedulerQueue.length;
|
||||
}
|
||||
|
||||
tickToNext(step: number = 1, doTick?: (elapsed: number) => void, tickOptions?: {
|
||||
processNewMacroTasksSynchronously: boolean
|
||||
}) {
|
||||
if (this._schedulerQueue.length < step) {
|
||||
return;
|
||||
}
|
||||
// Find the last task currently queued in the scheduler queue and tick
|
||||
// till that time.
|
||||
const startTime = this._currentTime;
|
||||
const targetTask = this._schedulerQueue[step - 1];
|
||||
this.tick(targetTask.endTime - startTime, doTick, tickOptions);
|
||||
}
|
||||
|
||||
tick(millis: number = 0, doTick?: (elapsed: number) => void, tickOptions?: {
|
||||
processNewMacroTasksSynchronously: boolean
|
||||
}): void {
|
||||
@ -212,6 +237,18 @@ class Scheduler {
|
||||
}
|
||||
}
|
||||
|
||||
flushOnlyPendingTimers(doTick?: (elapsed: number) => void): number {
|
||||
if (this._schedulerQueue.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
// Find the last task currently queued in the scheduler queue and tick
|
||||
// till that time.
|
||||
const startTime = this._currentTime;
|
||||
const lastTask = this._schedulerQueue[this._schedulerQueue.length - 1];
|
||||
this.tick(lastTask.endTime - startTime, doTick, {processNewMacroTasksSynchronously: false});
|
||||
return this._currentTime - startTime;
|
||||
}
|
||||
|
||||
flush(limit = 20, flushPeriodic = false, doTick?: (elapsed: number) => void): number {
|
||||
if (flushPeriodic) {
|
||||
return this.flushPeriodic(doTick);
|
||||
@ -401,6 +438,10 @@ class FakeAsyncTestZoneSpec implements ZoneSpec {
|
||||
this._scheduler.setCurrentRealTime(realTime);
|
||||
}
|
||||
|
||||
getRealSystemTime() {
|
||||
return this._scheduler.getRealSystemTime();
|
||||
}
|
||||
|
||||
static patchDate() {
|
||||
if (!!global[Zone.__symbol__('disableDatePatching')]) {
|
||||
// we don't want to patch global Date
|
||||
@ -450,6 +491,20 @@ class FakeAsyncTestZoneSpec implements ZoneSpec {
|
||||
FakeAsyncTestZoneSpec.resetDate();
|
||||
}
|
||||
|
||||
tickToNext(steps: number = 1, doTick?: (elapsed: number) => void, tickOptions: {
|
||||
processNewMacroTasksSynchronously: boolean
|
||||
} = {processNewMacroTasksSynchronously: true}): void {
|
||||
if (steps <= 0) {
|
||||
return;
|
||||
}
|
||||
FakeAsyncTestZoneSpec.assertInZone();
|
||||
this.flushMicrotasks();
|
||||
this._scheduler.tickToNext(steps, doTick, tickOptions);
|
||||
if (this._lastError !== null) {
|
||||
this._resetLastErrorAndThrow();
|
||||
}
|
||||
}
|
||||
|
||||
tick(millis: number = 0, doTick?: (elapsed: number) => void, tickOptions: {
|
||||
processNewMacroTasksSynchronously: boolean
|
||||
} = {processNewMacroTasksSynchronously: true}): void {
|
||||
@ -486,6 +541,27 @@ class FakeAsyncTestZoneSpec implements ZoneSpec {
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
flushOnlyPendingTimers(doTick?: (elapsed: number) => void): number {
|
||||
FakeAsyncTestZoneSpec.assertInZone();
|
||||
this.flushMicrotasks();
|
||||
const elapsed = this._scheduler.flushOnlyPendingTimers(doTick);
|
||||
if (this._lastError !== null) {
|
||||
this._resetLastErrorAndThrow();
|
||||
}
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
removeAllTimers() {
|
||||
FakeAsyncTestZoneSpec.assertInZone();
|
||||
this._scheduler.removeAll();
|
||||
this.pendingPeriodicTimers = [];
|
||||
this.pendingTimers = [];
|
||||
}
|
||||
|
||||
getTimerCount() {
|
||||
return this._scheduler.getTimerCount() + this._microtasks.length;
|
||||
}
|
||||
|
||||
// ZoneSpec implementation below.
|
||||
|
||||
name: string;
|
||||
|
Reference in New Issue
Block a user