Testing NodeJS APIs pt. IV: writing the first test

Christian Benseler
3 min readDec 3, 2019

--

We have already created our server, the API and set up the test environment. Now it's time to write the first real test: let;'s check if the user's sign in is correct!

Add 2 new tasks to package.json and fix the test:

"scripts": {
"test": "cross-env MONGOURL=mongodb://localhost:27017/nodejs_jestsupertestmongodb_example_test NODE_ENV=test jest --testTimeout=10000",
"migrate:reset": "cross-env NODE_ENV=test MONGOURL=mongodb://localhost:27017/nodejs_jestsupertestmongodb_example_test node ./test/test_migrate.js",
"pretest": "npm run migrate:reset"
}

When we run npm test, the pretest task will be executed. It will set test as NODE_ENV and then run the migrate:reset task. This is needes because we don't want to mess with the development database; the task set a database in Mongo for the test environment and then run a node script(the test_migrate.js).

Now we have to write this script, that is a simple NodeJS script using Mongoose to drop our (test) database and create some fake data:

const mongoose = require(‘mongoose’)
const User = require(‘../models/User’)
const Post = require(‘../models/Post’)
async function createFakeUsers () {
const u = new User({
email: ‘fake@fake.com’,
password: ‘fake’
})
await u.save()
const uf = new User({
email: ‘fakedelete@fake.com’,
password: ‘fake’
})
await uf.save()
}
async function createFakePosts() {
const u = await User.findOne({ email: ‘fake@fake.com’ })
const post = new Post({ title: ‘test edit post title’, user: u })
await post.save()
const postToDelete = new Post({ title: ‘test delete post title’, user: u })
await postToDelete.save()
}
mongoose.connect(process.env.MONGOURL, { useNewUrlParser: true })
mongoose.connection.on(‘connected’, async () => {
console.log(‘MongoDB connection established successfully with test’)
await mongoose.connection.db.dropDatabase()
await createFakeUsers()
await createFakePosts()
process.exit()
})

After running the npm test, if you take a look at you MongoDB, you will see that the database and collections have been created and populated:

The collections
Users's collection populated

Let's test our sign in endpoint (POST /users/sign_in). Create a directory called controllers/ inside the test and there, a file user.test.js.
What we have to do:

  • import the jest framework
  • a test function, that will do the POST request and check the response
  • before all tests, start the server
  • after all tests, close the server

The source:

const request = require('supertest');
let app;
describe('User Authenticated Endpoints', () => {
beforeAll(async () => {
app = require('../../app')
})
afterAll(async () => {
await app.close()
})
it('should try to do login with valid credentials and success', async () => {
const res = await request(app)
.post('/users/signin')
.send({ email: 'fake@fake.com', password: 'fake' })
expect(res.statusCode).toEqual(200)
expect(res.body).toHaveProperty('token')
})
})

If you run the test again, you will see in the console:

Test Suites: 2 passed, 2 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 2.092s
Ran all test suites.

Sometimes you will see test instead of it in the file; the it is just an alias that the Jest team use in the framework, because other test frameworks use it.
What we are testing? A POST request to the sign in endpoint, sending the (fake) user credentials, and the response must have a 200 status and the body should have the token.

Let's add, too, a test for invalid credentials:

it('should try to do login with invalid credentials and fail', async () => {
const res = await request(app)
.post('/users/signin')
.send({ email: 'fakefail@fake.com', password: 'fake' })
expect(res.statusCode).toEqual(401)
})

The full and updated source from the project is in Github and the exact version from this Medium post is here.

--

--