如何测试setTimeout内部的函数调用?代码覆盖率未达标求助
解决setTimeout内部代码未被代码覆盖率统计的问题
问题核心
你的测试能正常运行,但setTimeout里的navigate("/home")始终没被覆盖率统计到,问题出在定时器处理逻辑有误和断言时机不对:
- 测试里额外加的
setTimeout(() => {...}, 4000)完全多余,会导致断言在测试结束后才执行,jest无法捕捉到那行代码的执行记录 - 可能没正确mock
createContact为resolved状态,或者没开启jest假定时器,导致try块里的setTimeout没被触发
修复步骤
开启jest假定时器并mock依赖
在测试的前置钩子中开启假定时器,同时确保createContact返回resolved的Promise(否则代码会进入catch块,跳过setTimeout逻辑):beforeEach(() => { jest.useFakeTimers(); jest.spyOn(router, "useNavigate").mockImplementation(() => navigate); // mock useContactsApi,确保createContact成功返回 jest.spyOn(require('./你的ContactsApi路径'), 'useContactsApi').mockReturnValue({ createContact: jest.fn().mockResolvedValue({}) }); }); afterEach(() => { jest.useRealTimers(); // 测试结束后恢复真实定时器 jest.restoreAllMocks(); // 重置所有mock,避免影响其他测试 });移除多余的外层setTimeout断言
调用jest.runAllTimers()后,所有待执行的定时器代码会立即触发,不需要延迟断言,直接在之后写验证逻辑即可。修改后的完整测试代码
const navigate = jest.fn(); beforeEach(() => { jest.useFakeTimers(); jest.spyOn(router, "useNavigate").mockImplementation(() => navigate); jest.spyOn(require('./路径/ContactsApi'), 'useContactsApi').mockReturnValue({ createContact: jest.fn().mockResolvedValue({}) }); }); afterEach(() => { jest.useRealTimers(); jest.restoreAllMocks(); }); test("Then it should call the navigate function", async () => { const newText = "test@prove"; render( <MemoryRouter> <Provider store={store}> <CreateContact /> </Provider> </MemoryRouter> ); const nameInput = screen.getByLabelText("Name") as HTMLInputElement; await userEvent.type(nameInput, newText); const submitBtn = screen.getByRole("button", { name: "Create contact" }); await userEvent.click(submitBtn); // 立即执行所有待处理的定时器 jest.runAllTimers(); // 直接断言,无需额外延迟 expect(navigate).toHaveBeenCalledTimes(1); expect(navigate).toHaveBeenCalledWith("/home"); });
可选优化
如果不想一次性执行所有定时器,也可以用jest.advanceTimersByTime(2500)模拟时间推进2500ms,精准触发目标定时器,效果和runAllTimers一致。
内容的提问来源于stack exchange,提问作者aronilie
相关产品推荐
相关产品推荐

