Ad

React Apollo Testing Is Not Working. Query Data Is Always Coming Undefined

I am getting loading state only and data as undefined in testing. I don't know why I am following everything in the given example. Please help.

Testing file. When i am waiting thsi line toexecute await wait(() => getByTestId('edit-category'));. It is giving response data of query as undefined. Error: TypeError: Cannot read property 'getCategory' of undefined Line 34 on 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>
  );
});

Edit: I tried @mikaelrs solution which is passed match. But it is not working. I also tried to pass id:1 as fixed. But it is still giving error.

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

This is not working. My query without veriable is working fine. Mutation is also working fine. I am having only problem with this. When i have to pass like varible like this.

Ad

Answer

What I do to wait for the loading state of the MockedProvider to pass is to use the wait function from waait. This is actually what Apollo recommends as well.

So in your test you would do:

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()
  });
});

Another solution is to use react-testing-librarys wait function to wait for an element that would be present after the loading state switches to true.

For instance

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()
  });
});
Ad
source: stackoverflow.com
Ad