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

Next.js 12.2.0升级后Jest模拟next/router致测试失败如何修复

问题复现

在Jest + React Testing Library测试环境中,原有模拟next/router依赖的实现如下:

import * as nextRouter from 'next/router';

export const routerData = {
  pathname: '/users/create',
  route: '/users/create',
  query: { },
  asPath: '/users/create',
  isFallback: false,
  basePath: '',
  isReady: true,
  isPreview: false,
  isLocaleDomain: false,
  events: {},
};

// mock router
jest.mock('next/router');
nextRouter.useRouter.mockImplementation(() => (routerData));

describe('a component that requires next/router, () => ... );

升级到Next.js 12.2.0版本后,所有依赖该mock的测试全部失败,抛出如下提示:

No router instance found.
You should only use "next/router" on the client side of your app.

问题原因

Next.js 12.2.0调整了next/router的内部校验逻辑:之前只要mockuseRouter的返回值就能正常运行,新版本会额外校验模块默认导出的Router实例是否存在,原写法只mock了useRouter方法,没有提供Router实例,自然过不了校验。另外新版本内部会调用events对象上的on/off/emit方法,原mock里events是空对象,就算过了实例校验也会报方法不存在的错。

修复方案

方案1:补全模块mock(改动最小)

直接在jest.mock里补全所有必要的模块导出,包括默认导出的Router实例,同时把缺失的路由方法、events方法补成jest mock函数:

// 先补全routerData缺失的字段和方法
export const routerData = {
  pathname: '/users/create',
  route: '/users/create',
  query: { },
  asPath: '/users/create',
  isFallback: false,
  basePath: '',
  isReady: true,
  isPreview: false,
  isLocaleDomain: false,
  // 补全events相关方法
  events: {
    on: jest.fn(),
    off: jest.fn(),
    emit: jest.fn(),
  },
  // 补全常用路由操作方法
  push: jest.fn(() => Promise.resolve(true)),
  replace: jest.fn(() => Promise.resolve(true)),
  reload: jest.fn(),
  prefetch: jest.fn(() => Promise.resolve()),
  back: jest.fn(),
  beforePopState: jest.fn(),
};

// 完整mock next/router模块,不要只mock useRouter
jest.mock('next/router', () => ({
  useRouter: () => routerData,
  default: routerData
}));

这个方案改动量最小,和原有测试逻辑完全兼容,替换掉之前的mock代码就能解决报错。

方案2:通过RouterContext注入路由实例(长期推荐)

不用硬mock整个next/router模块,直接用Next内部的RouterContext上下文,在渲染测试组件的时候注入路由配置,走的和生产环境一样的上下文逻辑,后续Next版本升级就算改了模块导出结构也不容易失效:

import { render } from '@testing-library/react';
import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime';

// 封装自定义渲染方法,自动注入路由上下文
const renderWithRouter = (ui, { routerConfig = routerData, ...renderOptions } = {}) => {
  return render(
    <RouterContext.Provider value={routerConfig}>
      {ui}
    </RouterContext.Provider>,
    renderOptions
  )
}

// 测试用例中直接调用即可,不需要单独写jest.mock('next/router')
test('渲染路由依赖组件', () => {
  renderWithRouter(<YourTestComponent />);
  // 后续正常写断言逻辑
})

用这个方案的时候也要注意,传入的routerConfig要包含前面提到的events方法和常用路由方法,避免运行时找不到方法报错。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:51:16