Table of contents
Open Table of contents
Setting up our sample application
We’ll be building out an application that reads information from non-persistent students record data. To continue, we need to have the following files and folders created:
--- controllers/
------ studentController.js
--- dummy/
------ students.js
--- routes/
------ index.js
--- tests/
------ test.js
--- .babelrc
--- server.js
--- package.json
To set up our dummy data, we need to include the data in the dummy/students.js file:
const students = [
{
id: 1,
name: 'Sean Grey',
age: 24,
},
{
id: 2,
name: 'John Doe',
age: 26,
},
{
id: 3,
name: 'Janet Dane',
age: 19,
},
];
export default students;dummy/students.js
The code block above assigns an array of objects, each object holding the details of a student.
Now let’s set up our package.json, so we can install all the packages we would be needing to build out and test our application.
{
"name": "student-record",
"version": "1.0.0",
"description": "An API to manage student record",
"main": "server.js",
"author": "Samuel Raphael",
"license": "MIT",
"scripts": {
"test": "mocha --require babel-register tests/*.js --exit",
"dev": "nodemon --exec babel-node --presets babel-preset-env ./server.js"
}
"dependencies": {
"body-parser": "^1.18.3",
"express": "^4.16.3"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-env": "^1.7.0",
"chai": "^4.1.2",
"chai-http": "^4.0.0",
"mocha": "^5.1.1",
"nodemon": "^1.17.4"
}
}package.json
In the package.json file, we include our mocha and chai, which we’ll be using to write our tests. We also needed to include chai-HTTP which is a plugin that allows us to run HTTP integrations with chai assertions. We can now run npm install to install the packages and get ready to finish setting up our application.
The next step is to create our routes and server.js files, but first, we should create our controller file as we would be needing to import it into our routes file. In the controllers/studentController.js file, we should include:
import students from '../dummy/students.js';
class StudentController {
// Get all students
static getAllStudents(req, res) {
return res.status(200).json({
students,
message: "All the students",
});
}
// Get a single student
static getSingleStudent(req, res) {
const findStudent = students.find(
student => student.id === parseInt(req.params.id, 10));
if (findStudent) {
return res.status(200).json({
student: findStudent,
message: "A single student record",
});
}
return res.status(404).json({
message: "Student record not found",
});
}
}
export default StudentController;controllers/studentController.js
In the controllers/studentController.js file, we imported our dummy data, created a class to hold our controller methods and created two static methods each for what we want to achieve with the controller class. The first method, getAllStudents, as the name implies gets all the students record we have in our dummy data and returns them with a 200 HTTP status code, while the second method, getSingleStudent, get the record of a single student and returns it with a 200 HTTP status. If a record is not found, a 404 HTTP status code is returned.
Now that we have our controller set up, we can now go back to working on our routes and server.js. In our routes/index.js file, we should add the following code:
import { Router } from 'express';
import StudentController from '../controllers/studentController.js';
const routes = Router();routes.get('/', StudentController.getAllStudents);
routes.get('/:id', StudentController.getSingleStudent);
export default routes;routes/index.js
We imported Router (express router) from express and assigned it to routes, we also imported our StudentController class from our controllers/studentController.js file. We used the Router we imported to create two routes, which are tied respectively to their corresponding controller methods.
Now we should create our server.js file so we can test the code we’ve been writing if it works.
import express from 'express';
import bodyParser from 'body-parser';
import routes from './routes/index';
// Instantiate express
const app = express();// Set our port
const port = process.env.PORT || 8000;
// Configure app to user bodyParser
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// Register our routes in app
app.use('/', routes);
// Start our server
app.listen(port, () => {
console.log(`Server started on port ${port}`);
});
// Export our app for testing purposes
export default app;server.js
Because we’re writing ES6 code, we need babel to compile our code, and for that to work, we need to add the following code to our .babelrc file:
{
"presets": ["env"]
}.babelrc
Now that we have our application all set up, we can go ahead to run npm run dev to run our application and test our endpoints using Postman.
Writing tests for our application
Our application works well, but we need to write tests for it. To make sure we don’t break it, while also covering all edge cases. In our tests/test.js file, we’ll write our tests.
// Import the dependencies for testing
import chai from 'chai';
import chaiHttp from 'chai-http';
import app from '../server';
// Configure chai
chai.use(chaiHttp);
chai.should();
describe("Students", () => {
describe("GET /", () => {
// Test to get all students record
it("should get all students record", (done) => {
chai.request(app)
.get('/')
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a('object');
done();
});
});
// Test to get single student record
it("should get a single student record", (done) => {
const id = 1;
chai.request(app)
.get(`/${id}`)
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a('object');
done();
});
});
// Test to get single student record
it("should not get a single student record", (done) => {
const id = 5;
chai.request(app)
.get(`/${id}`)
.end((err, res) => {
res.should.have.status(404);
done();
});
});
});
});tests/test.js
At the beginning of the file, we imported all packages needed to make the test run, then we configured chai to use the chai-HTTP plugin. We also configured chai to use the should interface by running chai.should(). Each describe blocks, are used to group our tests together for easier access and better organization.
The first it block is a test that runs on the first endpoint to get all student record from the data, it asserts that the response should have a status of 200 and it should return an object. The second it block is a test that runs on the second endpoint to get a single student request. Assuming the student exists, it asserts that the response should have a status of 200 and it should return an object. And finally, the third it block is a test that runs also on the second endpoint to get a single request. Assuming the student does not exist, it asserts that the response should have a status of 404.
All that is remaining is for us to run npm run test and we’ll see our tests passing before our very eyes.
Beautiful, isn’t it?