使用jest.useFakeTimers仍遇轮询函数超时,求正确测试用例
轮询函数测试超时问题及解决方案
实现的轮询函数
export const wait = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms)); /** * @param fn 异步函数,返回待轮询的结果 * @param cb 验证结果的回调,返回true时停止轮询 * @param ms 轮询间隔时间 * @returns 符合条件的结果 */ export async function polling<T>( fn: () => Promise<T>, cb: (res: T) => boolean, ms: number ): Promise<T> { try { const res = await fn(); if (cb(res)) { return res; } await wait(ms); return polling(fn, cb, ms); } catch (error) { throw error; } }
我编写的测试用例
it('should poll for 5 times', async () => { jest.useFakeTimers(); let count = 0; const fn = () => { count += 1; return count; }; const cb = (res) => res === 5; const resP = polling(fn, cb, 1); jest.runAllTimers(); const res = await resP; jestExpect(res).toBe(6); });
遇到的超时错误
● Test Data Science Common Utility functions › should poll 5 times : Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Error: 95 | }); 96 | > 97 | it('should poll for 5 times', async () => { | ^ 98 | jest.useFakeTimers(); 99 | let count = 0; 100 | const fn = () => {
问题分析与正确测试用例
你的测试用例存在3个核心问题导致超时:
fn不是异步函数,但polling要求参数必须返回Promise,类型不匹配打乱了异步流程jest.runAllTimers()是同步执行逻辑,无法处理递归轮询产生的异步计时器链- 断言逻辑错误:当
res===5时回调返回true,轮询会立即停止,最终结果应为5而非6
以下是修正后的测试用例:
it('should poll until the result meets the condition', async () => { jest.useFakeTimers(); let count = 0; // 修正:让fn返回Promise,符合polling的参数要求 const fn = async () => { count += 1; return count; }; // 当count等于5时停止轮询 const cb = (res: number) => res === 5; const resP = polling(fn, cb, 100); // 使用runAllTimersAsync处理异步递归的计时器 await jest.runAllTimersAsync(); const res = await resP; // 断言最终结果是符合条件的5 expect(res).toBe(5); // 额外验证:fn确实被调用了5次 expect(count).toBe(5); // 测试完成后恢复真实计时器,避免影响其他测试 jest.useRealTimers(); });
关键修改说明
- 异步fn:必须将
fn改为async函数,确保返回Promise,匹配polling的参数类型定义 - runAllTimersAsync:递归轮询会不断生成新的异步计时器,该方法会等待所有异步计时器执行完成,解决超时问题
- 修正断言值:回调返回true时,当前的
res就是目标结果,所以最终返回值为5 - 恢复真实计时器:测试结束后调用
jest.useRealTimers(),避免fake timers干扰其他测试用例
内容的提问来源于stack exchange,提问作者bhushan laware
相关产品推荐
相关产品推荐

