Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implement async_hooks manually
  • Loading branch information
SimenB committed May 6, 2018
commit 1b1545114cd109444325266c38ce41f4e9e2b897
4 changes: 2 additions & 2 deletions docs/CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ Print debugging info about your Jest config.
Attempt to collect and print open handles preventing Jest from exiting cleanly.
Use this in cases where you need to use `--forceExit` in order for Jest to exit
to potentially track down the reason. Implemented using
[`why-is-node-running`](https://github.com/mafintosh/why-is-node-running), so it
only works in Node 8 and newer.
[`async_hooks`](https://nodejs.org/api/async_hooks.html), so it only works in
Node 8 and newer.

### `--env=<environment>`

Expand Down
5 changes: 1 addition & 4 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -963,10 +963,7 @@ structure as the first argument and return it:
"numPassedTests": number,
"numFailedTests": number,
"numPendingTests": number,
"openHandles": Array<{
title: string,
entries: Array<{file: string, line: string}>,
}>,
"openHandles": Array<Error>,
"testResults": [{
"numFailingTests": number,
"numPassingTests": number,
Expand Down
3 changes: 0 additions & 3 deletions packages/jest-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@
"which": "^1.2.12",
"yargs": "^11.0.0"
},
"optionalDependencies": {
"why-is-node-running": "^2.0.2"
},
"bin": {
"jest": "./bin/jest.js"
},
Expand Down
19 changes: 2 additions & 17 deletions packages/jest-cli/src/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import type {GlobalConfig, Path, ProjectConfig} from 'types/Config';
import {Console, clearLine, createDirectory} from 'jest-util';
import {validateCLIOptions} from 'jest-validate';
import {readConfig, deprecationEntries} from 'jest-config';
import {formatStackTrace} from 'jest-message-util';
import {version as VERSION} from '../../package.json';
import * as args from './args';
import chalk from 'chalk';
import createContext from '../lib/create_context';
import exit from 'exit';
import getChangedFilesPromise from '../get_changed_files_promise';
import {formatHandleErrors} from '../get_node_handles';
import fs from 'fs';
import handleDeprecationWarnings from '../lib/handle_deprecation_warnings';
import logDebugMessages from '../lib/log_debug_messages';
Expand Down Expand Up @@ -106,27 +106,12 @@ export const runCLI = async (
const {openHandles} = results;

if (openHandles && openHandles.length) {
const handles = openHandles
.map(({title, entries}) => ({
// Fake column to make it a valid stack trace
stack: entries.map(({file}) => `at ${file}:0`).join('\n'),
title,
}))
.map(
({title, stack}) =>
title +
'\n' +
// First config should be fine
formatStackTrace(stack, configs[0], {noStackTrace: false}),
)
.join('\n\n');

const openHandlesString = pluralize('open handle', openHandles.length, 's');

const message =
chalk.red(
`\nJest has detected the following ${openHandlesString} potentially keeping Jest from exiting:\n\n`,
) + handles;
) + formatHandleErrors(openHandles, configs[0]).join('\n\n');

console.error(message);
}
Expand Down
50 changes: 0 additions & 50 deletions packages/jest-cli/src/format_why_node_running.js

This file was deleted.

77 changes: 77 additions & 0 deletions packages/jest-cli/src/get_node_handles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. 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.
*
* @flow
*/

import type {ProjectConfig} from 'types/Config';

import {formatStackTrace, separateMessageFromStack} from 'jest-message-util';

// 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(): () => Array<Error> {
const activeHandles: Map<string, Error> = new Map();

function initHook(asyncId, type) {
const error = new Error(type);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using an error here for the free sourcemap support it provides. Then I don't need to talk to runtime to get them


if (Error.captureStackTrace) {
Error.captureStackTrace(error, initHook);
}

if (error.stack.includes('Runtime.requireModule')) {
activeHandles.set(asyncId, error);
}
}

let hook;

try {
// $FlowFixMe: Node core module
const asyncHooks = require('async_hooks');
hook = asyncHooks.createHook({
destroy(asyncId) {
activeHandles.delete(asyncId);
},
init: initHook,
});

hook.enable();
} catch (e) {
const nodeMajor = Number(process.versions.node.split('.')[0]);
if (e.code === 'MODULE_NOT_FOUND' && nodeMajor < 8) {
throw new Error(
'You can only use --detectOpenHandles on Node 8 and newer.',
);
} else {
throw e;
}
}

return () => {
hook.disable();

const result = Array.from(activeHandles.values());

activeHandles.clear();

return result;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can save a bit of vertical space by removing the newlines in this function :P

};
}

export function formatHandleErrors(
errors: Array<Error>,
config: ProjectConfig,
): Array<string> {
return errors.map(err => {
const {message, stack} = separateMessageFromStack(err.stack);

return (
message + '\n\n' + formatStackTrace(stack, config, {noStackTrace: false})
);
});
}
25 changes: 7 additions & 18 deletions packages/jest-cli/src/run_jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import TestSequencer from './test_sequencer';
import {makeEmptyAggregatedTestResult} from './test_result_helpers';
import FailedTestsCache from './failed_tests_cache';
import JestHooks, {type JestHookEmitter} from './jest_hooks';
import formatWhyRunning from './format_why_node_running';
import collectNodeHandles from './get_node_handles';

const setConfig = (contexts, newConfig) =>
contexts.forEach(
Expand Down Expand Up @@ -75,11 +75,11 @@ const processResults = (runResults, options) => {
onComplete,
outputStream,
testResultsProcessor,
whyRunning,
collectHandles,
} = options;

if (whyRunning) {
runResults.openHandles = formatWhyRunning(whyRunning);
if (collectHandles) {
runResults.openHandles = collectHandles();
} else {
runResults.openHandles = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can get rid of this check by assigning default value to whyRunning

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meh, it gave me lots of flow issues

}
Expand Down Expand Up @@ -254,21 +254,10 @@ export default (async function runJest({
// paths when printing.
setConfig(contexts, {cwd: process.cwd()});

let whyRunning;
let collectHandles;

if (globalConfig.detectOpenHandles) {
try {
whyRunning = require('why-is-node-running');
} catch (e) {
const nodeMajor = Number(process.versions.node.split('.')[0]);
if (e.code === 'MODULE_NOT_FOUND' && nodeMajor < 8) {
throw new Error(
'You can only use --detectOpenHandles on Node 8 and newer.',
);
} else {
throw e;
}
}
collectHandles = collectNodeHandles();
}

if (globalConfig.globalSetup) {
Expand Down Expand Up @@ -308,11 +297,11 @@ export default (async function runJest({
await globalTeardown();
}
return processResults(results, {
collectHandles,
isJSON: globalConfig.json,
onComplete,
outputFile: globalConfig.outputFile,
outputStream,
testResultsProcessor: globalConfig.testResultsProcessor,
whyRunning,
});
});
9 changes: 2 additions & 7 deletions types/TestResult.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export type AggregatedResultWithoutCoverage = {
numRuntimeErrorTestSuites: number,
numTotalTests: number,
numTotalTestSuites: number,
openHandles: Array<OpenHandle>,
openHandles: Array<Error>,
snapshot: SnapshotSummary,
startTime: number,
success: boolean,
Expand All @@ -140,11 +140,6 @@ export type Suite = {|
tests: Array<AssertionResult>,
|};

export type OpenHandle = {|
title: string,
entries: Array<{file: string, line: string}>,
|};

export type TestResult = {|
console: ?ConsoleBuffer,
coverage?: RawCoverage,
Expand All @@ -155,7 +150,7 @@ export type TestResult = {|
numFailingTests: number,
numPassingTests: number,
numPendingTests: number,
openHandles: Array<OpenHandle>,
openHandles: Array<Error>,
perfStats: {|
end: Milliseconds,
start: Milliseconds,
Expand Down
10 changes: 0 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8802,10 +8802,6 @@ stack-utils@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620"

[email protected]:
version "0.0.2"
resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b"

stacktrace-parser@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.4.tgz#01397922e5f62ecf30845522c95c4fe1d25e7d4e"
Expand Down Expand Up @@ -9685,12 +9681,6 @@ which@^1.2.1, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0:
dependencies:
isexe "^2.0.0"

why-is-node-running@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.0.2.tgz#faf352f095356c8c37a28bf645f874e5648c8d02"
dependencies:
stackback "0.0.2"

wide-align@^1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
Expand Down