Reputation: 2009
I am doing a basic end to end testing here, for the moment it's failing, but first I can't get rid of the open handle.
Ran all test suites.
Jest has detected the following 1 open handle potentially keeping Jest from exiting:
● TCPSERVERWRAP
40 | }
41 | return request(app.getHttpServer())
> 42 | .post('/graphql')
| ^
43 | .send(mutation)
44 | .expect(HttpStatus.OK)
45 | .expect((response) => {
at Test.Object.<anonymous>.Test.serverAddress (../node_modules/supertest/lib/test.js:61:33)
at new Test (../node_modules/supertest/lib/test.js:38:12)
at Object.obj.<computed> [as post] (../node_modules/supertest/index.js:27:14)
at Object.<anonymous> (app.e2e-spec.ts:42:8)
import { Test, TestingModule } from '@nestjs/testing'
import { HttpStatus, INestApplication } from "@nestjs/common";
import * as request from 'supertest'
import { AppModule } from '../src/app.module'
describe('AppController (e2e)', () => {
let app: INestApplication
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile()
app = moduleFixture.createNestApplication()
await app.init()
})
afterAll(async () => {
await app.close()
})
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(HttpStatus.OK)
.expect('Hello World!')
})
it('mutation', async () => {
const mutation = {
query: `mutation Create($title: String!) {
create(title: $title) {
id,
title
}
}`,
variables: {
title: 'Mon programme',
},
}
return request(app.getHttpServer())
.post('/graphql')
.send(mutation)
.expect(HttpStatus.OK)
.expect( (response) => {
expect(response.body).toBe({
id: expect.any(String),
title: 'Mon programme',
})
})
})
})
Any idea what's blocking the test runner ?
Note that, as I am using NestJs, I shouldn't need to use the .end(done)
method at the end of the test.
PS: apparently I have to much code on this question and I need to add some more details, but have no clue what I can say more.
Upvotes: 42
Views: 80135
Reputation: 1
Error: TCPWRAP
In my case, I was closing mongo connection in global teardown, but in one of my testcase file I was declaring mongo used functionality and functions but not using anywhere, removed those and worked.
Upvotes: 0
Reputation: 324
Had a similar problem with mongoose, I just added process.exit()
in my global teardown file and that solved everything.
Upvotes: 1
Reputation: 11
For me I had to close connection with the server and with my db's client.
afterAll(async () => {
await server.close();
await pool.end();
});
Upvotes: 1
Reputation: 21
Had the same issue.
"test:e2e": "jest --config ./test/jest-e2e.json --no-cache --detectOpenHandles",
worked fine for me
Upvotes: 1
Reputation: 628
This is the problem right here
it('/ (GET)', () => {
return request(app.getHttpServer())
^^^^^^^^^^^^^^^^^^^^^
.get('/')
.expect(HttpStatus.OK)
.expect('Hello World!')
})
The server isn't being closed and remains open after the test. You need to create a variable to reference the instance and close it after each test. I just spent a couple of hours trying to figure this out. And hope this helps anyone experiencing similar issues.
Here is an example of your code with my idea for a fix:
describe('AppController (e2e)', () => {
let app: INestApplication
let server: SERVER_TYPE
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile()
app = moduleFixture.createNestApplication()
await app.init()
// Reference the server instance
server = app.getHttpServer()
})
afterEach(async () => {
await app.close()
// Close the server instance after each test
server.close()
})
it('/ (GET)', async () => {
// Make the request on the server instance
return await request(server)
.get('/')
.expect(HttpStatus.OK)
.expect('Hello World!')
})
Also, I noticed you're using beforeEach
and afterAll
. You're creating a new app each time for each test so I think that could also cause some issues for the HTTP server. I'm not certain on that though.
import { Test, TestingModule } from '@nestjs/testing'
import { HttpStatus, INestApplication } from "@nestjs/common";
import * as request from 'supertest'
import { AppModule } from '../src/app.module'
beforeEach(() => {
...
})
afterEach(() => {
...
})
describe('tests', () => {
...
})
But, that's just my preference, up to you. :)
UPDATE: Meant to use beforeEach
not beforeAll
because we need to close the server before EACH test, not a global setup and teardown.
UPDATE 2: Using async/await otherwise, it will always pass because request is asynchronous and doesn't complete unless you wait for it to finish.
Upvotes: 26
Reputation: 2009
I still haven't found a perfect solution, but for the moment I went for this workaround :
jest --config ./test/jest-e2e.json --forceExit
The --forceExit option kill the openHandles somehow and unlock everything. Yet, I'm still looking for the "proper way" of handling that issue.
Upvotes: 43
Reputation: 71
To anyone who still encountering error even though you already close the connection and its and intermittent error you can try to add --no-cache --watchAll
. Below is the full syntax:
"test": "jest --watchAll --no-cache --detectOpenHandles"
Upvotes: 7
Reputation: 1331
Also check your package.json
file in the scripts
section to find the test:e2e
key. Check the value of it and remove the parameter --detectOpenHandles
.
the key-value pair of script can be as follow: "test:e2e": "jest --config ./test/jest-e2e.json --forceExit"
Upvotes: -1
Reputation: 433
Answer from Toomuchrice4u has helped me. I had a logout method in one of the services that component uses, so I called it in afterEach
, like this:
afterEach(async () => {
await userService.logout();
});
Upvotes: 0
Reputation: 11
// on each test
it('the description', (done) => {
request(app)
.get('/some-path')
.end(done);
});
Upvotes: 0
Reputation: 577
Instead of it
try using test
and pass done
as a parameter and call that. This worked for me.
test('mutation', async (done) => {
const mutation = {
query: `mutation Create($title: String!) {
create(title: $title) {
id,
title
}
}`,
variables: {
title: 'Mon programme',
},
}
const response = request(app.getHttpServer())
.post('/graphql')
.send(mutation)
expect(response).to.be(HttpStatus.Ok)
done()
})
Upvotes: 0
Reputation: 1645
You are re-creating the whole app again beforeEach
, but tearing it down only in afterAll
, which means you are probably leaking some memory along the way. You are assigning a new instance to the app variable, but there are most likely hidden references that prevent the garbage colletor from clearing the previous instance - like the reference that the request
function got.
Change beforeEach
to beforeAll
and you should be good to go.
Upvotes: 10