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

使用Enzyme测试调用react-apollo readQuery的React组件

嘿,我来帮你搞定这个Enzyme测试React Apollo组件的问题!核心就是得给组件提供一个模拟的Apollo Client,让它在测试环境里能正常调用readQuery,不会因为找不到client而报错。下面给你两种实用的解决方案:

解决Enzyme测试React Apollo组件时未模拟Apollo Client的报错问题

方案一:用Apollo官方的MockedProvider(推荐)

这是Apollo官方推荐的测试方式,它能模拟整个Apollo Client的上下文环境,让组件可以像在真实环境里一样执行查询操作,还能自定义返回的数据。

具体步骤:

  1. 从@apollo/client/testing里导入MockedProvider
  2. 定义你需要模拟的查询,以及对应的返回数据
  3. 用MockedProvider把要测试的组件包裹起来,传入模拟的查询配置

示例代码:

import { MockedProvider } from '@apollo/client/testing';
import { mount } from 'enzyme';
import YourComponent from './YourComponent';
import { YOUR_TARGET_QUERY } from './your-queries-file'; // 替换成你实际的查询

// 配置模拟的查询和返回数据
const queryMocks = [
  {
    request: {
      query: YOUR_TARGET_QUERY,
      variables: { /* 如果你的查询需要变量,这里填对应的值 */ }
    },
    result: {
      data: { /* 这里填组件通过readQuery期望拿到的具体数据 */ }
    }
  }
];

describe('YourComponent测试', () => {
  it('componentDidMount后能正常渲染', async () => {
    const wrapper = mount(
      <MockedProvider mocks={queryMocks} addTypename={false}>
        <YourComponent />
      </MockedProvider>
    );
    
    // 因为Apollo查询是异步的,需要等模拟查询完成再更新组件
    await new Promise(resolve => setTimeout(resolve, 0));
    wrapper.update();
    
    // 这里写你的断言逻辑,比如检查组件是否渲染了预期内容
    expect(wrapper.find('.your-target-element').text()).toBe('你期望的文本');
  });
});

注:addTypename={false}是为了避免Apollo自动添加的__typename字段导致查询匹配失败,如果你在真实代码里用到了这个字段,可以去掉这个配置。

方案二:手动模拟Apollo Client并通过上下文传递

如果你不想用官方的MockedProvider,也可以自己手动创建一个模拟的Apollo Client实例,然后通过Apollo的上下文传递给组件。这种方式更灵活,适合需要精准控制client方法调用的场景。

具体步骤:

  1. 导入ApolloProvider
  2. 用jest.fn()创建一个带有readQuery方法的模拟client,自定义它的返回值
  3. 用ApolloProvider包裹组件,把模拟的client传进去

示例代码:

import { ApolloProvider } from '@apollo/client';
import { mount } from 'enzyme';
import YourComponent from './YourComponent';
import { YOUR_TARGET_QUERY } from './your-queries-file';

// 手动模拟Apollo Client实例
const mockApolloClient = {
  readQuery: jest.fn(() => ({
    // 返回组件期望的查询结果
    user: { id: 1, name: 'Mock User' }
  }))
};

describe('YourComponent测试', () => {
  it('componentDidMount时会调用readQuery', () => {
    const wrapper = mount(
      <ApolloProvider client={mockApolloClient}>
        <YourComponent />
      </ApolloProvider>
    );
    
    // 断言readQuery是否被调用
    expect(mockApolloClient.readQuery).toHaveBeenCalled();
    // 还可以检查调用的参数是否正确
    expect(mockApolloClient.readQuery).toHaveBeenCalledWith({
      query: YOUR_TARGET_QUERY,
      variables: { /* 如果有变量,这里填对应的值 */ }
    });
  });
});

额外提示

  • 不管你的组件是用useApolloClient钩子获取client,还是用withApollo高阶组件注入client,上面两种方案都能正常生效
  • 处理异步操作时,一定要记得等待组件更新后再做断言,不然可能会拿到未更新的DOM
  • 如果你用的是老版本的react-apollo(不是@apollo/client),只需要把导入路径换成react-apollo/testing即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:16:08