I have a component that I'm trying to test, but it seems like Apollo's cache isn't being cleared between tests. I'm using React Testing Library and Jest.
Here are a couple of my tests that test opposite situations:
it('shows a "show more" button when there is `hasNextPage` is true', async () => {
render(
<MemoryRouter initialEntries={['/media/1']}>
<MockedProvider mocks={[getCharacterMock, getMediaMock]} cache={cache}>
<Route path='/media/:id'>
<Media />
</Route>
</MockedProvider>
</MemoryRouter>
);
await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
userEvent.click(screen.getByRole('button', { name: /characters/i }));
await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
expect(screen.getByRole('button', { name: /show more/i })).toBeInTheDocument();
});
it("doesn't show a 'show more' button when `hasNextPage` is false", async () => {
render(
<MemoryRouter initialEntries={['/media/1']}>
<MockedProvider mocks={[getCharacterMockNextPageFalse, getMediaMock]} cache={cache}>
<Route path='/media/:id'>
<Media />
</Route>
</MockedProvider>
</MemoryRouter>
);
await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
userEvent.click(screen.getByRole('button', { name: /characters/i }));
await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
expect(screen.queryByText(/show more/i)).toBeNull();
});
The first test passes, but the second test fails because 'loading' is not on the screen at all. The DOM that logs to the console shows that the component has already rendered with the data it was supposed to get from the mock getMediaMock. If I comment out the to waitForElementToBeRemoved lines, the the test then fails because "Show More" is actually rendered, even though the mock getCharacterMockNextPageFalse sets hasNextPage to false (which would mean that the "Show More" button shouldn't be rendered). The only reason I can think for this to happen is because the test is using the mock data from the previous test where hasNextPage was set to true.
Is there a way to clear the cache between tests? Or is something else causing this behaviour?
So, as far as I can tell, if tests use the same Apollo cache, then the exact same cache will be used for every test (i.e. it won't be cleared between tests). The way I fixed it in this case was just to remove the cache from the second test's MockedProvider (because I didn't really need it in this test), but creating a new inMemoryCache with the same settings for that test would have worked too.
The second test now looks like this:
it("doesn't show a 'show more' button when `hasNextPage` is false", async () => {
render(
<MemoryRouter initialEntries={['/media/1']}>
<MockedProvider mocks={[getCharacterMockNextPageFalse, getMediaMock]}>
<Route path='/media/:id'>
<Media />
</Route>
</MockedProvider>
</MemoryRouter>
);
await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
userEvent.click(screen.getByRole('button', { name: /characters/i }));
await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
expect(screen.queryByText(/show more/i)).toBeNull();
});