0

I have a function for which I am writing unit test but that function is calling another function and there I am not able to mock/stub that function.

for example :

function getValue( param1, param2, callback){
    getData(param1, param3).then( response) => {
         return callback();
    }, (err) => {
         return callback();
    });
}

So I don't know how to mock getData() function.

ankuselfie
  • 65
  • 1
  • 1
  • 11
  • Where is `getData` defined ? – maazadeeb Apr 01 '19 at 06:15
  • `getData` is defined in some other file which I am importing. – ankuselfie Apr 01 '19 at 06:21
  • Then ask the question accordingly, There's no way to mock getData if it's random function, only it's an import. – Estus Flask Apr 01 '19 at 06:25
  • Just to be complete, it **is** possible to mock `getData` even if it is a random function in the same file, but it must be **exported** and it must be called using the **module export**. (See [this answer](https://stackoverflow.com/a/52770749/10149510) for an ES6 version, a Node.js module would export `getData` like this: `exports.getData = getData;` and then call it within `getValue` like this: `exports.getData(...)`) – Brian Adams Apr 01 '19 at 07:14
  • hey @brian-lives-outdoors getData is being exported. – Atul Kumar Apr 01 '19 at 19:43
  • I'm aware of that (and that's how I coded my answer below), just pointing out that it's possible to mock `getData` even if it *isn't* exported since an earlier comment made it sound like that wasn't possible. @AtulKumar – Brian Adams Apr 01 '19 at 19:45
  • Thanks for responding @brian-lives-outdoors, I am testing your code and will update it that work or not in my case. – Atul Kumar Apr 01 '19 at 19:46

2 Answers2

1

Here is a working example that demonstrates what you are trying to do:

lib.js

function getData(param1, param2) {
  return fetch('someUrl');  // <= something that returns a Promise
}

exports.getData = getData;

code.js

const lib = require('./lib');

export function getValue(param1, param2, callback) {
  return lib.getData(param1, param2).then(response => {
    callback(response);
  }).catch(err => {
    callback(err);
  });
}

exports.getValue = getValue;

code.test.js

const sinon = require('sinon');

const lib = require('./lib');
const { getValue } = require('./code');

describe('getValue', () => {
  it('should do something', async () => {
    const stub = sinon.stub(lib, 'getData');
    stub.resolves('mocked response');

    const callback = sinon.spy();
    await getValue('val1', 'val2', callback);

    sinon.assert.calledWithExactly(stub, 'val1', 'val2');  // Success!
    sinon.assert.calledWithExactly(callback, 'mocked response');  // Success!
  });
});

Update

OP added in the comments that they can't use async / await and are exporting the function using module.exports = getData;.

In that case the module export is the function and the entire module needs to be mocked with something like proxyquire.

The assertions should be done in a then callback and the test should return the resulting Promise so mocha knows to wait for it to resolve.

Updated example:

lib.js

function getData(param1, param2) {
  return fetch('someUrl');  // <= something that returns a Promise
}

module.exports = getData;

code.js

const getData = require('./lib');

function getValue(param1, param2, callback) {
  return getData(param1, param2).then(response => {
    callback(response);
  }).catch(err => {
    callback(err);
  });
}

module.exports = getValue;

code.test.js

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

describe('getValue', () => {
  it('should do something', () => {
    const stub = sinon.stub();
    stub.resolves('mocked response');

    const getValue = proxyquire('./code', { './lib': stub });

    const callback = sinon.spy();
    return getValue('val1', 'val2', callback).then(() => {
      sinon.assert.calledWithExactly(stub, 'val1', 'val2');  // Success!
      sinon.assert.calledWithExactly(callback, 'mocked response');  // Success!
    });
  });
});
Brian Adams
  • 43,011
  • 9
  • 113
  • 111
  • Hey I am using `module.exports = getData` also async() is not working in node js 6 and as of now it is throwing following error `TypeError: Cannot stub non-existent own property getData`. Please respond . Thanks – ankuselfie Apr 01 '19 at 20:28
  • I added an update with an example that works with those constraints. @ankuselfie – Brian Adams Apr 02 '19 at 05:06
  • `TypeError: Cannot read property 'then' of undefined` this what I am getting. Also actual function is being called. – ankuselfie Apr 02 '19 at 10:30
  • hey @brian-lives-outdoors this is not working, it is still not stubbing 'getData` function. Thanks :) – ankuselfie Apr 03 '19 at 05:07
0
function getValue( param1, param2, callback){
    getData(param1, param3).then( response) => {
         callback(response);
    });
}

getvalue(param1, param2, function(error, response)) {
   console.log(response)
}

It might help you.

narayansharma91
  • 2,273
  • 1
  • 12
  • 20