因为定时器依赖于实时时间,所以在测试时不是很方便。
Jest 可以将定时器换成允许我们自己控制时间的功能。

定时器模拟

jest.useFakeTimers();   // 使用标准计时器函数的模拟版本
jest.useRealTimers()    // 使用标准计时器函数的真实版本
jest.clearAllTimers();  // 从计时器系统中删除任何挂起的计时器

通常每次测试之前手动调用或者在 beforeEach 函数中调用 useFakeTimers。不这样做会导致未重置内部使用计数器。

runAllTimers

通常在测试时我们不想等待那么长时间才真正执行回调。Jest 提供 jest.runAllTimers函数来运行所有等待中的 timer。

jest.useFakeTimers();

it('closes some time after being opened.', (done) => {
  // An automatic door that fires a `closed` event.
  const autoDoor = new AutoDoor();
  autoDoor.on('closed', done);
  autoDoor.open();
  // 直接运行所有等待中的 timer
  jest.runAllTimers();
});

runTimersToTime

如果不想一次性运行所有计时器怎么办?runTimersToTime 可以只模拟时间流逝。

jest.useFakeTimers();

it('announces it will close before closing.', (done) => {
  const autoDoor = new AutoDoor();
  // The test passes if there's a `closing` event.
  autoDoor.on('closing', done);
  // The test fails if there's a `closed` event.
  autoDoor.on('closed', done.fail);
  autoDoor.open();
  // Only move ahead enough time so that it starts closing, but not enough that it is closed.
  jest.runTimersToTime(autoDoor.TIME_BEFORE_CLOSING);
});

runOnlyPendingTimers

只执行当前挂起的宏任务(即,只包括到目前为止由setTimeout()或setInterval()排队的任务。如果当前挂起的任何宏任务调度了新的宏任务,那么这个调用将不会执行这些新任务。

例如递归地调用setTimeout(),在这个场景中使用 runOnlyPendingTimers 能够一次只向前运行一步。

advanceTimersByTime

把计时器都提前指定的毫秒。将执行已经通过setTimeout()或setInterval()排队并且将在此时间帧期间执行所有待处理"宏任务"。此外,如果这些宏任务调度将在同一时间帧内执行的新宏任务,那么将执行这些宏任务,直到队列中不再有宏任务应该在msToRun毫秒内运行。