Writing basic tests for Express
Writing tests is an important step to being a well rounded developer. When we make changes to our code base we can have some assurance that it is stable if all our tests pass, this helps make our code more structurally sound. I will be talking about how to write basics tests for express.
To write out tests we will be using the mocha test framework and the assertion library chai, these can be installed through any package manager, for this example we will be using node package manager or npm for short.
npm install mocha chai
I will be using this simple array as our data.
const weapons = [{
id: 0,
name: 'Sword',
type: 'Melee'
},{
id: 1,
name: 'Bow',
type: 'Ranged'
},{
id: 2,
name: 'Staff',
type: 'Magic'
},{
id: 3,
name: 'Spear',
type: 'Melee'
},{
id: 4,
name: 'Chakram',
type: 'Ranged'
},]
When writing tests there are 3 main parts to keep track of, the describe() groups together similar tests and helps provide test files structure making it easier to read.
describe('Get Routes', () => {
it statements go inside here
})
The it() represents the tests that we will be performing and generally includes the result that said test should have in its text.
it('get all route should return 5 weapons', () => {
expect statement goes here
})
After that is the expect() that is where the actual tests are being run and checked to see if they match the expected output.
expect(weapons.length).to.be.equal(5)
There are other helpful functions such as beforeEach() and afterEach(), when you have multiple tests using the same data it can be mutated and affect the results of other tests. These functions make sure that the data being used is refreshed or kept clean from any changes made by other tests.
We will start with writing tests for express, all of these tests will be written inside a tests folder to make our file structures neater.
To write tests for express we need an additional library called supertest, we will then require and connect it to our server like this.
Const app = require(‘./server’)
Const agent = require(‘supertest’)(app)
With this we can now request from our server and get back a response to test, you can either use the async await or the .then function to get access to the response like this.
it('returns all weapons', () => {
agent.get('/weapons')
.then(response => {
expect(response.body.length).to.be.equal(weapons.length)
})
})orit('returns all weapons', async () => {
const response = await agent.get('/weapons')
expect(response.body.length).to.be.equal(weapons.length)
})
For the async await to work in tests you would need to add “ — require @babel/polyfill” in you npm test script.
If you console log the response you’ll be met with a huge object but for writing basic tests we will only focus on two of its properties the status and body. The status is the code being passed along indicating what type of response it is like 200s for successful responses, 400s for client errors, and 500s for server errors.
The body is what your server is sending back on these requests and here is where you will test to make sure that the server is sending what you want it to send.
Here is an example of get routes
describe('Weapons Route', () => {
describe('Get /weapons', () => {
it('returns all weapons', () => {
request.get('/weapons')
.then(response => {
expect(response.body.length).to.be.equal(5)
})
})
}) describe('Get /weapons/:id', () => {
it('returns specified weapon', () => {
const id = 3
request.get(`/weapons/${id}`)
.then(response => {
expect(response.body.id).to.be.equal(3)
expect(response.body.name).to.be.equal('Spear')
})
})
it('should return 404 for a weapon not found', () => {
const id = 90
request.get(`/weapons/${id}`).then(response => {
expect(response.status).to.be.equal(404)
})
})
})
})
This is the command to run the tests.
"test": "mocha tests --recursive --watch"
tests indicate the folder where we keep all of our test files, recursive helps look through all of the sub-directories in tests for files, and watch allows us to not have to keep typing npm test every time we make a change to our test files.
Make sure to include an if statement around the listen function in the server
if (!module.parent){
app.listen(PORT, () => {
console.log(`listening to http://localhost:${PORT}`)//
})
}
When we refresh the tests with watch this if statement prevents the server from trying to open up a server on that port preventing the error “address is already in use”.
I hope this article helped you get a basic understanding of writing tests in express.