Sinon - stubbing function with callback - causing test method to timeout

express, javascript, mocha.js, node.js, sinon

Solution

Sinon stubs will not automatically fire any callback functions, you need to do this manually. It's actually really east to do though:

describe('POST /account/register', function(done) {

    var email;

    beforeEach(function(done) {
        accountToPost = {
            firstName: 'Alex',
        };

        email = require('../../app/helpers/email');
        sinon.stub(email);
        email.sendOne.callsArg(2);

        done();
    });

    afterEach(function(done) {
        email.sendOne.restore();
        done();
    })

    it('creates account', function(done) {
        request(app)
            .post('/account/register')
            .send(this.accountToPost)
            .expect(200)
            .end(function(err, res) {
                should.not.exist(err)
                //todo: asserts
                done();
            });
    });

    it('sends welcome email', function(done) {
        request(app)
            .post('/account/register')
            .send(this.accountToPost)
            .expect(200)
            .end(function(err, res) {
                should.not.exist(err)
                sinon.assert.calledWith(email.sendOne, 'welcome');
                done();
            });
    });
});

Notice the specific line:

        email.sendOne.callsArg(2);

The Sinon Stubs API has some good documentation on callsArg, and also callsArgWith (which may be useful for you testing error scenarios)

Problem

I have a method on a express route that looks like this: ``` exports.register_post = function(req, res) { var account = new Account(); account.firstName = req.param('firstName'); //etc... account.save(function(err, result) { email.sendOne('welcome', {}, function(err) { res.render('account/register', { title: 'Register' }); }); }); }; ``` I've got a test, where I have `email` stubbed. `email` is a module I `require` in the route. It has a function like: ``` exports = module.exports.sendOne = function(templateName, locals, cb) ``` My test looks like this: ``` describe('POST /account/register', function(done) { var email; beforeEach(function(done) { accountToPost = { firstName: 'Alex', }; email = require('../../app/helpers/email'); sinon.stub(email) done(); }); afterEach(function(done) { email.sendOne.restore(); done(); }) it('creates account', function(done) { request(app) .post('/account/register') .send(this.accountToPost) .expect(200) .end(function(err, res) { should.not.exist(err) //todo: asserts done(); }); }); it('sends welcome email', function(done) { request(app) .post('/account/register') .send(this.accountToPost) .expect(200) .end(function(err, res) { should.not.exist(err) sinon.assert.calledWith(email.sendOne, 'welcome'); done(); }); }); }); ``` When I run the test, both fail, citing: 1) Controller.Account POST /account/register creates account: Error: timeout of 2000ms exceeded at null. (/usr/local/lib/node_modules/mocha/lib/runnable.js:165:14) at Timer.listOnTimeout [as ontimeout] (timers.js:110:15) 2) Controller.Account POST /account/register sends welcome email: Error: timeout of 2000ms exceeded at null. (/usr/local/lib/node_modules/mocha/lib/runnable.js:165:14) at Timer.listOnTimeout [as ontimeout] (timers.js:110:15) If I comment out `email.sendOne('welcome', {}, function(err) {` in my route, then the first test (create account) passes. Have I missed something when setting up my sinon stub?

Original source