Patrick
Patrick

Reputation: 1474

Starting node.js with full config from gruntjs (before executing mocha tests)

I use Mocha to test my Node/Express.js services, and I'd like to automate these with Grunt to run against a test instance of the server (i.e., identical configuration just listening on a different port).

While I can fire up a new (read: unconfigured) instance of the server using grunt-contrib-connect, there doesn't seem to be a way to utilize my existing app.js directives that contain all the API paths, middleware, etc. I see a couple options, neither of which are attractive:

  1. According to the documentation and examples -- https://github.com/gruntjs/grunt-contrib-connect/blob/master/Gruntfile.js -- I could pass all of the relevant statements from my config file to the 'middleware' option, but this seems to be as clear a case of reinventing the wheel as there can be.

  2. On the other hand, I could use grunt-exec -- https://github.com/jharding/grunt-exec -- to fire up node, passing the configuration file as normal, along with an environment variable (e.g., NODE_ENV=test) that would cause said config file to bind to a different port. Unfortunately, this command blocks the execution of the tests, and would require another hack to shut it down when finished.

Thus, SO, I'm open to ideas! What is the most elegant way to automatically start my node server with full config directives so that I can test them with grunt and mocha?

Upvotes: 0

Views: 910

Answers (1)

Dan Kohn
Dan Kohn

Reputation: 34327

We configure our app.js to start on a different port when being run from tests, so that we can keep the dev server running (using nodemon) on their regular ports at the same time. Here's our code:

// Start server.

if (process.env.TEST == 'true') {
    var port = process.env.PORT || 3500; // Used by Heroku and http on localhost
    process.env['PORT'] = process.env.PORT || 4500; // Used by https on localhost
}
else {
    var port = process.env.PORT || 3000; // Used by Heroku and http on localhost
    process.env['PORT'] = process.env.PORT || 4000; // Used by https on localhost
}

http.createServer(app).listen(port, function () {
    console.log("Express server listening on port %d in %s mode", this.address().port, app.settings.env);
});

// Run separate https server if not on heroku
if (process.env.HEROKU != 'true') {
    https.createServer(options, app).listen(process.env.PORT, function () {
        console.log("Express server listening with https on port %d in %s mode", this.address().port, app.settings.env);
    });
};

Then, a mocha file, such as this one testing the serving of the favicon, looks like this:

process.env['TEST'] = 'true'; // Use test database
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0" // Avoids DEPTH_ZERO_SELF_SIGNED_CERT error for self-signed certs
var request = require("request").defaults({ encoding: null });
var crypto = require('crypto');
var fs = require('fs');
var expect = require('expect.js');
var app = require("../../app.js");
var hash = function(file) { crypto.createHash('sha1').update(file).digest('hex') };


describe("Server", function () {
    after(function () {
        process.env['TEST'] = 'false'; // Stop using test database.
    });


    describe("Static tests", function () {
        it("should serve out the correct favicon", function (done) {
            var favicon = fs.readFileSync(__dirname + '/../../../public/img/favicon.ico')
            request.get("https://localhost:" + process.env.PORT + "/favicon.ico", function (err, res, body) {
                // console.log(res)
                expect(res.statusCode).to.be(200);
                expect(hash(body)).to.be(hash(favicon));
                done();
            });
        });
    });
});

Also note that while grunt is a great tool, you can call mocha from your package.json scripts section and then just npm test to run it.

Upvotes: 2

Related Questions