From 9e19f782e574a17c566d1f51c5b7e32641c4e4f8 Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Sun, 9 Oct 2022 06:21:59 +0800 Subject: [PATCH] fix --- CHANGELOG.md | 1 + .../src/__tests__/collectHandles.test.js | 12 +++++++ packages/jest-core/src/collectHandles.ts | 31 +++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8db5b756640b..c8d87a2d1d70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - `[jest-reporters]` Revert: Transform file paths into hyperlinks ([#13399](https://github.com/facebook/jest/pull/13399)) - `[@jest/types]` Infer type of `each` table correctly when the table is a tuple or array ([#13381](https://github.com/facebook/jest/pull/13381)) - `[@jest/types]` Rework typings to allow the `*ReturnedWith` matchers to be called with no argument ([#13385](https://github.com/facebook/jest/pull/13385)) +- `[jest-core]` Fix `collectHandles` false positives for some special objects such as `TLSWRAP`. ([#13414](https://github.com/facebook/jest/pull/13414)) ### Chore & Maintenance diff --git a/packages/jest-core/src/__tests__/collectHandles.test.js b/packages/jest-core/src/__tests__/collectHandles.test.js index 229ccb9a2c7a..2455149f4526 100644 --- a/packages/jest-core/src/__tests__/collectHandles.test.js +++ b/packages/jest-core/src/__tests__/collectHandles.test.js @@ -10,6 +10,7 @@ import * as crypto from 'crypto'; import {promises as dns} from 'dns'; import http from 'http'; import {PerformanceObserver} from 'perf_hooks'; +import {TLSSocket} from 'tls'; import zlib from 'zlib'; import collectHandles from '../collectHandles'; @@ -134,4 +135,15 @@ describe('collectHandles', () => { expect.objectContaining({message: 'TCPSERVERWRAP'}), ); }); + + it('should collect handles for some special objects such as `TLSWRAP`', async () => { + const handleCollector = collectHandles(); + + const socket = new TLSSocket(); + socket.destroy(); + + const openHandles = await handleCollector(); + + expect(openHandles).toHaveLength(0); + }); }); diff --git a/packages/jest-core/src/collectHandles.ts b/packages/jest-core/src/collectHandles.ts index 5e69fd920e71..2cc5f7c76b7e 100644 --- a/packages/jest-core/src/collectHandles.ts +++ b/packages/jest-core/src/collectHandles.ts @@ -8,6 +8,8 @@ /* eslint-disable local/ban-types-eventually */ import * as asyncHooks from 'async_hooks'; +import * as v8 from 'v8'; +import * as vm from 'vm'; import {promisify} from 'util'; import stripAnsi = require('strip-ansi'); import type {Config} from '@jest/types'; @@ -45,6 +47,27 @@ const hasWeakRef = typeof WeakRef === 'function'; const asyncSleep = promisify(setTimeout); +let gcFunc: typeof global.gc | undefined; +function runGC() { + if (!gcFunc) { + if (typeof global.gc === 'function') { + gcFunc = global.gc; + } else { + v8.setFlagsFromString('--expose-gc'); + gcFunc = vm.runInNewContext('gc'); + v8.setFlagsFromString('--no-expose-gc'); + if (!gcFunc) { + console.warn( + 'Cannot find `global.gc` function. Please run node with `--expose-gc`', + ); + gcFunc = () => {}; + } + } + } + + gcFunc(); +} + // Inspired by https://github.com/mafintosh/why-is-node-running/blob/master/index.js // Extracted as we want to format the result ourselves export default function collectHandles(): HandleCollectionResult { @@ -125,6 +148,14 @@ export default function collectHandles(): HandleCollectionResult { // callback, we will not yet have seen the resource be destroyed here. await asyncSleep(100); + if (activeHandles.size !== 0) { + // For some special objects such as `TLSWRAP`. + // Ref: https://github.com/facebook/jest/issues/11665 + runGC(); + + await asyncSleep(0); + } + hook.disable(); // Get errors for every async resource still referenced at this moment