Search code examples
node.jsexpressmocha.jssinon-chai

Testing express middleware usage with mocha and sinon-chai


I`m having some problems with testing middelware usage, need your help!

Configuring my app:

var express         = require('express');
var path            = require('path');
var errorHandler    = require('errorhandler');
var routes          = require('./routes');
var morgan          = require('morgan');

module.exports = function(app) {
    app.set('port', process.env.PORT || 3300);
    app.use(morgan('dev'));
    app.use('/public', express.static(path.join(__dirname, '../public')));
    routes.initialize(app);
    if ('development' === app.get('env')) {
        app.use(errorHandler());
    }
    return app;
};

I want to cover it with tests (using mocha, and sinon-chai for stubs and spies). So when I`m writing test case for morgan usage:

app.use(morgan('dev'));

I`m setting app.use() as a spy, and expect it to be called with morgan('dev') as the only argument.

var app;
var express     = require('express');
var configure   = require('../../../server/configure');
var morgan      = require('morgan');

describe('Server configurations', function() {
     it('should use morgan', function() {
        app = {
            get: sinon.spy(),
            set: sinon.spy(),
            use: sinon.spy()
        };
        configure(app);
        expect(app.use).to.be.calledWith(morgan('dev'));
     });

});

And I`m getting such an error:

AssertionError: expected use to have been called with arguments function logger() {}
    use(function () {})
    use(function logger() {})
    use(/public, function serveStatic() {})

Can`t figure out why. Are there some things to be concerned about, when making a middleware usage function as a spy?

Thanks in advance.


Solution

  • I have found one way to check if a middleware is connected. You should look for it in app._router.stack. I have wrote a function for doing this and it looks like:

    function isMiddlewareSet(app, middlewareName) {
        var _return = false;
        app._router.stack.filter(function(layer) {
            if (layer.handle.name == middlewareName) {
                _return = true;
            }
        });
        return _return;
    }
    

    Then I use it in my tests.

        beforeEach(function() {
            app = express();
            configure(app);
        });
    
        it('should use "errorHandler" middleware in dev env', function() {
            app.get = sinon.stub().returns('development');
            expect(isMiddlewareSet(app, 'errorHandler')).to.equal(true);
        });
    
        it('should use "morgan" middleware logger', function() {
            expect(isMiddlewareSet(app, 'logger')).to.equal(true);
        });
    
        it('should use "bodyParser.json" middleware', function() {
            expect(isMiddlewareSet(app, 'json')).to.equal(true);
        });
    ...
    

    But I guess it is not the best solution.