Emz
Emz

Reputation: 527

How to use Jest global Setup and Teardown in a nodeJS project?

I added tests to my node js project using jest but for each test suite there's a beforeAll method that creates a new test server and connects to a mongo database and an afterAll method that closes both test server and the database. I would like to perform the above tasks globally for all the test suites not one at a time. Below is a sample of my code.

app.js

const express = require("express");
const app = express();
const { connectToDb } = require("./startup/db");
require("./startup/routes")(app);
connectToDb();
...

const port = process.env.PORT || 3000;

if (process.env.NODE_ENV !== "test") {
  app.listen(port, () => winston.info(`Listening on port ${port}...`));
}

module.exports = app;

auth.test.js

const request = require("supertest");
const http = require("http");
const { disconnectDb } = require("../../startup/db");

describe("auth middleware", () => {
  let server;

  beforeAll((done) => {
    const app = require("../../app");
    server = http.createServer(app);
    server.listen(done);
  });

  afterAll((done) => {
    server.close(done);
    disconnectDb();
  });

  it("should return 401 if no token is provided", async () => {
    const res = request(server)
      .post("/api/genres")
      .set("x-auth-token", "")
      .send({ name: "genre1" });
    expect(res.status).toBe(401);
  });

...

jest.config.js

module.exports = {
  testEnvironment: "node",
};

Upvotes: 21

Views: 30116

Answers (3)

Mara
Mara

Reputation: 403

I had the same problem, I wanted to make one database connection before all test files and close the connection after all tests in all files.

But....I did not achieve what I wanted and MAYBE we don't need to do this.

I found a solution to launch functions beforeAll(),afterAll() etc... really before ALL TEST FILES and after ALL TEST FILES etc.. So you define these functions once in a certain file and they run for every test file. To do that, all we need is to create a setupFile.ts and add path to this file in jest.config or in package.json "setupFilesAfterEnv": ["<rootDir>/__tests__/settings/setupTests.ts"],

Here is an example of my jest configuration.

    "jest": {
    "preset": "ts-jest",
    "testEnvironment": "node",
    "setupFilesAfterEnv": ["<rootDir>/__tests__/settings/setupTests.ts"],
    "rootDir": "src",
    "verbose": true,
    "clearMocks": true,
    "testMatch": [
      "**/**/*.test.ts"
    ]
  },

Here is an example of setupFile.ts

import usersCollection from "../../database/user-schema";

import mongoose from "mongoose";

beforeAll(async () => {
  try {
    await mongoose.connect(process.env.MONGODB_URL!);
    await usersCollection.deleteMany({});
  } catch (error) {
    console.log(error);
  }
});

afterAll(async () => {
  try {
    await mongoose.disconnect();
  } catch (error) {
    console.log(error);
  }
});

It means that we will establish a connection to the database FOR EVERY TEST FILE BEFORE ALL TESTS IN THAT FILE and close connection after all tests in every test file.

What I realized for myself:

In real life we have many test files and not every file needs a connection to a database. It's perfectly fine to open a connection to a database in files which need a connection and close after all tests in that file, for example integration tests when we test API endpoints.

In other tests to not use real database for many unit tests we can consider to mock(simulate) a database. It's another very interesting topic 😊

If I say something wrong you can correct me

P.S I also want to mention what is written in the Mongoose documentation

Do not use globalSetup to call mongoose.connect() or mongoose.createConnection(). Jest runs globalSetup in a separate environment, so you cannot use any connections you create in globalSetup in your tests.

https://mongoosejs.com/docs/jest.html

Upvotes: 3

M. Emre Yal&#231;ın
M. Emre Yal&#231;ın

Reputation: 654

use this config: setupFiles: ['./tests/setup.js']

your setup file should look like this:

// setup.js
(async () => {
  const app = require('../app.js')
  global.app = app
})()

then you will be able to use app globally in every test suite

Upvotes: 0

Alecu Marian Alexandru
Alecu Marian Alexandru

Reputation: 705

Try with this jest.config.js:

module.exports = {
  testEnvironment: "node",
  globalSetup: '<rootDir>/src/testSetup.ts'
};

And in testSetup.ts you can do:

// testSetup.ts
module.exports = async () => {
    const app = require("../../app");
    server = http.createServer(app);
    server.listen(done);
};

Upvotes: 20

Related Questions