question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

MockedProvider doesn't log error when mock is missing, and provides no way to inspect the queries being made during a test

See original GitHub issue

Hi ! I came across the following scenario several time when developping unit tests with MockedProvider, and I think some features could make it easier and more efficient to debug the tests.

Sometimes, the mocked queries I wrote don’t match the queries actually made by the component (either a typo when creating the mock, or the component evolves and changes some query variables). When this happens, MockedProvided returns the NetworkError Error: No more mocked responses for the query to the component. However in the test suite, no warning is displayed. This is frustrating, because sometimes my components do nothing with the error returned by the client, thus it goes unnoticed. This cause my tests, which used to pass, to suddenly fail silently, and gives me a hard time to find the cause.

This is an example of component using useQuery :

import React from 'react';
import {gql} from 'apollo-boost';
import {useQuery} from '@apollo/react-hooks';


export const gqlArticle = gql`
  query Article($id: ID){
    article(id: $id){
      title
      content
    }
  }
`;


export function MyArticleComponent(props) {

  const {data} = useQuery(gqlArticle, {
    variables: {
      id: 5
    }, 
  });

  if (data) {
    return (
      <div className="article">
        <h1>{data.article.title}</h1>
        <p>{data.article.content}</p>
      </div>
    );
  } else {
    return null;
  }
}

And this is a unit test, in which I made a mistake, because the variables object for the mock is {id: 6} instead of {id: 5} which will be requested by the component.

  it('the missing mock fails silently, which makes it hard to debug', async () => {
    let gqlMocks = [{
      request:{
        query: gqlArticle,
        variables: {
          /* Here, the component calls with {"id": 5}, so the mock won't work */
          "id": 6,
        }
      },
      result: {
        "data": {
          "article": {
            "title": "This is an article",
            "content": "It talks about many things",
            "__typename": "Article"
          }
        }
      }
    }];

    const {container, findByText} = render(
      <MockedProvider mocks={gqlMocks}>
        <MyArticleComponent />
      </MockedProvider>
    );

    /* 
     * The test will fail here, because the mock doesn't match the request made by MyArticleComponent, which
     * in turns renders nothing. However, no explicit warning or error is displayed by default on the console,
     * which makes it hard to debug
     */
    let titleElement = await findByText("This is an article");
    expect(titleElement).toBeDefined();
  });

To me, it seems that most of the time, this error would not be intentional, and that the expected behavior isn’t to send it to the component as a real world error, but instead would be to display a warning in the unit test. I understand the error being sent to the component, but I think MockedProvider should also provide a warning by default (which could be configured to be turned off), and/or an easy way to instrospect what’s going on with the queries and mocks happening during the test.

I put some stuff together to achieve what I want, but I suggest this be part of the functionality offered by MockedProvider :

Log the error “no more mocked responses for the query” by default

I chained the MockLink with an apollo error link in order to catch the error and log it.

import React from 'react';
import {MockedProvider} from '@apollo/react-testing';
import {MockLink} from '@apollo/react-testing';
import {onError} from "apollo-link-error";
import {ApolloLink} from 'apollo-link';

export function MyMockedProvider(props) {
  let {mocks, ...otherProps} = props;

  let mockLink = new MockLink(mocks);
  let errorLoggingLink = onError(({ networkError }) => {
    if (networkError) {
      /No more mocked responses for the query/.test(networkError.message);
      console.warn(`[Network error]: ${networkError}`);
    }
  });
  let link = ApolloLink.from([errorLoggingLink, mockLink]);

  return <MockedProvider {...otherProps} link={link} />;
}

Provide a way to inspect which queries are made to the MockLink

I wanted a way to be sure which queries where made by the component I was testing, in order to understand why it didn’t use the mock I provided. The only way I found to make this was to extend MockLink to put a spy in it.

import React from 'react';
import {MockedProvider} from '@apollo/react-testing';
import {MockLink} from '@apollo/react-testing';
import {onError} from "apollo-link-error";
import {ApolloLink} from 'apollo-link';

class MyMockLink extends MockLink {
  request(operation) {
    console.log(operation);
    return super.request(operation);
  }
}

export function MyMockedProvider(props) {
  let {mocks, ...otherProps} = props;

  let mockLink = new MyMockLink(mocks);

  return <MockedProvider {...otherProps} link={mockLink} />;
}

I don’t know how it could be designed, but I would find nice to have a way to log or inspect what is going on with the query, in the spirit of this snippet.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:103
  • Comments:18 (1 by maintainers)

github_iconTop GitHub Comments

80reactions
TomasBcommented, Mar 30, 2021

Please bump the priority of this issue. This issue would save way more time for developers than whatever feature you have planned for the next release.

20reactions
GhaythFuadcommented, Jul 27, 2021

This has literally wasted half of my day today, a simple error in the query syntax that’s easily discoverable on the playground can waste a lot of your time trying to figure it out! (when you don’t have an accessible playground)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Testing React components - Apollo GraphQL Docs
The MockedProvider component enables you to define mock responses for individual queries that are executed in your test. This means your test doesn't...
Read more >
apollo's MockedProvider doesn't warn clearly about missing ...
The problem is that sometimes, my mock doesn't match the query actually made by the component (either a typo when creating the mock,...
Read more >
Debugging Apollo GraphQL MockedProvider - Swarmia
Let's go through five practical tips to make debugging Apollo MockedProvider more enjoyable. 1. Add logging with MockLink. Queries fail silently ...
Read more >
Testing React components - Apollo GraphQL Docs
This behavior affects how tests should be written for components that use Apollo ... missing Apollo Client in the context it('should render without...
Read more >
apollo's MockedProvider doesn't warn clearly about missing ...
If not using a custom MockedProvider , you can still be alerted to missing mocks if you handle the error that comes back...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found