react-apollo
react-apollo copied to clipboard
writeQuery doesn't work in unit tests on useMutation
Intended outcome:
I have a mutation with an update
option which calls cache.writeQuery
.
This is updating the cache and re-rendering queries as expected when we run in the browser.
In unit tests for that component, the cache is not updating when cache.writeQuery
is called.
Container.js
const customerAddressesQuery = gql`...`
const customerAddressDelete = gql`...`
const Container = () => {
const [deleteAddress] = useMutation(customerAddressDelete, {
update: (cache, { data }) => {
const { deletedAddressId } = data.customerAddressDelete
const { customer } = cache.readQuery({ query: customerAddressesQuery })
cache.writeQuery({
query: customerAddressesQuery,
data: {
customer: {
...customer,
addresses: {
...customer.addresses,
edges: customer.addresses.edges.filter(
item => item.node.id !== deletedAddressId
),
},
},
},
})
},
})
return <Component deleteAddress={deleteAddress} />
})
Container.test.js
import { render, waitForElement, waitForElementToBeRemoved, fireEvent } from '@testing-library/react'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { MockedProvider } from '@apollo/react-testing'
import Container from '../Container'
test('should able to delete the address', async () => {
const MOCKS = [
{
request: {
query: customerAddressesQuery,
},
result: {
data: {
customer: {
id: 'customer_id_0001',
addresses: {
edges: [
{
node: {
company: 'company name',
id: 'address_id_0001',
name: 'Name A',
phone: '+0000000000',
formatted: ['address', 'apartment', 'city', 'country'],
__typename: 'MailingAddress',
},
__typename: 'MailingAddressEdge',
},
],
__typename: 'MailingAddressConnection',
},
defaultAddress: {
id: 'address_id_0001',
__typename: 'MailingAddress',
},
__typename: 'Customer',
},
},
},
},
{
request: {
query: customerAddressDelete,
variables: {
addressId: 'address_id_0001',
},
},
result: {
data: {
customerAddressDelete: {
customerUserErrors: [],
deletedCustomerAddressId: 'address_id_0001',
__typename: 'CustomerAddressDeletePayload',
},
},
},
},
]
const cache = new InMemoryCache()
const { getByTestId, getByText } = render(
<MockedProvider cache={cache} mocks={MOCKS}>
<Container />
</MockedProvider>
)
const deleteButton = await waitForElement(() => getByTestId('delete-button'))
fireEvent.click(deleteButton)
await waitForElementToBeRemoved(() => getByText('Name A'))
// <------ Test fails here because element is not removed
expect(getByText('Name A')).toBeNull()
})
Actual outcome:
How to reproduce the issue:
Log the entire cache to the console before and after writeQuery
is called.
Value never changes.
Version
@testing-library/[email protected]
@apollo/[email protected]
[email protected]
@apollo/[email protected]
@muhraff hi, did you fix this?
@korgara Unfortunately No.
In my case, as I inspect cache
in the debugger, readQuery
and writeQuery
are not defined at all. I'm trying to mock them out in my tests, without success so far.
@dmt0 Thank you for the clue. I can solve my problem with this code
I'm using react-testing-library
const renderWithProvider = async (mocks, cache) =>
<MockedProvider {...{ mocks }} cache={cache} addTypename={false}>
<MyComponent />
</MockedProvider>
it("example test case.", async () => {
const cache = new InMemoryCache({ addTypename: false });
const utils = await renderWithProvider(cache);
// Doing call mutation with writeQuery
// Don't forget to check the mutation is done
const afterMutationResult = cache.readQuery({
query: {WRITED_QUERY_HERE}
});
// then, the 'afterMutationResult' has data after writeQuery
expect(afterMutationResult).toStrictEqual(whatYouExpecting);
});
I ended up solving this like so:
export const mockCache = () => {
const map = new Map();
return {
size: () => map.size,
readQuery: ({query, variables}) =>
map.get(query + JSON.stringify(variables)),
writeQuery: ({query, variables, data}) =>
map.set(query + JSON.stringify(variables), data),
};
};
const cache = new InMemoryCache();
Object.assign(cache, mockCache());