From 125101d32a3e72493f3291a3cae354ae3f636c3a Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Thu, 28 Dec 2023 09:39:09 +0800 Subject: [PATCH 1/5] fix --- .../src/__tests__/collectHandles.test.js | 12 ++----- packages/jest-core/src/collectHandles.ts | 35 +++++++++---------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/packages/jest-core/src/__tests__/collectHandles.test.js b/packages/jest-core/src/__tests__/collectHandles.test.js index 0c77e7783e11..d34e6272928e 100644 --- a/packages/jest-core/src/__tests__/collectHandles.test.js +++ b/packages/jest-core/src/__tests__/collectHandles.test.js @@ -32,10 +32,8 @@ describe('collectHandles', () => { it('should not collect the PerformanceObserver open handle', async () => { const handleCollector = collectHandles(); - let obs = new PerformanceObserver((list, observer) => {}); + const obs = new PerformanceObserver((list, observer) => {}); obs.observe({entryTypes: ['mark']}); - obs.disconnect(); - obs = null; const openHandles = await handleCollector(); @@ -47,12 +45,9 @@ describe('collectHandles', () => { it('should not collect the DNSCHANNEL open handle', async () => { const handleCollector = collectHandles(); - let resolver = new dns.Resolver(); + const resolver = new dns.Resolver(); resolver.getServers(); - // We must drop references to it - resolver = null; - const openHandles = await handleCollector(); expect(openHandles).not.toContainEqual( @@ -141,11 +136,10 @@ describe('collectHandles', () => { ); }); - it('should not be false positives for some special objects such as `TLSWRAP`', async () => { + it('should not collect the `TLSWRAP` open handle', async () => { const handleCollector = collectHandles(); const socket = new TLSSocket(); - socket.destroy(); const openHandles = await handleCollector(); diff --git a/packages/jest-core/src/collectHandles.ts b/packages/jest-core/src/collectHandles.ts index 2f16c999f54c..02d52afe744c 100644 --- a/packages/jest-core/src/collectHandles.ts +++ b/packages/jest-core/src/collectHandles.ts @@ -9,8 +9,7 @@ import * as asyncHooks from 'async_hooks'; import {promisify} from 'util'; -import * as v8 from 'v8'; -import * as vm from 'vm'; +import {getHeapSnapshot} from 'v8'; import stripAnsi = require('strip-ansi'); import type {Config} from '@jest/types'; import {formatExecError} from 'jest-message-util'; @@ -46,20 +45,9 @@ const hasWeakRef = typeof WeakRef === 'function'; const asyncSleep = promisify(setTimeout); -let gcFunc: (() => void) | undefined = (globalThis as any).gc; function runGC() { - if (!gcFunc) { - v8.setFlagsFromString('--expose-gc'); - gcFunc = vm.runInNewContext('gc'); - v8.setFlagsFromString('--no-expose-gc'); - if (!gcFunc) { - throw new Error( - 'Cannot find `global.gc` function. Please run node with `--expose-gc` and report this issue in jest repo.', - ); - } - } - - gcFunc(); + // It is more aggressive than `gc()`. + getHeapSnapshot(); } // Inspired by https://github.com/mafintosh/why-is-node-running/blob/master/index.js @@ -82,7 +70,20 @@ export default function collectHandles(): HandleCollectionResult { // Skip resources that should not generally prevent the process from // exiting, not last a meaningfully long time, or otherwise shouldn't be // tracked. - if (type === 'PROMISE') { + if ( + [ + 'PROMISE', + 'TIMERWRAP', + 'ELDHISTOGRAM', + 'PerformanceObserver', + 'RANDOMBYTESREQUEST', + 'DNSCHANNEL', + 'ZLIB', + 'SIGNREQUEST', + 'TLSWRAP', + 'TCPWRAP', + ].includes(type) + ) { return; } const error = new ErrorWithStack(type, initHook, 100); @@ -136,8 +137,6 @@ export default function collectHandles(): HandleCollectionResult { await asyncSleep(30); if (activeHandles.size > 0) { - // For some special objects such as `TLSWRAP`. - // Ref: https://github.com/jestjs/jest/issues/11665 runGC(); await asyncSleep(0); From 280f5d0e354ea5c7c51bd88c26476c900a541438 Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Thu, 28 Dec 2023 09:49:59 +0800 Subject: [PATCH 2/5] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca32e2a69b4c..79e575e5a977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - `[@jest/core]` [**BREAKING**] Group together open handles with the same stack trace ([#13417](https://github.com/jestjs/jest/pull/13417), & [#14543](https://github.com/jestjs/jest/pull/14543)) - `[@jest/core]` Add `perfStats` to surface test setup overhead ([#14622](https://github.com/jestjs/jest/pull/14622)) - `[@jest/core]` [**BREAKING**] Changed `--filter` to accept an object with shape `{ filtered: Array }` to match [documentation](https://jestjs.io/docs/cli#--filterfile) ([#13319](https://github.com/jestjs/jest/pull/13319)) +- `[@jest/core]` [**BREAKING**] Revert breaking changes for `detectOpenHandles`. ([#14789](https://github.com/jestjs/jest/pull/14789)) - `[@jest/core, @jest/test-sequencer]` [**BREAKING**] Exposes `globalConfig` & `contexts` to `TestSequencer` ([#14535](https://github.com/jestjs/jest/pull/14535), & [#14543](https://github.com/jestjs/jest/pull/14543)) - `[jest-environment-jsdom]` [**BREAKING**] Upgrade JSDOM to v22 ([#13825](https://github.com/jestjs/jest/pull/13825)) - `[@jest/environment-jsdom-abstract]` Introduce new package which abstracts over the `jsdom` environment, allowing usage of custom versions of JSDOM ([#14717](https://github.com/jestjs/jest/pull/14717)) From 6c70cf75dbefd8d4e70da3da41b3ebaca418df0a Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Thu, 28 Dec 2023 10:27:22 +0800 Subject: [PATCH 3/5] update test --- e2e/__tests__/__snapshots__/detectOpenHandles.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/__tests__/__snapshots__/detectOpenHandles.ts.snap b/e2e/__tests__/__snapshots__/detectOpenHandles.ts.snap index 904ae1025ae1..67fed22a3f21 100644 --- a/e2e/__tests__/__snapshots__/detectOpenHandles.ts.snap +++ b/e2e/__tests__/__snapshots__/detectOpenHandles.ts.snap @@ -19,7 +19,7 @@ exports[`prints message about flag on slow tests with a custom timeout 1`] = ` exports[`prints out info about open handlers 1`] = ` "Jest has detected the following 1 open handle potentially keeping Jest from exiting: - ● DNSCHANNEL,TCPSERVERWRAP + ● TCPSERVERWRAP 12 | const app = new Server(); 13 | From 9543abb5787f7eb591faf1c3e52c297630285f29 Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Thu, 28 Dec 2023 17:34:59 +0800 Subject: [PATCH 4/5] review --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79e575e5a977..ef81ea88accc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,9 @@ - `[jest-config]` [**BREAKING**] Add `mts` and `cts` to default `moduleFileExtensions` config ([#14369](https://github.com/facebook/jest/pull/14369)) - `[jest-config]` [**BREAKING**] Update `testMatch` and `testRegex` default option for supporting `mjs`, `cjs`, `mts`, and `cts` ([#14584](https://github.com/jestjs/jest/pull/14584)) - `[jest-config]` Loads config file from provided path in `package.json` ([#14044](https://github.com/facebook/jest/pull/14044)) -- `[@jest/core]` [**BREAKING**] Group together open handles with the same stack trace ([#13417](https://github.com/jestjs/jest/pull/13417), & [#14543](https://github.com/jestjs/jest/pull/14543)) +- `[@jest/core]` [**BREAKING**] Group together open handles with the same stack trace ([#13417](https://github.com/jestjs/jest/pull/13417), & [#14789](https://github.com/jestjs/jest/pull/14789)) - `[@jest/core]` Add `perfStats` to surface test setup overhead ([#14622](https://github.com/jestjs/jest/pull/14622)) - `[@jest/core]` [**BREAKING**] Changed `--filter` to accept an object with shape `{ filtered: Array }` to match [documentation](https://jestjs.io/docs/cli#--filterfile) ([#13319](https://github.com/jestjs/jest/pull/13319)) -- `[@jest/core]` [**BREAKING**] Revert breaking changes for `detectOpenHandles`. ([#14789](https://github.com/jestjs/jest/pull/14789)) - `[@jest/core, @jest/test-sequencer]` [**BREAKING**] Exposes `globalConfig` & `contexts` to `TestSequencer` ([#14535](https://github.com/jestjs/jest/pull/14535), & [#14543](https://github.com/jestjs/jest/pull/14543)) - `[jest-environment-jsdom]` [**BREAKING**] Upgrade JSDOM to v22 ([#13825](https://github.com/jestjs/jest/pull/13825)) - `[@jest/environment-jsdom-abstract]` Introduce new package which abstracts over the `jsdom` environment, allowing usage of custom versions of JSDOM ([#14717](https://github.com/jestjs/jest/pull/14717)) From 838dc913778c8bd69ae502dc26f030386a2a5869 Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Mon, 1 Jan 2024 12:09:37 +0800 Subject: [PATCH 5/5] revert and changelog --- CHANGELOG.md | 2 +- packages/jest-core/src/collectHandles.ts | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef81ea88accc..86d006b78741 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - `[jest-config]` [**BREAKING**] Add `mts` and `cts` to default `moduleFileExtensions` config ([#14369](https://github.com/facebook/jest/pull/14369)) - `[jest-config]` [**BREAKING**] Update `testMatch` and `testRegex` default option for supporting `mjs`, `cjs`, `mts`, and `cts` ([#14584](https://github.com/jestjs/jest/pull/14584)) - `[jest-config]` Loads config file from provided path in `package.json` ([#14044](https://github.com/facebook/jest/pull/14044)) -- `[@jest/core]` [**BREAKING**] Group together open handles with the same stack trace ([#13417](https://github.com/jestjs/jest/pull/13417), & [#14789](https://github.com/jestjs/jest/pull/14789)) +- `[@jest/core]` Group together open handles with the same stack trace ([#13417](https://github.com/jestjs/jest/pull/13417), & [#14789](https://github.com/jestjs/jest/pull/14789)) - `[@jest/core]` Add `perfStats` to surface test setup overhead ([#14622](https://github.com/jestjs/jest/pull/14622)) - `[@jest/core]` [**BREAKING**] Changed `--filter` to accept an object with shape `{ filtered: Array }` to match [documentation](https://jestjs.io/docs/cli#--filterfile) ([#13319](https://github.com/jestjs/jest/pull/13319)) - `[@jest/core, @jest/test-sequencer]` [**BREAKING**] Exposes `globalConfig` & `contexts` to `TestSequencer` ([#14535](https://github.com/jestjs/jest/pull/14535), & [#14543](https://github.com/jestjs/jest/pull/14543)) diff --git a/packages/jest-core/src/collectHandles.ts b/packages/jest-core/src/collectHandles.ts index 02d52afe744c..8ef0faa684f2 100644 --- a/packages/jest-core/src/collectHandles.ts +++ b/packages/jest-core/src/collectHandles.ts @@ -9,7 +9,8 @@ import * as asyncHooks from 'async_hooks'; import {promisify} from 'util'; -import {getHeapSnapshot} from 'v8'; +import * as v8 from 'v8'; +import * as vm from 'vm'; import stripAnsi = require('strip-ansi'); import type {Config} from '@jest/types'; import {formatExecError} from 'jest-message-util'; @@ -45,9 +46,20 @@ const hasWeakRef = typeof WeakRef === 'function'; const asyncSleep = promisify(setTimeout); +let gcFunc: (() => void) | undefined = (globalThis as any).gc; function runGC() { - // It is more aggressive than `gc()`. - getHeapSnapshot(); + if (!gcFunc) { + v8.setFlagsFromString('--expose-gc'); + gcFunc = vm.runInNewContext('gc'); + v8.setFlagsFromString('--no-expose-gc'); + if (!gcFunc) { + throw new Error( + 'Cannot find `global.gc` function. Please run node with `--expose-gc` and report this issue in jest repo.', + ); + } + } + + gcFunc(); } // Inspired by https://github.com/mafintosh/why-is-node-running/blob/master/index.js