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

如何在Vitest单元测试中Mock Next.js的next/router?

针对Next.js中useRouter的Vitest Mock方案

基础Mock方案(Pages Router通用)

直接在测试文件顶部mock next/router,模拟useRouter返回的常用属性与方法:

import { vi } from 'vitest'
import { useRouter } from 'next/router'

// Mock整个next/router模块
vi.mock('next/router', () => ({
  useRouter: vi.fn(() => ({
    route: '/',
    pathname: '/',
    query: {},
    asPath: '/',
    push: vi.fn().mockResolvedValue(true),
    replace: vi.fn().mockResolvedValue(true),
    back: vi.fn(),
    prefetch: vi.fn().mockResolvedValue(undefined),
  })),
}))

测试用例中可动态修改返回值,比如模拟带query参数的路由:

test('组件接收query参数时正常渲染', () => {
  // 覆盖原有mock返回值
  useRouter.mockReturnValue({
    ...useRouter.mock.results[0].value,
    query: { id: '123' },
  })
  
  // 编写你的测试逻辑
})

App Router(Next.js 13+)适配方案

App Router的useRouter来自next/navigation,需针对性mock:

import { vi } from 'vitest'
import { useRouter } from 'next/navigation'

vi.mock('next/navigation', () => ({
  useRouter: vi.fn(() => ({
    push: vi.fn().mockResolvedValue(true),
    replace: vi.fn().mockResolvedValue(true),
    back: vi.fn(),
    forward: vi.fn(),
    refresh: vi.fn(),
  })),
}))

全局Mock方案(减少重复代码)

在测试统一配置中设置全局mock,无需每个测试文件重复编写:

  1. 修改vitest.config.ts指定setup文件:
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  test: {
    environment: 'jsdom',
    setupFiles: './tests/setup.ts',
  },
})
  1. 在tests/setup.ts中添加全局mock:
import { vi } from 'vitest'

// Mock Pages Router的useRouter
vi.mock('next/router', () => ({
  useRouter: vi.fn(() => ({
    route: '/',
    pathname: '/',
    query: {},
    asPath: '/',
    push: vi.fn().mockResolvedValue(true),
    replace: vi.fn().mockResolvedValue(true),
    back: vi.fn(),
  })),
}))

// 同时Mock App Router的useRouter(按需添加)
vi.mock('next/navigation', () => ({
  useRouter: vi.fn(() => ({
    push: vi.fn().mockResolvedValue(true),
    replace: vi.fn().mockResolvedValue(true),
    back: vi.fn(),
  })),
}))

验证Router方法调用

测试中可断言路由方法是否被正确触发:

test('点击按钮跳转至详情页', async () => {
  render(<YourComponent />)
  
  // 触发跳转行为,比如点击按钮
  await screen.getByRole('button', { name: '查看详情' }).click()
  
  // 断言push方法的调用参数
  expect(useRouter().push).toHaveBeenCalledWith('/details/123')
})

内容的提问来源于stack exchange,提问作者Mayank Kumar Chaudhari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 13:20:15