Search code examples
javascriptunit-testingpromisemocha.jsmiddleware

Test functions that call promises inside of them with mocha


I have a javascript function like this:

var otherModule = require('../otherModule');

function myFn(req, res, next) {

  otherModule.queryFunction()
    .then(function(results) {
      res.json(results);
    })
    .catch(function(err)) {
      res.json({
        err: err
      });
    });
}

In order to test myFn function I've mocked (with mockery) otherModule.queryFunction in my unit test so it returns some known results. In myFn unit test I want to test that res.json is being called. I know if I were testing otherModule.queryFunction I could accomplish that by returning the promise or by passing done argument to the spectation function. But i can't figure out how to make an asynchronous test if the asynchronous part is inside a function called by the function i'm testing.

I've tried this approach without success:

'use strict';
var chai = require('chai');
var mockery = require('mockery');
var expect = chai.expect;
var spies = require('chai-spies');
var myFn = require('path/to/myFn');
chai.use(spies);

describe('myFn tests', function (){

  var otherModule;
  var SOME_DATA = {data: 'hi'};
  beforeEach(function (){
    otherModule = {
      queryFunction: function queryFunctionMock(){
        var promise = new Promise(function(resolve, reject){
          resolve(SOME_DATA);
        });

        return promise;
      }
    };
  });

  beforeEach(function (){
    mockery.enable({
      warnOnReplace: false,
      useCleanCache: true
    });

    mockery.registerMock('../otherModule', otherModule);
  });

  afterEach(function (){
    mockery.disable();
  });

  it('res.json should be called with otherModule.queryFunction results', function (){
    req = chai.spy();
    res = chai.spy.object(['json']);
    next = chai.spy();

    myFn(req, res, next);

    expect(res.json).to.have.been.called();    
  });
});

Solution

  • I think the only thing wrong here, is that you need to move the require of your component under test, after you initialized mockery:

    'use strict';
    var chai = require('chai');
    var mockery = require('mockery');
    var expect = chai.expect;
    var spies = require('chai-spies');
    var myFn;
    chai.use(spies);
    
    describe('myFn tests', function (){
    
      // [...]
    
      beforeEach(function (){
        mockery.enable({
          warnOnReplace: false,
          useCleanCache: true
        });
    
        mockery.registerMock('../otherModule', otherModule);
    
        // now load the component:
        myFn = require('path/to/myFn');
      });