Question

I have an https server running by express, which i test using mocha and supertest.

My problem is - if i run only the test - its ok. If i try to run gruntfile with test then run express - i see lot of EADDRINUSE errors, even if in test files i do after() with app.close(). Same applies to watch task on tests.

Here is my exapmle test:

/* jshint node: true*/
/*global describe, it, after*/
(function() {
    'use strict';
    process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
    var request = require('supertest');
    var app = require('../server.js').app;
    var expect = require('chai').expect;
    var Cookies;

    after(function(done) {
        app.close();
        setTimeout(function(){done();}, 1500);
    });

    describe('/login', function() {
        it('should auth the user', function(done) {
            request(app)
                .post('/login')
                .send({login: "test", password: 'test'})
                .expect(302)
                .end(function(err, res) {
                    expect(err).to.be.equal(null);
                    expect(res.text).to.be.equal("Moved Temporarily. Redirecting to /");
                    Cookies = res.headers['set-cookie'].pop().split(';')[0];
                    done();
            });

        });
    });
    // testing API for serving session data for angualar factory
    describe('/api/session', function() {
        it('should return session data in JSON', function(done) {
            var req = request(app).get('/api/session');             
                req.cookies = Cookies;
                req.set('Accept','application/json')
                .end(function(err, res) {
                    expect(err).to.be.equal(null);
                    expect(res.body).to.have.property("_id");
                    done();
            });
        });
    });

}());

Im aware that those test are far from perfect. Im just beginning my adventure with proper software testing.

All those "port already in use" are obvious, and none of them... give any issue. all tests work fine, server works fine, but stdout is crazy. Such behaviour is far from ideal, and probably full of potential problems and unstability issues.

My question is - how to get rid of it?

My ideas are:

  • create dedicated server for test on just different port. Unfortunately i have to clue how to implement this.

  • make some conditional for superagent to run server if it is not running, or just... pass it to superagent otherwise?

  • use something else then superagent (like request, but im not sure if all the cookies and node_tls_reject_unauthorized would work.

As You can see - i struggle with that topic and have more questions than answers, and not enough experiance to know where to look at.

I kindly appreciate any help.

EDIT:

I found, that i can do:

before(function(done) {
    app.listen(3001, function() { done(); });
});

which starts test on another port but... the whole server.js is loaded anyway, so it starts anyway too. Then, when firing it together with running server, there is obvious EADDRINUSE.

Was it helpful?

Solution

When using superagent, you should always pass it an Express application which has been configured (middleware registered, controllers routed, etc.)--but not initialized as a HTTP server. It will do that for you and it will defer, through http.createServer, to the OS to pick an available port.

If you currently have that the server.js module is already providing a static instance of a full-blown HTTP server, that is most likely the source of your problems. In either case, try extracting the application configuration/bootstrapping from the actual server instantiation like so:

// server.js
var express = require('express');
var middleware = require('./middleware');
var controllers = require('./controllers');

// Configures the Express application instance.
exports.setup = function (app) {
    app.use(middleware.foo);
    app.get('/bar', controllers.bar);

    app.locals.baz = 'quux';
}

// You might shoot yourself in the foot if parts of your application depend
// on a static reference at `server.app`.
exports.app = setup(express());
exports.app.listen(3000);

Then, in your tests, you can do something along the lines:

// tests.js
var express = require('express');
var server = require('./server');

describe('Server tests', function () {
    // Create a fresh server instance prior to each test
    beforeEach(function createNewSever() {
        this.app = server.setup(express());
    });

    describe('Foo', function () {
        it('barrs', function () {
            request(this.app)  // initializes a server instance on port A
            // ... supertests
        });

        it('bazzes', function () {
            request(this.app)  // initializes a server instance on port B
            // ... more supertests
        });
    });
});

This is just for illustrative purposes, where the when/how of instantiating the application instance will depend on your test context. The important thing to take away is that you should be able to create fresh, clean, independent and isolated server instances for your test cases. It is an absolute necessity should you use a test runner that executes tests in parallel or in a random order.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top