diff --git a/CHANGELOG.md b/CHANGELOG.md index 4013ef2dd32d..66d8e321591e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ - `[jest-config]` [**BREAKING**] Add `mjs` and `cjs` to default `moduleFileExtensions` config ([#12578](https://github.com/facebook/jest/pull/12578)) - `[jest-config, jest-haste-map]` Allow searching for tests in `node_modules` by exposing `retainAllFiles` ([#11084](https://github.com/facebook/jest/pull/11084)) - `[jest-core]` [**BREAKING**] Exit with status `1` if no tests are found with `--findRelatedTests` flag ([#12487](https://github.com/facebook/jest/pull/12487)) +- `[jest-core]` Do not report unref-ed subprocesses as open handles ([#12705](https://github.com/facebook/jest/pull/12705)) - `[jest-each]` `%#` is not replaced with index of the test case ([#12517](https://github.com/facebook/jest/pull/12517)) - `[jest-each]` Fixes error message with incorrect count of missing arguments ([#12464](https://github.com/facebook/jest/pull/12464)) - `[jest-environment-jsdom]` Make `jsdom` accessible to extending environments again ([#12232](https://github.com/facebook/jest/pull/12232)) diff --git a/e2e/__tests__/detectOpenHandles.ts b/e2e/__tests__/detectOpenHandles.ts index 797ad18d59cb..97586bbbbf16 100644 --- a/e2e/__tests__/detectOpenHandles.ts +++ b/e2e/__tests__/detectOpenHandles.ts @@ -108,6 +108,17 @@ it('does not report timeouts using unref', () => { expect(textAfterTest).toBe(''); }); +it('does not report child_process using unref', () => { + // The test here is basically that it exits cleanly without reporting anything (does not need `until`) + const {stderr} = runJest('detect-open-handles', [ + 'child_process', + '--detectOpenHandles', + ]); + const textAfterTest = getTextAfterTest(stderr); + + expect(textAfterTest).toBe(''); +}); + it('prints out info about open handlers from inside tests', async () => { const run = runContinuous('detect-open-handles', [ 'inside', diff --git a/e2e/detect-open-handles/__tests__/child_process.js b/e2e/detect-open-handles/__tests__/child_process.js new file mode 100644 index 000000000000..3440138ba757 --- /dev/null +++ b/e2e/detect-open-handles/__tests__/child_process.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const {spawn} = require('child_process'); + +test('something', () => { + const subprocess = spawn( + process.argv[0], + [require.resolve('../interval-code')], + { + detached: true, + stdio: 'ignore', + }, + ); + subprocess.unref(); + expect(true).toBe(true); +}); diff --git a/e2e/detect-open-handles/interval-code.js b/e2e/detect-open-handles/interval-code.js new file mode 100644 index 000000000000..3e1309e032cf --- /dev/null +++ b/e2e/detect-open-handles/interval-code.js @@ -0,0 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +setInterval(() => { + console.log('XX'); +}, 1000); diff --git a/packages/jest-core/src/collectHandles.ts b/packages/jest-core/src/collectHandles.ts index 88fe14a4b1de..61afcf7fd846 100644 --- a/packages/jest-core/src/collectHandles.ts +++ b/packages/jest-core/src/collectHandles.ts @@ -93,24 +93,19 @@ export default function collectHandles(): HandleCollectionResult { if (fromUser) { let isActive: () => boolean; - if (type === 'Timeout' || type === 'Immediate') { - // Timer that supports hasRef (Node v11+) - if ('hasRef' in resource) { - if (hasWeakRef) { - // @ts-expect-error: doesn't exist in v12 typings - const ref = new WeakRef(resource); - isActive = () => { - return ref.deref()?.hasRef() ?? false; - }; - } else { - isActive = resource.hasRef.bind(resource); - } + // Handle that supports hasRef + if ('hasRef' in resource) { + if (hasWeakRef) { + // @ts-expect-error: doesn't exist in v12 typings + const ref = new WeakRef(resource); + isActive = () => { + return ref.deref()?.hasRef() ?? false; + }; } else { - // Timer that doesn't support hasRef - isActive = alwaysActive; + isActive = resource.hasRef.bind(resource); } } else { - // Any other async resource + // Handle that doesn't support hasRef isActive = alwaysActive; }