Skip to content

Commit

Permalink
feat(jest-config): openHandlesTimeout config option (#13875)
Browse files Browse the repository at this point in the history
  • Loading branch information
robhogan committed Feb 23, 2023
1 parent 39a0e05 commit ab510f5
Show file tree
Hide file tree
Showing 16 changed files with 74 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@

- `[jest-changed-files]` Support Sapling ([#13941](https://github.com/facebook/jest/pull/13941))
- `[jest-cli, jest-config, @jest/core, jest-haste-map, @jest/reporters, jest-runner, jest-runtime, @jest/types]` Add `workerThreads` configuration option to allow using [worker threads](https://nodejs.org/dist/latest/docs/api/worker_threads.html) for parallelization ([#13939](https://github.com/facebook/jest/pull/13939))
- `[jest-config]` Add `openHandlesTimeout` option to configure possible open handles warning. ([#13875](https://github.com/facebook/jest/pull/13875))
- `[@jest/create-cache-key-function]` Allow passing `length` argument to `createCacheKey()` function and set its default value to `16` on Windows ([#13827](https://github.com/facebook/jest/pull/13827))
- `[jest-message-util]` Add support for [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) ([#13946](https://github.com/facebook/jest/pull/13946))
- `[jest-worker]` Add `start` method to worker farms ([#13937](https://github.com/facebook/jest/pull/13937))
Expand Down
4 changes: 4 additions & 0 deletions docs/CLI.md
Expand Up @@ -310,6 +310,10 @@ Activates notifications for test results. Good for when you don't want your cons

Alias: `-o`. Attempts to identify which tests to run based on which files have changed in the current repository. Only works if you're running tests in a git/hg repository at the moment and requires a static dependency graph (ie. no dynamic requires).

### `--openHandlesTimeout=<milliseconds>`

When `--detectOpenHandles` and `--forceExit` are _disabled_, Jest will print a warning if the process has not exited cleanly after this number of milliseconds. A value of `0` disables the warning. Defaults to `1000`.

### `--outputFile=<filename>`

Write test results to a file when the `--json` option is also specified. The returned JSON structure is documented in [testResultsProcessor](Configuration.md#testresultsprocessor-string).
Expand Down
6 changes: 6 additions & 0 deletions docs/Configuration.md
Expand Up @@ -1078,6 +1078,12 @@ Specifies notification mode. Requires `notify: true`.
- `success-change`: send a notification when tests pass or once when it fails.
- `failure-change`: send a notification when tests fail or once when it passes.

### `openHandlesTimeout` \[number]

Default: `1000`

Print a warning indicating that there are probable open handles if Jest does not exit cleanly this number of milliseconds after it completes. Use `0` to disable the warning.

### `preset` \[string]

Default: `undefined`
Expand Down
8 changes: 7 additions & 1 deletion e2e/__tests__/__snapshots__/detectOpenHandles.ts.snap
Expand Up @@ -7,7 +7,13 @@ exports[`prints message about flag on forceExit 1`] = `"Force exiting Jest: Have
exports[`prints message about flag on slow tests 1`] = `
"Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with \`--detectOpenHandles\` to troubleshoot this issue."
'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with \`--detectOpenHandles\` to troubleshoot this issue."
`;

exports[`prints message about flag on slow tests with a custom timeout 1`] = `
"Jest did not exit 0.5 seconds after the test run has completed.
'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with \`--detectOpenHandles\` to troubleshoot this issue."
`;

exports[`prints out info about open handlers 1`] = `
Expand Down
2 changes: 2 additions & 0 deletions e2e/__tests__/__snapshots__/showConfig.test.ts.snap
Expand Up @@ -44,6 +44,7 @@ exports[`--showConfig outputs config info and exits 1`] = `
],
"moduleNameMapper": [],
"modulePathIgnorePatterns": [],
"openHandlesTimeout": 1000,
"prettierPath": "prettier",
"resetMocks": false,
"resetModules": false,
Expand Down Expand Up @@ -121,6 +122,7 @@ exports[`--showConfig outputs config info and exits 1`] = `
"notifyMode": "failure-change",
"onlyChanged": false,
"onlyFailures": false,
"openHandlesTimeout": 1000,
"passWithNoTests": false,
"projects": [],
"rootDir": "<<REPLACED_ROOT_DIR>>",
Expand Down
14 changes: 14 additions & 0 deletions e2e/__tests__/detectOpenHandles.ts
Expand Up @@ -29,6 +29,20 @@ it('prints message about flag on slow tests', async () => {
expect(textAfterTest).toMatchSnapshot();
});

it('prints message about flag on slow tests with a custom timeout', async () => {
const run = runContinuous('detect-open-handles', [
'outside',
'--openHandlesTimeout=500',
]);
await run.waitUntil(({stderr}) =>
stderr.includes('Jest did not exit 0.5 seconds'),
);
const {stderr} = await run.end();
const textAfterTest = getTextAfterTest(stderr);

expect(textAfterTest).toMatchSnapshot();
});

it('prints message about flag on forceExit', async () => {
const run = runContinuous('detect-open-handles', ['outside', '--forceExit']);
await run.waitUntil(({stderr}) => stderr.includes('Force exiting Jest'));
Expand Down
6 changes: 6 additions & 0 deletions packages/jest-cli/src/args.ts
Expand Up @@ -423,6 +423,12 @@ export const options: {[key: string]: Options} = {
description: 'Run tests that failed in the previous execution.',
type: 'boolean',
},
openHandlesTimeout: {
description:
'Print a warning about probable open handles if Jest does not exit ' +
'cleanly after this number of milliseconds. `0` to disable.',
type: 'number',
},
outputFile: {
description:
'Write test results to a file when the --json option is ' +
Expand Down
12 changes: 9 additions & 3 deletions packages/jest-cli/src/run.ts
Expand Up @@ -132,18 +132,24 @@ const readResultsAndExit = (
}

exit(code);
} else if (!globalConfig.detectOpenHandles) {
} else if (
!globalConfig.detectOpenHandles &&
globalConfig.openHandlesTimeout !== 0
) {
const timeout = globalConfig.openHandlesTimeout;
setTimeout(() => {
console.warn(
chalk.yellow.bold(
'Jest did not exit one second after the test run has completed.\n\n',
`Jest did not exit ${
timeout === 1000 ? 'one second' : `${timeout / 1000} seconds`
} after the test run has completed.\n\n'`,
) +
chalk.yellow(
'This usually means that there are asynchronous operations that ' +
"weren't stopped in your tests. Consider running Jest with " +
'`--detectOpenHandles` to troubleshoot this issue.',
),
);
}, 1000).unref();
}, timeout).unref();
}
};
1 change: 1 addition & 0 deletions packages/jest-config/src/Defaults.ts
Expand Up @@ -60,6 +60,7 @@ const defaultOptions: Config.DefaultOptions = {
noStackTrace: false,
notify: false,
notifyMode: 'failure-change',
openHandlesTimeout: 1000,
passWithNoTests: false,
prettierPath: 'prettier',
resetMocks: false,
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-config/src/ValidConfig.ts
Expand Up @@ -116,6 +116,7 @@ export const initialOptions: Config.InitialOptions = {
notifyMode: 'failure-change',
onlyChanged: false,
onlyFailures: false,
openHandlesTimeout: 1000,
passWithNoTests: false,
preset: 'react-native',
prettierPath: '<rootDir>/node_modules/prettier',
Expand Down Expand Up @@ -262,6 +263,7 @@ export const initialProjectOptions: Config.InitialProjectOptions = {
},
modulePathIgnorePatterns: ['<rootDir>/build/'],
modulePaths: ['/shared/vendor/modules'],
openHandlesTimeout: 1000,
preset: 'react-native',
prettierPath: '<rootDir>/node_modules/prettier',
resetMocks: false,
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-config/src/index.ts
Expand Up @@ -113,6 +113,7 @@ const groupOptions = (
notifyMode: options.notifyMode,
onlyChanged: options.onlyChanged,
onlyFailures: options.onlyFailures,
openHandlesTimeout: options.openHandlesTimeout,
outputFile: options.outputFile,
passWithNoTests: options.passWithNoTests,
projects: options.projects,
Expand Down Expand Up @@ -169,6 +170,7 @@ const groupOptions = (
moduleNameMapper: options.moduleNameMapper,
modulePathIgnorePatterns: options.modulePathIgnorePatterns,
modulePaths: options.modulePaths,
openHandlesTimeout: options.openHandlesTimeout,
prettierPath: options.prettierPath,
resetMocks: options.resetMocks,
resetModules: options.resetModules,
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/normalize.ts
Expand Up @@ -912,6 +912,7 @@ export default async function normalize(
case 'notifyMode':
case 'onlyChanged':
case 'onlyFailures':
case 'openHandlesTimeout':
case 'outputFile':
case 'passWithNoTests':
case 'replname':
Expand Down
Expand Up @@ -28,6 +28,7 @@ exports[`prints the config object 1`] = `
"moduleNameMapper": [],
"modulePathIgnorePatterns": [],
"modulePaths": [],
"openHandlesTimeout": 1000,
"prettierPath": "prettier",
"resetMocks": false,
"resetModules": false,
Expand Down Expand Up @@ -90,6 +91,7 @@ exports[`prints the config object 1`] = `
"notifyMode": "failure-change",
"onlyChanged": false,
"onlyFailures": false,
"openHandlesTimeout": 1000,
"passWithNoTests": false,
"projects": [],
"reporters": [],
Expand Down

0 comments on commit ab510f5

Please sign in to comment.