使用react-test-renderer+TypeScript测试MUI Menu组件报错的解决方法
我之前也碰到过一模一样的问题,用react-test-renderer给Material-UI的Menu组件写快照测试时,总会因为DOM模拟的问题抛出错误,咱们一步步来解决:
原组件代码(Menu.tsx)
import React, { useState } from 'react'; import { Grid, Button, Menu, MenuItem } from '@material-ui/core'; const Component = () => { const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); const handleMenuClick = (event: React.MouseEvent<HTMLButtonElement>) => { setAnchorEl(event.currentTarget); }; const handleMenuClose = () => { setAnchorEl(null); }; return ( <Grid> <Button variant="contained" onClick={handleMenuClick}> Open Menu </Button> <Menu anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleMenuClose} > <MenuItem>Option 1</MenuItem> <MenuItem>Option 2</MenuItem> </Menu> </Grid> ); }; export default Component;
原测试代码(Menu.test.tsx)
import React from 'react'; import { create } from 'react-test-renderer'; import Menu from './Menu'; describe('Menu Snapshot', () => { it('renders correctly', () => { const tree = create(<Menu />).toJSON(); expect(tree).toMatchSnapshot(); }); });
问题分析
运行测试时出现的TypeError: parentInstance.children.indexOf is not a function,本质是Material-UI的Menu组件依赖真实DOM元素计算位置,但react-test-renderer默认的无DOM环境没法提供完整的节点模拟。你之前尝试的createNodeMock写法不对,直接返回element并不是符合要求的DOM节点模拟对象。
正确的测试方案
我们需要在createNodeMock里返回一个包含组件必要属性/方法的模拟DOM对象,修改后的测试代码如下:
import React from 'react'; import { create } from 'react-test-renderer'; import Menu from './Menu'; describe('Menu Snapshot', () => { it('renders correctly', () => { const tree = create(<Menu />, { createNodeMock: () => { // 模拟Menu组件运行时需要的DOM元素属性与方法 return { getBoundingClientRect: () => ({ top: 0, left: 0, bottom: 0, right: 0, width: 0, height: 0 }), addEventListener: () => {}, removeEventListener: () => {}, // 可根据组件实际需求补充其他属性 }; }, }).toJSON(); expect(tree).toMatchSnapshot(); }); });
补充说明
createNodeMock的作用是为React元素生成模拟DOM节点,这里我们只需要提供Menu组件运行时用到的方法(比如计算位置的getBoundingClientRect、事件监听方法),不需要完全复刻真实DOM的所有属性。- 这样修改后,测试就能正常执行并生成正确的组件快照了。
内容的提问来源于stack exchange,提问作者sashko
相关产品推荐
相关产品推荐

