profile
viewpoint

Ask questionsMockProvider is not reporting results.errors

Intended outcome:

Following https://www.apollographql.com/docs/react/recipes/testing/#testing-error-states we have:

To simulate GraphQL errors, define errors with an instantiated GraphQLError object that represents your error, along with any data in your result.

const dogMock = {
  // ...
  result: {
    errors: [new GraphQLError('Error!')],
  },
};

It should return errors with useQuery(), but it's not.

Actual outcome:

The useQuery() returned errors remain undefined, however networkStatus becomes 8 (error).

Using error instead of result.error provides the same behavior.

How to reproduce the issue:

// jest test:
import React from 'react';
import renderer from 'react-test-renderer';
import { useQuery } from 'react-apollo';
import { MockedProvider } from '@apollo/react-testing';
import { GraphQLError } from 'graphql';
import gql from 'graphql-tag';

it('renders errors', (): void => {
  const query = gql`
    query TestQuery {
      rates(currency: "USD") {
        rate
      }
    }
  `;
  const mocks = [
    {
      request: { query },
      result: {
        errors: [new GraphQLError('forced error')],
      },
    },
  ];
  const TestComponent = (): JSX.Element => {
    const { error } = useQuery(query);
    return <>{`error: ${error}`}</>;
  };

  jest.useFakeTimers();
  const instance = renderer.create(
    <MockedProvider mocks={mocks} addTypename={false}>
      <TestComponent />
    </MockedProvider>,
  );
  renderer.act((): void => {
    jest.runAllTimers();
  });
  expect(instance.toJSON()).not.toBe('error: undefined');
});

Currently fails:

$ jest bugreport.tsx
 FAIL bugreport.tsx
  ✕ renders errors (32ms)

  ● renders errors

    expect(received).not.toBe(expected) // Object.is equality

    Expected: not "error: undefined"

      37 |     jest.runAllTimers();
      38 |   });
    > 39 |   expect(instance.toJSON()).not.toBe('error: undefined');
         |                                 ^
      40 | });
      41 | 

      at Object.toBe (bugreport.tsx:39:33)

Version

$ npx envinfo@latest --preset apollo --clipboard
npx: installed 1 in 1.624s

  System:
    OS: macOS 10.14.5
  Binaries:
    Node: 10.16.0 - ~/.nvm/versions/node/v10.16.0/bin/node
    Yarn: 1.16.0 - ~/Development/git/test/node_modules/.bin/yarn
    npm: 6.9.0 - ~/.nvm/versions/node/v10.16.0/bin/npm
  Browsers:
    Chrome: 75.0.3770.100
    Firefox: 67.0.4
    Safari: 12.1.1
  npmPackages:
    apollo: ^2.15.0 => 2.15.0 
    apollo-boost: ^0.4.3 => 0.4.3 
    apollo-cache-inmemory: ^1.6.2 => 1.6.2 
    apollo-client: ^2.6.3 => 2.6.3 
    apollo-link: ^1.2.12 => 1.2.12 
    apollo-link-error: ^1.1.11 => 1.1.11 
    apollo-link-http: ^1.5.15 => 1.5.15 
    react-apollo: 3.0.0-beta.3 => 3.0.0-beta.3 

Other:

@apollo/react-hooks: ^0.1.0-beta.10
@apollo/react-testing: ^0.1.0-beta.5
apollographql/react-apollo

Answer questions hwillson

Thanks for reporting this @barbieri. For some reason Jest is having a hard time working with the setTimeout calls we make in MockLink, to allow people to set a delay on the Observable. If I disable the setTimeout calls, everything works properly (the error is properly set).

@definitelycarter I believe you're pointing to the correct source of the issue, but the error destructuring should be okay. It's that setTimeout that is giving Jest grief. If that block of the MockLink code is updated to be:

return new Observable(observer => {
  if (error) {
    observer.error(error);
  } else {
    if (result) {
      observer.next(
        typeof result === 'function'
          ? (result as ResultFunction<FetchResult>)()
          : result
      );
    }
    observer.complete();
  }
});

the following test passes properly:

it("should render GraphQLError's", () => {
  const query = gql`
    query TestQuery {
      rates(currency: "USD") {
        rate
      }
    }
  `;

  const mocks = [
    {
      request: { query },
      result: {
        errors: [new GraphQLError('forced error')]
      }
    }
  ];

  const Component = () => {
    const result = useQuery(query);
    if (!result.loading) {
      expect(result.error).toBeDefined();
      expect(result.error!.message).toEqual('GraphQL error: forced error');
    }
    return null;
  };

  render(
    <MockedProvider mocks={mocks}>
      <Component />
    </MockedProvider>
  );
});

More details coming shortly.

useful!
source:https://uonfu.com/
Github User Rank List