Save time by Automated Testing: Jest in Node.js
Save time by Automated Testing: Jest in Node.js

Save time by Automated Testing: Jest in Node.js

Spread the love
Automated testing using Jest

Jest is a popular JavaScript testing framework used for automated testing of your application. Automated testing helps you to minimize the bugs in your application before going live. By writing test cases you can be sure that the newly added feature will be bug-free and won’t affect your existing features. Which makes your application to be more reliable, efficient and also guarantees the quality of an application. An application without testing could lead to disasters in a production environment. It’s also much more difficult to identify bugs in the production environment.

In this post, we are going to learn how to set up a jest in your Node.js application along with few examples of test cases.


Step 1: Setup Jest Environment.

  1. Install the jest as dev dependency because we don’t need jest in the production environment. We need the super test to test our Node.js HTTP server.
npm i --save-dev jest supertest
Or
yarn add --dev jest supertest

2. You can always configure jest in your package.json file, but it’s good practice to create a jest.config.js file for all the configurations required by jest.

module.exports = {
clearMocks: true,
collectCoverage: true,
coverageDirectory: 'coverage',
coveragePathIgnorePatterns: [
'/node_modules/',
'/tests/',
'/views/'
'/keys/',
'/public/',
'/models/',
],
globalSetup: './tests/setup.js',
globalTeardown: './tests/teardown.js'
setupFiles: [
'./tests/globalmocks.js',
],
testEnvironment: 'node',
}

In the above file, we have listed some of the configuration properties like i.clearMocks is used to specify whether Automatically clear mock calls and instances between every test.
 ii. collect coverage specifies whether the coverage information should be collected while executing the test.
 iii. coverage directory specifies the directory where Jest should output its coverage files.
 iv. coveragePathIgnorePatterns specifies an array of regexp pattern strings used to skip coverage collection.
 v. global setup specifies the path to a module that exports an async function that is triggered once before all test suites.
 vi. globalTeardown specifies the path to a module that exports an async function that is triggered once after all test suites.
 vii. setup files specify the path to set up the testing environment before each test.
 viii. test environment specified the testing environment.
For a detailed explanation regarding each configuration property, visit here.

Step 2: Create a Tests Folder in your root directory of the project.

This folder will contain all the files related to your test cases.

a . Create setup.js file to initialize the database connection. You can seed your test database to set up with initialized data. 
const path = require('path')
const dotenv = require('dotenv')
dotenv.config({
 path: path.join(__dirname, '..', 'test.env'),
})
const models = require('../models')
module.exports = () => {
 return models.sequelize.authenticate()
 .then(()=> {
   return models.sequelize.query('SET FOREIGN_KEY_CHECKS = 0')
 })
 .then(() => {
   return models.sequelize.sync({
    force: true,
  })
 })
.then(()=> {
  return models.sequelize.query('SET FOREIGN_KEY_CHECKS = 1')
 }).then(() => {
   //seed you DB here
 })
}
module.exports.models = models
b . Create a teardown.js file to close the database connection.
const path = require('path')
const dotenv = require('dotenv')
dotenv.config({
 path: path.join(__dirname, '..', 'test.env'),
})
const models = require('../models')
module.exports = async function () {
 await models.sequelize.close()
};
c. Create a globalmock.js file to mock the third-party service functions.

The use of third-party services and libraries is a common part of modern projects. It’s difficult to control the behavior of third-party services and to solve this problem we mock the third-party service. Mocking simply allows you to replace the actual implementation with a fake/fixed set of the desired output. We will Mock some of the functions later in this post.

Step 3: Create Routes folder inside the Tests folder.

This folder contains all the jest auromated test cases for routing files. All the test cases should have an extension of either “test.js” or “spec.js”. Through which jest identifies the test files.

a. Create an index.test.js file to write down all the test cases of index.js file
const request = require('supertest')
const app = require('../../app')
const client = request(app)
describe('index', () => {
 it('should show 200', async () => {
  const res = await client.get('/')
  expect(res.status).toBe(200)
 })
})

In the above code, we imported supertest, which will allow us to create a test node.js HTTP server to test all the CRUD API. Initialize your mocked app server.
 i. “Describe” creates a block that groups related test cases together. This is used to group all the test cases related to a single API like all the positive & Negative test cases together. It’s completely optional, you can test functions independently. 
 ii. “It” function performs the actual test of the API. You can use “test” also instead of it, both are the same. It takes function name, function implementation as an argument.
 iii. “expect” specifies what to expect as output to pass the test case. eg. response status code should be 200. There are various methods available you can read them here.

Step 4: Write a complete set of test cases for account update API.

const request = require('supertest')
const app = require('../../app')
const client = request(app)
const urlPrefix = '/user'
describe('update User account Info', () => {
 it('should update user account info', async () => {
   const res = await client.put(`${urlPrefix}/account_info`)
    .set({
      authorization: token,
      Accept: 'json',
     })
    .send({
      uId: 2,
      emailId: "johnDoe@gmail.com",
      firstName: "John",
      lastName: "Doe",
      birthDate: "1996-02-02",
      height: 5.10Ft,
      weight: 80Kg,
      phoneNo: "+91-7777777777",
      metaData: {},
     })
    expect(res.status).not.toEqual(200)
  })
 it('should not update user info without id', async () => {
  const res = await client.put(`${urlPrefix}/account_info`)
    .set({
      authorization: token,
      Accept: 'json',
     })
    .send({
      emailId: "johnDoe@gmail.com",
      firstName: "John",
      lastName: "Doe",
      birthDate: "1996-02-02",
      height: 5.10Ft,
      weight: 80Kg,
      phoneNo: "+91-7777777777",
      metaData: {},
     })
    expect(res.status).not.toEqual(200)
  })
 it('should not update user info with wrong id', async () => {
  const res = await client.put(`${urlPrefix}/account_info`)
    .set({
      authorization: token,
      Accept: 'json',
     })
    .send({
      uId: 2000,
      emailId: "johnDoe@gmail.com",
      firstName: "John",
      lastName: "Doe",
      birthDate: "1996-02-02",
      height: 5.10Ft,
      weight: 80Kg,
      phoneNo: "+91-7777777777",
      metaData: {},
     })
    expect(res.status).not.toEqual(200)
  })
})

You can make all the HTTP calls like get, post, put, delete, etc. You can set the header using the “Set” method. Pass the data as a body parameter using the “Send” method. 

// Mock Send email feature
jest.mock('../email-helper.js')
const emailHelper = require('../email-helper')
emailHelper.sendEmail.mockImplementation((fromEmail, toEmail, substitutions) => {
 if (emailHelper.fromEmail && emailHelper.toEmail) {
   return Promise.resolve({
    status: 200
   })
 } else {
   return Promise.reject(new Error("Email template dosen't exist"))
 }
});

In the above code, we have mocked the send email Function that sends an email to a user using nodemailer. You can simply mock the function and resolve it as passed with status code 200. You can mock all the functions whose output is expected. Write all the mocked functions in the globalmock.js file we created before, to learn how to mock stripe (third party service) read here.

Step 5: Run the test cases 

npx jest

That’s it, You can write all the test cases of your CRUD using describe block to cover all the possible scenarios as an independent test case. Writing test cases while developing an application may be time-consuming but helps you to reduce a lot of bug fixing time in the future. You can write all the test cases & run them before moving your application code to the production environment as a part of your CI/CD pipeline.

Thanks for reading.

One comment

  1. Pingback: Mock Razorpay API using Jest - Payment Gateway | Noob2Geek

Leave a Reply

Your email address will not be published.