React组件测试:如何用Vitest正确Mock jwt_decode函数解决报错?
修正后的AuthProvider单元测试代码
你的测试报错根源有两个:
vi.spyOn(jwt_decode)用法错误:spyOn要求第一个参数是对象,第二个是对象上的方法名,但jwt_decode是直接导入的独立函数,不是某个对象的属性,应该用vi.mock模拟整个模块。- 错误mock了
useEffect:你试图监听AuthProvider的useEffect,这完全错误——useEffect是React内置钩子,不属于AuthProvider组件的属性。
另外原测试通过判断子元素是否存在验证状态的逻辑不成立,AuthProvider始终会渲染子组件,和isLoggedIn状态无关。正确做法是直接从Context中获取状态进行断言。
以下是修正后的完整测试代码:
import React, { useContext } from "react"; import { vi, expect, test, describe, beforeEach, afterEach } from 'vitest'; import jwt_decode from "jwt-decode"; import { render, screen } from "@testing-library/react"; import { AuthProvider, AuthContext } from "../contexts/authContext"; // 模拟jwt-decode模块 vi.mock("jwt-decode"); // 测试前后清理环境,避免测试污染 beforeEach(() => { localStorage.clear(); // 重置document.cookie Object.defineProperty(document, 'cookie', { writable: true, value: '', }); jwt_decode.mockReset(); }); afterEach(() => { vi.restoreAllMocks(); }); describe("AuthProvider", () => { test("renders children without errors", () => { render( <AuthProvider> <div>Test Child</div> </AuthProvider> ); const childElement = screen.getByText("Test Child"); expect(childElement).toBeInTheDocument(); }); test('sets isLoggedIn to false if cookie decoding fails', () => { // 让jwt_decode抛出错误 jwt_decode.mockImplementation(() => { throw new Error("Decoding error"); }); // 创建组件消费AuthContext,用于获取状态 const TestConsumer = () => { const { isLoggedIn } = useContext(AuthContext); return <div data-testid="is-logged-in">{isLoggedIn.toString()}</div>; }; render( <AuthProvider> <TestConsumer /> </AuthProvider> ); // 断言isLoggedIn被设为false expect(screen.getByTestId("is-logged-in")).toHaveTextContent("false"); // 断言localStorage同步更新状态 expect(localStorage.getItem("isLoggedIn")).toBe("false"); }); });
关键修正点说明:
- 用
vi.mock("jwt-decode")模拟整个模块,可在测试中灵活控制其行为。 - 添加
beforeEach/afterEach钩子,清理localStorage、document.cookie并重置mock,保证测试独立性。 - 通过自定义测试组件消费Context,直接获取并展示
isLoggedIn状态,实现精准断言。 - 移除错误的
useEffectmock代码,组件内部的钩子会自动执行,无需手动干预。
内容的提问来源于stack exchange,提问作者Ahmed Adnan
相关产品推荐
相关产品推荐

