-
Notifications
You must be signed in to change notification settings - Fork 764
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open handle keeps Jest from exiting ( TCPSERVERWRAP) #520
Comments
@lucianonooijen Does it works if you manually invoke |
@jonathansamines I tried adding afterEach(() => app.close()); and afterEach(app.close()); but both give the same error:
Did I invoke them wrong or am I missing something somewhere? |
+1 i could use help with this issue also, same env as above and same errors. |
@lucianonooijen @danielantelo Sorry about that, I sometimes confuse the express app with the server object. When supertest is used in an express application not yet bound to a port, it will try to automatically bound it to a random port, holding a reference to the net server internally. To gain control over that process, you may want to try manually listen on a port yourself, so that you can close the connections manually. let server, agent;
beforeEach((done) => {
server = app.listen(4000, (err) => {
if (err) return done(err);
agent = request.agent(server); // since the application is already listening, it should use the allocated port
done();
});
});
afterEach((done) => {
return server && server.close(done);
});
it('description', async () => {
// use agent instead of manually calling `request(app)` each time
await agent.get('/some-path-relative-to-the-express-app')
}); As an alternative to setting up an agent, you can also use the // on each test
it('the description', (done) => {
request(app)
.get('/some-path')
.end(done);
}); However, I am not sure how well this method plays with the promise based interface, because as you can see is expecting a callback. References: Hope it helps! |
thanks for the reply @jonathansamines , appreciate it! Still having issues tho. This is my setupTestFrameworkScriptFile:
and then a test in another file:
my tests pass, but jest does not exit due to open handles in using Any ideas what i am missing on the setup before/afters? Much appreciated! |
@danielantelo @lucianonooijen Unless you are promisifying the server methods |
@jonathansamines you mean passing the done like in your example?
this is not solving it either |
@danielantelo What error are you getting while using the callback based api? |
got it working with just jest/supertest/mongoose (removing mockgoose). Thanks for the help.
Now time to figure out the issue with mockgoose 😂 |
This fix doesn't work if you have multiple test files. The server doesn't seem to be closing properly and you will get port collisions when trying to start the server in the different test files.
|
@skykanin you are right, after i got mockgoose working i realised that when i ran multiple files there was still an issue. With mockgoose i had to close the connection after each test, otherwise would leave open handles on a single file. But doing that on the server just breaks things further. So think we are now stuck on the same issue.
Jest23 runs the first file, then fails to run any other files and gives lots of async timeout errors. |
@danielantelo Sorry, I am not familiar with the mockgoose library. Most I can do, is to ask a couple of questions: Is await Promise.all(mongoose.connections.map(con => con.close())) Here I am assumming Also, is |
Are you using Apollo Engine by any chance? I was able to solve this problem by disabling the engine in Apollo Server when testing. |
I'm not using Apollo Engine and I still get the same error. |
I have the same issue:Node version: 11.0.0 package.json {
"name": "authentication",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"lint": "eslint --fix server.js src/**",
"start": "node server.js",
"start:dev": "nodemon server.js",
"test": "jest --forceExit --detectOpenHandles"
},
"husky": {
"hooks": {
"post-pull": "npm install",
"pre-commit": "npm run lint && npm test"
}
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^3.0.3",
"body-parser": "^1.18.3",
"dotenv": "^6.2.0",
"express": "^4.16.4",
"jsonwebtoken": "^8.4.0",
"lodash": "^4.17.11",
"morgan": "^1.9.1"
},
"devDependencies": {
"eslint": "^5.11.1",
"eslint-plugin-node": "^8.0.1",
"eslint-plugin-security": "^1.4.0",
"husky": "^1.3.1",
"jest": "^23.6.0",
"nodemon": "^1.18.9",
"prettier": "^1.15.3",
"supertest": "^3.3.0"
}
}
test task in package.json "scripts": {
"test": "jest --forceExit --detectOpenHandles"
}, app.test.js const request = require('supertest');
const app = require('../app');
describe('App Request', () => {
it('should responds with 404', () => {
request(app)
.get('/')
.expect('Content-Type', /json/)
.expect(404)
.end((error, response) => {
if (error) {
return error;
}
return response;
});
});
}); Error:
|
Try this in your app.test
|
I am experiencing the same error. I suppose a solution for the time being is to use --forceExit with Jest. |
I found out that if you are using process.env in any test it also won't exit. |
I'd chased this down, just to find out that it was a simple forgetfulness on my part. Our application fell back on the database that wasn't set up on CI or stubbed, causing a long wait that manifested in tl;dr Check your application for other reasons that your request could hang |
i also have the same problem, need help, did some solved it ? |
For me this did the trick afterAll(async () => {
await new Promise(resolve => setTimeout(() => resolve(), 500)); // avoid jest open handle error
}); Seems like it needs some more ticks to close that handle. |
@yss14 Thanks for your help, It solved the issue for me too, which I was chasing for couple of days but can you elaborate why this resolve the issues? |
i"m also interested in knowing how it solves the issue. |
@sharmaar12 @angristan I don't know the reason for sure, because I'm not familiar with the supertest code base. I guess that during the shutdown of supertest, somewhere the thread is not waiting for an async system operation to finish. Thus, the operation is delegated to the system but the execution is not blocked or does not wait for the async operation to finish. In the meantime, your test case execution finishes, jest is shuting down, and complains about an open handle. If I'm wrong, please someone corrects me :) |
This didn't helped me. But I manged to force Jest to exit with this flag: However I am still getting the warring that Jest detected an open handle. |
Were any other solutions found for this issue? I have a similar problem. When I run my test suite normally, I get the warning that Jest did not exit one second after completion of the test run. Calling with If I add @yss14 's code in the I'm testing a middleware function, and my suite looks like this:
Binding to a port and closing manully does not work, nor does getting rid of Does anyone have any ideas? This is a serious issue because it seems that every test suite that relies on Express/Supertest is leaking memory, eventually to the point that my tests terminate with a Thank you. |
More detailed information for my above comment can be found in this SO question: https://stackoverflow.com/questions/56027190/jest-memory-leak-testing-express-middleware |
@lucianonooijen @danielantelo @marcospgp Did you ever find a solution other than |
@JamieCorkhill have you tried any of the suggestions stated at this comment? If any of those worked for you, it is very likely that the actual issue is somewhere else in your application. I could help with that, but I'll need an isolated reproduction example to take a look at. |
For me, it was solved with a condition for adding the listener to the app if not 'test'. Jest run as NODE_ENV=test if (process.env.NODE_ENV !== 'test') {
app.listen(port, (): void => {
console.log(`Server running on port ${port}`);
});
} And for avoiding this warning (https://github.com/lorenwest/node-config/wiki/Strict-Mode), I added a config json file with |
Hi @niftylettuce , is there any workaround for this? None of the above solutions seem to work and this is coming in very simple individual tests as well. |
Hello, I was doing the following test of the code, since I am following this course https://fullstackopen.com/en/part4/testing_the_backend
which the message is generated: Jest did not exit one second after the test run has completed. I decided to continue adding tests to the file since I did not find a solution and I came across the following note.
so that I am running 2 additional tests on the same file that involve modifying the database and it no longer shows me the jest message. Best regards |
I think this one is the answer! |
This solution worked for me. |
Thanks, this work for me |
I eliminated my open handle errors by restarting my pc. But restart in my case helps for only one run of tests only. Then errors are back. |
This worked!package.json"scripts": {
"test": "dotenv -e .env.test -- jest -i"
}
server.ts// Listen to requests
const applistener = app.listen(PORT, () => {
console.log(`Web server is running on port ${PORT}.`);
});
export default applistener; test-file1.tsimport supertest from "supertest";
import app from "../../server";
const request = supertest(app);
describe("Books Endpoints Tests", () => {
afterAll(() => {
app.close()
})
describe("GET /books", () => {
test("Return array of books", async () => {
const response = await request.get("/books");
expect(response.status).toBe(200);
});
});
}); test-file2.tsimport supertest from "supertest";
import app from "../../server";
const prisma = new PrismaClient();
const request = supertest(app);
describe("Expression Endpoints Tests", () => {
afterAll(async () => {
await prisma.$executeRaw`TRUNCATE TABLE expressions CASCADE`;
await prisma.$executeRaw`ALTER SEQUENCE expressions_id_seq RESTART WITH 1`;
app.close();
});
describe("POST /expressions", () => {
test("Create new expression and return it", async () => {
const response = await request.post("/expressions").send({
"textu": "exp1",
"textf": "exp1.1",
"definition": "exp-def"
});
expect(response.status).toBe(201);
expect(response.body.data.textf).toBe("exp1.1");
expect(response.body.data.definition).toBe("exp-def");
});
});
}); Sounds weird, but this is how it worked with me! |
Tried this out but ran into a couple of issues that I think is caused by this:
|
In my case, all I did to solve the problem, was install weak-napi as a dev dependency and then set detectLeaks and detectOpenHandles to true in my jest config file like so:
|
@nfroidure Thanks for doing this digging, my excellent internet friend! I am no longer getting the
nastygram warning at the end of my functional tests after I added the
I find that I still have an unaccounted-for 30 second pause after the tests run unless I add Generally speaking, there are multiple unacceptable pauses I am seeing when running this Express+Supertest combo that make the test suites lag horribly. I would like all the suites to finish in a second or two, but it takes more like 20 seconds to complete and most of that time is spent before any test cases have yet run. What's the holdup? Thanks again, you improved my quality of life!
|
just remove --detectOpenHandles from command. |
I was facing the same issue and it turned out the MySQL connection stays active after finish the test and prevent Jest from closing. So I think this can be your mongoose db connection manager? Thanks |
Hello ! I just had the problem and fixed it (I think). I made the http server starting listening (just did |
For some reason, removing
mostly occurs when await request(app.getHttpServer())
.post('/load/tag/index/create')
.send(payload); |
I was having similar issue with Mongoose and getting beforeAll(async () => {
await mongoose.connect(MONGODB_URL, MONGODB_OPTIONS);
});
describe('Sum', () => {
it('should return 2 for 1 + 1', async () => {
expect(1 + 1).toBe(2);
});
});
afterAll(async () => {
await mongoose.disconnect();
}); Simply connecting and disconnecting from Mongoose was causing issues. 👇 Jest has detected the following 1 open handle potentially keeping Jest from exiting:
● TLSWRAP
9 |
10 | beforeAll(async () => {
> 11 | await mongoose.connect(MONGODB_URL, MONGODB_OPTIONS);
| ^
12 | });
13 |
14 | describe('Sum', () => {
at resolveSRVRecord (node_modules/mongodb/src/connection_string.ts:80:7) I've tried pretty much all suggestions here. beforeAll(async () => {
await new Promise((res) => {
setTimeout(res, 1);
});
await mongoose.connect(MONGODB_URL, MONGODB_OPTIONS);
}); ☝️ Notice the duration for setTimeout does not have to be more than 1 ms. This smells like a process nextTick issue somewhere. Meanwhile Mongoose website screams to not use Jest with Mongoose apps and not to use global setups and not to use fake timers etc... But of course I didn't listen and thought what could go wrong. Now ended up wasting hours.. SolutionI am not fan of using timers to fix things, so for now I am moving forward with just calling disconnect in beforeAll(async () => {
await mongoose.disconnect();
await mongoose.connect(MONGODB_URL, MONGODB_OPTIONS);
}); I am hoping this holds for me and helps anyone else out there 🤙 |
I had the same issue. I was providing both |
I too would like to see a great way to fix this. From someone who has a complete understanding of why it happens. This person could describe the optimal and clean solution. |
For me, it was solved with a condition for adding the listener and mongoose
|
@jonathansamines 's first solution worked for me. Here is an working example with async/await syntax of it: beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [AppModule], // your app module
}).compile();
app = module.createNestApplication();
server = await app.listen(5325);
await app.init();
});
it(`do something`, async () => {
const result = await request(server).post('/cats').send(catDto);
expect(result.status).toBe(201);
const { body } = result;
expect(body.name).toEqual(catDto.name);
expect(body.age).toEqual(catDto.age);
expect(body.breed).toEqual(catDto.breed);
});
afterEach(async () => {
await app.close();
await server.close();
}); |
I was having this issue and eventually traced it back to an issue with Jest and its If you are using |
I tried all candidate solutions mentioned here. Thanks all for share. It seems that there is an odd behavior with Mongoose and an internal import type {Server} from 'http';
import {agent as request} from 'supertest';
let server: Server;
beforeAll(async () => {
server = await initServer();
});
afterAll(async () => {
server.close();
});
it(`POST "${v1}/products" responds with the entity created`, async () => {
const payload: IProduct = { /* ... */ };
// odd fix for Jest open handle error
await Promise.resolve(process.nextTick(Boolean));
const reply = await request(server).post(`${v1}/products`).send(payload);
expect(reply.statusCode).toEqual(200);
}); |
That issue was happening to me as well, but since my solution was quite different from other solutions posted here, I decided to share the issue (wich was not related to supertest itself). import { MongoClient as mc } from 'mongodb'
import expresss from 'express'
import { Server } from 'socket.io'
const client = new mc(url)
const app = expresss()
const server = protocol.createServer(app)
server.listen(port, () =>() ))
const io = new Server(server)
const mdb = await client.connect()
export {server, io, mdb} And then in my test file: import { server, io, mdb } from '../app.mjs'
after(() => {
server.close()
io.close()
mdb.close()
}) I hope that helps. |
Error:
Env:
Testcode:
Full console output:
The text was updated successfully, but these errors were encountered: