DEV Community

shyamajp
shyamajp

Posted on

Testing Node.js/Express app + MongoDB with jest and supertest

Introduction

I find it quite hard to find the right steps when you already have a set of technologies in your project, and as the title goes, my target audience are those who already know how to develop a backend application in Express + MongoDB but not how to write tests for it. If you are still with me, let's get started.

Tech Stack

  • Node.js JavaScript runtime environment outside of browser
  • Express Backend application framework for Node.js
  • MongoDB NoSQL database like JSON.
  • Jest JavsScript testing framework maintained by Facebook
  • supertest npm package that helps test HTTP

Writing tests

Steps

  1. Prepare a mongodb in memory server for testing
  2. Write tests with jest and supertest
  3. (Optional) Set up NODE_ENV to test

Prepare a mongodb in memory server for testing

First, install the in-memory-mongodb-server with the command below.
npm i -D mongodb-memory-server

I put all test files inside __test__ folder but feel free to modify the path as needed.

/__tests__/config/database.js

import mongoose from "mongoose";
import { MongoMemoryServer } from "mongodb-memory-server";
import { MongoClient } from "mongodb";

let connection: MongoClient;
let mongoServer: MongoMemoryServer;

const connect = async () => {
  mongoServer = await MongoMemoryServer.create();
  connection = await MongoClient.connect(mongoServer.getUri(), {});
};

const close = async () => {
  await mongoose.connection.dropDatabase();
  await mongoose.connection.close();
  await mongoServer.stop();
};

const clear = async () => {
  const collections = mongoose.connection.collections;
  for (const key in collections) {
    await collections[key].deleteMany({});
  }
};
export default { connect, close, clear };
Enter fullscreen mode Exit fullscreen mode

As you do with ordinary MongoDB, you connect to the database before running tests and you close connection after running tests. You can also nuke the data in database using clear. I use default export here to import the module as db and use the functions like db.connect() or db.clear(), but it is totally up to you or TypeScript settings.

Write tests with jest and supertest

I assume most of you already have installed the testing dependencies, but if not, please run the command below.
npm i -D jest supertest

import request from "supertest";
import app from "../src/index";
import db from "./config/database";

const agent = request.agent(app);

beforeAll(async () => await db.connect());
afterEach(async () => await db.clear());
afterAll(async () => await db.close());

describe("tags", () => {
  describe("POST /tags", () => {
    test("successful", async () => {
      const res = await agent.post("/tags").send({ name: "test-tag"});
      expect(res.statusCode).toEqual(201);
      expect(res.body).toBeTruthy();
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

As mentioned in the previous step, you can make use of beforeAll, afterEach, and afterAll hooks for the database connections/modifications. If you want to keep the data that you create with POST, you can remove db.clear() from afterEach hook so you can interact with the same object for other methods like PUT or DELETE.

Set up NODE_ENV to test

For better maintanance, I have passed NODE_ENV=test just before tests.

package.json

"scripts": {
  "test": "export NODE_ENV=test && jest --forceExit --runInBand",
}
Enter fullscreen mode Exit fullscreen mode

In order to avoid port collision, my express app will not occupy the port while testing. And I use dotenv for dealing with environment variables for those who aren't familiar with this.

/src/index.ts

if (process.env.NODE_ENV !== "test") {
  app.listen(port, () => {
    console.log(`Express app listening at ${process.env.BASE_URI}:${port}`);
  });
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

In the end, it is all about the database setup for testing. And I hope this post was right for you.

Feel free to reach out if you have any questions or suggestions to make this article better. Thank you for reading. Happy Coding!

Discussion (1)