apollo-client icon indicating copy to clipboard operation
apollo-client copied to clipboard

Testing Error State of Mutation is throwing Global Error

Open mkaraula opened this issue 4 years ago • 19 comments

I want to reopen https://github.com/apollographql/react-apollo/issues/2614 from the old repo as I ran into the exact same Issue today with @apollo/client": "3.2.2.

I have a component that uses the useMutation hook and renders differently when useMutation returns an error

export const DELETE_DOG_MUTATION = gql`
  mutation deleteDog($name: String!) {
    deleteDog(name: $name) {
      id
      name
      breed
    }
  }
`;

export function DeleteButton() {
  const [mutate, { loading, error, data }] = useMutation(DELETE_DOG_MUTATION);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error!</p>;
  if (data) return <p>Deleted!</p>;

  return (
    <button onClick={() => mutate({ variables: { name: 'Buck' } })}>
      Click me to Delete Buck!
    </button>
  );
}

I want to Test this behaviour as described in the Docs

it('should show error UI', async () => {
  const deleteDog = { name: 'Buck', breed: 'Poodle', id: 1 };
  const mocks = [
    {
      request: {
        query: DELETE_DOG_MUTATION,
        variables: { name: 'Buck' },
      },
      error: new Error('aw shucks'),
    },
  ];

  const component = renderer.create(
    <MockedProvider mocks={mocks} addTypename={false}>
      <DeleteButton />
    </MockedProvider>,
  );

  // find the button and simulate a click
  const button = component.root.findByType('button');
  button.props.onClick(); // fires the mutation

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

  const tree = component.toJSON();
  expect(tree.children).toContain('Error!');
});

Intended outcome:

The Test should pass without throwing an error.

Actual outcome:

Passing mocks with an Error to <MockedProvider /> does actually throw a global Error

    aw shucks

      at new ApolloError (node_modules/@apollo/client/errors/index.js:26:28)
      at Object.error (node_modules/@apollo/client/core/QueryManager.js:146:48)
      at notifySubscription (node_modules/zen-observable/lib/Observable.js:140:18)
      at onNotify (node_modules/zen-observable/lib/Observable.js:179:3)
      at SubscriptionObserver.error (node_modules/zen-observable/lib/Observable.js:240:7)
      at node_modules/@apollo/client/utilities/observables/iteration.js:4:68
          at Array.forEach (<anonymous>)
      at iterateObserversSafely (node_modules/@apollo/client/utilities/observables/iteration.js:4:25)
      at Object.error (node_modules/@apollo/client/utilities/observables/Concast.js:33:21)
      at notifySubscription (node_modules/zen-observable/lib/Observable.js:140:18)

I figured out that when I add an onError option to useMutation my test runs as expected but I guess this is just a workaround.

  const [mutate, { loading, error, data }] = useMutation(DELETE_DOG_MUTATION, {onError: () => {}});

How to reproduce the issue:

I cant share the code of the application I am working on but I can try to create a Codesandbox if neccessary but I hope my explanation is detailed enough.

Versions System: OS: macOS Mojave 10.14.6 Binaries: Node: 10.16.0 - /usr/local/bin/node npm: 6.11.2 - /usr/local/bin/npm Browsers: Chrome: 86.0.4240.80 Firefox: 81.0.1 Safari: 12.1.2 npmPackages: @apollo/client: ^3.2.2 => 3.2.2 "jest": "^24.9.0",

mkaraula avatar Oct 14 '20 15:10 mkaraula