Testing with Async Jest

Johnson Kow
5 min readFeb 15, 2021

--

Before you read this blog, I highly recommend reading ‘Testing with Jest’ as this is a follow up! These are the last steps before I complete my Task Manager App!

In the previous blog, we started testing some example problems for the app but now we need to make sure that our endpoints work as expected. You should consider what endpoints require authentications and which don’t. Test both cases, whether a user is authenticated and whether they aren’t.

Before we start, let’s breakdown what we’re doing. Right now, I’m in my local production. When running ‘npm run test’, I’m actually developing on a different server called ‘task-manager-api-test’ because when we test our endpoints, we need to make sure we aren’t testing on our real database with real users. To double check them, we create some assertions.

In my ‘user.test.js’ app, we want to require a couple of things:

  1. supertest — helps us test our endpoint before ‘app.listen()’
  2. app — the file that currently runs all of our endpoints and initiates our nodeJS server
  3. Users model- as we will need to make sure we compare our input and outputs from the database
  4. Wipe Test Database Function — when we run our tests, we’d like to wipe everything from our test database since we will be reusing an example instance of our user.
const request = require('supertest')const app = require('../src/app')const User = require('../src/models/user')const {userOneID, userOne, setUpDatabase} = require('./fixtures/db')

Inside of our db.js folder, we have the id to our user which will be used more than once in different tests, so we created a variable just for it. We also have the actual instance of our user, userOne. Lastly, a function named setUpDatabase that wipes all the user from the database. The db.js file looks as such.

const mongoose = require('mongoose')const jwt = require('jsonwebtoken')const User = require('../../src/models/user')
const userOneID = new mongoose.Types.ObjectId();const userOne = ({ _id: userOneID, name:'Mike', email: 'mike@example.com', password: 'What1244!', tokens:[{ token: jwt.sign({_id: userOneID}, process.env.JWT_SECRET) }]})const setUpDatabase = async () => { await User.deleteMany()await new User(userOne).save()}module.exports = { userOneID, userOne, setUpDatabase}

The things we need are Mongoose, jwt, and the User model to communicate with our database, authenticate with tokens, and specify which table we’re testing.

BeforeEach()

The beforeEach method is a life cycle method which provides a nice setup before we run the rest of our code. Back inside of our user.test.js, we’ll set up our tests by running setUpDatabase. As seen above, this will wipe the users tables in our database and save our first instance.

beforeEach(setUpDatabase)test('Should Sign Up User', async() => {   const response = await request(app).post('/users').send({       name: "Johnson",      email: "jkow95@example.com",      password: "Mypass2021"}).expect(201)

Okay, the first test I’ve set up is called ‘Should Sign Up User’. An async test that tests whether we get a successful status code or if it fails. Inside of our block, we use superjest as request. Requesting to use the app an create a post request to the ‘/users’ endpoint. We want to send an object that every use will send when creating their profile; their name, email, and password.

Before running all this and making sure we’re getting the correct information back, let’s take a look at our package.json file because we want to make some changes.

"scripts": {"start": "node src/index.js","dev": "env-cmd -f ./config/dev.env nodemon src/index.js","test": "env-cmd -f ./config/test.env jest --watch --runInBand"},"jest": {"testEnvironment": "node"},

Add the ‘test’ key under the scripts object. When we run ‘npm run test’ we are creating a shorthand to run “env-cmd -f ./config/test/.env jest — watch — runInBand”.

For the sake of this tutorial, should be okay with just including ‘jest — watch — runInBand” as everything prior is for environment variables which I highly recommend you look into OR let me know if you’d like me to make a blog about it.

Great! Now we can run ‘npm run test’ and get something that looks like this.

PASS  test/user.test.js
✓ Should Sign Up User (267 ms)

Assertions

Assertions refers to extra testing. Right now we’ve only passed because our expected status code matches the output status code but we can further investigate by making sure that the user we created exists inside of our database!

Inside the block of the same test, let’s create a user variable which looks for a user based off the information inside the body of our request (which holds our user object).

const user = await User.findById(response.body.user._id)expect(user).not.toBeNull()expect(response.body).toMatchObject({   user:{   name: "Johnson",   email: "jkow95@example.com",},   token: user.tokens[0].token})expect(user.password).not.toBe("Mypass2021")

I’ve created a couple of assertions here to make sure we are in fact doing everything we possibly can to cross check that my endpoint is doing what we intend it to do. The user variable searches the User table in our database from the _id of our request.body, where the object we created earlier in the test is found.

We expect the user to not be null. Pretty self explanatory on that one. Now let’s check a couple of things. The user object we provided SHOULD match the object that is now in the database. So for that test, we want the user to match all it’s attributes as well as the token that’s used to authenticate them which we access through the user variable!

Lastly, the password. In this project, we used bcrypt to encrypt our password and therefore our password lives in the database as a string of jibberish. We should NOT be getting the actual string we provide for our sign up. Check out my authentication blog if that’s confusing!

All this is happening asynchronously, as we are both posting to our database and then reading from our database to compare user objects.

I hope this helps to serve as a beginner level introduction to async jest testing. I highly recommend using the jest documents to understand more about the functions I’ve used like .not or .toBe. or even expect().

As always, happy coding!

--

--

Johnson Kow
Johnson Kow

Written by Johnson Kow

Software Engineer based out of NYC. Learning more about programming everyday 👍

No responses yet