Challenge 05: Testing with Mocha Chai
For this challenge you will create a full suite of tests that confirm your app is working correctly. Then you'll setup Continuous Integration to ensure your app continues to work.
server.js
to support testsTo get started you need to install Mocha and Chai as dev dependencies and wire-up NPM to execute mocha
Mocha is a testing framework, its job is to find and run your tests. It provides a functions, describe
and it
to make it easy to write and document tests. It also provides the formatting output called "reporters" as well as life-cycle hooks: before
, beforeEach
, after
and afterEach
which you'll use when we discuss databases.
Chai is an assertion library, its job is to provide methods help you verify a given value matches the expected value. Chai provides three flavors of assertion styles: Assert, Should and Expect. We'll use the Expect style.
Type the following in your shell. Be sure to add the --save-dev
flag and check package.json
to ensure the packages were saved properly.
npm install --save-dev mocha chai
In package.json
, add the following test
command to the scripts
property.
Open the package.json
file and add the following test
script property.
...
"scripts": {
"start": "node server.js",
"test": "mocha"
},
...
Rhe scripts
property allows NPM to run the command. The start
and test
commands are just a couple of the pre-defined properties which NPM supports. For these scripts you can simply run npm start
and npm test
, respectively. For custom scripts you need use npm run [SCRIPT NAME]
. See scripts docs for more info.
In your shell, run npm test
. You should see the following message.
$ npm test
> mocha
No test files found
npm ERR! Test failed. See above for more details.
Mocha ran successfully, but it could not find any test files. Let's fix that now.
Next, create a test file with a couple tests to confirm the packages are loaded and configured properly.
Create /test/server.test.js
and add the following:
const chai = require('chai');
const expect = chai.expect;
describe('Reality check', function () {
it('true should be true', function () {
expect(true).to.be.true;
});
it('2 + 2 should equal 4', function () {
expect(2 + 2).to.equal(4);
});
});
Back in the shell, run npm test
again. You should see the following output:
$ npm test
> mocha
Reality Check
✓ true should be true
✓ 2 + 2 should equal 4
2 passing (6ms)
Congrats, you've setup and run your first tests.
Next you will create tests to confirm the Express Static Server is working properly but you'll need to perform some additional setup first.
server.js
for testingIn server.js
wrap the app.listen
call with the following condition if (require.main === module) {...}
and then export the app
.
// Listen for incoming connections
if (require.main === module) {
app.listen(PORT, function () {
console.info(`Server listening on ${this.address().port}`);
}).on('error', err => {
console.error(err);
});
}
module.exports = app; // Export for testing
The above requires some explaining. When running the server, (e.g. npm start
or node server.js
) node sets the require.main
to the current module. That means that it is easy to determine if a file has been run directly by testing require.main === module
. Basically, the if (require.main === module) {...}
condition prevents the server from automatically starting when we run the tests.
The module.exports = app;
exports the Express app so it can be required and used in your test files.
Chai has a plug-in named chai-http
which allows you to make requests, send data, and receive the responses from endpoints.
In your shell, install chai-http
to the devDependencies
npm install --save-dev chai-http
In /test/server.test.js
, require the app
and chai-http
, then inform chai
to use chai-http
. At this point, the top of your file should look like this.
const app = require('../server');
const chai = require('chai');
const chaiHttp = require('chai-http');
const expect = chai.expect;
chai.use(chaiHttp);
describe('Reality check', function () {
// REMOVED FOR BREVITY
});
Run npm test
again to verify the tests are still working properly.
Your test environment is now ready to test Express. Below the "Reality check" tests, add the following two tests:
describe('Express static', function () {
it('GET request "/" should return the index page', function () {
return chai.request(app)
.get('/')
.then(function (res) {
expect(res).to.exist;
expect(res).to.have.status(200);
expect(res).to.be.html;
});
});
});
describe('404 handler', function () {
it('should respond with 404 when given a bad path', function () {
return chai.request(server)
.get('/DOES/NOT/EXIST')
.then(res => {
expect(res).to.have.status(404);
});
});
});
Run your tests to confirm everything is working properly.
Your challenge is to create tests for the rest of the endpoints. You should try to test both positive (eg 2XX) and negative (eg 4XX) outcomes.
Below is a list of requirements to help guide you.
Static server
404 handler
GET /api/notes
id
, title
and content
GET /api/notes/:id
id
, title
and content
for a given id/api/notes/DOESNOTEXIST
)POST /api/notes
title
in request body" when missing "title" fieldPUT /api/notes/:id
/api/notes/DOESNOTEXIST
)title
in request body" when missing "title" fieldDELETE /api/notes/:id
Good luck!
Excellent, you have a test suite! Now, let's set up CICD. If you prefer, here are command-line only instructions for the CLI Ninjas.
Before starting, make sure you have Travis and Heroku command line clients installed
On a Mac: gem install travis
Configure Travis CI to run your test suite when you or your teammates push changes to GitHub. Sign into Travis CI with your GitHub account.
Note: Free (org) vs Paid (com): Be sure to use Travis CI's free service on .org rather than the paid service not .com.
Activate Travis CI <> GitHub connection:
Verify a "Travis CI" setup on GitHub
In the root of your project, create a file name .travis.yml
and add the following.
language: node_js
node_js: node
Commit the file and push repo to Github
git add -A
git commit -m 'add .travis.yml'
git push origin master
On Travis CI:
Next you'll create an app on Heroku and configure it to automatically deploy when Travis CI tests pass
Back on your repo, make a change to any file and commit and push to trigger new build.
git commit -am 'setup heroku'
git push origin master
Add a Travis CI badge to your repo:
readme.md
file, commit and push[![Build Status](https://travis-ci.org/<USERNAME>/<REPO-NAME>.svg?branch=master)](https://travis-ci.org/<USERNAME>/<REPO-NAME>)
You can view an example solution and compare the differences between branches
Good Luck!