How to mock fetch and a state change in jest, react

tl;dr: I decided not to do it.

Since Enzyme is obsolete as of React 18, you would use <render /> and not <mount />. Therefore, you don't have a wrapper to manipulate and observe the state of the component being tested.

Furthermore, I'm really only testing the component because it's a best practice, and because of the expectation of future complexity. The state change itself is trivial:

  useEffect(() => {
    if (!jwtToken) { return; }
    fetch(apiRouter.periodsPath()).then(r => r.json()
      ).then(inns => {
        setPeriodsList(inns)
    })
  }, [ jwtToken ])

Does this really need to be tested? I decided that it isn't. Again: front-end testing is important and may be critical, but only for things that actually matter. 

It makes no sense to bog a developer down out of principle.

The test code that I was trying to get working, was as follows:

const spy = jest.spyOn(window, 'fetch'
  ).mockImplementation(mockFetch);
render(
  <AppProvider jwtToken="some-token" >
    <PeriodsProvider periodsModalOpen={true} >
      <PeriodsModal />
    </PeriodsProvider>
  </AppProvider>
)
expect(spy).toHaveBeenCalled();

The mockImplementation, for the curious, was as follows:

const mockFetch = async (url) => {
  logg(url, 'mockFetch')

  if (url == `${config.apiOrigin}/periods.json?jwt_token=some-token`) {
    return {
      ok: true,
      status: 200,
      json: async () => ({ hello: 'world' }),
    }
  }
}

logg() is a custom logger. 

Now, however, I no longer use a spy method and no longer fetch in the test:

test('PeriodsModal', async () => {
  render(
    <PeriodsCtx.Provider value={{
      periodsList: [],
      periodsModalOpen: true,
    }} >
      <PeriodsModal />
    </PeriodsCtx.Provider>
  )
  const el = screen.getAllByText("Some Text")[0]
  await expect( el ).toBeInTheDocument()
});

So, I force the modal to be open so that the element is visible. And the useEffect, fetch event doesn't happen, because the context (and provider) are given in the text - they replace what's in production, so the fetch doesn't happen in test.

Voila! I both (1) have a functioning test, and (2) didn't get bogged down in a complicated technicality at this time. This additionally serves as an example of how to solve some technical questions on time allocation of the dev team.

Please login or register to post a comment.