中继:预计会收到一个对象,其中传播了`...MyComponent_user`,但未找到片段引用`

Posted

技术标签:

【中文标题】中继:预计会收到一个对象,其中传播了`...MyComponent_user`,但未找到片段引用`【英文标题】:Relay: Expected to receive an object where `...MyComponent_user` was spread, but the fragment reference was not found` 【发布时间】:2021-05-12 07:46:55 【问题描述】:

我有一个使用 useFragment 钩子的组件,我试图弄清楚如何传入数据并使用 @testing-library/react 对其进行测试:

// @flow
import  graphql, useFragment  from 'react-relay/hooks';
import Field from '../../common/fields/Field.react';
import type  MyComponent_user  from './__generated__/MyComponent_user.graphql';

type Props = 
  user: MyComponent_user,
;
export default ( user: userFragment : Props) => 
  const user = useFragment(
    graphql`
      fragment MyComponent_user on UserType
 
        id
        fullName
        userType
        details 
          user 
            id
          
          address
          city
          state
          zipCode
          country
          phone
          title
          company
        
      
    `,
    userFragment,
  );

  const userDetails = user?.details;
  const userHref = '/user?userId=';
  return (
    <div className="user-container">
      user?.fullName && <Field label="Full Name" value=user.fullName />
      user?.userType && (
        <Field
          label="User Type"
          value=user.userType === '1' ? 'Employee' : 'User'
        />
      )
      userDetails?.address && <Field label="Address" value=userDetails.address />
      userDetails?.city && <Field label="City" value=userDetails.city />
      userDetails?.state && <Field label="State" value=userDetails.state />
      userDetails?.zipCode && <Field label="Zipcode" value=userDetails.zipCode />
      userDetails?.country && <Field label="Country" value=userDetails.country />
      userDetails?.phone && <Field label="Phone" value=userDetails.phone />
      userDetails?.title && <Field label="Title" value=userDetails.title />
      userDetails?.company && <Field label="Company" value=userDetails.company />
    </div>
  );
;

我正在尝试编写测试:

import  render, screen  from '@testing-library/react';

import  RelayEnvironmentProvider  from 'react-relay/hooks';
import RelayEnvironment from '../../../../environment';

import MyComponent from '../MyComponent.react';

const props = 
  user: 
    id: 1,
    fullName: 'Meek Mill',
    userType: '0',
    details: 
      address: '294 Oak Street',
      city: 'Philadelphia',
      state: 'PA',
      zipCode: '19019',
      country: 'US',
      phone: '555-555-5555',
      title: 'Owner',
      company: 'Dream Chasers Records',
      user: 
        id: '237895024906790',
      ,
    ,
  ,
;

describe('when the user type is 0', () => 
  it('displays User as the User Type', () => 
    render(
      <RelayEnvironmentProvider environment=RelayEnvironment>
        <MyComponent ...props />
      </RelayEnvironmentProvider>,
    );

    screen.debug();
  );
);

我收到此错误:

  Invariant Violation: Relay: Expected to receive an object where `... MyComponent_user` was spread, but the fragment reference was not found`. This is most likely the result of:
    - Forgetting to spread ` MyComponent_user` in `useFragment()`'s parent's fragment.
    - Conditionally fetching ` MyComponent_user` but unconditionally passing a fragment reference prop to `useFragment()`. If the parent fragment only fetches the fragment conditionally - with e.g. `@include`, `@skip`, or inside a `... on SomeType  ` spread  - then the fragment reference will not exist. In this case, pass `null` if the conditions for evaluating the fragment are not met (e.g. if the `@include(if)` value is false.)

      12 |   console.log('userFragment:', userFragment);
      13 |   console.log('props:', props);
    > 14 |   const user = useFragment(
         |                ^
      15 |     graphql`
      16 |       fragment MyComponent_user on UserType 
      17 |         id

如果在文档中添加一些测试示例会很棒。

【问题讨论】:

【参考方案1】:

在测试 Relay 框架时,您需要了解几件事。

我们需要在中继测试中使用两个主要模块: createMockEnvironment: 它提供中继环境接口和模拟层,允许resolvingreject 和模拟操作querymutation订阅mockPayloadGenerator:允许您为需要测试的组件生成和维护一组模拟数据。 根据您希望在测试中涵盖的测试用例数量,您需要提供一组不同的模拟数据并将其传递给MockPayloadGenerator
import  render, cleanup  from '@testing-library/react';
import  MockPayloadGenerator  from 'relay-test-utils';

const DEFAULT_PROPS = 
      user: 
        id: 1,
        fullName: 'Meek Mill',
        userType: '0',
        details: 
          address: '294 Oak Street',
          city: 'Philadelphia',
          state: 'PA',
          zipCode: '19019',
          country: 'US',
          phone: '555-555-5555',
          title: 'Owner',
          company: 'Dream Chasers Records',
          user: 
            id: '237895024906790',
          ,
        ,
      ,
    ;

    function TestRenderer(): React.Node 
      const node = useLazyLoadQuery<MyTopLevelComponentTestQuery>(
        graphql`
         query MyTopLevelComponentTestQuery
         @relay_test_operation 
           node(id: "TEST_FAKE_USER_ID") 
             ...MyComponent_user
           
         
        `,
        ,
      );
      return user != null && <MyComponent user=node />;
    
    
    describe('MyComponent', () => 
      let environment = createMockEnvironment();

      function renderWithEnvironment(node: React.Node): React.Node 
         return (
           <RelayEnvironmentProvider environment=environment>
             <Suspense fallback=null>node</Suspense>
           </RelayEnvironmentProvider>,
         );
      
 
      function mockNextOperation(props): void   
        // if you use `resolveMostRecentOperation` you don't need to 
        // have MyTopLevelComponentTestQuery
        // environment.mock.resolveMostRecentOperation(operation =>
        environment.mock.queueOperationResolver(operation =>
        MockPayloadGenerator.generate(operation, 
          UserType() 
            return 
              node: 
                ...props,
              ,
            ;
          ,
        ),
       );
      

      beforeEach(() => 
       environment = createMockEnvironment();
       cleanup();
      );

     it('when the user type is 0', () => 
       mockNextOperation(DEFAULT_PROPS);
       const getByText = render(
         renderWithEnvironment(<TestRenderer />),
       );
       // whatever your logic is to test your component 
       expect(getByText('User Type: User')).toBeTruthy();
     );

     it('when the user type is 1', () => 
       mockNextOperation(ANOTHER_TEST_PROPS);
       const getByText = render(
         renderWithEnvironment(<TestRenderer />),
       );
       // whatever your logic is to test your component
       expect(getByText('User Type: Employee')).toBeTruthy();
     );
  );

【讨论】:

以上是关于中继:预计会收到一个对象,其中传播了`...MyComponent_user`,但未找到片段引用`的主要内容,如果未能解决你的问题,请参考以下文章

React.Children.only 预计会收到单个 React 元素子错误

当 2 个模型在 flask-sqlalchemy 中继承相同的对象时收到警告

我收到一个错误“传播类型只能从对象 types.ts(2698) 创建”

我收到“错误:React.Children.only 预计会收到一个 React 元素子项。”带有 TouchableWithoutFeedback

基本知识

React.Children.only 预计在使用 Ref 时会收到单个 React 元素子错误