简体   繁体   English

中继 - usePreloadedQuery 挂钩在使用酶安装时暂停渲染

[英]Relay - usePreloadedQuery hook is suspending rendering while mounting with enzyme

I get the below error while trying to unit test a component which uses usePreloadedQuery :尝试对使用usePreloadedQuery的组件进行单元测试时出现以下错误:

Error: A React component suspended while rendering, but no fallback UI was specified.

Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.

I have a parent component that receives a query reference, and it is using usePreloadedQuery to retrieve the data as shown below:我有一个接收查询引用的父组件,它使用usePreloadedQuery来检索数据,如下所示:

type Props = {
   queryReference: PreloadedQuery<parentComponentQuery>,
};

export const ParentComponent = ({ queryReference }: Props) => {
  const { data } = usePreloadedQuery(
    graphql`
        query parentComponentQuery($someId: ID!) {
            something(someId: $someId) {
                    ...childComponentFragment
                }
            }
        }
    `,
    queryReference,
  );

  return (
      <div>
         <ChildComponent fragmentRef={data.childData} />
      </div>
   )
}

The queryReference here is created via call to loadQuery , which is handled by an internal hook, that is a wrapper around react-resource-router 's useResource for relay resources.这里的queryReference是通过调用loadQuery创建的,它由一个内部钩子处理,它是react-resource-router用于中继资源的useResource的包装器。


I'm trying to test this component using Jest and Enzyme with the following code:我正在尝试使用 Jest 和 Enzyme 使用以下代码测试此组件:

let queryReference;
const mockRelayPayload = () => {
  const environment = createMockEnvironment();
  environment.mock.queueOperationResolver((operation) =>
    MockPayloadGenerator.generate(operation, {
        Something: () => ({
            // ... data
        }),
    }),
  );
  environment.mock.queuePendingOperation(QUERY, {});

  act(() => {
     queryReference = loadQuery(environment, QUERY, {}); // fire mocked API call
  });

  return environment;
};

it('should render correctly', () => {
    const environment = mockRelayPayload();
    const wrapper = mount(
        <RelayEnvironmentProvider environment={environment}>
            {/*<Suspense fallback={<div>Loading... </div>}>*/}
               <ParentComponent  queryReference={queryReference}/>
            {/*</Suspense>*/}
        </RelayEnvironmentProvider>
    );
    
    expect(wrapper.find(Wrapper)).toExist();
});

According to the docs Testing Relay Components :根据文档测试中继组件

in order for the usePreloadedQuery hook to not suspend, one must call these functions:为了使usePreloadedQuery挂钩不挂起,必须调用这些函数:

  • queueOperationResolver(resolver)
  • queuePendingOperation(query, variables)
  • preloadQuery(mockEnvironment, query, variables) with the same query and variables that were passed to queuePendingOperation . preloadQuery(mockEnvironment, query, variables)与传递给queuePendingOperation的相同查询和变量。 preloadQuery must be called after queuePendingOperation preloadQuery必须在queuePendingOperation之后调用

I'm doing the first two steps, but I'm not able to import preloadQuery from react-relay , based on github source/flowtypes looks like it is deprecated/removed.我正在执行前两个步骤,但我无法从react-relay导入preloadQuery ,基于 github source/flowtypes 看起来它已被弃用/删除。 So instead I'm using loadQuery as in所以我使用的是loadQuery

act(() => {
     queryReference = loadQuery(environment, QUERY, {}); // fire mocked API call
});

But it throws the error mentioned earlier.但它会抛出前面提到的错误。

As you can tell from the commented code, I've also tried using <Suspense> as suggested in the error, unfortunately it throws Error: Enzyme Internal Error: unknown node with tag 2 from enzyme-adapter-react-16正如您从注释代码中可以看出的那样,我也尝试按照错误中的建议使用<Suspense> ,不幸的是它抛出Error: Enzyme Internal Error: unknown node with tag 2来自enzyme-adapter-react-16标签为2的未知节点

Finally found the issue after days of struggle, it was here:经过几天的努力终于找到了问题,它就在这里:

  environment.mock.queuePendingOperation(QUERY, {});

  act(() => {
     queryReference = loadQuery(environment, QUERY, {});
  });

This should be这应该是

environment.mock.queuePendingOperation(QUERY, { someId: "value" });

let queryReference;
act(() => {
    queryReference = loadQuery(environment, QUERY, { someId: "value" }); 
});

It seems like when you use queueOperationResolver , it'll only resolve if the query "signature" exactly matches the query and variables you pass to queuePendingOperation and loadQuery .似乎当您使用queueOperationResolver时,只有当查询“签名”与您传递给queuePendingOperationloadQuery的查询和变量完全匹配时,它才会解析

In my case I was passing an empty variables object {} instead of { someId: "value" } so the resolver wasn't resolving the query at all.在我的情况下,我传递了一个空变量 object {}而不是{ someId: "value" }所以解析器根本没有解析查询。

Unfortunately the error message thrown here isn't very useful, instead of saying the query is never resolved it just tells you to use <Suspense> which is a bit misleading.不幸的是,这里抛出的错误消息不是很有用,而不是说查询永远不会解决它只是告诉你使用<Suspense>这有点误导。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM