Search code examples
promisemocha.jsbluebirdchai-as-promised

Mocha single test with promises fails and passes at the same time


I am currently writing some tests in a legacy system and am confused about a test result here. I have one test here which fails as expected but mocha shows as a result 1 passing and 1 failing.

I am using Bluebird Promises, mocha, chai-as-promised and sinon with sinon-chai for spies and stubs. This is the test (I have removed stuff not needed for understanding my problem):

describe("with a triggerable activity (selection)", function () {

    beforeEach(function stubData() {
      stubbedTriggerFunction = sinon.stub(trigger, "newParticipation");
      activityLibStub = ... // stub
      selectionLibStub = ... // stub
      fakeActivities   = ... // simple data with just ONE element
      fakeSelection   = ... // simple data with just ONE element

      // stub methods to return synthetic data
      activityLibStub.returns(new Promise(function (resolve) {
        resolve(fakeActivities);
      }));

      selectionLibStub.withArgs(1).returns(new Promise(function (resolve) {
        resolve(fakeSelection);
      }));
    });

    afterEach(function releaseStubs() {
      // restore stubs...
    });

    it("should call the newParticipation function", function () {

        var member = memberBuilder.buildCorrect();
        trigger.allActivities(member)
        .then(function () {
          return expect(stubbedTriggerFunction).to.not.have.been.called;
        })
        .done();
      })
    });

This test fails as expected, because the function is actually invoked. However, mocha tells me that one test passed and one test failed. This is the only test I have implemented in this module.

I am pretty sure this has something to do with the promises but I don't seem to figure out what it is. Also if I add

.catch(function(){
  chai.assert.fail();
})

after the then-block, mocha still claims that one test passed. The method is also just invoked one time and I have only one synthetic dataset which I am working with. So I don't see what it is which tells mocha that this has passed while failed...

Any ideas?

Regards, Vegaaaa


Solution

  • Return your promise, return your promise, return your promise. Let's chant it all together now "Return, yoooooooour promise!"

    it("should call the newParticipation function", function () {
    
        var member = memberBuilder.buildCorrect();
        return trigger.allActivities(member)
          .then(function () {
            return expect(stubbedTriggerFunction).to.not.have.been.called;
          });
      })
    });
    

    I've also removed .done() because that's not generally useful with Bluebird and would be downright harmful here. Mocha still needs to use your promise. (It's use is generally discouraged, see here.) If you do not return your promise, then Mocha treats you test as synchronous and most likely that's going to be successful because your test is not really testing anything synchronously. Then if you get an asychronous failure, Mocha has to decide what failed exactly and will do its best to record the failure but it can lead to funny things like having an incorrect number of tests or the same test being reported as failed and successful!