如何在Jest中伪造timers/promises中的setTimeout定时器?
解决Jest中mock timers/promises setTimeout的问题
因为timers/promises里的setTimeout是不可配置属性,直接用jest.spyOn修改它会触发"Cannot redefine property"错误,而且Jest默认的fake timers不支持Promise版本的定时器,这里给你几个可行方案:
方案1:Mock整个timers/promises模块
直接用jest.mock模拟整个模块,让setTimeout立即返回resolved的Promise,跳过等待:
jest.mock('timers/promises', () => ({ setTimeout: jest.fn(() => Promise.resolve()) }));
在测试用例中,调用依赖这个方法的代码时,setTimeout会立刻完成,不需要等待实际时间。
方案2:使用Jest现代Fake Timers
Jest 27+版本支持现代fake timers,能处理Promise-based的定时器。你需要启用modern: true配置,然后用异步版本的timer方法快进时间:
- 启用现代fake timers:
jest.useFakeTimers({ modern: true });
- 在测试中执行完目标代码后,运行所有pending的定时器:
// 执行你的业务代码,比如调用了timersPromises.setTimeout的函数 await yourFunctionThatUsesPromiseTimeout(); // 快进所有定时器,处理完所有Promise await jest.runAllTimersAsync(); // 然后进行断言 expect(yourMock).toHaveBeenCalled();
方案3:手动封装定时器(推荐长期维护)
在业务代码里封装一层定时器逻辑,比如写一个delay函数:
// utils/delay.js import { setTimeout as promiseTimeout } from 'timers/promises'; export const delay = (ms) => promiseTimeout(ms);
然后在测试中mock这个封装的函数,这样就不会直接依赖timers/promises,mock起来更灵活:
jest.mock('../utils/delay', () => ({ delay: jest.fn(() => Promise.resolve()) }));
内容的提问来源于stack exchange,提问作者Michael Goldstein
相关产品推荐
相关产品推荐

