jest: TLSWRAP open handle wrongly detected with MongoDB connections

đź’Ą Regression Report

Running Jest with --detectOpenHandles detects a TLSWRAP potential open handle on MongoDb connections, even if they are properly closed in an “afterAll” enclosure and jest exits without issues. The exact message is:

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

  â—Ź  TLSWRAP

       6 |
       7 | beforeAll(async () => {
    >  8 |   await client.connect()
         |                ^
       9 | })
      10 |
      11 | afterAll(async () => {

      at Object.resolveSRVRecord (node_modules/mongodb/src/connection_string.ts:69:7)
      at Object.connect (node_modules/mongodb/src/operations/connect.ts:51:12)
      at node_modules/mongodb/src/mongo_client.ts:410:7
      at Object.maybePromise (node_modules/mongodb/src/utils.ts:618:3)
      at MongoClient.connect (node_modules/mongodb/src/mongo_client.ts:409:12)
      at app.test.js:8:16
      at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
      at runJest (node_modules/@jest/core/build/runJest.js:387:19)
      at _run10000 (node_modules/@jest/core/build/cli/index.js:408:7)
      at runCLI (node_modules/@jest/core/build/cli/index.js:261:3)

This seems to happen with MongoDb’s official NodeJs driver, and, by extension, any other packages that use that driver (in my case I got it with mongoose and connect-mongo-session)

Last working version

Worked up to version: 26.6.3

Stopped working in version: 27.0.0

To Reproduce

NOTE: A valid MongoDB URI is needed to reproduce this issue.

Within an empty directory:

  1. Create a new empty Node project with:
npm init 
  1. Install jest and mongodb
npm install jest mongodb
  1. Create a app.test.js file with following contents (add a valid MongoDB URI where necessary):
const { MongoClient } = require("mongodb");

// Replace the uri string with your MongoDB connection string.
const uri ='YOUR-MONGODB-URI'
const client = new MongoClient(uri)

beforeAll(async () => {
  await client.connect()
})

afterAll(async () => {
  await client.close()
})

test('testing', () => {
  expect(client).toBeDefined()
})
  1. Run the test with jest and --detectOpenHandles
jest --detectOpenHandles

Expected behavior

No open handles should be found.

Link to repl or repo (highly encouraged)

Use the code snippet provided above.

Run npx envinfo --preset jest

Paste the results here:

System:
    OS: macOS 11.4
    CPU: (8) arm64 Apple M1
  Binaries:
    Node: 16.4.2 - /opt/local/bin/node
    npm: 7.19.1 - /opt/local/bin/npm
  npmPackages:
    jest: ^27.0.0 => 27.0.6 

Thank you for your help! ❤️

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 19
  • Comments: 24 (4 by maintainers)

Most upvoted comments

The problem seems to be that the Async hooks module in Node doesn’t emit a destroy event for the “TLSWRAP” hook type.

In Jest we have today something like:

if (type === 'PROMISE' ||
    type === 'TIMERWRAP' ||
    type === 'ELDHISTOGRAM' ||
    type === 'PerformanceObserver' ||
    type === 'RANDOMBYTESREQUEST' ||
    type === 'DNSCHANNEL' ||
    type === 'ZLIB'
  ) return;

These are all problematic hook types that are simply ignored. And “TLSWRAP” should probably be added to this list.

(Since there is always an underlying socket object which is what we’re really interested in.)

But to test this, we’d have to set up a TLS session object which is not exactly trivial.

I have the same issue with something as simple as this using axios

import axios from "axios";

it("runs without open handles", async () => {
  await axios.get("https://jsonplaceholder.typicode.com/todos/1");
  expect(true).toBe(true);
});

“axios”: “^0.21.4”, “jest”: “^27.2.4”, “ts-jest”: “^27.0.5”

I have a much simpler reproduction for this issue:

const tls = require('tls');

describe('Test', () => {
  it("runs a test", () => {
      const socket = new tls.TLSSocket();
      socket.destroy();
  });
});

Prints:

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

  â—Ź  TLSWRAP

      3 | describe('Test', () => {
      4 |   it("runs a test", () => {
    > 5 |       const socket = new tls.TLSSocket();
        |                      ^
      6 |       socket.destroy();
      7 |   });
      8 | });

      at Object.<anonymous> (index.test.ts:5:22)

Having the same issue with Axios

I’m having the same issue as well

I can confirm having exactly the same issue with Jest 27.0.4.