How to mock a promise chain

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the javascript category.

Last Updated: 2021-05-15

I wanted to test the following code by using mocks in Jest (a JavaScript testing library)

fetch(locationQualityUrl)
  .then(response => response.json())
  .then(json => {
    return json["locationQuality"]
  })

How?

The trick is to work backwards from the final then and set a variable equal to the object returned:

const mockSuccessResponse = { locationQuality }

Next create a Promise that resolves to that object for each then statement in the chain. We have two to deal with, so we get:

// The code from the previous step
const mockSuccessResponse = { locationQuality }

// New code
// First: We wrap the final output in a Promise
const mockJsonPromise = Promise.resolve(mockSuccessResponse)
// Next: We wrap the intermediary promise in another promise
const mockFetchPromise = Promise.resolve({
  json: () => mockJsonPromise
})

Lastly, we would mock the function under test with this:

// Essentially we are replacing `window.fetch` with our mock implementation
window.fetch = jest.fn().mockImplementation(() => mockFetchPromise)

// We would usually need some clean up code too:
function clearFetchMock() {
  window.fetch.mockClear()
  delete window.fetch
}
afterEach(clearFetchMock)