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
相关产品推荐
相关产品推荐

