Unable to mock node-fetch using fetch-mock
Asked Answered
H

2

2

I am trying to do unit testing for a simple function which sends a get request, receives a response and then returns a promise object with the success or the failure message. Following is the function:

module.exports.hello = async (event, context) => {
  return new Promise((resolve, reject) => {
    fetch("https://httpstat.us/429", { headers: { 'Content-Type': 'application/json' } }).then(response => {
      console.log(response);
      if (response.status == 200) {
        return response;
      } else {
        throw Error(response.status + ": " + response.statusText);
      }
    }).then(tokenData => {
      resolve({ status: 200, body: JSON.stringify({ statusText: 'Success' }) });
    }).catch(error => {
      reject(error.message);
    });
  });
};

While unit testing, I am using fetch-mock to mock the call to the api and have a custom response. Following is the code:

it('hello returns failure message', (done) => {
    fetchMock.get('*',  {
        status: 429,
        statusText: "Too Many Nothings",
        headers: { 'Content-type': 'application/json' }
     });

    edx.hello(null, null).catch(error => {
        expect(error).to.equal('429: Too Many Requests');
    }).then(() => {
        done();
    }).catch(error => {
        done(error);
    });
});

But this code is not mocking the fetch request as when I print the response text it is "Too Many Requests" which is being sent as a response by the API and not "Too Many Nothings" which is being mocked. I am new to NodeJS. Please tell me what am I doing wrong.

Hb answered 13/2, 2019 at 21:6 Comment(0)
D
0

If you use node-fetch package, it's not available at the global scope in Node.js. In order to make fetch-mock work you either have to assign fetch to global object (e.g. by import "node-fetch"; instead of import fetch from "node-fetch";) or make fetch injectable to your tested method.

From http://www.wheresrhys.co.uk/fetch-mock/#usageglobal-non-global:

Global or non-global

fetch can be used by your code globally or locally. It’s important to determine which one applies to your codebase as it will impact how you use fetch-mock

Global fetch

In the following scenarios fetch will be a global

  • When using native fetch (or a polyfill) in the browser
  • When node-fetch has been assigned to global in your Node.js process (a pattern sometimes used in isomorphic codebases)

By default fetch-mock assumes fetch is a global so no more setup is required once you’ve required fetch-mock. Non-global fetch library

In the following scenarios fetch will not be a global

  • Using node-fetch in Node.js without assigning to global
  • Using fetch-ponyfill in the browser
  • Using libraries which use fetch-ponyfill internally
  • Some build setups result in a non-global fetch, though it may not always be obvious that this is the case

The sandbox() method returns a function that can be used as a drop-in replacement for fetch. Pass this into your mocking library of choice. The function returned by sandbox() has all the methods of fetch-mock exposed on it, e.g.

const fetchMock = require('fetch-mock');
const myMock = fetchMock.sandbox().mock('/home', 200); // pass myMock in to your application code, instead of fetch, run it, then...
expect(myMock.called('/home')).to.be.true;
Doc answered 24/5, 2019 at 1:17 Comment(0)
R
0

How is fetch imported in your file used by your function? I've got a really basic (almost) VanillaJs file that was using import fetch from "cross-fetch"; but that meant fetchMock from my test file was being ignored. Switching to import "cross-fetch/polyfill"; allowed me to have tests that provided mocked fetch data and I could have tests that that accessed real data as well.

Recede answered 10/11, 2022 at 19:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.