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')
})
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With