A Mehmeto
A Mehmeto

Reputation: 2009

Jest has detected the following 1 open handle potentially keeping Jest from exiting: TCPSERVERWRAP

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

Answers (12)

Zain Mansuri
Zain Mansuri

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

Maxwell
Maxwell

Reputation: 324

Had a similar problem with mongoose, I just added process.exit() in my global teardown file and that solved everything.

Upvotes: 1

clo
clo

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

AntiHero
AntiHero

Reputation: 21

Had the same issue.

    "test:e2e": "jest --config ./test/jest-e2e.json --no-cache --detectOpenHandles",

worked fine for me

Upvotes: 1

Toomuchrice4u
Toomuchrice4u

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

A Mehmeto
A Mehmeto

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

tonskton
tonskton

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

Ramin Ar
Ramin Ar

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

fadingbeat
fadingbeat

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

// on each test

it('the description', (done) => {
        request(app)
          .get('/some-path')
          .end(done);
  });

Upvotes: 0

ShadyAmoeba
ShadyAmoeba

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

Papooch
Papooch

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

Related Questions