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

React Router useNavigate模拟失败:点击按钮未触发导航调用

问题

我想要验证按钮是否能将用户跳转至首页,但在模拟react-router的useNavigate函数时遇到问题。

当前使用的模拟代码:

const mockNavigate = vi.fn();
vi.mock("react-router", async () => {
    const actual = await vi.importOriginal();

    return {
        ...actual,
        useNavigate: mockNavigate
    }
})

测试代码:

it("should take the user to the home page", async () => {
    renderElement();

    const homeBtn = screen.getByRole("link");
    await userEvent.click(homeBtn)
    expect(mockNavigate).toHaveBeenCalledWith("/")
})

执行测试后返回错误:
Assertion error: expected "spy" to be called with arguments: [ '/' ]

将断言替换为toHaveBeenCalledOnce()后,得到错误:
AssertionError: expected "spy" to be called once, but got 0 times

解决方法

1. 修正路由库的模拟路径

浏览器环境下使用的路由库是react-router-dom,而非react-router,同时useNavigate是一个钩子函数,调用后才会返回实际的跳转方法,所以模拟逻辑需要调整:

const mockNavigate = vi.fn();
vi.mock("react-router-dom", async () => {
  const actual = await vi.importOriginal();
  return {
    ...actual,
    useNavigate: () => mockNavigate
  };
});

2. 确保组件在Router上下文内渲染

react-router的所有钩子必须在Router上下文环境中才能正常工作,渲染测试组件时需要用MemoryRouter包裹:

import { MemoryRouter } from "react-router-dom";

const renderElement = () => {
  render(
    <MemoryRouter>
      {/* 你的目标组件 */}
    </MemoryRouter>
  );
};

3. 检查目标元素的定位是否准确

  • 如果是Link组件,用getByRole("link")定位没问题;如果是普通按钮(通过点击事件手动调用navigate),则应该用getByRole("button")获取元素。
  • 可以在测试中加入screen.debug()打印当前DOM结构,确认是否正确选中了目标按钮。

4. 重置Mock状态(可选)

如果多个测试用例共享同一个Mock,需要在每个测试前重置状态,避免历史调用记录干扰:

beforeEach(() => {
  mockNavigate.mockClear();
});

内容的提问来源于stack exchange,提问作者Marco Antônio Dal Vesco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 06:41:07