React Apollo 测试不起作用。查询数据总是未定义

Posted

技术标签:

【中文标题】React Apollo 测试不起作用。查询数据总是未定义【英文标题】:React Apollo Testing is not working. Query data is always coming undefined 【发布时间】:2019-08-24 22:00:27 【问题描述】:

我只得到加载状态和测试中未定义的数据。我不知道为什么我要遵循给定示例中的所有内容。请帮忙。

测试文件。当我等待这条线执行await wait(() => getByTestId('edit-category'));。它给出了未定义的查询响应数据。 错误:TypeError: Cannot read property 'getCategory' of undefined 第 34 行 editConatinerCategory.tsx => category=data!.getCategory!

import React from 'react';
import gql from 'graphql-tag';
import  cleanup, wait  from 'react-testing-library';
import  customRender  from '../../../test-utils/customRender';
import  EditCategoryContainer  from './Container';

afterEach(() => 
  cleanup();
  console.error;
);
console.error = jest.fn();

const getCategoryMock = 
  request: 
    query: gql`
      query getCategory($id: Int!) 
        getCategory(id: $id) 
          id
          name
          active
          position
        
      
    `,
    variables: 
      id: 1
    
  ,
  result: 
    data: 
      getCategory: 
        id: 1,
        name: 'category',
        active: true,
        position: 1
      
    
  
;

describe('create edit category module', () => 
  test('Rendering correct', async () => 
    const  container, debug, getByTestId  = customRender(<EditCategoryContainer />, [
      getCategoryMock
    ]);
    await wait(() => getByTestId('edit-category'));
    await wait(() => expect(container).toMatchSnapshot());
//Getting this TypeError: Cannot read property 'getCategory' of undefined. Because i am data as undefined from my query response

  );
);

CustomRender.tsx

import React from 'react';
import  render  from 'react-testing-library';
import  MockedProvider, MockedResponse  from 'react-apollo/test-utils';
import  Router, Switch  from 'react-router-dom';
import  createMemoryHistory  from 'history';

export const customRender = (
  node: JSX.Element | null,
  mocks?: MockedResponse[],
  
    route = '/',
    history = createMemoryHistory( initialEntries: [route] )
   = 
) => 
  return 
    history,
    ...render(
      <MockedProvider mocks=mocks addTypename=false>
        <Router history=history>
          <Switch>node</Switch>
        </Router>
      </MockedProvider>
    )
  ;
;

EditCategoryContainer.tsx

import React from 'react';
import  withRouter  from 'react-router';
import  Spin  from 'antd';
import 
  AddCategoryComponent,
  GetCategoryComponent
 from '../../../generated/graphql';
import  EditCategory  from './Edit';
import  LoadingComponent  from '../../../components/LoadingComponent';

export const EditCategoryContainer = withRouter(( history, match ) => 
  const id: number = parseInt(match.params.id, 10);
  return (
    <GetCategoryComponent
      variables=
        id
      
    >
      ( data, loading: getCategoryLoading ) => 
        console.log(getCategoryLoading, 'getCategoryLoading');
        if (getCategoryLoading) 
          return <LoadingComponent />;
        
        if (data && !data.getCategory) 
          return <div>Category not found!</div>;
        
        console.log(data);
        return (
          <AddCategoryComponent>
            (addCategory,  loading, error ) => 
              return (
                <EditCategory
                  data-testid="edit-category"
                  category=data!.getCategory!
                  loading=loading || getCategoryLoading
                  onSubmit=values => 
                    addCategory( variables: values ).then(() => 
                      history.push('/dashboard/categories');
                    );
                  
                />
              );
            
          </AddCategoryComponent>
        );
      
    </GetCategoryComponent>
  );
);

编辑: 我尝试了通过匹配的@mikaelrs 解决方案。但它不起作用。我也尝试通过 id:1 固定。但它仍然给出错误。

 <GetCategoryComponent
      variables=
        id:1
      
    >
...rest of code.
</GetCategoryComponent>

这不起作用。我没有验证的查询工作正常。突变也可以正常工作。我只有这个问题。当我必须像这样通过变量时。

【问题讨论】:

【参考方案1】:

等待MockedProvider 的加载状态通过的方法是使用waait 中的wait 函数。这实际上也是Apollo 推荐的。

所以在你的测试中你会这样做:

import React from 'react';
import gql from 'graphql-tag';
import  cleanup  from 'react-testing-library';
import wait from 'waait'

import  customRender  from '../../../test-utils/customRender';
import  EditCategoryContainer  from './Container';

afterEach(() => 
  cleanup();
);

const getCategoryMock = 
  request: 
    query: gql`
      query getCategory($id: Int!) 
        getCategory(id: $id) 
          id
          name
          active
          position
        
      
    `,
    variables: 
      id: 1
    
  ,
  result: 
    data: 
      getCategory: 
        id: 1,
        name: 'category',
        active: true,
        position: 1
      
    
  
;

describe('create edit category module', () => 
  test('Rendering correct', async () => 
    const  container, debug  = customRender(<EditCategoryContainer />, [
      getCategoryMock
    ]);

    await wait(0);

    // Your loading state should be false after this, and your component should
    // get it's data from apollo for you to do any assertion you would like to 
    // after this point. To see that the component is rendered with data invoke 
    // the debug function from react-testing-library after this point


    debug();


    expect(container).toMatchSnapshot()
  );
);

另一种解决方案是使用react-testing-librarys wait 函数等待加载状态切换为true后将出现的元素。

例如

describe('create edit category module', () => 
  test('Rendering correct', async () => 
    const  container, debug, queryByText  = customRender(<EditCategoryContainer />, [
      getCategoryMock
    ]);

    await wait(()=> queryByText("Some Data"));

    // Your loading state should be false after this, and your component should
    // get it's data from apollo for you to do any assertion you would like to 
    // after this point

    expect(container).toMatchSnapshot()
  );
);

【讨论】:

我正在使用 react-testing-library 等待功能。但它仍然给我未定义, 但是你在 await 函数内部做了一个期望。你能尝试等待'waait'的等待,这是从阿波罗测试最终状态的推荐方法。 apollographql.com/docs/react/recipes/… 也从 wait 库中尝试过等待。我仍然遇到同样的错误。 好的,我会试试的,我会告诉你的。 什么都试过了。最后,从 wait 包中添加 wait 起到了神奇的作用。我所要做的就是包括等待等待(0)。非常感谢@mikaelrs【参考方案2】:

我遇到了类似的问题。以下是我解决问题的方法。

首先,按照@mikaelrs 和the docs 的建议,等待查询解决:

await new Promise(resolve => setTimeout(resolve, 0));

这样做之后,loading 属性为false,但data 仍为undefined。我发现我的模拟结果对象缺少属性。一旦我将缺少的属性添加到模拟结果中,data 就会按预期填充。

【讨论】:

以上是关于React Apollo 测试不起作用。查询数据总是未定义的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React + Apollo GraphQL 中查询先前查询的结果?

React Apollo 多次重新获取不起作用

UseQuery 在通过 apollo react 使用 useMutations 重定向后不起作用

使用 React Hook 客户端测试 Apollo 查询

Apollo 客户端持久缓存不起作用

Apollo graphql 将标头设置为 authmiddleware 不起作用