Sling Academy
Home/Node.js/How to Perform Unit Testing in Node.js using Mocha and Chai

How to Perform Unit Testing in Node.js using Mocha and Chai

Last updated: December 29, 2023

Introduction

Unit testing is a vital part of software development that involves testing individual units or components of software to ensure that each one functions correctly. In Node.js, a popular choice for this is the combination of Mocha, a feature-rich JavaScript test framework running on Node.js, and Chai, a BDD/TDD assertion library. This tutorial aims to guide you through the process of setting up and writing unit tests for your Node.js applications using Mocha and Chai, showcasing various examples from basic to advanced scenarios.

Setting Up

To start, you’ll need Node.js installed on your machine. Once that’s done, you can initiate a new project and install Mocha and Chai as development dependencies using the following commands:

mkdir my-new-project
cd my-new-project
npm init -y
npm install mocha chai --save-dev

Add a ‘test’ script in your package.json that runs Mocha:

{
  "scripts": {
    "test": "mocha"
  }
}

Basic Test Structure

A basic Mocha test looks like the following example:

const assert = require('chai').assert;
describe('Array', () => {
  describe('#indexOf()', () => {
    it('should return -1 when the value is not present', () => {
      assert.equal([1, 2, 3].indexOf(4), -1);
    });
  });
});

This test checks that calling the ‘indexOf’ method on an array returns -1 when the value is not present. The ‘describe’ and ‘it’ functions structure your test suite and test cases.

Assertion Styles

Chai provides several assertion styles, the most common being Expect and Should style. The Expect style allows you to write assertions in a very natural language manner, which is highly readable:

const expect = require('chai').expect;
describe('Math', () => {
  it('does basic arithmetic', () => {
    expect(2 + 2).to.equal(4);
  });
});

The Should style extends any object with a ‘should’ property, which allows you to write very readable tests that read like English:

const should = require('chai').should();
(2 + 2).should.equal(4);

Remember that you must execute ‘should’ once before you can use it to manipulate ‘Object.prototype’:

chai.should();

Asynchronous Code Testing

Testing asynchronous code can be tricky, but Mocha makes it simple. For callback-based asynchronous code, provide a ‘done’ callback to your ‘it’ function and call it when your assertion is complete:

it('should call a callback', (done) => {
  fs.readFile('file.txt', 'utf8', (err, contents) => {
    if (err) done(err);
    contents.should.include('Hello');
    done();
  });
});

For Promise-based code, simply return the Promise and Mocha will wait for it to resolve or reject:

it('should work with promises', () => {
  return fetch('https://my.api/endpoint').then((response) => {
    expect(response.status).to.equal(200);
  });
});

Advanced Usage

Once you’re familiar with basic testing, you can explore more advanced features of Mocha and Chai like:

  • Chai plugins for extended functionalities.
  • Using ‘beforeEach’ and ‘afterEach’ for setup and teardown.
  • Timeout control for tests that require a longer execution time.
  • ‘only’ and ‘skip’ methods to control test execution.
  • Integration with other tools like Sinon for spies, stubs, and mocks.

Real-world Example

Consider a scenario where you have an API route to test:

const chai = require('chai');
const chaiHttp = require('chai-http');
const app = require('../app'); ///<- Your Express app

chai.use(chaiHttp);
const expect = chai.expect;

describe('/GET book', () => {
  it('it should GET all the books', (done) => {
    chai.request(app)
      .get('/book')
      .end((err, res) => {
        expect(res).to.have.status(200);
        expect(res.body).to.be.a('array');
        done();
      });
  });
});

In this example, we’re using Chai’s ‘chai-http’ plugin to make HTTP requests to our app and run assertions on the response.

Conclusion

This tutorial has covered the basics and some advanced topics in unit testing with Mocha and Chai for Node.js applications. By writing tests for your code, you’ll ensure that each part is correctly doing its job, and you can refactor with confidence. Unit tests are an essential aspect of a healthy development cycle, and mastering unit testing will make you a stronger and more capable Node.js developer.

Next Article: Should you use Docker or PM2 to run Node.js apps in production

Previous Article: How to Setup a Node.js Cluster for Speed & Stability

Series: Node.js Intermediate Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates