Teoman shipahi
Teoman shipahi

Reputation: 23132

Spy could not track on Async function test with Mocha and Sinon

I have isMember function as below;

function isMember(req, res, next) {
MyService.GetUserAsync(authCookie)
        .then(function (user) {
            next();
        })
        .catch(function (err) {
            if (err.status === 400) {
                return res.redirect("/notAllowed");
            }
            else {
                return next(err);
            }
        });
}

My test is like below;

 beforeEach(function () {        
            // Overwrite the global timer functions (setTimeout, setInterval) with Sinon fakes
            this.clock = sinon.useFakeTimers();
        });
        afterEach(function () {
            // Restore the global timer functions to their native implementations
            this.clock.restore();
        });

 it.only("pass authentication and set authCookie", function (done) {
            var user = {
                userNameField: "fakeUserName"
            };
            sinon.stub(MyService, "GetUserAsync").returns(Promise.resolve(user));            
            var spyCallback = sinon.spy();
            var req {};
            var res = {};
            isMember(req, res, spyCallback);
            // Not waiting here!
            this.clock.tick(1510);
            // spyCallback.called is always false
            expect(spyCallback.called).to.equal(true);           
            done();
        });

For some reason this.clock.tick is not working and spyCallback.called is always false. How can I achieve that my spy will wait until next() is called in isMember function?

Upvotes: 3

Views: 3180

Answers (2)

Bettina
Bettina

Reputation: 93

The sinon fakeTimers replace the global setTimeout function, but your code does not contain any timeout function.

You can use a setTimeout function to delay the execution of the expectation and then resolve your test by calling done() inside the setTimeout. You can try something like this:

setTimeout(function () {
  expect(spyCallback.called).to.equal(true);
  done();
}, 0);

Upvotes: 1

The SWE
The SWE

Reputation: 404

You need to put done() inside a callback, because of how the event loop works in javascript. First all synchronous code gets executed and then all pending async tasks are executed.

Mocha has support for promises. If you return a promise from it(), it will be waited. So, you can do something like

it.only("pass authentication and set authCookie", function (done) {
    var user = {
        userNameField: "fakeUserName"
    };
    sinon.stub(MyService, "GetUserAsync").returns(Promise.resolve(user));            
    var spyCallback = sinon.spy();
    var req {};
    var res = {};
    return isMember(req, res, spyCallback).then(function () {
        expect(spyCallback.called).to.equal(true); 
    });   
});

Upvotes: 0

Related Questions