Next.js 13中usePathname钩子组件测试报错求助
问题分析与解决方案
你遇到的报错核心原因有两点:
- jest.mock的提升机制:jest.mock会被自动提升到文件代码执行的最顶部,你在它之后定义的
mockUsePathname变量,在jest.mock执行时还未初始化,此时值为undefined,导致模拟的usePathname函数返回undefined,触发类型错误。 - 错误的mock逻辑:你让模拟的
usePathname返回mockUsePathname这个jest函数实例,而非让usePathname本身成为mock函数并返回路径字符串。组件调用usePathname()会得到一个函数,而非预期的路径字符串,既破坏组件逻辑也可能引发错误。
修正后的测试代码
import { expect, jest } from "@jest/globals"; import { cleanup, render, screen } from "@testing-library/react"; import { AuthContext } from "src/app/Context/AuthContext.tsx"; import * as mocks from "__mocks__/AuthContextMocks.ts"; import LoggedInPage from "./page.tsx"; import authContextPropsMock from "../../../../__mocks__/AuthContextMockFunc.ts"; import UserNavigationLayout from "./layout.tsx"; import { usePathname } from "next/navigation"; // 导入usePathname用于后续mock // 正确模拟next/navigation模块 jest.mock("next/navigation", () => ({ useRouter: () => ({ push: jest.fn(), prefetch: jest.fn(), }), usePathname: jest.fn(), // 直接将usePathname设为jest mock函数 })); describe("with usePathname", () => { // 重置mock避免测试用例污染 beforeEach(() => { (usePathname as jest.Mock).mockReset(); }); it("should render the Logged In page when userRole is available in context", () => { // 指定当前路径的mock返回值 (usePathname as jest.Mock).mockReturnValue("/dashboard"); render( <AuthContext.Provider value={{ ...authContextPropsMock, firstName: mocks.firstNameMock1, lastName: mocks.lastNameMock1, }} > <UserNavigationLayout> <LoggedInPage /> </UserNavigationLayout> </AuthContext.Provider>, ); expect(screen.getByText("Initial Dashboard")).toBeInTheDocument(); }); });
可选优化:保留原模块其他导出
如果你需要保留next/navigation中未被模拟的其他导出(如useSearchParams),可以用jest.requireActual合并原模块内容:
jest.mock("next/navigation", () => ({ ...jest.requireActual("next/navigation"), // 保留原模块未被mock的导出 useRouter: () => ({ push: jest.fn(), prefetch: jest.fn(), }), usePathname: jest.fn(), }));
额外测试场景示例
如果需要测试路径匹配时的样式逻辑,只需修改mock返回值即可:
it("should apply active style when path matches link href", () => { (usePathname as jest.Mock).mockReturnValue("/dashboard"); render( <DefaultLink href="/dashboard" name="Dashboard" styleBox="default" styleBoxOpen="active" /> ); expect(screen.getByText("Dashboard")).toHaveClass("active"); });
内容的提问来源于stack exchange,提问作者GwenP
相关产品推荐
相关产品推荐

