React testing-library测试多用例场景下无法重新渲染Modal的问题
测试用例并行执行模态框渲染异常解决方案
问题根因
- 测试代码异步逻辑写法错误:Promise实例未调用resolve,前序用例的异步状态没有正确结束,状态泄露到后续用例;同时async/await和done回调混用,导致测试生命周期混乱,提前结束用例导致DOM未重置。
- 模态框使用React Portal实现:React Testing Library默认的cleanup方法只会清理render方法挂载的容器节点,Portal挂载到document.body的模态框节点不会被自动清理,多个用例的模态框实例冲突导致第二个用例无法正常渲染。
- props引用复用:如果多组测试用例复用同一个props对象引用,前序用例如果修改了props属性,会导致后续用例拿到的初始配置错误。
修复方案
步骤1:配置全局清理逻辑
在测试文件开头的afterEach钩子中,手动清理Portal挂载的节点:
import { cleanup, render, screen, fireEvent } from '@testing-library/react'; import { act } from 'react-dom/test-utils'; afterEach(() => { // 清理React Testing Library默认渲染节点 cleanup(); // 手动移除挂载在body下的模态框根节点,可根据实际模态框挂载节点的类名/id调整选择器 const modalRoot = document.querySelector('.modal-root') || document.getElementById('modal-root'); if (modalRoot) { modalRoot.remove(); } // 兜底重置body内容 document.body.innerHTML = ''; // 重置所有jest mock调用状态 jest.clearAllMocks(); });
步骤2:修正测试用例异步写法
去掉冗余的done回调,使用findBy*查询替代getBy*适配模态框的异步渲染逻辑:
// 每个用例重新生成props,避免引用复用导致的属性污染 const getTestProps = () => ({ visible: true, onCancel: jest.fn(), onOk: jest.fn(), // 其余自定义属性 }); it("点击取消按钮时关闭模态框", async () => { render(<MyModal {...getTestProps()} />); const modalComponent = await screen.findByTestId('modal-client-id'); const cancelButton = await screen.findByTestId('modal-cancel-button'); await act(async () => { fireEvent.click(cancelButton); // 等待模态框状态更新、关闭动画等异步逻辑执行完成 await new Promise(resolve => setTimeout(resolve, 0)); }); expect(modalComponent).not.toBeInDocument(); }); it("点击确认按钮时关闭模态框", async () => { render(<MyModal {...getTestProps()} />); const modalComponent = await screen.findByTestId('modal-client-id'); const okButton = await screen.findByTestId('modal-ok-button'); await act(async () => { fireEvent.click(okButton); await new Promise(resolve => setTimeout(resolve, 0)); }); expect(modalComponent).not.toBeInDocument(); });
额外排查点
- 检查模态框组件卸载逻辑是否完整:如果组件绑定了window/body级别的事件监听、定时器,需要在useEffect的清理函数中移除,避免全局事件残留影响后续用例。
- 排查模态框是否有全局状态依赖:如果模态框的显隐状态由Redux、Mobx等全局状态管理,需要在afterEach中重置全局状态,避免前序用例的状态修改影响后续渲染。
内容的提问来源于stack exchange,提问作者Niru
相关产品推荐
相关产品推荐

