Skip to content

Commit e72e24f

Browse files
committed
fix
1 parent 1ba37a3 commit e72e24f

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- `[jest-reporters]` Revert: Transform file paths into hyperlinks ([#13399](https://github.com/facebook/jest/pull/13399))
1515
- `[@jest/types]` Infer type of `each` table correctly when the table is a tuple or array ([#13381](https://github.com/facebook/jest/pull/13381))
1616
- `[@jest/types]` Rework typings to allow the `*ReturnedWith` matchers to be called with no argument ([#13385](https://github.com/facebook/jest/pull/13385))
17+
- `[jest-core]` Fix `detectOpenHandles` false positives for some special objects such as `TLSWRAP`. ([#13414](https://github.com/facebook/jest/pull/13414))
1718

1819
### Chore & Maintenance
1920

packages/jest-core/src/__tests__/collectHandles.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import * as crypto from 'crypto';
1010
import {promises as dns} from 'dns';
1111
import http from 'http';
1212
import {PerformanceObserver} from 'perf_hooks';
13+
import {TLSSocket} from 'tls';
1314
import zlib from 'zlib';
1415
import collectHandles from '../collectHandles';
1516

@@ -134,4 +135,15 @@ describe('collectHandles', () => {
134135
expect.objectContaining({message: 'TCPSERVERWRAP'}),
135136
);
136137
});
138+
139+
it('should collect handles for some special objects such as `TLSWRAP`', async () => {
140+
const handleCollector = collectHandles();
141+
142+
const socket = new TLSSocket();
143+
socket.destroy();
144+
145+
const openHandles = await handleCollector();
146+
147+
expect(openHandles).toHaveLength(0);
148+
});
137149
});

packages/jest-core/src/collectHandles.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
/* eslint-disable local/ban-types-eventually */
99

1010
import * as asyncHooks from 'async_hooks';
11+
import * as v8 from 'v8';
12+
import * as vm from 'vm';
1113
import {promisify} from 'util';
1214
import stripAnsi = require('strip-ansi');
1315
import type {Config} from '@jest/types';
@@ -45,6 +47,27 @@ const hasWeakRef = typeof WeakRef === 'function';
4547

4648
const asyncSleep = promisify(setTimeout);
4749

50+
let gcFunc: typeof global.gc | undefined;
51+
function runGC() {
52+
if (!gcFunc) {
53+
if (typeof global.gc === 'function') {
54+
gcFunc = global.gc;
55+
} else {
56+
v8.setFlagsFromString('--expose-gc');
57+
gcFunc = vm.runInNewContext('gc');
58+
v8.setFlagsFromString('--no-expose-gc');
59+
if (!gcFunc) {
60+
console.warn(
61+
'Cannot find `global.gc` function. Please run node with `--expose-gc`',
62+
);
63+
gcFunc = () => {};
64+
}
65+
}
66+
}
67+
68+
gcFunc();
69+
}
70+
4871
// Inspired by https://github.com/mafintosh/why-is-node-running/blob/master/index.js
4972
// Extracted as we want to format the result ourselves
5073
export default function collectHandles(): HandleCollectionResult {
@@ -125,6 +148,14 @@ export default function collectHandles(): HandleCollectionResult {
125148
// callback, we will not yet have seen the resource be destroyed here.
126149
await asyncSleep(100);
127150

151+
if (activeHandles.size !== 0) {
152+
// For some special objects such as `TLSWRAP`.
153+
// Ref: https://github.com/facebook/jest/issues/11665
154+
runGC();
155+
156+
await asyncSleep(0);
157+
}
158+
128159
hook.disable();
129160

130161
// Get errors for every async resource still referenced at this moment

0 commit comments

Comments
 (0)