如何在Jest中正确Mock react-dom/client?
问题背景
当前react-dom的渲染API已更新为从react-dom/client导入createRoot,使用方式如下:
const root = createRoot(document.getElementById('root')); root.render(<App />);
需要在Create React App的测试环境中Mock这个API,同时要导出index.js中的Redux Store变量(因教学需求不想将Store移至单独文件),但直接导入index.js时会触发渲染,而测试环境无DOM节点导致报错。此前尝试创建__mocks__/react-dom/client.js结构未生效,测试文件显式Mock又与React Testing Library冲突。
正确Mock配置步骤
1. 构建正确的__mocks__文件夹结构
Jest会自动识别__mocks__目录下与真实模块路径匹配的文件。针对react-dom/client的导入路径,需要创建如下结构:
项目根目录 ├── __mocks__ │ └── react-dom │ └── client.js └── src └── index.js
2. 编写Mock内容
在__mocks__/react-dom/client.js中写入以下代码,MockcreateRoot方法使其返回一个带有空实现render方法的对象:
export const createRoot = jest.fn(() => ({ render: jest.fn(), }));
Jest会自动在测试环境中用这个Mock替代真实的react-dom/client模块,无需在测试文件中显式调用jest.mock。
3. 导出Redux Store并避免渲染报错
在src/index.js中直接导出Store变量,由于我们已经Mock了createRoot和render,导入index.js时不会执行真实的DOM渲染逻辑:
// src/index.js import { createRoot } from 'react-dom/client'; import { Provider } from 'react-redux'; import { configureStore } from '@reduxjs/toolkit'; import App from './App'; // 导出Store供测试使用 export const store = configureStore({ reducer: { // 你的reducer配置 }, }); const root = createRoot(document.getElementById('root')); root.render( <Provider store={store}> <App /> </Provider> );
在测试文件中直接导入Store即可使用,不会触发渲染报错:
// 测试文件示例 import { store } from '../src/index'; test('验证Store初始状态', () => { expect(store.getState()).toEqual({ // 预期的初始状态 }); });
处理与React Testing Library的冲突
如果你的部分测试使用React Testing Library的render方法,而该方法依赖真实的react-dom API,可以在这些测试文件中取消Mock:
// 使用RTL的测试文件 jest.unmock('react-dom/client'); import { render, screen } from '@testing-library/react'; import App from '../src/App'; test('渲染App组件', () => { render(<App />); expect(screen.getByText('欢迎文本')).toBeInTheDocument(); });
这样RTL可以正常使用真实的渲染逻辑,而其他导入index.js的测试仍会使用Mock。
内容的提问来源于stack exchange,提问作者Dane Smith

