You need to enable JavaScript to run this app. Jest结合React Testing Library mock fetch报错问题
优惠活动
大模型
产品
解决方案
定价
更多

Jest结合React Testing Library mock fetch报错问题

Jest + React Testing Library 环境下fetch mock报错的解决方案

核心问题根因

所有TypeError: Cannot read property 'json' of undefined报错的本质,是测试执行时实际调用的全局fetch根本没有被替换为自定义mock,拿到的fetch返回值为undefined,导致后续调用.json()方法失败。常见的触发原因包括:

  • 测试环境的全局变量被Jest的自动重置逻辑覆盖,自定义的fetch mock没有正确挂载到全局作用域
  • jsdom版本过旧,本身没有内置fetch实现,也没有提前在全局层做polyfill
  • 异步测试流程没有等待微任务队列清空,组件effect还没执行完就触发了断言,甚至让mock函数在fetch调用前就被重置
  • mock返回的数据结构和被测代码的取值路径不匹配,就算mock生效也会引发后续属性读取错误

正确实现步骤

  1. 在全局测试入口初始化mock
    在setupTests.js中统一挂载全局fetch,避免每个测试文件重复定义被环境重置:

    // src/setupTests.js
    global.fetch = jest.fn()
    
    // 每个测试用例执行前清空之前的mock状态,避免用例间污染
    beforeEach(() => {
      fetch.mockClear()
    })
    

    如果使用jest-fetch-mock工具,必须在这个文件里显式开启mock能力,仅安装依赖不会自动替换全局fetch:

    import fetchMock from 'jest-fetch-mock';
    fetchMock.enableMocks();
    
  2. 构造和业务逻辑完全匹配的mock返回结构
    针对getPokemon函数的取值逻辑,mock返回的对象必须正确实现链式调用:先返回一个包含json方法的对象,再让json方法返回Promise resolve的宝可梦数据,不能把字段嵌套错层级:

    const mockPokemonDetail = {
      name: "charizard",
      sprites: {
        other: {
          "official-artwork": {
            front_default: "https://fake-static-url/charizard-art.png"
          }
        }
      }
    }
    
    fetch.mockResolvedValue({
      json: jest.fn().mockResolvedValue(mockPokemonDetail)
    })
    

    注意:之前很多人写的json: () => Promise.resolve({ data: { name: 'Charizard' } })是和被测代码逻辑不匹配的——被测代码是直接从json结果顶层取name、sprites字段,不需要额外套一层data,就算mock生效后续也会报读取sprites属性的错误。

  3. 等待异步流程执行完成再做断言
    测试React组件时,useEffect里触发的fetch是异步执行的,必须通过RTL提供的waitFor等待所有微任务(fetch请求、状态更新)跑完,不能在刚渲染完组件就做校验:

    test("组件加载完成后展示获取到的宝可梦信息", async () => {
      render(<Pokemon pokemonTrainer="ash" />)
    
      // 等待异步操作执行完成
      await waitFor(() => {
        expect(screen.getByText("charizard")).toBeInTheDocument()
      })
    
      // 校验fetch调用参数符合预期
      expect(fetch).toHaveBeenCalledTimes(1)
      expect(fetch).toHaveBeenCalledWith(
        expect.stringContaining("https://pokeapi.co/api/v2/pokemon/")
      )
    })
    

常见踩坑补充

  • 不要在单个测试文件的顶层随意修改全局fetch,如果开启了Jest的resetMocks配置,文件执行前会自动重置所有全局mock,导致fetch回到未定义状态
  • 依赖注入方案失败的原因,通常是没有把自定义fetch作为参数显式传入getPokemon函数,测试时实际还是调用了全局原生fetch,没有走到注入的mock逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.15 13:06:03