Can't mock fetch() with jest

Viewed 1056

I hit a wall trying to mock fetch() with jest.

I've tried 2 approaches:

Approach 1: doing it manually as follows:

const pokemon = {
    id: 1,
    name: 'fake1',
    sprites: {other: {'official-artwork': {front_default: 'picture'}}},
    types: ['earth']
  }
const fakePokemons = JSON.stringify([pokemon, pokemon])


global.fetch = jest.fn(() =>
  Promise.resolve({
    json: () => Promise.resolve(fakePokemons),
  })
);

fetchData([1, 4, 7]) // this is the actual funciton call

The error I get is:

TypeError: Cannot read property 'other' of undefined

Which relates to sprites.other.etc... property that the function is failing to extract. I don't understand why when it's clearly there.

Approach 2: using jest-fetch-mock code:

fetch.mockResponseOnce(JSON.stringify(fakePokemons));
fetchData([1, 4, 7])

In this case I'm stuck with:

FetchError: invalid json response body at  reason: Unexpected end of JSON input

I tried with and without JSON.stringify() - no luck. I'm following this tutorial and there both approaches seem to be working

What am I missing?

2 Answers

You mistake what jest is really doing. Jest is simply replacing native fetch with function that will return a simple resolved promise containing an an object with a json property , in turn containing a resolved promise with fakePokemons as a string and it wraps it with mock utilities to monitor callings.

You shall not stringify fakePokemons as the expected output of fetch.json call is the object itself and not a stringified form :

const pokemon = {
    id: 1,
    name: 'fake1',
    sprites: {other: {'official-artwork': {front_default: 'picture'}}},
    types: ['earth']
  }
const fakePokemons = [pokemon, pokemon] // HERE


global.fetch = jest.fn(() =>
  Promise.resolve({
    json: () => Promise.resolve(fakePokemons),
  })
);

You may also take care of removing all mocks with fetch.mockClear() after each test.

See Jest mocks documentation for more informations.

In the second approach, fakePokemons is surely stringified twice actually and leads to an error.

I recently had success with spyOn and mockResolvedValue. Give this a shot:

// somewhere global like outside of any describe or test blocks
jest.spyOn(global, 'fetch');

// ...

// for me, it made sense to include this in beforeEach
global.fetch.mockResolvedValue({
  ok: true,
  json: () => pokemon  // note no stringify, just the data
});

This was inspired by an article making a case to stop mocking fetch.

Related