Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ensuring Express App is running before each Mocha Test

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?

like image 300
Haseeb Khan Avatar asked Sep 22 '13 08:09

Haseeb Khan


People also ask

Do mocha tests run sequentially?

It has a very simple interface for testing both synchronous and asynchronous code. Mocha. js executes tests in a sequential/serial order to provide flexible and accurate reporting, while also mapping uncaught exceptions to their respective test cases.

Do mocha tests run in parallel?

Mocha does not run individual tests in parallel. If you only have one test file, you'll be penalized for using parallel mode.

How do you skip the mocha test?

This inclusive ability is available in Mocha by appending . skip() to the suite or to specific test cases. The skipped tests will be marked as "pending" in the test results.

Is Mocha A test runner?

Mocha is a feature-rich JavaScript test framework running on Node. js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases. Hosted on GitHub.


3 Answers

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

like image 126
tmaximini Avatar answered Nov 01 '22 12:11

tmaximini


I ran into the same issue while using jasmine/supertest to test my express app. I solved the issue by emitting when the app was ready and only running my tests afterwards. Here is my directory structure

- server.js
- spec
    - setup.spec.js
    - test.spec.js

In server.js when ever your server is set up and you are ready to run your tests add app.emit('started');. And make sure to export your app! In setup.spec.js you can watch for the event to be emitted.

server.js

const express = require('express');
const app = express();
module.exports = app; // for testing

setTimeout(() => {
    app.listen(process.env.PORT || 3000);
});

setup.spec.js

const server = require('../index');

beforeAll(done => server.on('started', done));

test.spec.js

const request = require('supertest');
const server = require('../index');

describe('test', () => {
    it('test server works', done => {
        request(server).get('/test').expect(200);
     });
});

The same idea should work for mocha as well. Here is an article explaining this for mocha. You should just change beforeAll to before.

like image 40
jjbskir Avatar answered Nov 01 '22 13:11

jjbskir


There might be a more straightforward way, but I went to Grunt for automating my functional tests. There's an express and mocha plugin to reach your goal. My gruntfile:

'use strict';

module.exports = function (grunt) {
grunt.initConfig({
    express: {
        options: {}
      , test: {
            options: {
                script: './app.js'
            }
        }
    }
  , simplemocha: {
        options: {
            globals: ['should']
          , timeout: 8000
          , ignoreLeaks: false
          , ui: 'bdd'
          , reporter: 'tap'
        }
      , all: { src: ['tests/*.test.js'] }
    }
})

grunt.loadNpmTasks('grunt-express-server')
grunt.loadNpmTasks('grunt-simple-mocha')

grunt.registerTask('default', ['express:test', 'simplemocha', 'express:test:stop'])
}

bonus: add 'grunt' as a git pre-commit hook. This way you cannot commit without passing all the tests

like image 23
Raf Avatar answered Nov 01 '22 11:11

Raf