Mocking Multiple Queries for Mock Provider

When testing Apollo and GraphQL, Mock Provider is a nice tool to use when components need to communicate with a GraphQL server. With Mock Provider, you can define what comes back with each query call and assert the state of the component according to what has been defined.

The documentation is fairly straightforward describing how to set up single mock response per query. However, in my current project, we have a component that is conditionally rendering another component that happens to be calling the same query. After some debugging, I’ve taken note of the following when mocking multiple query responses.

Mocked queries must have the exact same variables as called

Looking at the source code for Mock Provider, in mockLink.ts, Mock Provider will stringify the request variables and store them as key to the response object. And, if the variables do not match exactly, then the response will not be found.

 const queryString =
     request.query &&
     print(addTypename ? addTypenameToDocument(request.query) : request.query);
   const requestKey = { query: queryString };
   return JSON.stringify(requestKey);

Each query call will consume the mocked response in the response object

 this.mockedResponsesByKey[key].splice(responseIndex, 1);

From the same source code in mockLink.ts,  Mock Provider will remove a response once it’s been called. Therefore, a second query call will cause an exception throw stating “no more mocked response for the query:…”. From here, there’s two ways to mock the same query call multiple times.  

Return the mock multiple times.

Simply duplicate the number of mocks within the mock.

 const myQueryCallMock = {
   request: {
     query: GetSomeInfoDocument,
     variables: {
       id: 1
     }
   },
   result: {
     data: {
       client: {
         id: 1,
         info: "information for you!"
       }
     }
   },
   newData: () => {
     
  } 
 }
 <MockProvider
   mocks={[myQueryCallMock, myQueryCallMock]}
   addTypename={false}
 > 
   <MyComponent /> 
 </MockProvider> 

However, this gets complicated when you have to keep track of multiple queries and how many times a query gets called inside a larger component.

Add a newData function into your mock.

The source code mockLink.ts indicates that if there is a newData function, then it will automatically push that object as the response.

 const { newData } = response;
 if (newData) {
   response.result = newData();
   this.mockedResponsesByKey[key].push(response);
 }
 const myQueryCallMock = {
   request: {
     query: GetSomeInfoDocument,
     variables: {
       id: 1
     }
   },
   result: {
     data: {
       client: {
         id: 1,
         info: "information for you!"
       }
     }
   },
   newData: () => {
         data: {
       client: {
         id: 1,
         info: "information for you!"
       }
     }
   }
 }
 <MockProvider
   mocks={[myQueryCallMock]}
   addTypename={false}
 > 
   <MyComponent /> 
 </MockProvider> 

Mock Multiple Query Responses for Mock Provider

This will ensure that regardless of how many times your query is called, it will always return the same result. There’s also no need to keep track of how many times to add the query to the mocks array as well.