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 issueHi ! 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:
- Created 4 years ago
- Reactions:103
- Comments:18 (1 by maintainers)
Top GitHub Comments
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.
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)