Testing the Authentication Routes in Mocha

With all the changes made in the last few posts, obviously my Hello World tests would now fail and I needed to write new ones to verify the authentication was working correctly.

Tests

I created a testData.js file to house all of the dummy data to be used during testing:

testData/test
module.exports = {
    authentication: [
        {username: 'testuser@email.com', password: 'a_string', app_access: true}
    ]
}

Before each test run, I needed to first destroy any database schema that already exists, so I can be sure that the test environment is set up in a known state. So I always destroy the existing setup and then initialise including the above test data.

database/initTest.js
const Database = require('./database');
const testData = require('./testData');
require('dotenv').config({path: './.env'});
const dbURL = process.env['DB_URL'];

const db = new Database(dbURL);

/**
 * Destroy any existing instance of the tables required for the node-app
 * @returns { Promise } of string | Error
 */
const destroy = async() => {
  await db.destroySchema();
  process.exit;
}

/**
 * Initialises the database with all of the tables required for the node-app
 * @returns { Promise } of string | Error
 */
const initialise = async () => {
  await db.initDatabase(testData);
  process.exit();
}

/**
 * To remove the test authentication user after testing
 * @returns { Promise } of string | Error
 */
const cleanup = async () => {
  await db.deleteUser('testuser@email.com');
  process.exit();
}

destroy();
initialise();

I updated the package.json file to include the init and test commands:

package.json
    "scripts": {
        "initDB": "node ./database/init.js",
        "cleanTest": "node ./database/cleanTest.js",
        "initTestDB": "node ./database/initTest.js",
        "test": "mocha --recursive --timeout 100000 --exit",
        "dev-server": "./node_modules/.bin/node-dev ./index.js"
    }

Now to actually write the testcases for the new authentication routes. First I needed to send a POST request with the login credentials to ensure that a token is issued. Then I use this token in a header to send a GET request and recieve a positive response. I also did negative testing to ensure that the correct codes are returned on the various failure cases.

test/authtest.js
const request = require('supertest');
const app = require('../index.js');
const chai = require('chai');
const chaiHttp = require('chai-http');

const { expect } = chai;
chai.use(chaiHttp);

describe('GET / SUCCESS', function() {

    var token = null;

    before(function(done) {
        request(app)
            .post('/login')
            // TODO: need to properly implement knex to create more valid test data!
            .send({ username: "admin", password: "password" })
            .end(function(err, res) {
                token = res.body.token; // Or something
                done();
            });
      });

    it('Respond with success', function(done) {
        request(app)
            .get('/')
            .set("Authorization", "Bearer " + token) 
            .set({'Accept': 'application/json'})
            .end(function(err, res) {
                expect(res).to.exist;
                expect(res.statusCode).to.equal(200);
                expect(res.body.response).to.include('Success');
                done();
            })
    });
});

describe('GET / FAILURE: missing Token', function() {
    it('Respond with 400: check the request', function(done) {
        request(app)
            .get('/')
            .set({'Accept': 'application/json'})
            .end(function(err, res) {
                expect(res).to.exist;
                expect(res.statusCode).to.equal(400);
                expect(res.body.error).to.include('check the request');
                done();
            })
    });
});

describe('GET / FAILURE: invalid Token', function() {
    it('Respond with 401: unorthorized', function(done) {
        request(app)
            .get('/')
            .set("Authorization", "Bearer totally_legit_token") 
            .set({'Accept': 'application/json'})
            .end(function(err, res) {
                expect(res).to.exist;
                expect(res.statusCode).to.equal(401);
                expect(res.body.error).to.include('invalid');
                done();
            })
    });
});

describe('POST /login SUCCESS', function() {
    it('Respond with login token', function(done) {
        request(app)
            .post('/login')
            // TODO: need to properly implement knex to create more valid test data!
            .send({ username: "admin", password: "password" })
            .end(function(err, res) {
                expect(res).to.exist;
                expect(res.statusCode).to.equal(200);
                expect(res.body.token).to.exist;
                done();
            });
    })
});

I also had to update the general routes tests to just fail with the correct error codes:

const request = require('supertest');
const app = require('../index.js');
const chai = require('chai');
const chaiHttp = require('chai-http');

const { expect } = chai;
chai.use(chaiHttp);

describe('GET /', function() {
    it('Respond with fail', function(done) {
        request(app)
            .get('/')
            .set('Accept', 'application/json')
            .end(function(err, res) {
                expect(res.statusCode).to.equal(400);
                done();
            })
    });
});

describe('POST /', function() {
    it('Respond with fail', function(done) {
        request(app)
            .post('/')
            .set('Accept', 'application/json')
            .end(function(err, res) {
                expect(res.statusCode).to.equal(400);
                done();
            })
    });
});

All that’s left is to run the tests using first npm run initTestDB then npm run test.

>npm run test

> node-app@0.0.3 test C:\Users\twulz\Documents\GitHub\node-app
> mocha --recursive --timeout 100000 --exit



  GET / SUCCESS
POST /login 200 170.380 ms - 238
GET / 200 1.606 ms - 50
    √ Respond with success

  GET / FAILURE: missing Token
GET / 400 0.418 ms - 88
    √ Respond with 400: check the request

  GET / FAILURE: invalid Token
GET / 401 0.355 ms - 87
    √ Respond with 401: unorthorized

  POST /login SUCCESS
POST /login 200 78.885 ms - 238
    √ Respond with login token (73ms)

  GET /
GET / 400 0.156 ms - 88
    √ Respond with fail

  POST /
POST / 400 0.130 ms - 88
    √ Respond with fail


  6 passing (326ms)

And finally add the tests to the Build in Jenkins:

Jenkins build

And done! with the Mocha tests passing in Jenkins my builds could finally be deployed to my production server! Now what did I want to do with my server again…?


About Me

Engineer, maker, do-er...
I basically just like to make things.

Archives