1

Im trying to unit test a function that calls a promise...

Using Mocha, Sinon. I have a functional block like this:

myfile.js:

    let OuterDependecy = require('mydep');
    function TestFunction(callback) {
        OuterDependency.PromiseFunction().then(response => {  

       //some logic here
     }).catch(err => {callback(err)});

inside my test i have used proxyquire to mock the outerdependecy

testfile.js

let proxyquire = require('proxyquire');
let OuterDepStub = {};
let testingFunc = proxyquire('myfile.js', {'mydep': OuterDepStub});

... then inside my testing block

    let stubCallback = function() {
                console.log('Stub dubadub dub'); //note...i can use sinon.spy here instead
    };

   beforeEach(()=>{
            OuterDependency.PromiseFunction = function(arg) {
               return  new Promise((resolve, reject)=>{
                   reject('BAD');
               });
            };


            spy = sinon.spy(stubCallback);
       });

my actual test now calls the main "testfunction"

it('Catches Errors, and calls back using error', done => {
            TestFunction(stubCallback);
            expect(spy).to.have.been.called;
            done();
        });

I see the stub being called (the console log, hence why i didnt want to use sinon.spy) but the spy is saying its not called. and unit test fails.

I believe this is probably due to a race condition of sorts where the promise is resolving after my test is run... is there anyway to delay the test until my promise is resolve.

i know in in angularjs promise testing, there was a way to "tick" the promise so it resolves when you want to. possible in nodejs?

Nate
  • 1,630
  • 2
  • 24
  • 41

1 Answers1

1
  • is there anyway to delay the test until my promise is resolve.

As far as I understand your issue, yes, you should only call done() after the promise is settled. In order to do that,you need two things:

1- Enforce TestFunction to return a Promise, so you can wait until it resolves:

    function TestFunction(callback) {
     return OuterDependency.PromiseFunction().then(response => {

        //some logic here
    }).catch(err => { callback(err) });
}

2- Wait to that promise to settle, then call done.

it('Catches Errors, and calls back using error', done => {
    TestFunction(stubCallback).then(() => {
        expect(spy).to.have.been.called;
        done();
    })
});

now, our then block won't run until the catch block within TestFunction, so if the test works as expected (i.e. the catch block fires and the callback gets fired), the expectation and the done calls will always fire after the callback gets called.

  • I see the stub being called (the console log, hence why i didnt want to use sinon.spy) but the spy is saying its not called. and unit test fails.

That's because your expectation runs right after the TestFunction calls, without waiting for it to settle. However, it will get called lately, thus the console.log appears in the next spec.

Sergeon
  • 6,638
  • 2
  • 23
  • 43
  • so bad! did someone change when you tried? Like the order of the `console.log` statements? Are you sure `TestFunction` is actually failing? – Sergeon Nov 29 '17 at 18:31
  • I checked in webstorm debug test...and my assumption was correct, the stub part is being called AFTER my unit test. The testfunction does fail (i.e it does call stub) – Nate Nov 30 '17 at 16:52
  • @nate The above answer is mostly correct, but you need to use `.catch()`, not `.then()`, because in your stub you reject the promise. See this SO answer, although there are other ways of doing the rejection catch: https://stackoverflow.com/questions/28704791/testing-failed-promises-with-mochas-built-in-promise-support – Daniel T. Dec 02 '17 at 04:52
  • Yep @DanielT. you are right....that worked. It still sucks though in nodejs there doesnt seem to be a way to resolve promises "globally" so that you dont have to return a promise from the main function – Nate Dec 11 '17 at 15:38