React Apollo测试无法正常工作。查询数据总是不确定的

时间:2019-04-03 11:26:38

标签: reactjs react-apollo react-testing-library

我仅获得加载状态,并且在测试中未定义数据。我不知道为什么我要遵循给定示例中的所有内容。请帮忙。

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

上的第34行
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>

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

2 个答案:

答案 0 :(得分:1)

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

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

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

执行此操作后,loading 属性为 false,但 data 仍为 undefined。我发现我的模拟结果对象缺少一个属性。一旦我将缺少的属性添加到模拟结果中,data 就会按预期填充。

答案 1 :(得分:0)

我要等待MockedProvider的加载状态通过的方法是使用wait中的waait函数。这实际上也是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-library的{​​{1}}函数等待在加载状态切换为true后出现的元素。

例如

wait