Skip to content

Commit

Permalink
create @jest/core package (#7696)
Browse files Browse the repository at this point in the history
  • Loading branch information
SimenB committed Feb 16, 2019
1 parent c14a45d commit 6af2f67
Show file tree
Hide file tree
Showing 101 changed files with 385 additions and 317 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -42,6 +42,7 @@
- `[jest-snapshot]`: Migrate to TypeScript ([#7899](https://github.com/facebook/jest/pull/7899))
- `[@jest/transform]`: New package extracted from `jest-runtime` ([#7915](https://github.com/facebook/jest/pull/7915))
- `[babel-plugin-jest-hoist]`: Migrate to TypeScript ([#7898](https://github.com/facebook/jest/pull/7898))
- `[@jest/core]` Create new package, which is `jest-cli` minus `yargs` and `prompts` ([#7696](https://github.com/facebook/jest/pull/7696))

### Performance

Expand Down
6 changes: 3 additions & 3 deletions jest.config.js
Expand Up @@ -39,9 +39,9 @@ module.exports = {
'/packages/.*/build',
'/packages/.*/build-es5',
'/packages/.*/src/__tests__/setPrettyPrint.ts',
'/packages/jest-cli/src/__tests__/test_root',
'/packages/jest-cli/src/__tests__/__fixtures__/',
'/packages/jest-cli/src/lib/__tests__/fixtures/',
'/packages/jest-core/src/__tests__/test_root',
'/packages/jest-core/src/__tests__/__fixtures__/',
'/packages/jest-cli/src/init/__tests__/fixtures/',
'/packages/jest-haste-map/src/__tests__/haste_impl.js',
'/packages/jest-haste-map/src/__tests__/dependencyExtractor.js',
'/packages/jest-resolve-dependencies/src/__tests__/__fixtures__/',
Expand Down
34 changes: 2 additions & 32 deletions packages/jest-cli/package.json
Expand Up @@ -2,54 +2,24 @@
"name": "jest-cli",
"description": "Delightful JavaScript Testing.",
"version": "24.1.0",
"main": "build/jest.js",
"main": "build/index.js",
"dependencies": {
"@jest/reporters": "^24.1.0",
"@jest/transform": "^24.1.0",
"ansi-escapes": "^3.0.0",
"@jest/core": "^24.1.0",
"chalk": "^2.0.1",
"exit": "^0.1.2",
"glob": "^7.1.2",
"graceful-fs": "^4.1.15",
"import-local": "^2.0.0",
"is-ci": "^2.0.0",
"jest-changed-files": "^24.0.0",
"jest-config": "^24.1.0",
"jest-environment-jsdom": "^24.0.0",
"jest-get-type": "^24.0.0",
"jest-haste-map": "^24.0.0",
"jest-message-util": "^24.0.0",
"jest-regex-util": "^24.0.0",
"jest-resolve-dependencies": "^24.1.0",
"jest-runner": "^24.1.0",
"jest-runtime": "^24.1.0",
"jest-snapshot": "^24.1.0",
"jest-util": "^24.0.0",
"jest-validate": "^24.0.0",
"jest-watcher": "^24.0.0",
"micromatch": "^3.1.10",
"p-each-series": "^1.0.0",
"pirates": "^4.0.0",
"prompts": "^2.0.1",
"realpath-native": "^1.1.0",
"rimraf": "^2.5.4",
"string-length": "^2.0.0",
"strip-ansi": "^5.0.0",
"which": "^1.2.12",
"yargs": "^12.0.2"
},
"devDependencies": {
"@types/ansi-escapes": "^3.0.0",
"@types/exit": "^0.1.30",
"@types/glob": "^7.1.1",
"@types/graceful-fs": "^4.1.2",
"@types/is-ci": "^1.1.0",
"@types/micromatch": "^3.1.0",
"@types/prompts": "^1.2.0",
"@types/rimraf": "^2.0.2",
"@types/string-length": "^2.0.0",
"@types/strip-ansi": "^3.0.0",
"@types/which": "^1.3.1",
"@types/yargs": "^12.0.2"
},
"bin": {
Expand Down
279 changes: 42 additions & 237 deletions packages/jest-cli/src/cli/index.js
Expand Up @@ -12,34 +12,23 @@ import type {Argv} from 'types/Argv';
import type {GlobalConfig, Path} from 'types/Config';

import path from 'path';
import {Console, clearLine, createDirectory, preRunMessage} from 'jest-util';
import {clearLine} from 'jest-util';
import {validateCLIOptions} from 'jest-validate';
import {readConfigs, deprecationEntries} from 'jest-config';
import {deprecationEntries} from 'jest-config';
import {runCLI} from '@jest/core';
import * as args from './args';
import chalk from 'chalk';
import createContext from '../lib/create_context';
import exit from 'exit';
import getChangedFilesPromise from '../getChangedFilesPromise';
import {formatHandleErrors} from '../collectHandles';
import handleDeprecationWarnings from '../lib/handle_deprecation_warnings';
import runJest from '../runJest';
import Runtime from 'jest-runtime';
import TestWatcher from '../TestWatcher';
import watch from '../watch';
import pluralize from '../pluralize';
import yargs from 'yargs';
import rimraf from 'rimraf';
import {sync as realpath} from 'realpath-native';
import init from '../lib/init';
import logDebugMessages from '../lib/log_debug_messages';
import getVersion from '../version';
import init from '../init';

const {print: preRunMessagePrint} = preRunMessage;
import {version as VERSION} from '../../package.json';

export async function run(maybeArgv?: Argv, project?: Path) {
try {
// $FlowFixMe:`allow reduced return
const argv: Argv = buildArgv(maybeArgv, project);
const argv: Argv = buildArgv(maybeArgv);

if (argv.init) {
await init();
Expand All @@ -59,129 +48,9 @@ export async function run(maybeArgv?: Argv, project?: Path) {
}
}

export const runCLI = async (
argv: Argv,
projects: Array<Path>,
): Promise<{results: AggregatedResult, globalConfig: GlobalConfig}> => {
const realFs = require('fs');
const fs = require('graceful-fs');
fs.gracefulify(realFs);

let results;

// If we output a JSON object, we can't write anything to stdout, since
// it'll break the JSON structure and it won't be valid.
const outputStream =
argv.json || argv.useStderr ? process.stderr : process.stdout;

const {globalConfig, configs, hasDeprecationWarnings} = readConfigs(
argv,
projects,
);

if (argv.debug) {
logDebugMessages(globalConfig, configs, outputStream);
}

if (argv.showConfig) {
logDebugMessages(globalConfig, configs, process.stdout);
exit(0);
}

if (argv.clearCache) {
configs.forEach(config => {
rimraf.sync(config.cacheDirectory);
process.stdout.write(`Cleared ${config.cacheDirectory}\n`);
});

exit(0);
}

await _run(
globalConfig,
configs,
hasDeprecationWarnings,
outputStream,
(r: AggregatedResult) => (results = r),
);

if (argv.watch || argv.watchAll) {
// If in watch mode, return the promise that will never resolve.
// If the watch mode is interrupted, watch should handle the process
// shutdown.
return new Promise(() => {});
}

if (!results) {
throw new Error(
'AggregatedResult must be present after test run is complete',
);
}

const {openHandles} = results;

if (openHandles && openHandles.length) {
const formatted = formatHandleErrors(openHandles, configs[0]);

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

const message =
chalk.red(
`\nJest has detected the following ${openHandlesString} potentially keeping Jest from exiting:\n\n`,
) + formatted.join('\n\n');

console.error(message);
}

return Promise.resolve({globalConfig, results});
};

const readResultsAndExit = (
result: ?AggregatedResult,
globalConfig: GlobalConfig,
) => {
const code = !result || result.success ? 0 : globalConfig.testFailureExitCode;

// Only exit if needed
process.on('exit', () => {
if (typeof code === 'number' && code !== 0) {
process.exitCode = code;
}
});

if (globalConfig.forceExit) {
if (!globalConfig.detectOpenHandles) {
console.error(
chalk.red.bold('Force exiting Jest\n\n') +
chalk.red(
'Have you considered using `--detectOpenHandles` to detect ' +
'async operations that kept running after all tests finished?',
),
);
}

exit(code);
} else if (!globalConfig.detectOpenHandles) {
setTimeout(() => {
console.error(
chalk.red.bold(
'Jest did not exit one second after the test run has completed.\n\n',
) +
chalk.red(
'This usually means that there are asynchronous operations that ' +
"weren't stopped in your tests. Consider running Jest with " +
'`--detectOpenHandles` to troubleshoot this issue.',
),
);
// $FlowFixMe: `unref` exists in Node
}, 1000).unref();
}
};

export const buildArgv = (maybeArgv: ?Argv, project: ?Path) => {
export const buildArgv = (maybeArgv: ?Argv) => {
const version =
getVersion() +
(__dirname.includes(`packages${path.sep}jest-cli`) ? '-dev' : '');
VERSION + (__dirname.includes(`packages${path.sep}jest-cli`) ? '-dev' : '');

const rawArgv: Argv | string[] = maybeArgv || process.argv.slice(2);
const argv: Argv = yargs(rawArgv)
Expand Down Expand Up @@ -234,108 +103,44 @@ const getProjectListFromCLIArgs = (argv, project: ?Path) => {
return projects;
};

const buildContextsAndHasteMaps = async (
configs,
globalConfig,
outputStream,
) => {
const hasteMapInstances = Array(configs.length);
const contexts = await Promise.all(
configs.map(async (config, index) => {
createDirectory(config.cacheDirectory);
const hasteMapInstance = Runtime.createHasteMap(config, {
console: new Console(outputStream, outputStream),
maxWorkers: globalConfig.maxWorkers,
resetCache: !config.cache,
watch: globalConfig.watch || globalConfig.watchAll,
watchman: globalConfig.watchman,
});
hasteMapInstances[index] = hasteMapInstance;
return createContext(config, await hasteMapInstance.build());
}),
);

return {contexts, hasteMapInstances};
};

const _run = async (
globalConfig,
configs,
hasDeprecationWarnings,
outputStream,
onComplete,
const readResultsAndExit = (
result: ?AggregatedResult,
globalConfig: GlobalConfig,
) => {
// Queries to hg/git can take a while, so we need to start the process
// as soon as possible, so by the time we need the result it's already there.
const changedFilesPromise = getChangedFilesPromise(globalConfig, configs);
const code = !result || result.success ? 0 : globalConfig.testFailureExitCode;

const {contexts, hasteMapInstances} = await buildContextsAndHasteMaps(
configs,
globalConfig,
outputStream,
);
// Only exit if needed
process.on('exit', () => {
if (typeof code === 'number' && code !== 0) {
process.exitCode = code;
}
});

globalConfig.watch || globalConfig.watchAll
? await runWatch(
contexts,
configs,
hasDeprecationWarnings,
globalConfig,
outputStream,
hasteMapInstances,
changedFilesPromise,
)
: await runWithoutWatch(
globalConfig,
contexts,
outputStream,
onComplete,
changedFilesPromise,
if (globalConfig.forceExit) {
if (!globalConfig.detectOpenHandles) {
console.error(
chalk.red.bold('Force exiting Jest\n\n') +
chalk.red(
'Have you considered using `--detectOpenHandles` to detect ' +
'async operations that kept running after all tests finished?',
),
);
};

const runWatch = async (
contexts,
configs,
hasDeprecationWarnings,
globalConfig,
outputStream,
hasteMapInstances,
changedFilesPromise,
) => {
if (hasDeprecationWarnings) {
try {
await handleDeprecationWarnings(outputStream, process.stdin);
return watch(globalConfig, contexts, outputStream, hasteMapInstances);
} catch (e) {
exit(0);
}
}

return watch(globalConfig, contexts, outputStream, hasteMapInstances);
};

const runWithoutWatch = async (
globalConfig,
contexts,
outputStream,
onComplete,
changedFilesPromise,
) => {
const startRun = async () => {
if (!globalConfig.listTests) {
preRunMessagePrint(outputStream);
}
return await runJest({
changedFilesPromise,
contexts,
failedTestsCache: null,
globalConfig,
onComplete,
outputStream,
startRun,
testWatcher: new TestWatcher({isWatchMode: false}),
});
};
return await startRun();
exit(code);
} else if (!globalConfig.detectOpenHandles) {
setTimeout(() => {
console.error(
chalk.red.bold(
'Jest did not exit one second after the test run has completed.\n\n',
) +
chalk.red(
'This usually means that there are asynchronous operations that ' +
"weren't stopped in your tests. Consider running Jest with " +
'`--detectOpenHandles` to troubleshoot this issue.',
),
);
// $FlowFixMe: `unref` exists in Node
}, 1000).unref();
}
};

0 comments on commit 6af2f67

Please sign in to comment.