【问题标题】:Apollo's MockedProvider doenst work when a component has multiple useQuery's?组件有多个useQueries时Apollo MockedProvider不起作用?
【发布时间】:2021-06-01 22:31:07
【问题描述】:

我有一个简单的 Apollo 设置。在这个 CodeSandbox 示例中,我使用的是 MockedProvider,但实时的也可以:

https://codesandbox.io/s/winter-glitter-o8ug5?file=/src/App.js:0-1164

import { ApolloClient, InMemoryCache } from "@apollo/client";
import { gql, useQuery, ApolloProvider } from "@apollo/client";
import { MockedProvider } from "@apollo/client/testing";

const client = new ApolloClient({
  uri: "https://48p1r2roz4.sse.codesandbox.io",
  cache: new InMemoryCache()
});

const EXCHANGE_RATES_1 = gql`
  query GetExchangeRates {
    rates(currency: "USD") {
      rate
    }
  }
`;

const mocks = [
  {
    request: {
      query: EXCHANGE_RATES_1
    },
    result: {
      data: {
        rates: [
          {
            __typename: "ExchangeRate",
            rate: "123"
          }
        ]
      }
    }
  }
];

const MyComponent = () => {
  const { data: data1, loading: loading1 } = useQuery(EXCHANGE_RATES_1);
  if (loading1) return <p>Loading...</p>;
  return (
    <div>
      <h1>{data1?.rates[0].rate}</h1>
    </div>
  );
};

const AppMocked = () => {
  return (
    <MockedProvider addTypename={false} mocks={mocks}>
      <MyComponent />
    </MockedProvider>
  );
};

const AppLive = () => {
  return (
    <ApolloProvider client={client}>
      <MyComponent />
    </ApolloProvider>
  );
};

export default AppMocked;

我需要在MyComponent 中添加一个useQuery。我知道这是一个奇怪的例子,因为它应该只是一个查询,但它说明了我遇到的问题。

https://codesandbox.io/s/magical-dewdney-j451d?file=/src/App.js:0-1630

import { ApolloClient, InMemoryCache } from "@apollo/client";
import { gql, useQuery, ApolloProvider } from "@apollo/client";
import { MockedProvider } from "@apollo/client/testing";

const client = new ApolloClient({
  uri: "https://48p1r2roz4.sse.codesandbox.io",
  cache: new InMemoryCache()
});

const EXCHANGE_RATES_1 = gql`
  query GetExchangeRates {
    rates(currency: "USD") {
      rate
    }
  }
`;
const EXCHANGE_RATES_2 = gql`
  query GetExchangeRates {
    rates(currency: "USD") {
      currency
    }
  }
`;

const mocks = [
  {
    request: {
      query: EXCHANGE_RATES_1
    },
    result: {
      data: {
        rates: [
          {
            __typename: "ExchangeRate",
            rate: "123"
          }
        ]
      }
    }
  },
  {
    request: {
      query: EXCHANGE_RATES_2
    },
    result: {
      data: {
        rates: [
          {
            __typename: "ExchangeRate",
            currency: "YOLO"
          }
        ]
      }
    }
  }
];

const MyComponent = () => {
  const { data: data1, loading: loading1 } = useQuery(EXCHANGE_RATES_1);
  const { data: data2, loading: loading2 } = useQuery(EXCHANGE_RATES_2);
  if (loading1 || loading2) return <p>Loading...</p>;
  return (
    <div>
      <h1>{data1?.rates[0].rate}</h1>
      <h2>{data2?.rates[0].currency}</h2>
    </div>
  );
};

const AppMocked = () => {
  return (
    <MockedProvider addTypename={false} mocks={mocks}>
      <MyComponent />
    </MockedProvider>
  );
};

const AppLive = () => {
  return (
    <ApolloProvider client={client}>
      <MyComponent />
    </ApolloProvider>
  );
};

export default AppMocked;

实时版本运行良好,但模拟版本的 H1 为空。当我注销data1 时,我可以看到它最初确实有数据,但在随后的渲染中变为“未定义”

我在文档中看不到任何东西来解释为什么模拟不起作用:https://www.apollographql.com/docs/react/development-testing/testing/

【问题讨论】:

    标签: mocking apollo-client


    【解决方案1】:

    由于某种原因,在您的设置中,查询被多次调用。

    这会在后台导致“查询不再有模拟响应”错误(请参阅mockLink.ts),因为每个查询调用都会消耗一个模拟响应。
    第一次调用查询时,它会返回模拟数据,这就是您最初看到它的原因。下一次调用虽然会引发错误并将数据设置为undefined

    我找到了两种方法来解决这个问题:

    选项 1 通过将 fetch-policy 设置为 no-cache 来禁用 MockedProvider 上的缓存:

    <MockedProvider 
      mocks={mocks} 
      defaultOptions={{
        watchQuery: { fetchPolicy: 'no-cache' },
        query: { fetchPolicy: 'no-cache' },
      }}
    >
      <MyComponent />
    </MockedProvider>
    

    选项 2 通过提供 newData 函数允许多次使用模拟响应:

    const mocks = [
      {
        request: {
          query: EXCHANGE_RATES_1
        },
        result: {
          data: {
            rates: [
              {
                __typename: "ExchangeRate",
                rate: "123"
              }
            ]
          }
        },
        newData: () => ({
          data: {
            rates: [
              {
                __typename: "ExchangeRate",
                rate: "123"
              }
            ]
          }
        })
      },
      {
        request: {
          query: EXCHANGE_RATES_2
        },
        result: {
          data: {
            rates: [
              {
                __typename: "ExchangeRate",
                currency: "YOLO"
              }
            ]
          }
        },
        newData: () => ({
          data: {
            rates: [
              {
                __typename: "ExchangeRate",
                currency: "YOLO"
              }
            ]
          }
        })
      }
    ];
    

    【讨论】:

    • 有趣,newData 是否记录在任何地方?我在这个页面上看不到它:apollographql.com/docs/react/development-testing/testing
    • 我在任何地方都没有看到它正确记录。我是在浏览源文件 mockLinks.ts 时看到的。
    • 我只花了4个小时解决这个问题,非常感谢您的解决方案!
    猜你喜欢
    • 2020-09-02
    • 2018-10-17
    • 2020-12-19
    • 2020-01-03
    • 2018-06-17
    • 2020-05-13
    • 2021-02-16
    • 2019-04-02
    • 2021-11-12
    相关资源
    最近更新 更多