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

React Testing Library waitFor报MutationObserver构造函数错误

React Testing Library 中waitFor抛出MutationObserver is not a constructor错误修复

问题场景

编写DraftPage组件单元测试时,需等待页面加载完成、删除图标渲染后再执行后续点击、断言步骤,调用waitFor方法时触发运行错误。

相关代码

导入部分

import { render, screen, waitFor, fireEvent } from '../../../TestMocks/CustomRender';
import DraftPage from '../DraftPage';
import '@testing-library/jest-dom';
import React from 'react';

DraftPage组件核心逻辑

{
loader ?
<Grid data-testid="full page loader">
    <CircularProgress />
</Grid>
:
<Grid>
   <IconButton
      disabled={item.notSynced}>
      <DeleteIcon data-testid="draft delete icon" onClick={()=>{console.log('btn click')}} />
   </IconButton>
</Grid>
}

测试用例代码

it("delete a card number reduce", async () => {
    render(<DraftPage />);
    const loader = screen.getAllByTestId("full page loader")
    await waitFor(() => expect(screen.getByTestId("draft delete icon")).toBeInTheDocument())
    fireEvent.click(screen.getByTestId("draft delete icon"));
    expect(screen.getByText("draft delete dialog")).toBeInTheDocument();
})

报错输出

FAIL  src/Components/Draft/__Test__/DraftPage.test.js (11.746s)
  √ renders draft page (193ms)
  × delete a card number reduce (55ms)

  ● delete a card number reduce

    TypeError: MutationObserver is not a constructor

      75 |     const loader = screen.getAllByTestId("full page loader")
      76 |     console.log(loader)
    > 77 |     await waitFor(() => expect(screen.getByTestId("draft delete icon")).toBeInTheDocument())
         |           ^
      78 |     fireEvent.click(screen.getByTestId("draft delete icon"));
      79 |     expect(screen.getByText("draft delete dialog")).toBeInTheDocument();
      80 | })

      at node_modules/@testing-library/dom/dist/wait-for.js:106:18
      at waitFor (node_modules/@testing-library/dom/dist/wait-for.js:39:10)
      at node_modules/@testing-library/dom/dist/wait-for.js:188:54
      at node_modules/@testing-library/react/dist/pure.js:59:22
      at node_modules/@testing-library/react/dist/act-compat.js:63:24
      at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:21856:12)
      at act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:929:14)
      at node_modules/@testing-library/react/dist/act-compat.js:62:20
      at asyncAct (node_modules/@testing-library/react/dist/act-compat.js:40:14)
      at Object.asyncWrapper (node_modules/@testing-library/react/dist/pure.js:58:35)
      at waitForWrapper (node_modules/@testing-library/dom/dist/wait-for.js:188:35)
      at Object.<anonymous> (src/Components/Draft/__Test__/DraftPage.test.js:77:11)

错误根因

waitFor 内部依赖浏览器原生API MutationObserver 监听DOM树变化,在检测到DOM更新时重新执行传入的断言回调。该报错说明当前测试运行环境(多为Jest+jsdom组合)没有提供MutationObserver的实现,常见触发场景:

  • Jest 28及以上版本默认不再内置jsdom测试环境,未手动安装配置时运行在纯Node环境,缺少DOM相关API
  • 使用的jsdom版本过低,未内置MutationObserver实现
  • 测试启动配置未正确加载DOM相关polyfill

修复方案

按以下优先级排查处理:

  • 配置Jest使用jsdom测试环境
    Jest 28+版本需要先单独安装jsdom环境包:
    npm i -D jest-environment-jsdom
    
    然后在jest.config.js中添加配置:
    module.exports = {
      // 其余原有配置
      testEnvironment: 'jsdom',
    }
    
  • 确认@testing-library/jest-dom的导入位置
    确保该包在所有测试代码执行前导入(一般放在jest的setupFiles配置文件中统一引入),它会自动补全测试环境缺失的常用DOM API,避免兼容问题。
  • 优化测试逻辑
    现有测试只等待删除图标出现,没有显式处理加载态,容易出现时序问题,可以用waitForElementToBeRemoved先等待加载态消失,逻辑更稳定:
    import { render, screen, waitFor, fireEvent, waitForElementToBeRemoved } from '../../../TestMocks/CustomRender';
    
    it("delete a card number reduce", async () => {
        render(<DraftPage />);
        // 等待全屏加载组件消失
        await waitForElementToBeRemoved(() => screen.getByTestId("full page loader"))
        // 加载完成后删除图标已稳定渲染,可直接操作
        fireEvent.click(screen.getByTestId("draft delete icon"));
        expect(screen.getByText("draft delete dialog")).toBeInTheDocument();
    })
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 03:09:37