2 minute read

The MockedProvider component

The MockedProvider component enables you to define mock responses for individual queries that are executed in your test. This means your test doesn’t  need to communicate with a GraphQL server, which removes an external dependency and therefore improves the test’s reliability.

import React from 'react';
import { gql, useQuery } from '@apollo/client';

// Make sure that both the query and the component are exported
export const GET_DOG_QUERY = gql`
  query GetDog($name: String) {
    dog(name: $name) {
      id
      name
      breed
    }
  }
`;

export function Dog({ name }) {
  const { loading, error, data } = useQuery(
    GET_DOG_QUERY,
    { variables: { name } }
  );
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error!</p>;

  return (
    <p>
      {data.dog.name} is a {data.dog.breed}
    </p>
  );
}
import TestRenderer from 'react-test-renderer';
import { MockedProvider } from '@apollo/client/testing';
import { GET_DOG_QUERY, Dog } from './dog';

const mocks = []; // We'll fill this in next

it('renders without error', () => {
  const component = TestRenderer.create(
    <MockedProvider mocks={mocks} addTypename={false}>
      <Dog name="Buck" />
    </MockedProvider>,
  );

  const tree = component.toJSON();
  expect(tree.children).toContain('Loading...');
});
const mocks = [
  {
    request: {
      query: GET_DOG_QUERY,
      variables: {
        name: 'Buck',
      },
    },
    result: {
      data: {
        dog: { id: '1', name: 'Buck', breed: 'bulldog' },
      },
    },
  },
];

Testing the “loading” state

Don’t explicitly wait for the Promise

Testing the “success” state

await zero millisecond timeout before performing your checks. This delays the checks until the next “tick” of the event loop, which gives MockedProvider an opportunity to populate the mocked result

it('should render dog', async () => {
  const dogMock = {
    request: {
      query: GET_DOG_QUERY,
      variables: { name: 'Buck' },
    },
    result: {
      data: { dog: { id: 1, name: 'Buck', breed: 'poodle' } },
    },
  };

  const component = TestRenderer.create(
    <MockedProvider mocks={[dogMock]} addTypename={false}>
      <Dog name="Buck" />
    </MockedProvider>,
  );


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

  const p = component.root.findByType('p');
  expect(p.children.join('')).toContain('Buck is a poodle');
});

Testing error states

  • Network errors: errors that occur while your client attempts to communicate with your GraphQL server.

  • GraphQL errors: errors that occur while your GraphQL server attempts to resolve your client’s operation.

it('should show error UI', async () => {
  const dogMock = {
    request: {
      query: GET_DOG_QUERY,
      variables: { name: 'Buck' },
    },
    error: new Error('An error occurred'),
  };

  const component = TestRenderer.create(
    <MockedProvider mocks={[dogMock]} addTypename={false}>
      <Dog name="Buck" />
    </MockedProvider>,
  );

  await new Promise(resolve => setTimeout(resolve, 0)); // wait for response

  const tree = component.toJSON();
  expect(tree.children).toContain('An error occurred');
});
const dogMock = {
  // ...
  result: {
    errors: [new GraphQLError('Error!')],
  },
};

Comments