Next.js LeftSidebar组件测试:router.push模拟调用失败排查
问题排查与修复
核心问题分析
- 路由模块混淆:组件使用的是Next.js App Router的
next/navigation模块的useRouter,但测试中同时mock了旧版Pages Router的next/router模块,且在beforeEach中错误操作了next/router的useRouter,完全没有作用到组件实际依赖的路由方法。 - 拼写错误:
beforeEach里的ussRouter()是useRouter()的拼写错误,直接导致打印的router为undefined。 - Mock未正确关联:初始mock
next/navigation的useRouter时返回了自带的pushjest函数,但后续没有将这个函数与测试中的mockPush关联,导致断言时mockPush未被调用。
修复步骤
- 移除无用的
next/routermock:组件未使用该模块,直接删除相关导入和mock代码。 - 修正拼写错误:将
ussRouter()改为useRouter()。 - 正确覆盖
next/navigation的useRoutermock:在beforeEach中直接mocknext/navigation的useRouter,让它返回包含自定义mockPush的对象,确保组件调用的router.push就是我们的mock函数。 - 统一
usePathname的mock:根据测试场景,可按需设置usePathname的返回值,确保组件的激活状态逻辑正常。
修复后的测试代码
import { fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; import { useRouter, usePathname } from 'next/navigation'; import { LeftSideBar } from './LeftSidebar'; import { leftSidebarItems } from './LeftSidebarItems'; // 只mock组件实际使用的next/navigation模块 jest.mock('next/navigation', () => ({ useRouter: jest.fn(), usePathname: jest.fn(), })); describe('LeftSideBar', () => { describe('Click event on Sidebar', () => { let mockPush: jest.Mock; beforeEach(() => { // 初始化mockPush mockPush = jest.fn(); // 覆盖useRouter的mock,返回包含mockPush的router对象 (useRouter as jest.Mock).mockReturnValue({ push: mockPush, }); // 按需设置usePathname的返回值,这里默认返回根路径 (usePathname as jest.Mock).mockReturnValue('/'); }); afterEach(() => { jest.clearAllMocks(); }); it('should navigate to Orders page on click', () => { render(<LeftSideBar leftSideBarPathItems={leftSidebarItems} />); // 找到并点击Orders对应的li元素 const liElement = screen.getByText('Orders').closest('li')!; fireEvent.click(liElement); // 断言push被正确调用 expect(mockPush).toHaveBeenCalledWith('/Orders'); }); }); });
额外说明
- 确保
leftSidebarItems中对应Orders的path字段确实是'/Orders',否则断言会不匹配。 - 若需要测试路由激活状态(比如当前路径匹配时的样式),可在
beforeEach中修改usePathname的返回值,比如mockReturnValue('/Orders'),然后断言元素的className是否包含激活样式。
内容的提问来源于stack exchange,提问作者Saif Farooqui
相关产品推荐
相关产品推荐

