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

React单元测试中Material UI Dialog组件报TypeError读取undefined错误

问题描述

开发基于Material UI的React应用时,已实现自定义Dialog组件MyCustomDialog并在主组件TokensTabViewContent中引入使用。使用React Testing Library对主组件MyMainComp执行单元测试时,渲染组件后触发错误:

Error: Uncaught [TypeError: Cannot read properties of undefined (reading 'MuiDialog-root')]
错误原因分析
  • 组件内部变量冲突:MyCustomDialog组件在解构props时已获取open和setOpen,但又重新声明了同名的useState变量,覆盖了传入的props值,导致组件内部状态逻辑混乱,同时引发作用域冲突问题。
  • 缺少Material UI主题上下文:Material UI组件依赖ThemeProvider提供的主题上下文生成样式类名(如MuiDialog-root)。测试代码直接渲染MyMainComp,未用ThemeProvider包裹,导致MUI组件无法获取主题对象,进而无法读取样式类名相关属性,触发undefined错误。
解决思路

1. 修复组件内部变量冲突

移除MyCustomDialog内部重复声明的useState,直接使用props传入的状态和状态更新函数:

import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Button } from '@mui/material';
import React from 'react';

type Props = {
    open: boolean;
    setOpen: React.Dispatch<React.SetStateAction<boolean>>;
    myAsyncTask: () => Promise<{ readonly status: string }>;
};

export const MyCustomDialog: React.FC<Props>  = ({ open, setOpen, myAsyncTask }) => { 
    return <Dialog aria-labelledby='My Dialog' open={open} onClose={() => setOpen(false)}>
        <DialogTitle>My dialog</DialogTitle>
        <DialogContent>
            <DialogContentText>{`Do you agree on the terms?`}</DialogContentText>
        </DialogContent>
        <DialogActions>
            <Button onClick={() => setOpen(false)}>No</Button>
            <Button onClick={async () => { await myAsyncTask(); setOpen(false); }}>Yes</Button>
        </DialogActions>
    </Dialog>;
}

2. 为测试添加ThemeProvider包裹

在测试代码中,用Material UI的ThemeProvider配合默认主题包裹待渲染组件,确保MUI组件能获取主题上下文:

import { render, screen } from '@testing-library/react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import MyMainComp from './MyMainComp';

const defaultTheme = createTheme();

it('should render', async () => {
    render(
        <ThemeProvider theme={defaultTheme}>
            <MyMainComp />
        </ThemeProvider>
    );

    const userIdTxt = screen.getByText('user id');
    expect(userIdTxt).toBeInTheDocument();
});

3. 可选:隔离Dialog组件测试

如果测试目标仅为主组件的其他部分,无需渲染Dialog,可以通过jest.mock模拟MyCustomDialog组件,避免渲染真实的MUI Dialog:

import { render, screen } from '@testing-library/react';
import MyMainComp from './MyMainComp';

// 模拟自定义Dialog组件,不渲染任何内容
jest.mock('./MyCustomDialog', () => ({
    MyCustomDialog: () => null
}));

it('should render', async () => {
    render(<MyMainComp />);

    const userIdTxt = screen.getByText('user id');
    expect(userIdTxt).toBeInTheDocument();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 22:25:18