16

How can I mock fetch function in Node.js by Jest?

api.js

'use strict'
var fetch = require('node-fetch');

const makeRequest = async () => {
    const res = await fetch("http://httpbin.org/get");
    const resJson = await res.json();
    return resJson;
};

module.exports = makeRequest;

test.js

describe('fetch-mock test', () => {
    it('check fetch mock test', async () => {

        var makeRequest = require('../mock/makeRequest');

        // I want to mock here


         global.fetch = jest.fn().mockImplementationOnce(() => {
           return new Promise((resolve, reject) => {
            resolve({
                ok: true,
                status,
                json: () => {
                    return returnBody ? returnBody : {};
                },
               });
          });
        });

        makeRequest().then(function (data) {
            console.log('got data', data);
        }).catch((e) => {
            console.log(e.message)
        });

    });
});

I tried to use jest-fetch-mock, nock and jest.mock but failed.

Thanks.

Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297
Youichi Okada
  • 185
  • 1
  • 2
  • 11

3 Answers3

17

You can mock node-fetch using jest.mock. Then in your test set the actual mock response

import fetch from 'node-fetch'
jest.mock('node-fetch', ()=>jest.fn())

describe('fetch-mock test', () => {
    it('check fetch mock test', async () => {

        var makeRequest = require('../mock/makeRequest');


         const response = Promise.resolve({
                ok: true,
                status,
                json: () => {
                    return returnBody ? returnBody : {};
                },
               })
        fetch.mockImplementation(()=> response)
        await response
        makeRequest().then(function (data) {
            console.log('got data', data);
        }).catch((e) => {
            console.log(e.message)
        });

    });
});
Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297
  • Not sure why you'd care about mocking it and importing it in the test class... Why not mock it so that the target code the test is for that imports fetch, the test code needs to mock that. – Brian Sterling Jun 30 '20 at 21:06
  • 3
    fetch returns `undefined` in the code to be tested. – A-Sharabiani Nov 21 '20 at 20:10
  • 2
    For me as well, fetch is undefined, I cannot call mockImplementation on it. – Phil Dec 22 '20 at 09:10
  • Doesn't work with node-fetch 3.3.2 and ts-jest 29.1.1. The original fetch function is not mocked. It always returns the original fetch function, without mocked functions like mockResolvedValue. I tried adding jest.mock before and after the import – tonisives Aug 26 '23 at 07:48
12
import fetch, { Response } from 'node-fetch';

jest.mock('node-fetch');

describe('fetch-mock test', () => {
    const mockFetch = fetch as jest.MockedFunction<typeof fetch>;

    it('check fetch mock test', async () => {
      const json = jest.fn() as jest.MockedFunction<any>;
      json.mockResolvedValue({ status: 200}); //just sample expected json return value
      mockFetch.mockResolvedValue({ ok: true, json } as Response); //just sample expected fetch response
      await makeRequest();
      expect(json.mock.calls.length).toBe(1);
    })
})
Kerisnarendra
  • 877
  • 9
  • 14
  • Using jest 27, still encountering the same issue where I cannot call any methods on 'mockFetch' (trying to call 'mockImplementation' in my case) – Oisín Foley Dec 19 '22 at 15:47
-1

I've found that the easiest way to mock ECMAScript modules in Jest is by using jest.unstable_mockModule.

Example:

jest.unstable_mockModule("node-fetch", () => ({
  default: (url) => {
    if (url.includes("/groups/")) {
      return {
        ok: true,
        json: () => ({
          id: dummyGuid,
          name: "dummyStringForName",
          embedUrl: "https://example.com",
          datasetId: dummyGuid,
        }),
      }
    }
    if (url.endsWith("/GenerateToken")) {
      return {
        ok: true,
        json: () => ({
          token: "dummyStringForToken",
        }),
      }
    }
  },
}))
aercolino
  • 2,193
  • 1
  • 22
  • 20