Halina
Halina

Reputation: 265

Supertest and jest: cannot close express connection

I am using jest and supertest to raise instance of express and run tests on it.

I faced with the problem of busy port that cannot still solve.

In my test I do the next:

import supertest from 'supertest';
const agent = supertest(app);

Then I go requests with agent and everything works fine. Until I am running another test. In app.js I have:

var app = express();

app.post('/auth/changePassword',VerifyToken, auth.changePassword);

app.listen(4001, function () {
    console.log('Server is running');
});

So first spec runs perfect. But second tries to listen to the port that is already in use. I really do not know how to close the connection here.

I tried app.close() but got error that such method. This is clear, that I have to assign

server = app.listen(4001, function () {
    console.log('Server is running');
});
server.close();

But do not know how can I do that. I also tried to preset agent in jest.setup and assign it to global variable

import app from "../../server/app";
import supertest from 'supertest';

const agent = supertest(app);
global.agent = agent;

But situation is the same, first test passed, second tries to raise express on the same port.

Upvotes: 3

Views: 3573

Answers (2)

eskres
eskres

Reputation: 41

My solution for this is to make sure that NODE_ENV isn't set to 'test' before allowing express to listen for connections.

if (process.env['NODE_ENV'] !== 'test') {
  app.listen(port, host, () => {
    console.log(`[ ready ] http://${host}:${port}`);
  });
}

Upvotes: 0

Jack Dunleavy
Jack Dunleavy

Reputation: 287

Supertest is able to start and stop your app for you - you should never need to explicitly kill the express server during the tests (even when running in parallel)

The problem is that in app.js your server is actually started - this means that when the app tests are run your server is started every time app.js is read (or once per test case)

You can remedy this by splitting the server start logic into a seperate file, so that importing app.js doesn't start the app (rather returns an express server instance) The pattern I normally use for this is:

// app.js
import express from 'express'
export const app = express();

app.get("/example", (req,res) => {
  return res.status(200).json({data: "running"})
})

// server.js
import app from "./app"

app.listen(3000, () => console.log("listening on 3000"));

// app.spec.js
import app from "./app"
import request from "supertest"

it("should be running", async () => {
  const result = await request(app).get("/example");

  expect(result.body).toEqual({data: "running"});
});

Upvotes: 5

Related Questions