How to do it...

Let's perform the following steps to create a Mocha unit test for the authentication middleware of our Express web server:

  1. First, we'll need to create a new /test directory in the root of our Express project where we will keep our test files. We will also need to update our project's tsconfig.json TypeScript configuration file to include our test directory and any .ts files within it:
      {
...
"include": [
"src/**/*.ts",
"test/**/*.ts"
],
...
}
  1. Next, we'll create a new Mocha unit test file, called /test/unit/test-middleware-auth.ts. Note that we created another subdirectory called /test/unit to denote this file as a unit test. We also named the file in a way that represents its logical path in our application, which is /src/middleware/auth.js. Simple and consistent organization like this can make tracing test failures back to source code in our application much easier. Our test file simply imports the @suite decorator from mocha-typescript, which we will use to stub out a new test class:
import { suite } from 'mocha-typescript';

@suite class AuthMiddlewareUnitTest {

}
  1. Now, we can write our first Mocha test using the @test decorate from mocha-typescript. For this test, we will import the /src/middleware/auth.js middleware all on its own, and use Chai's assertion library to test that the various types and properties of the middleware are what we expect them to be. This sort of generic method testing is common in unit tests, but as we'll see, it isn't limited to that:
import { suite, test } from 'mocha-typescript';
import * as chai from 'chai';
const expect = chai.expect;

import * as auth from '../../src/middleware/auth';

@suite class AuthMiddlewareUnitTest {

@test("middleware exists")
public middlewareExists() {
expect(auth).to.be.a('object');
expect(auth).to.respondTo('logger');
expect(auth).to.respondTo('requireRole');
expect(auth).to.respondTo('unauthorized');
expect(auth.logger).to.be.a('function');
expect(auth.requireRole).to.be.a('function');
expect(auth.unauthorized).to.be.a('function');
}

}
  1. Next, we can extend our test to confirm that our middleware acts as we expect. Instead of running our whole Express application, we will use node-mocks-http to create a mock Express application that we can feed to our middleware to check its behavior. The main benefit of this is that our test is much more lightweight and very isolated to this particular middleware's behavior. We'll also need to extend the Session interface slightly to support providing a user object to it, as in our real application. As our requireRoleAllow test suite is testing Express middleware, it is naturally asynchronous and requires a callback to be completed. In order to test asynchronous behavior in Mocha, all we need to do is manually call the done() method passed into the test context in our callback:
import { suite, test } from 'mocha-typescript';
import * as chai from 'chai';
const expect = chai.expect;

import * as auth from '../../src/middleware/auth';
import { createMocks, RequestOptions, ResponseOptions, Session, Mocks } from 'node-mocks-http';
import { EventEmitter } from "events";

interface UserSession extends Session {
user: any;
}


@suite class AuthMiddlewareUnitTest {
private createExpressMock(reqOptions: RequestOptions): Mocks {
let resOptions:ResponseOptions = {
eventEmitter: EventEmitter
};

return createMocks(reqOptions, resOptions);
}


@test("middleware exists")
public middlewareExists() {
expect(auth).to.be.a('object');
expect(auth).to.respondTo('logger');
expect(auth).to.respondTo('requireRole');
expect(auth).to.respondTo('unauthorized');

expect(auth.logger).to.be.a('function');
expect(auth.requireRole).to.be.a('function');
expect(auth.unauthorized).to.be.a('function');
}

@test('requireRole allows valid user session role')
public requireRoleAllow(done:MochaDone) {
let role:string = 'super-admin';

let options:RequestOptions = {

session: <UserSession>{ user: {
role: role
}}
};

let expressMock:Mocks = this.createExpressMock(options);

auth.requireRole(role)(expressMock.req, expressMock.res, function() {

expect(expressMock.res.finished).is.false;
done();
});
}

}
  1. We want to test more than just the expected outcome of our application as well. We should ensure that failure cases for our middleware also fail as they are expected. This can be accomplished by registering an event listener for the end event broadcast by node-mocks-HTTP's response mock object. This behavior perfectly mimics the expected Express behavior in a much more lightweight fashion. Now, we simply need to inspect the state of the response data to assert that it matches our failure conditions:
...

@suite class AuthMiddlewareUnitTest {
...

@test('requireRole denies invalid user session role')
public requireRoleDeny(done:MochaDone) {
let role:string = 'super-admin';

let options:RequestOptions = {
session: <UserSession>{ user: {
role: 'user'
}}
};

let expressMock:Mocks = this.createExpressMock(options);
expressMock.res.on('end', function() {
expect(expressMock.res.statusCode).to.equal(403);
expect(expressMock.res._isJSON()).is.true;
let responseJSON = JSON.parse(expressMock.res._getData());
expect(responseJSON).has.property('errors');
expect(responseJSON.errors).to.be.a('array');
expect(responseJSON.errors).to.have.lengthOf(1);
done();
});

auth.requireRole(role)(expressMock.req, expressMock.res);
}
}
  1. Finally, we need to add a test command to the project's NPM scripts section of our package.json file. This command will simply invoke Mocha with the ts-node compiler so that Mocha can use TypeScript. We need to provide the --recursive flag so that our /test/unit directory is included as well:
{
...
"scripts": {
"test": "mocha --compilers ts:ts-node/register,tsx:ts-node/register --recursive",
"clean": "rimraf ./dist",
"start": "node $NODE_DEBUG_OPTION ./dist/express.bundle.js",
"debug": "DEBUG=express* node $NODE_DEBUG_OPTION ./dist/express.bundle.js",
"build": "webpack",
"watch": "npm-run-all clean build --parallel watch:server watch:build --print-label",
"watch:build": "webpack --watch",
"watch:server": "nodemon ./dist/express.bundle.js --watch ./dist --on-change-only"
},
...
}
  1. Running our Mocha tests is now as simple as invoking the script from the command line:
npm test
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.103.15