NextJS导航栏测试:userEvent.click不触发路径更新的解决方法
解决Next.js中Jest测试Link组件路径不更新的问题
问题核心
你的测试代码存在两个关键问题:
- 手动创建的
createMemoryHistory实例未与Next.js路由系统绑定,<Link>组件默认使用Next.js自身的路由机制,不会识别独立的history对象。 - 渲染
<Navbar>时未包裹Next.js的路由上下文,导致点击Link后无法触发路由状态更新。
解决方案(分Next.js版本)
针对Next.js 12及以下(Pages Router)
使用next-router-mock模拟Next.js路由,确保测试能捕获路由变化:
- 安装依赖
npm install --save-dev next-router-mock
- 修改测试代码
import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import '@testing-library/jest-dom/extend-expect'; import { useRouter } from 'next/router'; import Navbar from './Navbar'; import mockRouter from 'next-router-mock'; // 模拟next/router的useRouter钩子 jest.mock('next/router', () => ({ useRouter: () => mockRouter, })); describe('Navbar Component', () => { beforeEach(() => { // 每次测试前重置路由到根路径 mockRouter.push('/'); render(<Navbar />); }); it('navigates to /drones when clicking the drones link', async () => { const user = userEvent.setup(); await user.click(screen.getByText('drones')); expect(mockRouter.pathname).toBe('/drones'); expect(mockRouter.asPath).toBe('/drones'); }); it('navigates to /cameras when clicking the cameras link', async () => { const user = userEvent.setup(); await user.click(screen.getByText('cameras')); expect(mockRouter.asPath).toBe('/cameras'); }); });
针对Next.js 13+(App Router)
使用Next.js官方的MemoryRouter包裹组件,结合usePathname捕获当前路径:
- 确保依赖已安装(
create-next-app生成的项目默认已包含)
npm install --save-dev @testing-library/react @testing-library/user-event jest
- 修改测试代码
import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import '@testing-library/jest-dom/extend-expect'; import { MemoryRouter, usePathname } from 'next/navigation'; import Navbar from './Navbar'; // 辅助组件用于暴露当前路径 const CurrentPath = () => { const pathname = usePathname(); return <span data-testid="current-path">{pathname}</span>; }; describe('Navbar Component', () => { it('updates pathname to /drones when clicking drones link', async () => { render( <MemoryRouter initialEntries={['/']}> <Navbar /> <CurrentPath /> </MemoryRouter> ); const user = userEvent.setup(); await user.click(screen.getByText('drones')); expect(screen.getByTestId('current-path')).toHaveTextContent('/drones'); }); });
额外注意事项
- 若使用TypeScript,需安装对应类型依赖,比如
@types/next-router-mock(针对Pages Router方案)。 - 不要直接操作
window.location,Next.js客户端路由不会直接修改该对象(除非配置强制刷新)。 - 确保
jest.config.js使用Next.js预设(create-next-app生成的项目默认配置了next/jest)。
内容的提问来源于stack exchange,提问作者Tolgahan
相关产品推荐
相关产品推荐

