React Testing Library测试Modal Portal报错:目标容器非DOM元素
解决React createPortal Modal测试时"Target container is not a DOM element"错误
问题根源
你的Modal组件依赖document.getElementById('portal')作为createPortal的目标容器,但Jest测试环境的默认DOM结构里并没有这个节点,导致渲染时找不到目标元素报错。
两种可行解决方案
方案1:测试用例中动态创建/清理portal容器
在测试执行前手动添加目标DOM节点,测试结束后移除,避免污染其他测试:
test('modal', () => { // 提前创建portal容器 const portalDiv = document.createElement('div'); portalDiv.id = 'portal'; document.body.appendChild(portalDiv); const handleClose = jest.fn(); const { getByText } = render(<Modal onClose={handleClose} isOpen title={'title'} />); expect(getByText('title')).toBeTruthy(); // 测试完成后清理DOM document.body.removeChild(portalDiv); });
方案2:让组件支持自定义portal容器(更灵活)
给Modal组件增加一个可选的portalContainer属性,允许测试时传入自定义容器,同时保留原有的默认逻辑:
// 更新组件Props定义 interface IModalProps { isOpen: boolean; title?: string; className?: string; onClose: () => void; content?: React.ReactNode; // 替换React.ReactChildren,ReactNode是官方推荐的可渲染内容类型 portalContainer?: Element | null; } // 修改Modal组件的返回逻辑 const Modal = ({isOpen, title, content, onClose, className, portalContainer}: IModalProps) => { // ... 原有keydownHandler和useEffect逻辑不变 const modalInPortal = () => ( // ... 原有modal结构不变 ); // 优先使用传入的容器,否则取默认的portal节点 const targetContainer = portalContainer || document.getElementById('portal'); // 容错处理:如果容器不存在,返回null避免报错 if (!targetContainer) return null; return createPortal(modalInPortal(), targetContainer); };
对应的测试代码可以简化为:
test('modal', () => { const handleClose = jest.fn(); const testPortal = document.createElement('div'); const { getByText } = render( <Modal onClose={handleClose} isOpen title={'title'} portalContainer={testPortal} /> ); expect(getByText('title')).toBeTruthy(); });
额外提示
组件中content的类型React.ReactChildren | React.ReactChild建议替换为React.ReactNode,这是React官方定义的涵盖所有可渲染内容(元素、文本、Fragment等)的类型,更准确且通用。
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

