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

如何测试指定ApolloClient实例的useLazyQuery钩子?

问题:指定ApolloClient实例的useLazyQuery测试Mock不生效

在测试使用指定ApolloClient实例的useLazyQuery钩子时,遇到Mock数据无法被组件接收的问题:移除钩子中的client配置后测试正常,但业务逻辑依赖该特定客户端。

业务代码(useLazyQuery钩子)

const [
  getSpecificReport,
  { loading: contentLoading, error: contentError, data: content },
] = useLazyQuery<SpecificReportResponse>(
  SPECIFIC_REPORT(testResultsData?.getTestResults.testType),
  {
    client: cmsClient, // 特定的ApolloClient实例
    fetchPolicy: "network-only",
    onCompleted: () => {
      setScreenData();
    },
    onError: (err) => {
      // 省略错误处理逻辑
    },
  }
);

Mock配置

const mocks = [{
    request: {
      query: SPECIFIC_REPORT('Report Title'),
      fetchPolicy: 'network-only',
    },
    result: {
      data: {
        allReports: [getReportTestData()],
      } as SpecificReportResponse,
    },
}]

测试代码

...
const { getByText, getAllByText } = render(
    <MockedProvider
        mocks={mocks}
        addTypename={false}
    >
    <ResultsScreen {...mockProps} />
    </MockedProvider>
);

await waitFor(() => {
    new Promise((resolve) => setTimeout(resolve, 3000));
    expect(getByText(/Something/)).toBeTruthy();
    // 省略其他断言
}
...

解决思路与方案

核心原因

默认的MockedProvider只会拦截没有指定client的Apollo请求,或者拦截与自身绑定的客户端实例的请求。你的业务代码指定了client: cmsClient,导致MockedProvider无法识别并拦截该请求。

具体方案

方案1:给MockedProvider传入指定客户端实例

将业务中使用的cmsClient传入MockedProvider的client属性,让MockedProvider关联该客户端,从而拦截它的请求:

const { getByText, getAllByText } = render(
  <MockedProvider
    mocks={mocks}
    addTypename={false}
    client={cmsClient} // 绑定特定客户端实例
  >
    <ResultsScreen {...mockProps} />
  </MockedProvider>
);

注意:确保测试环境中的cmsClient没有配置真实的请求端点,否则仍可能发送真实网络请求。可以在测试前重置客户端的链路为Mock链路。

方案2:通过依赖注入替换客户端

避免在业务代码中硬编码cmsClient,改为通过props或React上下文传入,测试时替换为专用的测试客户端:

  • 调整业务代码:
// 通过props接收客户端实例
const ResultsScreen = ({ cmsClient, ...restProps }) => {
  const [
    getSpecificReport,
    { loading: contentLoading, error: contentError, data: content },
  ] = useLazyQuery<SpecificReportResponse>(
    SPECIFIC_REPORT(testResultsData?.getTestResults.testType),
    {
      client: cmsClient,
      fetchPolicy: "network-only",
      onCompleted: () => {
        setScreenData();
      },
      onError: (err) => {
        // 省略错误处理逻辑
      },
    }
  );
  // 组件其他逻辑
};
  • 测试中创建并传入测试客户端:
import { ApolloClient, InMemoryCache } from '@apollo/client';
import { MockLink } from '@apollo/client/testing';

// 创建测试用客户端,使用MockLink处理请求
const testCmsClient = new ApolloClient({
  link: new MockLink(mocks),
  cache: new InMemoryCache(),
});

const { getByText, getAllByText } = render(
  <ResultsScreen {...mockProps} cmsClient={testCmsClient} />
);

方案3:自定义请求匹配逻辑

如果无法修改客户端传入方式,可通过MockedProvider的matchRequest函数自定义匹配规则,确保能识别指定客户端的请求:

<MockedProvider
  mocks={mocks}
  addTypename={false}
  matchRequest={(request, mockRequest) => {
    // 匹配query、变量,可额外添加客户端相关判断
    return (
      request.query === mockRequest.query &&
      JSON.stringify(request.variables) === JSON.stringify(mockRequest.variables)
      // 若需匹配特定客户端,可根据request上下文判断:
      // request.context.client === cmsClient
    );
  }}
>
  <ResultsScreen {...mockProps} />
</MockedProvider>

额外优化:修复测试中的waitFor写法

原测试中waitFor内的setTimeout是多余的,waitFor本身会循环等待断言通过,修改为:

await waitFor(() => {
  expect(getByText(/Something/)).toBeInTheDocument();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 21:05:36