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

如何在不传入初始值的情况下测试内部带useState的ModalProvider?

无需传入初始值即可测试内部维护状态的ModalContext

问题根源

你在测试代码的顶层作用域直接调用useModalContext(),此时ModalProvider还未被渲染到测试DOM中,上下文完全未生效,必然触发hook里的错误提示。React Hooks的调用规则要求:必须在组件(或被render包裹的组件树)内部、且处于上下文Provider的覆盖范围内调用。

解决方案(无需修改ModalProvider)

下面两种方案都不需要给ModalProvider添加initialValue参数,完全保留原有的内部状态逻辑:

方案1:将上下文逻辑移到测试组件内部

把需要使用useModalContext的交互逻辑(比如按钮点击触发模态框)放到一个测试专用的组件里,确保hook在ModalProvider的上下文范围内被调用。

修改后的测试代码:

import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ModalProvider, useModalContext } from "./ModalContext";
import Modal from "./Modal";

const queryClient = new QueryClient();

const Wrapper = ({ children }: { children: React.ReactNode }) => (
    <ModalProvider>
        <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
    </ModalProvider>
);

// 封装测试组件,在内部使用上下文
const TestModalTrigger = () => {
    const { setShowModal } = useModalContext();
    return (
        <>
            <button onClick={() => setShowModal(true)}>Show modal</button>
            <Modal />
        </>
    );
};

describe("Modal test", () => {
    it("显示模态框当按钮被点击时", () => {
        render(<TestModalTrigger />, { wrapper: Wrapper });

        // 找到按钮并点击
        const showButton = screen.getByText("Show modal");
        fireEvent.click(showButton);

        // 验证模态框内容存在
        const modalContent = screen.getByText(/Show modal/i);
        expect(modalContent).toBeInTheDocument();
    });
});

方案2:用renderHook单独测试上下文hook

如果需要单独测试useModalContext的状态逻辑,可以使用@testing-library/react提供的renderHook函数,将其包裹在ModalProvider中,确保hook能获取到上下文值:

import { renderHook, act } from "@testing-library/react";
import { ModalProvider, useModalContext } from "./ModalContext";

describe("useModalContext Hook", () => {
    it("可以切换模态框显示状态", () => {
        const { result } = renderHook(() => useModalContext(), {
            wrapper: ({ children }) => <ModalProvider>{children}</ModalProvider>
        });

        // 初始状态为隐藏
        expect(result.current.showModal).toBe(false);

        // 触发显示
        act(() => {
            result.current.setShowModal(true);
        });
        expect(result.current.showModal).toBe(true);

        // 触发隐藏
        act(() => {
            result.current.setShowModal(false);
        });
        expect(result.current.showModal).toBe(false);
    });
});

内容的提问来源于stack exchange,提问作者asus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 07:05:01