Open handle detected in Node + Express API prevents Jest from exiting - node.js

I'm trying to test a very basic API made in Node + Express with Jest and Supertest but I'm getting the following output warning:
Jest has detected the following 1 open handle potentially keeping Jest from exiting:
● TCPSERVERWRAP
> 34 | const server = app.listen(PORT, () => {
| ^
35 | console.log(`Server is running on port ${PORT}.`);
36 | });
37 |
My server is defined like this on the server entry JS file:
const server = app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
module.exports = server;
And my test file looks like this:
describe('Users endpoint', () => {
let server;
beforeEach(() => { server = require('../server'); });
afterEach((done) => { server.close(done); });
it('should create new user if we do a POST', (done) => {
request(server)
.get('/api/users')
.expect(200)
.end(done);
});
});
As far as I know, calling server.close() passing the done argument on afterEach function should ensure the server closes after each unit test, but it doesn't.
Am I missing something?
ALREADY FOUND A SOLUTION
After adding a new test case besides the only one I had and modify the afterEach function removing the done argument like this:
afterEach(() => { server.close(); });
the open handle warning doesn't show anymore.

My server is defined like you. But I wanted to kill JEST after all my test where passed.
If someone wanna do the same
On the top of you file.test.js add
const server = require('../app');
And at the end
afterAll((done) => server.close(done));

Related

Ensure express app is running before starting mocha tests

I built an API for a couchbase database, using express and node.js. My problem is that when I run my tests some of them fail, because the server is not fully running. I found a solution here https://mrvautin.com/ensure-express-app-started-before-tests on how to solve this issue. The article stated that in order to solve this issue, you have to add an event emitter in your server file like this
app.listen(app_port, app_host, function () {
console.log('App has started');
app.emit("appStarted");
});
and then add this, in your test file
before(function (done) {
app.on("appStarted", function(){
done();
});
});
I have tried this, here is my implementation
Server File
app.listen(config['server']['port'], function(){
app.emit("appStarted");
logger.info("Listening")
})
Test File
before(function(done){
app.on("appStarted", function(){
done();
})
});
I keep on getting the following error
1) "before all" hook in "{root}":
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
at listOnTimeout (internal/timers.js:549:17)
at processTimers (internal/timers.js:492:7)
The article is from 2016, so I was thinking that maybe the syntax has been deprecated. I was wondering if someone could please help point me in the right direction?
You can add the below condition, more info see "Accessing the main module".
if (require.main === module) {
// this module was run directly from the command line as in node xxx.js
} else {
// this module was not run directly from the command line and probably loaded by something else
}
E.g.
index.ts:
import express from 'express';
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.sendStatus(200);
});
if (require.main === module) {
app.listen(port, () => {
console.log('App has started');
});
}
export { app, port };
index.test.ts:
import { app, port } from './';
import http from 'http';
import request from 'supertest';
describe('63822664', () => {
let server: http.Server;
before((done) => {
server = app.listen(port, () => {
console.log('App has started');
done();
});
});
after((done) => {
server.close(done);
console.log('App has closed');
});
it('should pass', () => {
return request(server)
.get('/')
.expect(200);
});
});
integration test result:
(node:22869) ExperimentalWarning: The fs.promises API is experimental
63822664
App has started
✓ should pass
App has closed
1 passing (26ms)
!Hi World! My little solution here:
Check this: All depends of your testing markup...
For example, I'm using Mocha and Chai Assertion Library.
const express = require('express');
const request = require("request");
const http = require("http");
const expect = require("chai").expect;
require('dotenv').config();
describe('Server', function() {
const { PORT } = process.env;
const app = express();
before((done) => {
http.Server = app.listen(PORT, () => {
console.log(`Listening Node.js server on port: ${PORT}`);
done();
});
});
it('should return 404 response code status', () => {
const url = `http://localhost:${PORT}/api/v1/yourPath`;
return request(url, (err, response, body) => {
/* Note this result 'cause I don't have any get('/')
controller o function to return another code status
*/
expect(response.statusCode).to.equal(404);
});
})
});

Why Jest doesn't recognise Server instance with Express.js?

First, I'm a bit of a beginner. I created an Express project using express-generator which contains a file: bin/www. www is actually a javascript file containing the server creation like below code snippet:
#!/usr/bin/env node
// This file is generated by express generator
var app = require('../app');
var debug = require('debug')('happy-meal:server');
var http = require('http');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var server = http.createServer(app);
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
function normalizePort(val) {}
function onError(error) {}
function onListening() {}
// Added by myself
exports.module = server;
The last line I added myself to get access to Server instance in jest test.
So, I want to run a simple integration test with the following code:
// integration test: users.test.js
const request = require("supertest");
describe("/api/v1/users", () => {
let server;
beforeEach(() => {
server = require("../../bin/www");
});
afterEach(() => {
server.close();
});
describe("GET /", () => {
it("should return all users", async (done) => {
const res = await request(server).get("/api/v1/users");
expect(res.status).toBe(200);
done();
});
});
});
This resulted in the following error output of jest:
TypeError: app.address is not a function
14 | describe("GET /", () => {
15 | it("should return all users", async (done) => {
> 16 | const res = await request(server).get("/api/v1/users");
| ^
17 |
18 | expect(res.status).toBe(200);
19 | done();
at Test.serverAddress (node_modules/supertest/lib/test.js:55:18)
at new Test (node_modules/supertest/lib/test.js:36:12)
at Object.get (node_modules/supertest/index.js:25:14)
at Object.<anonymous> (tests/integration/users.test.js:16:47)
● /api/v1/users › GET / › should return all users
TypeError: server.close is not a function
9 | });
10 | afterEach(() => {
> 11 | server.close();
| ^
12 | });
13 |
14 | describe("GET /", () => {
at Object.<anonymous> (tests/integration/users.test.js:11:16)
It looks like it doesn't recognise the "server"-variable as a Server object. Because of that, "server.close()" doesn't work, as a result the server is not shut down. Also the get-request doesn't work. Once again, the server object is not seen as a Server instance.
What am I doing wrong? I hope you can help me out here.
request(server) won't work, you have to use your app instance instead:
const app = require('../../app'); // Where your app instance is
...
const res = await request(app).get("/api/v1/users");
Also, try to import your server above all to see if it is recognized as Server object.
Edit
Either you want to create http server every test, either you want to do create http server once for all tests and then close it after tests end. Try this :
// integration test: users.test.js
const http = require('http');
const request = require("supertest")
const app = require('../../app'); // Where your app instance is
describe("/api/v1/users", () => {
beforeAll(done => {
server = http.createServer(app);
server.listen(done);
});
afterAll(done => {
server.close(done);
});
describe("GET /", () => {
it("should return all users", async (done) => {
const res = await request(app).get("/api/v1/users");
expect(res.status).toBe(200);
done();
});
});
});

why am getting server is already running on port 4000 even i have closed the server

I am running unit test with my node project using Jest library everything was working pretty fine. When I created new test for route authentication it starts showing server is already running on port 4000 even I am using afterEach() function to close the serve but don't know why am still getting server is already running on port 4000.
Even I have removed the new test for route authentication and restart my project by closing all the terminals but whenever I run the project it starts showing error that server is already running on port 4000.
Here is the code in user test file where am closing server properly and on the next test file I am again using same functions for server connection and closing.
const request = require("supertest");
const { Genre } = require("../../models/genre");
const { User } = require("../../models/user");
const mongoose = require("mongoose");
let server;
describe("/api/genres", () => {
beforeEach(() => {
server = require("../../index");
});
afterEach(async () => {
server.close();
await Genre.remove({});
});
second test file code
const { User } = require("../../models/user");
const { Genre } = require("../../models/genre");
const request = require("supertest");
describe("auth middleware", () => {
beforeEach(() => {
server = require("../../index");
});
afterEach(async () => {
await Genre.remove({});
server.close();
});
Here is the output of............................
● auth middleware › should return 401 if no token is provided
listen EADDRINUSE: address already in use :::4000
10 |
11 | const port = process.env.PORT || 4000;
> 12 | const server = app.listen(port, () =>
| ^
at Function.listen (node_modules/express/lib/application.js:618:24)
at Object.<anonymous> (index.js:12:20)
at Object.<anonymous> (tests/integration/auth.test.js:6:14)
Test Suites: 1 failed, 3 passed, 4 total
Tests: 1 failed, 26 passed, 27 total
Snapshots: 0 total
Time: 13.606s
Ran all test suites.
Index.js Code
const winston = require("winston");
const express = require("express");
const app = express();
require("./startup/logging")();
require("./startup/routes")(app);
require("./startup/db")();
require("./startup/config")();
require("./startup/validation")();
const port = process.env.PORT || 4000;
const server = app.listen(port, () =>
winston.info(`Listening on port ${port}...`)
);
module.exports = server;
I am not an expert in Node.js, but the nature of your bug is very simple; you're trying to listen on a port that is already being listened on.
This post offers a solid description of require(), which I believe is the source of your trouble.
By calling require("../../index") in each of your test case programs, you are effectively exporting server twice, which results in two app.listen() calls.
You would be infinitely better off exporting your server a single time to some main test program, in which you could then run all your test cases by calling require() on each of the test files. This approach is much better in the long run as well because adding additional test cases would 1000x easier; you could just write a new test script, export it to your main test program, and append it to your list of test cases.
Your test is creating the server (index.js) multiple times. This makes the server trying to listen to the same port in many instances. The Jest documentation reads,
If you have some work you need to do repeatedly for many tests, you
can use beforeEach and afterEach.
It is obvious that you should create the server one time, do all the tests and close it one time. The methods for this are beforeAll and afterAll.
In some cases, you only need to do setup once, at the beginning of a
file. This can be especially bothersome when the setup is
asynchronous, so you can't do it inline. Jest provides beforeAll and
afterAll to handle this situation.
So, your test should look like,
describe("auth middleware", () => {
beforeAll(() => {
server = require("../../index");
});
afterAll(async () => {
await Genre.remove({});
server.close();
});

EADDRINUSE :::3000 in jest

I know this error means that port 3000 is already in use but I also tried a different port but I am still getting the same errors for some specific tests only.
This is the code of one of those test
describe("GET /", () => {
it("should return all genres", async() => {
await Genre.collection.insertMany([
{name: 'genre1'},
{name: 'genre2'}
]);
const res = await request(server).get('/api/genres');
expect(res.status).toBe(200);
expect(res.body.length).toBe(2);
expect(res.body.some( g => g.name === 'genre1')).toBeTruthy();
expect(res.body.some( g => g.name === 'genre2')).toBeTruthy();
});
});
Any way to solve this error?
listen EADDRINUSE :::3000
10 |
11 | const port = process.env.PORT || 3000;
> 12 | const server = app.listen(port, () => winston.info(`Listening on port ${port}...`));
| ^
13 |
14 | module.exports = server;
15 |
at Function.listen (node_modules/express/lib/application.js:618:24)
at Object.listen (index.js:12:20)
● /api/returns › Should return 400 if customerId is not given
connect ECONNREFUSED 127.0.0.1:62801
This is what i'm getting in the console
I think that the issue is down to not closing the server between test runs in Jest.
If you're using jest --watch to run your tests then it might help to add an afterAll handler?
Example minimal express app:
// app.js
const express = require("express");
const app = express();
// Server port
const HTTP_PORT = 3000;
// Start server
server = app.listen(HTTP_PORT, () => {
//console.log(`Server running on port ${HTTP_PORT}`);
});
// Root endpoint
app.get("/", (req, res, next) => {
res.json({"message":"Ok yah!"})
});
// Default response for any other request
app.use(function(req, res){
res.status(404);
});
module.exports = server;
Test file:
// app.test.js
const app = require('../app');
describe('GET /', () => {
let response;
it('proves Jest works', () => {
expect(1).toBe(1);
});
it('proves maths still works', () => {
expect(1+1).toBe(2);
});
});
// remembering to CLOSE the server after tests completed.
afterAll(async () => {
await app.close();
});

NodeJS: Error found: listen EADDRINUSE :::3000?

I'm currently facing a bug that I can't resolve and I have been struggling for some hours.
I'm using the following versions:
Node: 8.11.3
Express: 4.16.3
Jest: 22.2.2
Mongoose: 5.2.3
I'm trying to do some integration tests with jest and I have 2 files with tests.
In each file I wrote the following:
// Create the server before each test.
beforeEach(() => {
server = require('../../index');
});
// Close the server after each test.
afterEach(async () => {
if (server) {
server.close();
}
});
In index.js I have the following (This is not all the code, but the relevant code for the bug):
// Listen to the server.
const port = config.PORT || process.env.PORT || 3000;
module.exports = app.listen(port, () => {
winston.info(`Listening to port ${port}...`);
});
When I run npm test
I get this exception all the time:
**listen EADDRINUSE :::3000**
10 | // Listen to the server
11 | const port = config.PORT || process.env.PORT || 3000;
> 12 | module.exports = app.listen(port, () => {
13 | winston.info(`Listening to port ${port}...`);
14 | });
15 |
I tried several ways to solve this by adding async await to beforeEach and for afterEach and tried also to put the sever.close in afterAll and in beforeAll but still got the same error.
Then, I tried to solve by doing this:
How Do I Shut Down My Express Server Gracefully When Its Process Is Killed?
But again, with no luck.
Finally, when I wrote all the tests in 1 file, it works without this error. Does anybody know how to solve this? I don't want to write all my integration tests in 1 file..
Thanks!
Try setting the --runInBand flag, this will run your tests sequentially.
https://jestjs.io/docs/en/cli#runinband
In package.json scripts:
"scripts": {
...
"test": "jest --watchAll --verbose --runInBand",
...
}
[UPDATE] On further investigation, while you can use --runInBand to run your tests sequentially, another option is to await the server.close() since it returns a promise. As such, in your afterEach:
...
await server.close();
...
[UPDATE] I believe a better way to solve this issue is to separate out the index.js file into an index.js and a server.js file. This enables you to pull your index.js file into your tests without .listen:
// index.js
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.status(200).send({ hello: "world!" });
});
module.exports = app;
Then in a separate server.js file:
const server = require("./index");
const PORT = process.env.PORT || 3001;
server.listen(PORT, () => {
console.log(`App running on: ${PORT}`);
});
module.exports = server;
When running your app, you run: node server.js.
This then enables you to test your routes by pulling your index.js file into your test as follows:
// test.js
const request = require("supertest");
const server = require("./index");
describe("GET /", () => {
test("should return status 200", async () => {
const res = await request(server).get("/");
expect(res.status).toBe(200);
});
});
I am following the same course and had the same issue. --runInBand solved it for me.
The issue here is requiring server file multiple times. You shouldn't require server file like that. Each time you do that, an instance starts, in your first test file an instance of server already started, while requiring server for your second file, it tries to start another instance, but then your server is already running on 3000 and hence the error.
I think your port 3000 is busy somewhere else Or maybe this app is running on somewhere else in the terminal, Check it and close all the instances of this app.
Or
Try to use below code:
// Listen to the server
11 | const port = config.PORT || process.env.PORT || 3001; // CHANGE POST 3000-> 3001
> 12 | module.exports = app.listen(port, () => {
13 | winston.info(`Listening to port ${port}...`);
14 | });

Resources