React-apollo: MockedProvider with client.readQuery doesn't run mocks

Created on 24 Oct 2019  路  7Comments  路  Source: apollographql/react-apollo

Intended outcome:

When using MockedProvider from @apollo/react-testing library with class component, which is wrapped with withApollo HoC, calling this.props.client.readQuery runs provided mocks during tests.

Actual outcome:

Calling this.props.client.readQuery on component mount doesn't run provided mocks during tests. result function isn't called and test fails on Invariant Violation: Can't find field on object undefined.

How to reproduce the issue:

  1. Create class component wrapped with withApollo HoC.
  2. Call this.props.client.readQuery on component mount.
  3. Write test for class using MockedProvider from @apollo/react-testing library.

Version

@apollo/react-common: ^3.1.1 => 3.1.1
@apollo/react-hooks: ^3.1.1 => 3.1.1
@apollo/react-ssr: ^3.1.1 => 3.1.1
@apollo/react-testing: ^3.1.1 => 3.1.1
apollo: ^2.19.0 => 2.19.0
apollo-cache-inmemory: ^1.6.3 => 1.6.3
apollo-client: ^2.6.4 => 2.6.4
apollo-link-http: ^1.5.16 => 1.5.16
react-apollo: ^3.1.1 => 3.1.1

Most helpful comment

Had the same issue. Solved it by creating a mock cache:

import { InMemoryCache } from 'apollo-cache-inmemory';

const cache = new InMemoryCache().restore({
  ROOT_QUERY: {
    user: {
      type: 'id',
      id: 'asdf',
      generated: false,
    },
  },
  asdf: {
    companyName: 'Example Company',
    email: '[email protected]',
    __typename: 'user',
  },
});

...

ReactDOM.render(
        <MockedProvider mocks={requestMocks} cache={cache}>
          ....
        </MockedProvider>,
        container
);

Hope that helps!

All 7 comments

Also experiencing this using the useApolloClient hook.

Found a temporary workaround until this gets sorted:

const client = useApolloClient();
let data;
try {
    data = client.readQuery({
      query: myGqlQuery,
    });
  } catch (error) {
    if (process.env.JEST_WORKER_ID !== undefined) { // or however you'd like to check for if unit testing
      data = someFixture.data;
    }
  }

Had the same issue. Solved it by creating a mock cache:

import { InMemoryCache } from 'apollo-cache-inmemory';

const cache = new InMemoryCache().restore({
  ROOT_QUERY: {
    user: {
      type: 'id',
      id: 'asdf',
      generated: false,
    },
  },
  asdf: {
    companyName: 'Example Company',
    email: '[email protected]',
    __typename: 'user',
  },
});

...

ReactDOM.render(
        <MockedProvider mocks={requestMocks} cache={cache}>
          ....
        </MockedProvider>,
        container
);

Hope that helps!

@Fl0rianFischer Hi, thanks for sharing your solution!

Could you please share what's in requestMocks variable, so I could understand better what actually has to be part of object passed to the restore function?

I'm trying to make your solution work, but as soon as I call client.readQuery directly from a class component, I once again get the Invariant Violation error (if I use useQuery hook instead, everything works fine).

Thanks!

@LuckyLuky in the requestMocks I only have the data that is actually fetched from the server with useQuery. So it shouldn't influence anything you pass into the mocked cache. I only passed the data into the mocked cache that I'm actually requesting with client.readQuery.

In my case I'm only using functional components. Maybe you can try converting your component and check again?

The big downside of using the hook useQuery is that it's async by default so if I request data from the cache I would have to use a loading state which doesn't make any sense.

@Fl0rianFischer I am using functional HoC right now as a workaround, because we have this one class component we'd like to keep. We were looking into a possibility of ditching these functional components and moving the logic to the class component, but unfortunately, it seems that it's not possible right now (if we want to create tests for the class component, which we want :) )

But anyway, thanks for your help!

another workaround:

jest.mock('@apollo/react-hooks', () => ({
  ...require.requireActual('@apollo/react-hooks'),
  useApolloClient: () => ({ readQuery: jest.fn() }), 
}));
Was this page helpful?
0 / 5 - 0 ratings