Intended outcome:
Be able to mock a query using MockProvider
import { MockedProvider } from '@apollo/client/testing';
import { GET_TEACHERS_AND_ADMINS_OF_MY_DISTRICT_QUERY } from '../queries';
const mocks = [
{
request: {
query: GET_TEACHERS_AND_ADMINS_OF_MY_DISTRICT_QUERY,
},
result: {
loading: false,
error: null,
data: {
teachersAndAdminsOfMyDistrict: [
{
[...]
...
<MockedProvider mocks={mocks} addTypename={false}>
<ComponentThatUsesTheQuery />
</MockedProvider>
Actual outcome:
After updating to 3.1.0 tests broke with:
No more mocked responses for the query: {
teachersAndAdminsOfMyDistrict {
[...]
How to reproduce the issue:
Described in the first section but if more info is needed I can add here.
Versions
System:
OS: Linux 5.4 Ubuntu 20.04.1 LTS (Focal Fossa)
Binaries:
Node: 10.19.0 - /usr/bin/node
npm: 6.14.4 - /usr/bin/npm
Browsers:
Chrome: 84.0.4147.105
Firefox: 79.0
npmPackages:
@apollo/client: ^3.1.0 => 3.1.0
apollo-upload-client: ^14.1.0 => 14.1.0
+1
We're also experiencing this issue
@tyagow as a work around, you can mock useQuery
like so:
import * as Apollo from '@apollo/client';
jest.spyOn(Apollo, 'useQuery').mockImplementation(() => {
return {
loading: false,
error: undefined,
data: { MOCK_DATA },
refetch: jest.fn()
}
});
@tyagow as a work around, you can mock
useQuery
like so:import * as Apollo from '@apollo/client'; jest.spyOn(Apollo, 'useQuery').mockImplementation(() => { return { loading: false, error: undefined, data: { MOCK_DATA }, refetch: jest.fn() } });
Thank you, great idea!
In the end, I used the new mock wrapper we created that uses the schema.graphql to auto-generate responses, here is a draft:
const mergeResolvers = (target, input) => {
const inputTypenames = Object.keys(input);
const merged = inputTypenames.reduce(
(accum, key) => {
const inputResolver = input[key];
if (target[key]) {
const targetResolver = target[key];
const resolvedInput = inputResolver();
const resolvedTarget = targetResolver();
if (
!!resolvedTarget &&
!!resolvedInput &&
isDict(resolvedTarget) &&
isDict(resolvedInput)
) {
const newValue = { ...resolvedTarget, ...resolvedInput };
return {
...accum,
[key]: () => newValue,
};
}
}
return { ...accum, [key]: inputResolver };
},
{ ...target }
);
return merged;
};
const buildSchema = mocks => {
const schemaStr = print(schemaGQL) + clientDefs;
const schema = makeExecutableSchema({
typeDefs: schemaStr,
resolverValidationOptions: {
requireResolversForResolveType: false,
},
});
return addMocksToSchema({ schema, mocks, preserveResolvers: true });
};
export const ApolloProviderWithMock = ({ customResolvers, client, children }) => {
const mocks = mergeResolvers(globalMocks, customResolvers);
const schema = buildSchema(mocks);
let apolloClient = client;
if (!client) {
apolloClient = new ApolloClient({
fetch,
link: new SchemaLink({ schema }),
cache: new InMemoryCache({ possibleTypes }),
typeDefs: schema,
});
}
return <ApolloProvider client={apolloClient}>{children}</ApolloProvider>;
};
Then in a test I just need to wrap the component being tested with it. Also, I can set specific values for specific queries
const customerResolver = {
Query: () => ({
SomeQuery: () => ({
[...]
})
})
}
<ApolloProviderWithMock customerResolver={customerResolver}>
<Component>
</ApolloProviderWithMock>
I am actually unable to get MockedProvider
working at all on any 3.x version of @apollo/client
.
import { render } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'
import { MockedProvider } from '@apollo/client/testing'
import { Route, MemoryRouter } from 'react-router-dom'
...
describe('pipeline: none', () => {
test('does not render environment section', async () => {
const { getByText } = render(
<MockedProvider
mocks={[
{
request: {
query: MARKETPLACE_OFFERING_QUERY,
variables: {
guid
}
},
result: {
data: {
offering: { guid, name: 'mock offering' }
}
}
}
]}
addTypename={false}
>
<MemoryRouter initialEntries={['builder/123/456']}>
<Route path="builder/:offering_guid/:plan_guid">
<Builder />
</Route>
</MemoryRouter>
</MockedProvider>
)
await new Promise(resolve => setTimeout(resolve, 0)) // wait for response
expect(getByText('mock offering')).toBeInTheDocument()
})
})
Leaving out this, the loading state is always true. With it the component is able to log out loading: true
and then loading: false
.
await new Promise(resolve => setTimeout(resolve, 0)) // wait for response
The assertion fails, data is always undefined in the component even when loading: false
from the useQuery
.
My team seem to have run into the same problem :(
Same here, the mock provider seems to stopped working in some cases while running the styleguidist server, and when generating the static version of the styleguidist, some cases do work. A bit unstable, and now we are currently deciding if we should revert, or look for a solution.
In my case it was the same problem as described here: https://github.com/apollographql/apollo-client/issues/6771
I added logging to my component that did the mutations and saw that the variables contained a field with an explicit undefined
instead of omitting the field. So I just explicitly added undefined
for the variable in my mock as well and it started working!
e.g.
From:
{
request: {
query: UPDATE_ITEM,
variables: {
teamId: 'team-1',
itemId: 'item-1',
},
},
To:
{
request: {
query: UPDATE_ITEM,
variables: {
teamId: 'team-1',
itemId: 'item-1',
optionalField: undefined
},
},
In my case I added the prop like that, <MockedProvider mocks={mock} addTypename={true}>
and the error stopped. I realized that the error message was with the data with __typename
. Like this:
products {
name
description
price
__typename
}
So I tried this and worked for me. However, the error still is a mystery for me.
Get this error - No more mocked responses for the query: mutation
. Seems like MockedProvider
broken or poorly documented.
I've resolved this with my post on this one
defaultOptions={{
watchQuery: { fetchPolicy: 'no-cache' },
query: { fetchPolicy: 'no-cache' },
}}
In my case it was the same problem as described here: #6771
I added logging to my component that did the mutations and saw that the variables contained a field with an explicit
undefined
instead of omitting the field. So I just explicitly addedundefined
for the variable in my mock as well and it started working!
I found the issue to be the same as @Markus-ipse
The change in behavior appears to have been introduced here, by switching to a different deep equal function: https://github.com/apollographql/apollo-client/commit/2593f8f62fbe87e5a3eebb8b44e0f5482a75c3f7#diff-fab0a81f7f7c1e746fd7f86a7a1458c9 and https://github.com/apollographql/apollo-client/commit/26849a804a1be65071818285c9c31de8a8e4fb13
(cc: @benjamn)
The previous isEqual
implementation ignored undefined
object properties. Unfortunately, we were relying on that behavior so hundreds of our tests are now failing in 3.1.x.
This behavior should be fixed/improved in @apollo/[email protected]
(just published to npm), thanks to #7108. Please give it another try after updating!
Getting the same No more mocked responses for the query
error.
Bumping to 3.3.0-beta.9 didn't resolve it.
Adding defaultOptions with fetchPolicy: "no-cache" didn't help either.
example
test:
describe("ProfileHeader", () => {
it.only("show a profile header", async () => {
const { container } = renderApollo(<ProfileHeader />, {
defaultOptions: {
query: { fetchPolicy: "no-cache" },
watchQuery: { fetchPolicy: "no-cache" },
},
});
await waitFor(() => {
expect(container).toMatchSnapshot();
});
});
renderApollo
import { MockedProvider, MockedResponse } from "@apollo/client/testing";
const renderApollo = (
node: any,
{
mocks,
addTypename,
defaultOptions,
cache,
resolvers,
...options
}: RenderApolloOptions = {}
): RenderResult => {
return render(
<MockedProvider
mocks={mocks}
addTypename={addTypename}
defaultOptions={defaultOptions}
cache={cache}
resolvers={resolvers}
>
{node}
</MockedProvider>,
options
);
};
Component:
const ProfileHeader: React.FC = () => {
const [queryExecutor, { loading, error, data }] = useLazyQuery<TMe>(
PROFILE_QUERY,
{
// fetchPolicy: "cache-only", // <!== If changing the fetchPolicy here, the test pass!
fetchPolicy: "cache-and-network",
nextFetchPolicy: "cache-first",
}
);
It would seem like MockedProvider doesn't replace my useLazyQuery options with the defaultOptions passed from the test.
Just in case, I also tried to replace useLazyQuery with useQuery, and am also getting the same error
EDIT: My issue is unrelated to this thread, sorry for the noise
While I still don't know how we're supposed to write tests for queries using fetchPolicy: "cache-and-network"
(I would very much like to test the different loading phases of my component), I could get my test to pass with a jest.spy
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
jest.spyOn(Apollo, "useLazyQuery").mockImplementation(() => {
return [
jest.fn(),
{
data: null,
error: undefined,
loading: false,
},
];
});
Still experiencing this issue, even with setting fetchPolicy: no-cache, even with using the new beta version. The Dog example from the docs fails on my environment with direct copy/paste, "no more mocked responses". https://www.apollographql.com/docs/react/development-testing/testing/
worth noting that addTypename
was set to FALSE but it's still expecting a __typename in one spot
UPDATE:
I was getting these errors because I had missed the necessity of cleanup between test runs.
in create-react-app, I needed
import { cleanup, render } from '@testing-library/react';
afterEach(cleanup)
FURTHER UPDATE: cleanup was not sufficient, the same specs were intermittently getting this error in CI even when passing locally. It was necessary to version bump to the beta.
This behavior should be fixed/improved in @apollo/[email protected] (just published to npm), thanks to #7108. Please give it another try after updating!
This fixes my issue @benjamn , do we have any visibility into a release schedule? This is blocking our development and it'd be great to have an estimate. Thanks!
I was having this issue on any 3.x.x version (my mocks have correct variables + __typenames and all that junk, this seemed like a legitimate bug with MockedProvider), upgrading to @apollo/[email protected] did NOT fix it for me, but upgrading to @apollo/[email protected] DID fix it for me.
edit: just wanted to say that this didn't fix everything, still had some tests that were failing that definitely should pass (spent hours checking typenames + variables, 100% sure things are accurate). We had the most trouble with components that had 2 different queries running in the same file as well as queries with empty variables), it always got confused.
ended up doing this in our jest
jest.mock('@apollo/client', () => ({
...jest.requireActual('@apollo/client'),
useQuery: (query, options) => jest.requireActual('@apollo/client').useQuery(query, {
...options,
fetchPolicy: 'no-cache'
})
})
)
basically just forcing no-cache for testing purposes
The current apollo-client release is 3.3.5, and this seems to be fixed now.
Most helpful comment
I've resolved this with my post on this one