You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试setTimeout内部的函数调用?代码覆盖率未达标求助

解决setTimeout内部代码未被代码覆盖率统计的问题

问题核心

你的测试能正常运行,但setTimeout里的navigate("/home")始终没被覆盖率统计到,问题出在定时器处理逻辑有误和断言时机不对:

  • 测试里额外加的setTimeout(() => {...}, 4000)完全多余,会导致断言在测试结束后才执行,jest无法捕捉到那行代码的执行记录
  • 可能没正确mockcreateContact为resolved状态,或者没开启jest假定时器,导致try块里的setTimeout没被触发

修复步骤

  1. 开启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,避免影响其他测试
    });
    
  2. 移除多余的外层setTimeout断言
    调用jest.runAllTimers()后,所有待执行的定时器代码会立即触发,不需要延迟断言,直接在之后写验证逻辑即可。

  3. 修改后的完整测试代码

    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 16:55:24