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

使用Jest测试时react-router-dom的useNavigate未被调用问题排查

问题:React登录组件测试中useNavigate Mock未被检测到调用

组件登录提交逻辑

...
const navigate = useNavigate();
...
const onSubmit = async (event) => {
  event.preventDefault();

  const { payload } = await dispatch(
    startLoginWithEmail({ email, password })
  );

  if (payload.ok) {
    navigate("/", {
      replace: true,
    });
  }
}
...

单元测试代码

test("should call startLoginWithEmail when the Login button is clicked", () => {
    const email = "email@example.com";
    const password = "12345678";

    render(
      <Provider store={store}>
        <MemoryRouter>
          <Login />
        </MemoryRouter>
      </Provider>
    );

    mockStartLoginWithEmail.mockResolvedValue({ payload: { ok: true } });
    
    const emailInputText = screen.getByRole("textbox", { name: /email/i });
    fireEvent.change(emailInputText, {
      target: { name: "email", value: email },
    });
    
    const passwordInputText = screen.getByLabelText(/password/i);
    fireEvent.change(passwordInputText, {
      target: { name: "password", value: password },
    });
    
    const form = screen.getByRole("form");
    fireEvent.submit(form);
    
    expect(mockStartLoginWithEmail).toHaveBeenCalledWith({ email, password });
    
    expect(mockUseNavigate).toHaveBeenCalledWith("/", {
       replace: true,
    });
  });

useNavigate的Mock实现

const mockUseNavigate = jest.fn();
jest.mock("react-router-dom", () => ({
  ...jest.requireActual("react-router-dom"),
  useNavigate: () => mockUseNavigate,
}));

问题现象

组件在应用中运行正常,但单元测试里mockUseNavigate始终显示调用次数为0。调试日志显示navigate逻辑应该被执行,但测试断言不通过。此前类似Mock方案在其他项目中有效。


修复方案

1. 等待异步操作完成

onSubmit是异步函数,fireEvent.submit不会等待内部异步逻辑执行完毕,导致断言时navigate还未被调用。有两种解决方式:

方式一:使用waitFor包裹断言

import { waitFor } from '@testing-library/react';

// 在fireEvent.submit之后添加:
await waitFor(() => {
  expect(mockUseNavigate).toHaveBeenCalledWith("/", { replace: true });
});

方式二:改用userEvent处理提交

@testing-library/user-event会自动等待异步操作完成,更贴近真实用户行为:

import userEvent from '@testing-library/user-event';

// 替换fireEvent.submit为:
await userEvent.submit(form);

// 之后直接断言即可
expect(mockUseNavigate).toHaveBeenCalledWith("/", { replace: true });

2. 确认Mock的正确性

当前Mock写法本身没问题,但需确保:

  • mockUseNavigate在测试前被正确初始化,且每次测试后被重置(可在beforeEach中调用mockUseNavigate.mockClear())
  • 组件中useNavigate的导入路径与Mock的react-router-dom一致,没有使用别名或相对路径导入

内容的提问来源于stack exchange,提问作者manou

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 03:09:26