Jest API testing giving false passes - node.js

I have a simple test script for my API, the specific route is not implemented at the moment. But for some reason tests pass. Here is the script:
const request = require('supertest')
const api = require('../api-server')
// testing data:
const pmOne = {
name: "Some Name",
tel: "234 123"
}
const pmTwo = {
name: "Some Other Name",
tel: "256 789"
}
describe('Basic CRUD API', () =>{
it('GET /pm --> array of all projectmanagers', () =>{
request(api)
.post('/pm')
.send(pmTwo)
.expect(207)
})
it('GET /pm/id --> new projectmanager', () => {
request(api)
.get('/pm/' + pmOneId)
.expect(200)
.then((res) => {
expect(res.body.name).toBe(pmOne.name)
expect(res.body.tel).toBe(pmOne.tel)
})
})
And here is my app.js:
require('dotenv').config()
const express = require('express')
const mongoose = require('mongoose')
const app = express()
const pmRouter = require('./routes/pm.router')
// establish mongodb connection
var options = {
user: process.env.DATABASE_USER,
pass: process.env.DATABASE_PASSWD
}
mongoose.connect(process.env.DATABASE_URL, options)
const db = mongoose.connection
db.on('error', (error) => console.error(error))
app.use(express.json())
//app.use('/pm', pmRouter)
module.exports = app
The
//app.use('/pm', pmRouter)
Is commented out, so the route is not valid. That means all request should return 404 (which they do), so why am I getting passes on my tests:
> jest --forceExit --runInBand
PASS tests/projectmanager.test.js
Basic CRUD API
✓ GET /pm --> array of all projectmanagers (5 ms)
✓ GET /pm/id --> new projectmanager (3 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.571 s, estimated 1 s
Ran all test suites matching /tests\/projectmanager.test.js/i.
Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished?

Supertest request returns a promise and if you want to assert the returned value it has to be awaited or returned explicitly.
Either return it or use async/await syntax.
In your case simply add a return statement.
it('GET /pm', () => {
return request(api).post('/pm').send(pmTwo).expect(207)
});

Related

server and db connection once before all test files jest

I have multiple test files in my project. Each test file has almost similar beforeAll and afterAll functions which opens server and db connections and terminate them in the afterAll function.
I was getting error for server connection which said the port is already in use and I was able to handle that by not specifying a port number in test environment. However I'm unable to solve for db.
The lines below in .test.js file are common in all test files. The test itself is a dummy test. I need to have access to server in order to call the APIs there.
.test.js
const db = require('../service/pg');
const createServer = require('../service/server');
let server;
let sequelize;
beforeAll(async () => {
sequelize = await db.init();
server = await createServer();
await server.start();
});
afterAll(async () => {
await server.stop();
await sequelize.drop();
await sequelize.close();
});
describe('testing...', () => {
test('one + one = 2', async () => {
const options = {
method: 'POST',
url: '/math',
};
const res= await server.inject(options);
expect(1).toEqual(1);
});
server.js
if (process.env.NODE_ENV !== 'test') {
server = Hapi.server({
port: process.env.PORT || 5000,
routes: { cors: true },
});
}
db.js
const sequelize = require('./sequelize');
await sequelize.sync();
sequelize.js
const user_db = new Sequelize(
env.dbName,
env.user,
env.password,
{
host: env.host,
port: env.port,
dialect: 'postgres',
logging: false,
}
);
.... // add models
Ideal solution would be initializing server and DB only once for all test files. Some global setup stuff. But I'm unable to do that.
If I have like 2 test files, one test file works file but the other would give error like:
console.error
Connection to the database failed: UniqueConstraintError [SequelizeUniqueConstraintError]: Validation error
Instead of setting up your db in the beforeAll do it outside of the describe scope once and stop the servers afterwards.
const db = require('../service/pg');
const createServer = require('../service/server');
let server;
let sequelize;
(async () => {
sequelize = await db.init();
server = await createServer();
await server.start();
})();
describe('testing...', () => {
test('one + one = 2', async () => {
const options = {
method: 'POST',
url: '/math',
};
const res= await server.inject(options);
expect(1).toEqual(1);
});
});
(async () => {
await server.stop();
await sequelize.drop();
await sequelize.close();
})();
If I have like 2 test files, one test file works file but the other would give error like: console.error Connection to the database failed: UniqueConstraintError [SequelizeUniqueConstraintError]: Validation error
The reason for this is that jest runs tests in parallel and it could be that your second test starts before the first one has been finished and the afterAll has been called.

Having trouble stubbing an asynchronous function

I am currently working on a full-stack application using the MERN stack. I have been writing unit tests for each route's request handler, and have been finding some difficulty testing error cases, particularly in trying to stub a function to reject a promise
I have the relevant code shown below:
One of my endpoints. Request handling is delegated to userController
const express = require("express");
const { body } = require("express-validator");
const router = express.Router();
const userController = require("../../controllers/user");
router.post(
"/",
body("username")
.isLength({
min: 3,
max: 30,
})
.withMessage(
"Your username must be at least 3 characters and no more than 30!"
),
body("password")
.isLength({ min: 3, max: 50 })
.withMessage(
"Your password must be at least 3 characters and no more than 50!"
),
userController.createNewUser
);
The request handler for the above endpoint. I am trying to test createNewUser. I want to stub createNewUser so that it causes an error to be thrown, so I can test that a 500 status code response is sent.
const bcrypt = require("bcryptjs");
const { validationResult } = require("express-validator");
const User = require("../models/User");
exports.createNewUser = async (req, res, next) => {
const { username, password } = req.body;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
errors: errors.array(),
});
}
try {
// Create a bcrypt salt
const salt = await bcrypt.genSalt(12);
// Hash the password
const hashedPassword = await bcrypt.hash(password, salt);
// Create a new user
const user = new User({
username,
password: hashedPassword,
});
const response = await user.save();
res.status(200).json(response);
} catch (err) {
res.status(500).json({ msg: err.message });
}
};
The unit test for User endpoints. I am unsure how to test the error case where a 500 status code is returned...
const request = require("supertest");
// const todosController = require("../controllers/todos");
const server = require("../server");
const User = require("../models/TodoItem");
const db = require("./db");
const agent = request.agent(server);
// Setup connection to the database
beforeAll(async () => await db.connect());
afterEach(async () => await db.clear());
afterAll(async () => await db.close());
describe("User endpoints test suite", () => {
describe("POST api/user", () => {
test("It should create a user successfully and return a 200 response code", async () => {
const response = await agent
.post("/api/user")
.set("content-type", "application/json")
.send({ username: "Bob", password: "12345" });
expect(response.body.username).toEqual("Bob");
expect(response.status).toBe(200);
});
});
});
When you are creating unit test, create something small first, you can add complexity and refactor later.
Below are example simple unit and integration tests based on your code.
You can start with user controller.
// File: user.controller.js
const bcrypt = require('bcryptjs');
exports.createNewUser = async (req, res) => {
try {
// Create a bcrypt salt.
const salt = await bcrypt.genSalt(12);
// Just make it simple, show the salt.
res.status(200).json(salt);
} catch (err) {
// Other wise, return the error message.
res.status(500).json({ msg: err.message });
}
};
Based on that try and catch, you can create unit test.
// File: user.controller.spec.js
const bcrypt = require('bcryptjs');
const user = require('./user.controller');
describe('User Controller', () => {
describe('create New User', () => {
const fakeJson = jest.fn();
const fakeStatus = jest.fn().mockReturnThis();
const fakeRes = {
status: fakeStatus,
json: fakeJson,
};
const spy = jest.spyOn(bcrypt, 'genSalt');
afterEach(() => {
jest.clearAllMocks();
});
it('should return salt', async () => {
const testSalt = 'salt';
// Mock the bcrypt.genSalt, always resolved with value testSalt.
spy.mockResolvedValue(testSalt);
// Call the function under test.
await user.createNewUser(undefined, fakeRes);
// Set the expectations.
expect(fakeStatus).toHaveBeenCalledWith(200);
expect(fakeJson).toHaveBeenCalledWith(testSalt);
expect(spy.mock.calls[0][0]).toBe(12);
});
it('should return error message when error', async () => {
const error = new Error('XXX');
// Mock the bcrypt.genSalt, always resolved with value testSalt.
spy.mockRejectedValue(error);
// Call the function under test.
await user.createNewUser(undefined, fakeRes);
// Set the expectations.
expect(fakeStatus).toHaveBeenCalledWith(500);
expect(fakeJson).toHaveBeenCalledWith({ msg: error.message });
expect(spy.mock.calls[0][0]).toBe(12);
});
});
});
When you run it on terminal:
$ npx jest user.controller.spec.js
PASS ./user.controller.spec.js
User Controller
create New User
✓ should return salt (5 ms)
✓ should return error message when error (1 ms)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
user.controller.js | 100 | 100 | 100 | 100 |
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.511 s, estimated 1 s
Ran all test suites matching /user.controller.spec.js/i.
Next, if you have sure with your controller, you can create integration test with express.
For example you create app index like this.
// File: index.js
const express = require('express');
const userController = require('./user.controller');
const router = express.Router();
router.post('/user', (req, res, next) => userController.createNewUser(req, res, next));
const app = express();
app.use('/api', router);
module.exports = app;
You can test it using jest for normal & error case like this.
// File: index.spec.js
const request = require('supertest');
const bcrypt = require('bcryptjs');
const server = require('./index');
const userController = require('./user.controller');
const agent = request.agent(server);
describe('App', () => {
describe('POST /', () => {
// Create spy on bcrypt.
const spy = jest.spyOn(bcrypt, 'genSalt');
const error = new Error('XXX');
afterEach(() => {
jest.clearAllMocks();
});
it('should create a salt successfully and return a 200 response code', async () => {
// This test is slow because directly call bcrypt.genSalt.
// To make it faster, mock bcrypt completely, or use spy.mockResolvedValue('SALT');
// Send post request.
const response = await agent.post('/api/user');
// Make sure the response.
expect(response.status).toBe(200);
expect(response.type).toBe('application/json');
expect(spy.mock.results[0].value).toBeDefined();
const spyResult = await spy.mock.results[0].value;
expect(response.body).toBe(spyResult)
});
it('should return 500 and error message when catch error', async () => {
// Makesure spy reject.
spy.mockRejectedValue(error);
// Send post request.
const response = await agent.post('/api/user');
// Make sure the response.
expect(response.status).toBe(500);
expect(response.type).toBe('application/json');
expect(response.body).toBeDefined();
expect(response.body.msg).toBeDefined();
expect(response.body.msg).toBe(error.message);
});
// Or play around with another spy to error alternatives.
it('should return 404 when pass to next', async () => {
// Makesure createNewUser error.
jest.spyOn(userController, 'createNewUser').mockImplementation((req, res, next) => {
// You can setup res here or other implementation to check.
// For example, do next.
next();
});
// Send post request.
const response = await agent.post('/api/user');
// Make sure the response.
expect(response.status).toBe(404);
// Method bcrypt.genSalt should not get called.
expect(spy).not.toHaveBeenCalled();
});
});
});
When you run it from terminal:
$ npx jest index.spec.js
PASS ./index.spec.js
App
POST /
✓ should create a salt successfully and return a 200 response code (40 ms)
✓ should return 500 and error message when catch error (4 ms)
✓ should return 404 when pass to next (5 ms)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.js | 100 | 100 | 100 | 100 |
user.controller.js | 100 | 100 | 100 | 100 |
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 0.809 s, estimated 1 s
Ran all test suites matching /index.spec.js/i.
Note: You do not need to use sinon, jest provides mock functions.

Jest + Supertest - API tests are using random ephemeral ports

I'm using Restify for my API and I'm trying to write tests for my endpoints.
At first, I had only a test for ping and it was okay, but now, after I added a new test, supertest is trying to ephemeral ports to the test server (80201).
I've searched a lot and tried some approaches that seem to work for most people but not for me. I'm probably messing something up, but I have no clue what it could be.
Check out my code:
server.js
require('dotenv').config();
const config = require('./config');
const routes = require('./src/routes');
const cors = require('restify-cors-middleware');
const http = require('http');
const https = require('https');
const restify = require('restify');
module.exports = function () {
http.globalAgent.keepAlive = true;
http.globalAgent.maxSockets = 256;
https.globalAgent.keepAlive = true;
https.globalAgent.maxSockets = 256;
const _cors = cors({
preflightMaxAge: 5,
origins: [new RegExp("^(https?:\/\/)?[-\w]+\.hackz\.co(\.\w+)?(:[\d]+)?$")],
allowHeaders: [
'authorization',
'x-requested-with',
'Content-MD5',
'Date',
'Accept-Version',
'Api-Version',
'Response-Time'
],
credentials: true
});
const server = restify.createServer({ name: config.apiName });
// Middlewares
server.pre(_cors.preflight);
server.use(_cors.actual);
server.use(restify.plugins.fullResponse());
server.use(restify.plugins.queryParser({ mapParams: true }));
server.use(restify.plugins.bodyParser({ mapParams: true }));
// Load Routes
routes.set(server);
server.on('error', function (req, res, route, error) {
if (error && (error.statusCode == null || error.statusCode !== 404)) {}
});
// Start Server
server.listen(config.apiPort, function () {
console.log(`${server.name} listening at ${server.url}.\nWe're in ${config.env} environment!`);
});
return server;
}();
tests/config/server.js
const server = require('../..');
const request = require('supertest');
function TestServer() {
return request(server);
}
module.exports = { TestServer };
tests/services/request.js
const { TestServer } = require("../config/server");
async function get(path, sessionkey = '', params = {}) {
const server = TestServer();
return await server
.get(path)
.query(params)
.set("authorization", sessionkey)
.set("content-type", "application/json")
;
}
async function post(path) {
const server = TestServer();
return await server
.post(path)
.set("content-type", "application/json")
;
}
module.exports = {
get,
post,
};
tests/config/setup.js
const server = require('../..');
afterAll(() => {
return server.close()
});
src/controllers/Ping.test.js
const { get } = require('../../tests/services/request');
describe('Ping Controller', () => {
describe('GET /ping', () => {
it('Should return 200', async () => {
const response = await get('/ping');
expect(response.status).toBe(200);
});
});
});
src/controllers/Session.test.js
const { post } = require('../../tests/services/request');
describe('Session Controller', () => {
const userId = 1;
describe('POST /:userId/create', () => {
it('Should create session successfully!', async () => {
const response = await post(`${userId}/create`);
expect(response.status).toBe(200);
expect(response.body.auth).toBe(true);
});
});
});
package.json (scripts and Jest config)
...
"scripts": {
"start": "node index.js",
"test": "jest --detectOpenHandles --forceExit --coverage",
"test:api": "npm run test -- --roots ./src/controllers"
},
...
"jest": {
"setupFilesAfterEnv": [
"jest-extended",
"<rootDir>/tests/config/setup.js"
],
...
}
This is the error output:
> user-session-api#1.0.0 test
> jest --detectOpenHandles --forceExit --coverage
FAIL src/controllers/Session.test.js
Session Controller
POST /:userId/create
✕ Should create session successfully! (39 ms)
● Session Controller › POST /:userId/create › Should create session successfully!
RangeError: Port should be >= 0 and < 65536. Received 80201.RangeError [ERR_SOCKET_BAD_PORT]: Port should be >= 0 and < 65536. Received 80201.
Things I've tried:
Passing the result of server.listen(...) (instead of the server instance) to supertest (as described here);
Using beforeEach for each test manually listening to a specific port;
This approach, which is similar to the first item.
HELP!
UPDATE:
Just realized that running npm run test "Ping.test.js" it succeeds and running npm run test "Session.test.js" (which is the new test) it fails. So there's probably something wrong with that single file.
I was also getting this error:
RangeError [ERR_SOCKET_BAD_PORT]: Port should be >= 0 and < 65536. Received 80201
Using supertest and Jest to test a NestJS application. I was also doing a
return request(app.getHttpServer())
.get(`route`)
Instead of
return request(app.getHttpServer())
.get(`/route`)
OH MY GOD!
I found the issue and, prepare yourself, the solution is ridiculous.
The request path in my test had a typo.
I was doing this:
const response = await post(`${userId}/create`); // with userId as 1
The path was missing an initial /, that's it haha.
THAT'S why supertest was appending a 1 to the server port and the RangeError was raised.
I'm hating myself right now.

res.body.some is not a function in node.js tests

I am writing some tests for a NodeJs API that I am creating and am getting an error when trying to check if a value exists in a MongoDB returned JSON object.
The error I am getting is:
TypeError: res.body.some is not a function
I am sampling some example code that I found, but I think perhaps the method may have been deprecated maybe.
If some is not a valid function what should be used instead?
Versions:
Node: v8.10.0
Express: 3.5.2
Request Object: const request = require('supertest');
Server Object
let server;
describe('/api/hosts', () => {
beforeEach(() => {
server = require('../../index');
})
afterEach(async () => {
await server.close();
await Host.deleteMany({});
});
Declaration of express and JSON parser:
const express = require('express');
const hosts = require('../routes/hosts');
module.exports = function(app) {
app.use(express.json());
app.use('/api/hosts', hosts);
}
Full Error:
GET /:ipV4
✕ should return a host when a valid IPv4 is passed (14ms)
● /api/hosts › GET /:ipV4 › should return a host when a valid IPv4 is passed
TypeError: res.body.some is not a function
61 |
62 | const res = await request(server).get('/api/hosts/' + host.ipV4);
> 63 | expect(res.body.some(h => h.ipV4 === '127.0.0.1')).toBeTruthy();
| ^
64 | expect(res.status).toBe(200);
65 | });
66 |
at Object.it (tests/integration/hosts.test.js:63:29)
Test
describe('GET /:ipV4', () => {
it('should return a host when a valid IPv4 is passed', async () => {
const host = new Host({ ipV4: '127.0.0.1' });
await host.save();
const res = await request(server).get('/api/hosts/' + host.ipV4);
expect(res.body.some(h => h.ipV4 === '127.0.0.1')).toBeTruthy();
expect(res.status).toBe(200);
});
});

How to solve listen EADDRINUSE: address already in use in integration tests

I am pretty new to Nodejs and i am learning Nodejs course on udemy, I am facing some trouble of listen EADDRINUSE: address already in use :::4000 while re-running integration tests multiple time. The first time its successful but afterward I am getting the above-mentioned error on the following line
const server = app.listen(port, () => {winston.info(`Listening on port ${port}`)});
I am pasting my index.js and two test files, if some can point me out it will be a great help for me.
Index.js
const Joi = require("#hapi/joi");
Joi.objectId = require("joi-objectid")(Joi);
const winston = require("winston");
const express = require("express");
const app = express();
require("./startup/logging")();
require("./startup/config")();
require("./startup/dbconnectivity")();
require("./startup/routes")(app);
const port = process.env.port || 4000;
const server = app.listen(port, () => {winston.info(`Listening on port ${port}`)});
// exporting server object to be used in integration tests.
module.exports = server;
**Integration test file for Genre**
const request = require("supertest");
let server;
const {Genere} = require("../../models/genere");
const {User} = require("../../models/user");
describe("/api/genere", () => {
beforeEach(() => {
console.log("Before each Genre");
server = require("../../index");
});
afterEach(async () => {
console.log("After each Genre");
await Genere.deleteMany({});
await server.close();
});
describe("/GET", () => {
it("should return list of generes", async() => {
await Genere.insertMany([
{name: "genre1"},
{name: "genre2"},
{name: "genre3"}
]);
const res = await request(server).get("/api/geners");
expect(res.status).toBe(200);
console.log("response body is : " + res.body);
expect(res.body.length).toBe(3);
expect(res.body.map(g => g.name)).toContain("genre1");
});
});
describe("/GET/:id", () => {
it("should return genre with id", async() => {
const genre = new Genere({name: "genre1"});
await genre.save();
const res = await request(server).get("/api/geners/"+ genre.id);
expect(res.status).toBe(200);
expect(res.body.name).toBe("genre1");
});
it("should return error with invalid id", async() => {
const genre = new Genere({name: "genre1"});
await genre.save();
const res = await request(server).get("/api/geners/1");
expect(res.status).toBe(404);
expect(res.text).toMatch(/Invalid/);
});
});
describe("/POST", () => {
it("should return 401 if not authorized", async() => {
const genere = new Genere({name: "genere1"});
const res = await request(server).post("/api/geners").send(genere);
expect(res.status).toBe(401);
});
it("should return 400 if the name is less than 4 chars", async() => {
const res = await createRequestWithGenre({name: "g1"});
expect(res.status).toBe(400);
});
it("should return 400 if the name is greater than 25 chars", async() => {
const genreName = Array(26).fill("a").join("");
const res = await createRequestWithGenre({name: genreName})
expect(res.status).toBe(400);
});
it("should return 201 with gener object if proper object is sent", async() => {
const res = await createRequestWithGenre({name: "genre1"})
expect(res.status).toBe(201);
expect(res.body).toHaveProperty("_id");
expect(res.body).toHaveProperty("name", "genre1");
const genre = await Genere.find({ name: "genre1"});
expect(genre).not.toBe(null);
});
async function createRequestWithGenre(genre) {
const token = new User().generateAuthToken();
return await request(server)
.post("/api/geners")
.set("x-auth-token", token)
.send(genre);
}
});
});
As soon as i add another file for integration test like the one below i started to get the error which is mentioned after this file code.
const {User} = require("../../models/user");
const {Genere} = require("../../models/genere");
const request = require("supertest");
let token;
describe("middleware", () => {
beforeEach(() => {
console.log("Before each Middleware");
token = new User().generateAuthToken();
server = require("../../index");
});
afterEach(async () => {
console.log("After each Middleware");
await Genere.deleteMany({});
await server.close();
});
const exec = async() => {
return await request(server)
.post("/api/geners")
.set("x-auth-token", token)
.send({name: "gener1"});
}
it("should return 400 if invalid JWT token is sent", async() => {
token = "invalid_token";
const res = await exec();
expect(res.status).toBe(400);
expect(res.text).toBe("Invalid auth token");
});
});
Console Error
middleware
✕ should return 400 if invalid JWT token is sent (510ms)
● middleware › should return 400 if invalid JWT token is sent
listen EADDRINUSE: address already in use :::4000
10 | require("./startup/routes")(app);
11 | const port = process.env.port || 4000;
> 12 | const server = app.listen(port, () => {winston.info(`Listening on port ${port}`)});
| ^
13 | // exporting server object to be used in integration tests.
14 | module.exports = server;
at Function.listen (node_modules/express/lib/application.js:618:24)
at Object.<anonymous> (index.js:12:20)
at Object.beforeEach (tests/integration/middleware.test.js:11:22)
If someone can help me why it fails on the multiple runs then it will be really helpful for me to understand why do we need to open and close server object every time.
Supertest is able to manage the setup/teardown of an express/koa app itself if you can import an instance of app without calling .listen() on it.
This involves structuring the code a little differently so app becomes a module, separate to the server .listen()
// app.js module
const app = require('express')()
require("./startup/logging")()
...
module.exports = app
Then the entrypoint for running the server imports the app then sets up the server with .listen()
// server.js entrypoint
const app = require('./app')
const port = process.env.port || 4000;
app.listen(port, () => {winston.info(`Listening on port ${port}`)});
When supertest uses the imported app, it will start its own server and listen on a random unused port without clashes.
// test
const request = require('supertest')
const app = require('./app')
request(app).get('/whatever')
The supertest "server" instance can be reused for multiple tests too
// reuse test
const supertest = require('supertest')
const app = require('./app')
describe('steps', () => {
const request = supertest(app)
it('should step1', async() => {
return request.get('/step1')
})
it('should step2', async() => {
return request.get('/step2')
})
})
One solution is to run jest with max workers specified to 1 which can be configured in your package.json in the following way:
"scripts": {
"test": "NODE_ENV=test jest --forceExit --detectOpenHandles --watchAll --maxWorkers=1"
},
If I understand your setup correctly, you have multiple intergration-test files which Jest will try to run in parallel (this is the default-mode). The error you're getting makes sense, since for each suite a new server instance is created before each test, but the server might already have been started while executing a different suite.
As described in the offical documentation instead of beforeEach it would make sense to use globalSetup where you would init your server once before running all test suites and stop the server afterwards:
// setup.js
module.exports = async () => {
// ...
// Set reference to your node server in order to close it during teardown.
global.__MY_NODE_SERVER__ = require("../../index");
};
// teardown.js
module.exports = async function() {
await global.__MY_NODE_SERVER__.stop();
};
// in your jest-config you'd set the path to these files:
module.exports = {
globalSetup: "<rootDir>/setup.js",
globalTeardown: "<rootDir>/teardown.js",
};
Alternatively you could run your tests with the --runInBand option and beforeAll instead of beforeEach in order to make sure that only one server is created before each test, but I'd recommend the first option.

Resources