To setup our test’s environment, first we are going to setup a new database that is going to be used for us to play with some fake data. This practice is largely used to make sure that an application
¹⁸https://mochajs.org
can work easily in multiple environments. For now, our API has just single environment, because all the examples were developed in thedevelopmentenvironment.
To enable the support for multiple environments, let’s rename the current libs/config.js file
to libs/config.development.js and then, create the libs/config.test.js file. The only new
parameter in this new file is the logging: falsewhich disables the SQL logs outputs. This will
be necessary to disable these logs to not mess the tests report in the terminal. See how this file (libs/config.test.js) must look like:
1 module.exports = { 2 database: "ntask_test", 3 username: "", 4 password: "", 5 params: { 6 dialect: "sqlite", 7 storage: "ntask.sqlite", 8 logging: false, 9 define: { 10 underscored: true 11 } 12 }, 13 jwtSecret: "NTASK_TEST",
14 jwtSession: {session: false}
15 };
Now, we have to setup some files, each one has specific data to his correspondent environments. To load the settings according to the current environment, we must create a code to identifies what environment it is. In this case, we can use theprocess.envobject which basically returns a lot of
several environment variables from the OS.
A good practice in Node.js projects is to work with the variableprocess.env.NODE_ENVand use his
value as a base, our application will have to load the settings fromtestordevelopmentenvironment.
By default, thedevelopmentwill be defined whenprocess.env.NODE_ENVreturns null or an empty
string.
Based on this brief explanation, let’s recreate thelibs/config.jsfile to load the settings according
1 module.exports = app => {
2 const env = process.env.NODE_ENV;
3 if (env) {
4 return require(`./config.${env}.js`);
5 }
6 return require("./config.development.js");
7 };
In our project, we are going to explore the acceptance tests only. To create them, we need to use these modules:
• babel-register: to run ES6 codes;
• mocha: to run the tests;
• chaito write BDD tests;
• supertestto do some requests in the API;
All these modules will be installed as adevDependenciesin thepackage.jsonto use them only as
test dependency. To do this, you need to use the--save-devflag in thenpm installcommand. See
the command below:
1 npm install [email protected] [email protected] [email protected] [email protected] --save-d\
2 ev
Now, let’s encapsulate the mocha test runner into the npm testalias command, to internally run
the command: NODE_ENV=test mocha test/**/*.js. To implement this new command, edit the
package.jsonand include thescripts.testattribute:
1 {
2 "name": "ntask-api",
3 "version": "1.0.0",
4 "description": "Task list API",
5 "main": "index.js",
6 "scripts": {
7 "start": "babel-node index.js",
8 "test": "NODE_ENV=test mocha test/**/*.js"
9 },
10 "author": "Caio Ribeiro Pereira",
11 "dependencies": {
12 "babel-cli": "^6.5.1",
13 "babel-preset-es2015": "^6.5.0",
15 "body-parser": "^1.15.0", 16 "consign": "^0.1.2", 17 "express": "^4.13.4", 18 "jwt-simple": "^0.4.1", 19 "passport": "^0.3.2", 20 "passport-jwt": "^2.0.0", 21 "sequelize": "^3.19.2", 22 "sqlite3": "^3.1.1" 23 }, 24 "devDependencies": { 25 "babel-register": "^6.5.2", 26 "chai": "^3.5.0", 27 "mocha": "^2.4.5", 28 "supertest": "^1.2.0" 29 } 30 }
Then, we are going to export our main API module, theindex.js, to allow the API can be started
during the tests. To do it, you must include themodule.exports = app in the end of theindex.js
file and we’ll also disable the logs created by theconsignmodule viaconsign({verbose: false})
settings to not pollute the tests report.
1 import express from "express";
2 import consign from "consign";
3
4 const app = express();
5 6 consign({verbose: false}) 7 .include("libs/config.js") 8 .then("db.js") 9 .then("auth.js") 10 .then("libs/middlewares.js") 11 .then("routes") 12 .then("libs/boot.js") 13 .into(app); 14 15 module.exports = app;
Now, the application can be internally started by thesupertestmodule during the tests. To avoid
the server runs twice in the tests environment, you need to modify thelibs/boot.js to run the
database sync and server listen only whenprocess.env.NODE_ENVhas not thetestvalue.
1 module.exports = app => {
2 if (process.env.NODE_ENV !== "test") {
3 app.db.sequelize.sync().done(() => {
4 app.listen(app.get("port"), () => {
5 console.log(`NTask API - Port ${app.get("port")}`);
6 });
7 });
8 }
9 };
To finish our test’s environment setup, let’s prepare some Mocha specific settings, to load the API server and the moduleschai andsupertestas global variables. This will accelerate the execution
of tests, after all, each one will load these modules again and again, and if we put all main things to load once, will save some milliseconds of the tests execution. To implement this simple practice, create the filetest/helpers.js:
1 import supertest from "supertest";
2 import chai from "chai";
3 import app from "../index.js";
4
5 global.app = app;
6 global.request = supertest(app);
7 global.expect = chai.expect;
Then, let’s create a simple file which allows to include some settings as parameters to themocha
command. This will be responsible to load thetest/helpers.jsand also use the--reporter spec
flag to show a detailed report about the tests. After that, we’ll include the--compilers js:babel-
registerflag, to Mocha be able to run the tests in ECMAScript 6 standard via babel-register
module.
The last flag is--slow 5000, this will wait five seconds before start all tests (time enough to start
the API server and database connection safely). Create thetest/mocha.optsfile using the following
parameters:
1 --require test/helpers
2 --reporter spec
3 --compilers js:babel-register
4 --slow 5000