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

使用Jest测试React-Apollo的MockedProvider遇异步问题,需设置超时?

解决Jest搭配MockedProvider测试时的异步行为问题

嘿,我完全懂你遇到的这个困扰——MockedProvider本身就是异步工作的,它模拟的是Apollo Client发起查询、接收响应的完整异步流程,不会在第一次渲染时就直接返回模拟数据。这也是为什么你直接断言可能总是拿到loading状态的原因,不一定非要设置超时,但得正确等待查询完成才行。

先帮你修正下组件里的语法小问题(避免测试时因为语法报错干扰判断):

const Component = () => (
  <Query query={query}>
    {({ loading, data }) => {
      if (loading) return 'loading';
      if (data) return 'data';
      return 'nothing';
    }}
  </Query>
);

下面给你几种靠谱的解决方案:

方法1:使用async/await + waitFor(推荐)

如果你的项目里用了@testing-library/react,waitFor可以帮你自动等待组件状态更新到预期值,不用手动处理超时逻辑:

import { waitFor } from '@testing-library/react';
import TestRenderer from 'react-test-renderer';
import { MockedProvider } from '@apollo/client/testing';
import Component from './Component';

it('renders data after query completes', async () => {
  const mocks = [
    {
      request: { query: yourQuery },
      result: { data: { /* 填入你的模拟数据 */ } },
    },
  ];

  const { getByText } = TestRenderer.create(
    <MockedProvider mocks={mocks} addTypename={false}>
      <Component />
    </MockedProvider>
  );

  // 初始渲染状态是loading
  expect(getByText('loading')).toBeInTheDocument();

  // 等待异步查询完成,直到渲染出data
  await waitFor(() => {
    expect(getByText('data')).toBeInTheDocument();
  });
});

方法2:利用TestRenderer回调 + setTimeout

如果不用testing-library,也可以用setTimeout给MockedProvider一点时间处理异步流程,配合Jest的done回调:

it('renders data after query completes', (done) => {
  const renderer = TestRenderer.create(
    <MockedProvider mocks={myMock} addTypename={false}>
      <Component />
    </MockedProvider>
  );

  // 初始渲染是loading状态
  expect(renderer.toJSON()).toMatch('loading');

  // 等待React完成状态更新(0毫秒足够触发异步队列)
  setTimeout(() => {
    expect(renderer.toJSON()).toMatch('data');
    done(); // 告诉Jest测试已完成
  }, 0);
});

方法3:临时设置Jest超时(应急可用)

如果上面的方法都没生效,可能是你的模拟逻辑有自定义延迟(比如自定义了resolver),这时候可以临时调整Jest的超时时间:

it('renders data after query completes', async () => {
  jest.setTimeout(1000); // 把超时设为1秒,Jest默认是5000毫秒其实足够

  // 剩下的测试逻辑和方法1一致
});

几个关键注意点:

  • 记得给MockedProvider加上addTypename={false},如果你的查询里没有包含__typename字段,不然会匹配不到模拟请求。
  • 确保mocks数组里的request.query和组件中使用的query完全一致,包括变量(如果有传参的话)。
  • 如果你用的是旧版react-apollo而非@apollo/client,MockedProvider的API略有差异,但异步处理逻辑是相通的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:04:16