Ensuring Express App is running before each Mocha Test

Haseeb Khan picture Haseeb Khan · Sep 22, 2013 · Viewed 15.6k times · Source

I am working on developing a REST API using ExpressJS, NodeJS, Mongoose and Mocha.

The thing is that I have an app.coffee file, thats responsible for setting up ExpressJS and connecting to Mongoose. The way I have set this up is that Mongoose is connected first and if that gets through, then, the ExpressJS App is started.

The issue is that when setting up Mocha, I need to make sure that ExpressJS App existing in app.coffee is completely started successfully including all asynchronous code before any testcase is executed.

For that, I have created a test_helper.coffee and placed the following code in it, but, the testcases start their execution even if the code in app.coffee hasn't completed its execution completely which actually makes sense:

before (done) ->
  require(__dirname + '/../src/app')
  done()

In a nutshell, I want to make sure that the ExpressJS app has fully completed its setup before any testcase is executed.

How I can do that?

Answer

tmaximini picture tmaximini · Oct 15, 2013

I am late to the party, but I found the best way to set up my mocha test suite for an express app is to make my app.js or server.js file export the app object, like this:

var mongoose = require('mongoose');
var express = require('express');
require('express-mongoose');

var env = process.env.NODE_ENV || 'development';
var config = require('./config/config')[env];

var models = require('./app/models');
var middleware = require('./app/middleware');
var routes = require('./app/routes');

var app = express();

app.set('port', process.env.PORT || config.port || 3000);
app.set('views', __dirname + '/app/views');
app.set('view engine', 'jade');

// database
mongoose.connect(config.db);

// middleware
middleware(app);

// Application routes
routes(app);

app.listen(app.get('port'));
console.log('Express server listening on port ' + app.get('port'));

// export app so we can test it
exports = module.exports = app;

make sure your config file has different environments like development, test, production set up:

var path = require('path');
var rootPath = path.normalize(__dirname + '/..');

module.exports = {
  development: {
    db: 'mongodb://localhost/my_dev_db',
    port: 3000
  },
  test: {
    db: 'mongodb://localhost/my_test_db',
    port: 8888
  },
  production: {
    // ...
  }
}

then in your test files you can go ahead and require your app, which will connect to the right db and on the right port:

var should = require('chai').should();
var request = require('supertest');
var mongoose = require('mongoose');

var app = require('../app');
var agent = request.agent(app);

var User = mongoose.model('User');

    // get users
    describe('GET /api/users', function() {
      it('returns users as JSON', function(done) {
        agent
        .get('/api/users')
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          res.body.should.have.property('users').and.be.instanceof(Array);
          done();
        });
      });
    });

And finally, to start up the whole monster you include this in your package.json (make sure to have nodemon and mocha in your devDependencies):

"scripts": {
    "start": "NODE_ENV=development ./node_modules/.bin/nodemon app.js",
    "test": "NODE_ENV=test ./node_modules/.bin/mocha --reporter spec test/**.js"
  }

Now you can start your test suite with npm test and your app with npm start.

Hope it helps! ps: most of the stuff I learned from looking at this amazing example: https://github.com/madhums/node-express-mongoose-demo