代码之家  ›  专栏  ›  技术社区  ›  Evanss

当一个组件有多个useQuery时,Apollo的MockedProvider不起作用?

  •  0
  • Evanss  · 技术社区  · 3 年前

    我有一个简单的阿波罗计划。在这个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;
    

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

    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/

    0 回复  |  直到 3 年前
        1
  •  8
  •   mcernak    3 年前

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

    这会在幕后导致“查询不再有模拟响应”错误(请参阅 mockLink.ts )因为每个查询调用消耗一个模拟响应。
    第一次调用查询时,它返回模拟的数据,这就是为什么你最初会看到它。不过,下一次调用会抛出一个错误,并将数据设置为 undefined .

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

    选项1 通过设置以下参数禁用MockedProvider上的缓存 fetch-policy no-cache :

    <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"
              }
            ]
          }
        })
      }
    ];