unit-testingsinonproxyquirenode-mocks-http

Trying to mock response body from a fetch for a unit test


I'm pretty new to sinon and proxyquire and I think I've read all the answers here on SO but I'm still not finding out what I need. Anyway, here's a sanitized version of my code.

const fetch = require('node-fetch');

async function deleteID(id, endpoint) {
  try {
      let url = `${endpoint}/delete/${id}`;
      let res = await fetch(url, { method: 'DELETE' });
      res = await res.json(); // <---- THIS FAILS WHEN fetch IS MOCKED
      // do stuff with res
  } catch (err) {
    logger.error(`Error: ${JSON.stringify(err)}`);
  }
}

It's pretty simple, it uses node-fetch to hit a url and then does stuff if the request succeeds or fails. Here's my test, lets setup the mocking for fetch:

const proxyquire = require('proxyquire').noCallThru();
const sinon = require('sinon');

  beforeEach((done) => {

    const validResponse = {
      status: 200,
      data: 'hello, world\n'
    };
    deleteProxy = proxyquire('./delete', {
      'node-fetch': sinon.stub().returns(Promise.resolve(JSON.stringify(validResponse)))
    });
  });

So the fetch call now returns validResponse instead of hitting the server. And here's my test:

    it.only('should delete', async () => {
    try {
      deleteProxy.deleteID('id', 'endpoint');
    } catch (err) {
      expect(err.message).to.have.lengthOf.at.least(0);
    }
  });

This fails since res is just an object with status and data, it is not a proper Response that has a Body etc... The rest of our code uses node-mocks-http but all of the tests using that module hit the url directly, not indirectly, via fetch, like I'm doing above.

How do I either create a mocked Response to fit into the above test or is there a different approach I should be using?


Solution

  • By looking at the code and my experience with sinon I would say as this is not an actual HTTP response so you have to mock json() as well. In beforeEach method:

     const body = {
      status: 200,
      data: 'hello, world\n'
    };
    var validResponse = { json: () => { return body } };
    deleteProxy = proxyquire('./delete', {
      'node-fetch': sinon.stub().returns(Promise.resolve(validResponse))
    });
    

    try with out JSON.stringify()

    Let me know if it doesn't work.