Jest 中 如何测试 setTimeout

Jest Time Mocks

原生的 time 函数 (比如,setTimeout, setInterval, clearTimeout, clearInterval) 不是很便于测试,因为需要依赖于真正的时间流逝,Jest 可以用函数来代替 timers, 从而让你来控制时间的流逝。

假设我们需要测试一段异步的代码:

function fun(obj) {
  setTimeout(() => {
    obj.a = 1;
  }, 1000);
}


test('test', () => {
  const obj = { a: 2 };
  fun(obj);
  expect(obj).toEqual({ a: 1 });   // error
});

以上代码会失败,因为 setTimeout 是异步代码,需要一段时间之后才能得到结果.

于是 Jest 提供了 runAllTimers() 这个函数来测试异步。

function fun(obj) {
  setTimeout(() => {
    obj.a = 1;
  }, 1000);
}


test('test', () => {
  const obj = { a: 2 };
  jest.useFakeTimers();        //  开启模拟定时器
  fun(obj);
  jest.runAllTimers();         // 加速,让所有的定时器都执行完毕
  expect(obj).toEqual({ a: 1 });
});

通过以上这种方式,异步代码就可以测试通过了。

但是,如果存在 timer 递归的时候runAllTimer() 就会失败,因为一直都存在定时器。

这个时候应该使用 runOnlyPendingTimers

另外,我们可以通过 advanceTimersByTime(time) 来指定加速多久。

还是这个例子:

以上定时器的测试例子,同样适用于测试 React 组件,如某个操作发生,需要 setTimeout 一定时间之后才改变 state 的场景。

Last updated

Was this helpful?