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

Next.js Jest RTL环境下如何监听useRouter的replace mock函数调用?

问题根因

当前的mock逻辑中,每次调用useRouter()都会返回一个全新的对象,你在测试代码里调用useRouter()通过spyOn监听的replace方法,和组件内部调用useRouter()拿到的replace是完全独立的两个mock实例。组件实际调用的是内部拿到的那个实例,所以会打印日志,但你监听的spy实例从未被调用,因此断言失败。

解决方案

将mock的replace方法提取为公共的单实例mock函数,保证所有useRouter()返回的对象都复用同一个replace实例,直接断言这个公共mock即可,不需要额外用spyOn:

  1. 修改mock代码:
// 定义全局共享的replace mock函数
const mockReplace = jest.fn((obj) => console.log("have been called", obj));

jest.mock("next/router", () => ({
  useRouter() {
    return {
      route: "/",
      pathname: "",
      locale: "pl",
      replace: mockReplace, // 所有router实例共用同一个replace mock
    };
  },
}));
  1. 修改测试代码:
test.only("should redirect when form submitted with success", async () => {
  // 每次测试前清空mock的调用记录,避免用例间互相干扰
  mockReplace.mockClear();

  render(<HomePage {...props} />);

  const submitBtn = screen.getByRole("button", {
    name: /submit/i,
  });

  // userEvent操作本身是异步的,建议加await
  await userEvent.click(submitBtn);

  await waitFor(() => expect(mockReplace).toHaveBeenCalled());
  // 也可以直接判断调用次数
  // expect(mockReplace).toHaveBeenCalledTimes(1);
});

注意事项

  • 不要在测试代码中反复调用useRouter()获取方法,默认mock逻辑下每次返回的都是全新实例,和组件内部使用的实例不共用
  • 多个测试用例共用同一个mock函数时,一定要在每个用例执行前调用mockClear()清空历史调用记录,避免用例结果互相影响

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 19:06:09