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

Jest报错:Cannot read properties of undefined (reading 'createRoot') 求助

问题:Jest测试中出现TypeError: Cannot read properties of undefined (reading 'createRoot')

问题场景

我的项目基于Vite + TypeScript,使用Jest(搭配React Testing Library)运行测试时触发如下错误:

Test suite failed to run

TypeError: Cannot read properties of undefined (reading 'createRoot')

export const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
^
<React.StrictMode>
return (<App />)

测试代码如下:

test("it should trigger form errors when description and amount is not filled", async () => {
  // arrange
  // render(<AddExpenditure />);
  render(
    <div id="root">
      <AddExpenditure />
    </div>
  );

  screen.debug();
});

测试其他组件时一切正常,只有测试AddExpenditure组件时会触发该错误。

现有配置

Jest配置

/** @type {import('ts-jest').JestConfigWithTsJest} */
export default {
  preset: "ts-jest",
  testEnvironment: "jsdom",
  moduleNameMapper: {
    "\\.(css)$": "./mocks/styleMock.js",
  },
};

tsconfig配置

{
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "allowJs": false,
    "skipLibCheck": true,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

问题原因

错误根源在项目入口文件(比如main.tsx)的ReactDOM.createRoot调用:
当Jest运行测试时,会加载所有被测试组件依赖的模块。如果AddExpenditure组件(或其依赖)引入了入口文件中导出的queryClient,Jest就会执行整个入口文件的代码。此时测试环境中还没创建id="root"的DOM元素,document.getElementById("root")返回undefined,导致调用createRoot时报错。

其他组件测试正常,是因为它们没有间接引入入口文件导出的全局变量,所以入口文件的渲染逻辑不会被执行。

修复方案

方案1:让入口文件仅在浏览器环境执行渲染

修改入口文件,添加环境判断,只在浏览器环境下执行DOM渲染逻辑:

export const queryClient = new QueryClient();

// 仅在浏览器环境执行渲染
if (typeof window !== 'undefined') {
  ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
    <React.StrictMode>
      <QueryClientProvider client={queryClient}>
        <App />
      </QueryClientProvider>
    </React.StrictMode>
  );
}

方案2:Mock入口文件的渲染逻辑

如果不想修改入口文件,可以在Jest配置中添加模块Mock,跳过入口文件的渲染代码:
在Jest配置的moduleNameMapper中添加:

moduleNameMapper: {
  "\\.(css)$": "./mocks/styleMock.js",
  "^./main.tsx$": "<rootDir>/mocks/mainMock.tsx" // 替换为你的入口文件路径
}

然后创建mocks/mainMock.tsx,只导出需要的变量,不执行渲染:

import { QueryClient } from '@tanstack/react-query';

export const queryClient = new QueryClient();

方案3:重构全局依赖,分离入口文件逻辑

把queryClient单独抽离到独立文件(比如src/utils/queryClient.ts),避免在入口文件中导出全局变量:

// src/utils/queryClient.ts
import { QueryClient } from '@tanstack/react-query';

export const queryClient = new QueryClient();

之后在入口文件和需要的组件中,都从这个文件导入queryClient。这样入口文件就不会因为导出变量而被测试代码加载执行渲染逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 06:15:04