ZedTuX
ZedTuX

Reputation: 3027

Testing response AND function call of library using fetch with Jest + node-fetch + fetch-mock

I'm writing a JavaScript/React library which uses fetch.

I'm using Jest in order to test this library, and what I'd like to achieve is :

  1. Mock HTTP requests in order to not send real calls and manipulate the answers (mock the backend server) so I'm using fetch-mock
  2. Test the passed parameters to the fetch function

In order to achieve the first point, I need to do

fetchMock.post(`${API_URL}/sessions`, {
  body: JSON.stringify({
    token: 'this-is-your-token'
  }),
  status: 201
})

In order to achieve the second point, I need to do

const spiedFetch = jest.spyOn(global, 'fetch')
// ...
expect(spiedFetch).toHaveBeenCalledTimes(1)

(The last line is within a series of describe() and it()).

I have a first test which ensures the response has the token field and so on, and the second test is ensuring that fetch has been called once.

When I run them, the first one passes, then second one fails. When I comment the fetchMock.post(...), the first one fails and the second one passes.

Based on this, I guess fetch-mock and jest.spyOn are incompatible.

Questions :

  1. Am I right thinking fetch-mock and jest.spyOn are incompatible?
  2. How can I achieve the testing of the fetch response AND the passed parameters? (I want to ensure the HTTP verb is this, and the passed headers are that).
  3. A way I could think of is to use fetch-mock as is, but using jest.spyOn on a function of my lib, which would embed fetch. Is that an okay way of doing it?

UPDATE: I tried my point 3 and it works.

Upvotes: 2

Views: 1313

Answers (1)

Brian Adams
Brian Adams

Reputation: 45810

jest.spyOn replaces the original function with a wrapper.

const fetchMock = require('fetch-mock'); doesn't immediately change the global fetch, but as soon as a function like fetchMock.get is called it replaces the global fetch.

Because they both work by modifying the global fetch they can be tricky to use together.

As it turns out, every time a method like fetchMock.get is called the global fetch gets replaced, but if jest.spyOn is called after all such methods are called on fetchMock then they will actually both work since jest.spyOn will wrap and track the final replaced fetch.

Having said that, there isn't really a need to use jest.spyOn(global, 'fetch') if you are already using fetch-mock since fetch-mock provides access to all the calls that were made to fetch.

To assert on the calls directly you can access them using fetchMock.calls().

Even easier is to simply call fetchMock.done() at the end of the test to assert that fetch was used exactly as expected.

Upvotes: 1

Related Questions