typescript Apollo客户端MockedProvider:跳装状态

vwkv1x7d  于 2023-04-22  发布在  TypeScript
关注(0)|答案(1)|浏览(227)

我用Apollo设置了一个React应用程序,它有一个 Package 器组件来处理从网络加载数据,这样下面的每个组件都可以直接从Apollo缓存中查询数据,而不必担心处理加载状态。因此,我的组件看起来像这样:

export const COUNT_OFF_ADAPTER_QUERY = gql`
  query CountOffAdapterQuery($vampId: ID!) {
    vamp(id: $vampId) @client {
      id
      countingOff
      countingOffStartTime
    }
  }
`;

export const CountOffAdapter: React.FC<{}> = () => {
  const vampId = useCurrentVampId();

  const {
    data: {
      vamp: { countingOff, countingOffStartTime }
    }
  } = useQuery<CountOffAdapterQuery>(COUNT_OFF_ADAPTER_QUERY, {
    variables: { vampId }
  });

  const prev = usePrevious({ countingOff, countingOffStartTime });

  const countOff = useCountOff();

  useEffect(() => {
    // Do react stuff
  }, [countOff, countingOff, prev]);

  return null;
};

在实践中(在浏览器中),这非常有效,因为在应用程序中Apollo将立即从该高速缓存返回数据,因此useQuery调用的loading结果永远不会是true,我可以解构数据,在后续的钩子中使用它,等等。
然而,当测试时,似乎MockedProvider * 必然 * 将loading返回为true,测试编写者无法控制是否跳过该状态注意,当useQuery返回loadingtrue时,渲染我的组件将出错,因为它正在解构data,这是未定义的。正因为如此,我永远不能在测试失败的情况下通过加载状态。
下面是我的测试代码:

it("works", async () => {
  (useCurrentVampId as jest.Mock).mockImplementation(
    () => "6070dedd58d7bf715eb2a6c5"
  );
  const component = mount(
    <MockedProvider
      mocks={[
        {
          request: {
            query: COUNT_OFF_ADAPTER_QUERY,
            variables: {
              vampId: "6070dedd58d7bf715eb2a6c5"
            }
          },
          result: {
            data: {
              vamp: {
                id: "6070dedd58d7bf715eb2a6c5",
                countingOff: true,
                countingOffStartTime: 1234
              }
            }
          }
        }
      ]}
      addTypename={false}
    >
      <CountOffAdapter></CountOffAdapter>
    </MockedProvider>
  );
  await wait(0);
  component.update();
});

我很好奇是否有办法解决这个问题,如果你能在查询mock中指定loading: false就好了,但是你不能。

qvsjd97n

qvsjd97n1#

我正在使用Next.js,我主要做服务器端渲染,所以我遇到了和你一样的情况,我决定进一步研究一下。看起来apollo-client在实际的mock中提供了延迟 prop ,例如:

const mock: MockedResponse = {
  request: {
    query: SomeDocument,
    variables: { slug: 'test' },
  },
  result: { data: fakeData },
  delay: 0, // <---------THIS ----------|(number or undefined)
};

但这也无济于事,所以我更深入地研究了源代码,在看到以下内容后,一切都变得清晰起来:

return new Observable(observer => {
      const timer = setTimeout(() => {
        if (configError) {
          try {
            // The onError function can return false to indicate that
            // configError need not be passed to observer.error. For
            // example, the default implementation of onError calls
            // observer.error(configError) and then returns false to
            // prevent this extra (harmless) observer.error call.
            if (this.onError(configError, observer) !== false) {
              throw configError;
            }
          } catch (error) {
            observer.error(error);
          }
        } else if (response) {
          if (response.error) {
            observer.error(response.error);
          } else {
            if (response.result) {
              observer.next(
                typeof response.result === 'function'
                  ? (response.result as ResultFunction<FetchResult>)()
                  : response.result
              );
            }
            observer.complete();
          }
        }
      }, response && response.delay || 0);

正如你在这里看到的,delay只作为setTimeout的毫秒参数使用,这是一个async code -〉means将添加在javascriptqueuehttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop)中的sync code之后。所以,为delay字段提供什么值并不重要。
你的问题的最后结论:目前无法跳过加载状态。

相关问题