mocha.jsbluebirdsinonchai-as-promised

Sinon check if other method of object is invoked with promise


I have a confusing not working test which I am unable to solve somehow (I am coming from Java background so I am sorry in advance if there are some mistakes in my terminology).

There is an object class Trigger which has some public functions, foo() and bar(). The logic is:

One can call foo() directly on another object, or if bar() is called (with an array), then Trigger.bar() invokes Trigger.foo() array.length times.

Trigger is implemented with bluebird Promises. This is the basic excerpt of Trigger (I deleted some logic, with this it seems kind of redundant but there happens much more in reality):

// Will be refactored afterwards
var self;

var Trigger  = function() {
  self = this;
};

Trigger.prototype.bar = function bar(members) {
  return new Promise(function (resolve, reject) {
    Promise.map(members, function (member) {
     self.foo(member)
     .then(function(res){
       ...
     })
     // catch
    });
  });
};

Trigger.prototype.foo = function foo(member) {
  return new Promise(function(resolve, reject){
    doSomethingWithMember(member)
    .then(function(res){
      ...
    })
    // catch
  });
}

So one can see, that bar() calls foo() on each member in the members array.

I wanted to write a test in which I spy the Trigger Object and check if it invoked foo() n times.

So what I currently did (with changed function names) where I am just checking if it is even called:

var chai = require('chai');
var expect = chai.expect;
var sinon = require('sinon');
var sinonChai = require('sinon-chai');

chai.use(require('chai-as-promised'));
chai.use(sinonChai);

var Trigger = require(...);
var trigger = new Trigger();

      ...

  describe("bla", function() {
    it("should invoke 'foo()' n times", function() {
      var spy = sinon.spy(trigger.foo);
      var member = MemberBuilder.buildCorrect();
      trigger.bar(member);
      return expect(spy).to.have.been.called; // does not pass 
    })
  });

This obviously doesn't work due to the promises of Trigger, thus tells me:

AssertionError: expected foo to have been called at least once, but it was never called

But no matter how I try to solve this in the then() block of bar(), it always claims that my spy has not been called.

  describe("bla", function() {
    it("should invoke 'foo()' n times", function() {
      var spy = sinon.spy(trigger.foo);
      var member = MemberBuilder.buildCorrect();
      trigger.bar(member)
        .then(function(){
          return expect(spy).to.have.been.called; // does not pass with the same AssertionError (has not been invoked)
      });
    })

I have done some logging and am sure that foo() is invoked. Any ideas of what I am doing wrong?

Regards,

vegaaaa


Solution

  • I have found my (stupid!) mistake. Misread the API...

    var spy = sinon.spy(trigger.foo);

    should become

    var spy = sinon.spy(trigger, "foo");

    so this works like a charm:

    describe("bla", function() {
      it("should invoke 'foo()'", function() {
        var spy = sinon.spy(trigger, "foo");
        var member = MemberBuilder.buildCorrect();
        trigger.bar(member)
        .then(function(res) {
          return expect(spy).to.have.been.called;
        })
      })
    

    Alternatively (because I found it more understandable):

    describe("bla", function() {
        it("should invoke 'foo()'", function() {
          sinon.spy(trigger, "foo");
          var member = MemberBuilder.buildCorrect();
          trigger.bar(member)
          .then(function() {
            return expect(trigger.foo).to.have.been.called;
          })
        })
    

    Hope this helps others running into the same issue with the api.