Testing: mocking node-fetch dependency that it is used in a class method

Viewed 7825

I have the following situation:

A.js

import fetch from 'node-fetch'
import httpClient from './myClient/httpClient'

 export default class{
    async init(){
       const response = await fetch('some_url')
       return httpClient.init(response.payload)
    }
}

A_spec.js

import test from 'ava'
import sinon from 'sinon'
import fetch from 'node-fetch'
import httpClient from './myClient/httpClient'
import A from './src/A'

test('a async test', async (t) => {
    const instance = new A()
    const stubbedHttpInit = sinon.stub(httpClient, 'init')
    sinon.stub(fetch).returns(Promise.resolve({payload: 'data'})) //this doesn't work

    await instance.init()
    t.true(stubbedHttpInit.init.calledWith('data'))
})

My idea it's check if the httpClient's init method has been called using the payload obtained in a fetch request.

My question is: How I can mock the fetch dependency for stub the returned value when i test the A's init method?

5 Answers

You can stub fetch() as decribed in the manual

import sinon from 'sinon'
import * as fetchModule from 'node-fetch'
import { Response } from 'node-fetch'
// ...
const stub = sinon.stub(fetchModule, 'default')
stub.returns(new Promise((resolve) => resolve(new Response(undefined, { status: 401 }))))
// ...
stub.restore()

Note, that fetch() is the default export from node-fetch so you neeed to stub default.

@mrtnlrsn's answer does not work for files generated from TypeScript in NodeJS, because default is a generated property, each module which imports such a dependency has its own, so stubbing one does not affect others.

However, NodeJS gives access to imported modules, so stubbing works this way:

const nodeFetchPath = require.resolve("node-fetch");
const nodeFetchModule = require.cache[nodeFetchPath];
assert(nodeFetchModule);
const stubNodeFetch = sinon.stub(nodeFetchModule, "exports");

Make sure you use the same node-fetch module as the tested module, e.g. using yarn dedupe. Or build your own nodeFetchPath.

Related