How do I expect a function to be called with specific args with sinon, mocha, and chai in nodejs?

15,172

Solution 1

try this:

var cuid = require('cuid');
var fs = require('fs');
var Q = require('q');
var AWS = require('aws-sdk');
var S3 = new AWS.S3();

module.exports = {
  initialize: initialize
};

function initialize(options) {
   return Q.nfcall(fs.readFile, options.path).then(function (file) {
    var fileParams = {
       Bucket: options.bucket,
       Key: options.name,
       Body: file,
       ContentType: options.contentType
    };

    return Q.ninvoke(S3, 'upload', fileParams);
  });
}

note in particular that you should return a promise from your initialize function. then in the test:

describe.only('when a file is read successfully', function() {
      var spy;

      beforeEach(function() {
      spy = chai.spy.on(Q, 'ninvoke');
      sinon.stub(Q, 'nfcall').withArgs(fs.readFile,fileParams.path).returns(Q.resolve(file));
   });

  it('Q.ninvoke should be called with args', function(done) {
    UploadCommand.initialize(fileParams).then(function(data) {
       expect(spy).to.have.been.called.with(S3, 'upload', params);
       done();
    });
  });
});

a couple of other things to note, in your main application code, you will also want to chain your initialize function to a 'then' function, and in the body of that then function is where the rest of your application code should go. also, the 'done' callback is the way you tell mocha that it is an asynchronous test.

Solution 2

Mike I was able to get it working finally thanks to you. I really appreciate it! Here is the final test.

describe.only('when a file is read successfully', function() {
  beforeEach(function() {
    sinon.stub(Q, 'nfcall').withArgs(fs.readFile, fileParams.path).returns(Q.resolve(file));
    sinon.stub(Q, 'ninvoke').withArgs(S3, 'upload', params).returns(Q.resolve('url'));
    chai.spy.on(Q, 'ninvoke')
  });

  it('Q.ninvoke should be called with args', function(done) {
    UploadCommand.initialize(fileParams).then(function(data) {
       expect(Q.ninvoke).to.have.been.called.with(S3, 'upload', params);
       done();
    });
  });
});
Share:
15,172
Logan Fisher
Author by

Logan Fisher

Updated on July 14, 2022

Comments

  • Logan Fisher
    Logan Fisher almost 2 years

    I have been having a problem trying to make sure Q.ninvoke is called with the args I am passing in. I am new to testing with Sinon, Mocha and Chai. I have been trying everything I have found online for 2 days now and I still cant get my test pass. What am I doing wrong?

    This is my code under test.

    var cuid = require('cuid');
    var fs = require('fs');
    var Q = require('q');
    var AWS = require('aws-sdk');
    var S3 = new AWS.S3();
    
    module.exports = {
      initialize: initialize
    };
    
    function initialize(options) {
      return Q.nfcall(fs.readFile, options.path).then(function (file) {
        var fileParams = {
          Bucket: options.bucket,
          Key: options.name,
          Body: file,
          ContentType: options.contentType
        };
    
        return Q.ninvoke(S3, 'upload', fileParams).then(function(data){
          return data.Location;
        });
      });
    }
    

    Here is my test.

    describe.only('when a file is read successfully', function() {
        var spy;
    
        beforeEach(function() {
            spy = chai.spy.on(Q, 'ninvoke');
            sinon.stub(Q, 'nfcall').withArgs(fs.readFile, fileParams.path).returns(Q.resolve(file));
        });
    
        it('Q.ninvoke should be called with args', function() {
            UploadCommand.initialize(fileParams)
            expect(spy).to.have.been.called.with(S3, 'upload', params);
        });
    });
    

    This is the error I am getting.

    1) UploadCommand .initialize when a file is read successfully Q.ninvoke should be called with args: AssertionError: expected { Spy } to have been called with [ Array(3) ]

  • Mike Atkins
    Mike Atkins over 8 years
    have a look at mochajs.org under the section on working with promises to an alternative to using 'done'.
  • Logan Fisher
    Logan Fisher over 8 years
    Looks like I am getting closer thanks a lot man. Now I am getting this error. Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.
  • Mike Atkins
    Mike Atkins over 8 years
    this bit is wrong: Q.resolve(file). maybe try Q.defer().resolve()
  • Logan Fisher
    Logan Fisher over 8 years
    Mike I was able to get it working finally thanks to you. I really appreciate it! Here is the final test.
  • Louis
    Louis over 6 years
    What specifically does this answer add that a) has not been covered by the earlier answers already posted years before yours, and b) is an issue raised by the question that the OP asked?