用 jest 的 fake timers 替代真实计时器,调用 jest.usefaketimers() 启用,jest.runalltimers() 立即执行定时回调,jest.advancetimersbytime() 可控推进,需 aftereach 中用 jest.userealtimers() 清理。

在 JS 测试中跳过 setTimeout 的等待,核心方法是**用 Jest 的定时器模拟(fake timers)替代真实计时器**,让所有定时任务立即执行或可控推进。
启用 Jest 的 fake timers
在测试文件顶部或 beforeEach 中调用:
-
jest.useFakeTimers();—— 启用模拟定时器,此后所有setTimeout、setInterval不会真实等待 - 建议搭配
jest.runAllTimers();立即执行所有已注册的定时回调 - 若需逐步推进(比如验证中间状态),可用
jest.advanceTimersByTime(ms);
常见测试场景写法
假设你有如下代码:
function delayedLog(msg) {
setTimeout(() => console.log(msg), 1000);
}
对应测试可写为:
test('should log after delay', () => {
jest.useFakeTimers();
const spy = jest.spyOn(console, 'log');
delayedLog('hello');
expect(spy).not.toHaveBeenCalled(); // 还没执行
jest.runAllTimers(); // 立即触发
expect(spy).toHaveBeenCalledWith('hello');
spy.mockRestore();
});
注意清理与重置
避免 fake timers 影响其他测试:
- 在
afterEach中调用jest.useRealTimers();恢复真实定时器 - 或在每个测试末尾显式重置:
jest.clearAllTimers(); - 不推荐全局启用(如在
setupFilesAfterEnv中),除非所有测试都依赖 fake timers
对 Promise + setTimeout 的处理(如 debounce)
如果逻辑封装在 Promise 中(例如 return new Promise(r => setTimeout(r, 300))),记得配合 await 和 jest.runAllTimers() 或 await jest.runAllTimersAsync()(Jest 27+ 推荐异步版本):
-
jest.runAllTimersAsync()确保 Promise 微任务队列也被清空 - 否则可能因 Promise 未 resolve 导致
await卡住











