Skip to content

Commit

Permalink
--testFailureExitCode (#4067)
Browse files Browse the repository at this point in the history
* --testFailureExitCode argument

* Update normalize.js
  • Loading branch information
aaronabramov authored and cpojer committed Jul 19, 2017
1 parent 3a5c2ea commit 200b032
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ exports[`--showConfig outputs config info and exits 1`] = `
\\"nonFlagArgs\\": [],
\\"notify\\": false,
\\"rootDir\\": \\"<<REPLACED_ROOT_DIR>>\\",
\\"testFailureExitCode\\": 1,
\\"testPathPattern\\": \\"\\",
\\"testResultsProcessor\\": null,
\\"updateSnapshot\\": \\"all\\",
Expand Down
46 changes: 46 additions & 0 deletions integration_tests/__tests__/test_failure_exit_code.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

'use strict';

const path = require('path');
const os = require('os');
const skipOnWindows = require('skipOnWindows');
const {cleanup, writeFiles} = require('../utils');
const runJest = require('../runJest');

const DIR = path.resolve(os.tmpdir(), 'test_failure_exit_code_test');

skipOnWindows.suite();

beforeEach(() => cleanup(DIR));
afterAll(() => cleanup(DIR));

test('exits with a specified code when test fail', () => {
writeFiles(DIR, {
'__tests__/test.test.js': `test('test', () => { expect(1).toBe(2); });`,
'package.json': JSON.stringify({
jest: {testEnvironment: 'node', testFailureExitCode: 99},
}),
});

let {status} = runJest(DIR);
expect(status).toBe(99);

({status} = runJest(DIR, ['--testFailureExitCode', '77']));
expect(status).toBe(77);

writeFiles(DIR, {
'__tests__/test.test.js': `test('test', () => { expect(1).toBe(2); });`,
'package.json': JSON.stringify({
jest: {testEnvironment: 'node'},
}),
});
({status} = runJest(DIR));
expect(status).toBe(1);
});
4 changes: 4 additions & 0 deletions packages/jest-cli/src/cli/args.js
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,10 @@ const options = {
description: 'Alias for --env',
type: 'string',
},
testFailureExitCode: {
description: 'Exit code of `jest` command if the test run failed',
type: 'string', // number
},
testMatch: {
description: 'The glob patterns Jest uses to detect test files.',
type: 'array',
Expand Down
48 changes: 29 additions & 19 deletions packages/jest-cli/src/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,22 @@ import TestWatcher from '../test_watcher';
import watch from '../watch';
import yargs from 'yargs';

function run(maybeArgv?: Argv, project?: Path) {
async function run(maybeArgv?: Argv, project?: Path) {
const argv: Argv = _buildArgv(maybeArgv, project);
const projects = _getProjectListFromCLIArgs(argv, project);
// If we're running a single Jest project, we might want to use another
// version of Jest (the one that is specified in this project's package.json)
const runCLIFn = _getRunCLIFn(projects);

runCLIFn(argv, projects, result => _readResultsAndExit(argv, result));
const {results, globalConfig} = await runCLIFn(argv, projects);
_readResultsAndExit(argv, results, globalConfig);
}

const runCLI = async (
argv: Argv,
projects: Array<Path>,
onComplete: (results: ?AggregatedResult) => void,
) => {
): Promise<{results: AggregatedResult, globalConfig: GlobalConfig}> => {
let results;
// Optimize 'fs' module and make it more compatible with multiple platforms.
_patchGlobalFSModule();

Expand All @@ -57,35 +58,45 @@ const runCLI = async (
const outputStream =
argv.json || argv.useStderr ? process.stderr : process.stdout;

argv.version && _printVersionAndExit(outputStream, onComplete);
argv.version && _printVersionAndExit(outputStream);

try {
const {globalConfig, configs, hasDeprecationWarnings} = _getConfigs(
projects,
argv,
outputStream,
);

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

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

return Promise.resolve({globalConfig, results});
} catch (error) {
_printErrorAndExit(error);
clearLine(process.stderr);
clearLine(process.stdout);
console.error(chalk.red(error.stack));
process.exit(1);
throw error;
}
};

const _printErrorAndExit = error => {
clearLine(process.stderr);
clearLine(process.stdout);
console.error(chalk.red(error.stack));
process.exit(1);
};

const _readResultsAndExit = (argv: Argv, result: ?AggregatedResult) => {
const code = !result || result.success ? 0 : 1;
const _readResultsAndExit = (
argv: Argv,
result: ?AggregatedResult,
globalConfig: GlobalConfig,
) => {
const code = !result || result.success ? 0 : globalConfig.testFailureExitCode;
process.on('exit', () => process.exit(code));
if (argv && argv.forceExit) {
process.exit(code);
Expand Down Expand Up @@ -137,10 +148,9 @@ const _printDebugInfoAndExitIfNeeded = (
}
};

const _printVersionAndExit = (outputStream, onComplete) => {
const _printVersionAndExit = outputStream => {
outputStream.write(`v${VERSION}\n`);
onComplete && onComplete();
return;
process.exit(0);
};

// Possible scenarios:
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ module.exports = ({
resetModules: false,
snapshotSerializers: [],
testEnvironment: 'jest-environment-jsdom',
testFailureExitCode: 1,
testMatch: ['**/__tests__/**/*.js?(x)', '**/?(*.)(spec|test).js?(x)'],
testPathIgnorePatterns: [NODE_MODULES_REGEXP],
testRegex: '',
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const getConfigs = (
reporters: options.reporters,
rootDir: options.rootDir,
silent: options.silent,
testFailureExitCode: options.testFailureExitCode,
testNamePattern: options.testNamePattern,
testPathPattern: options.testPathPattern,
testResultsProcessor: options.testResultsProcessor,
Expand Down
3 changes: 3 additions & 0 deletions packages/jest-config/src/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ function normalize(options: InitialOptions, argv: Argv) {
case 'silent':
case 'skipNodeResolution':
case 'testEnvironment':
case 'testFailureExitCode':
case 'testNamePattern':
case 'testRegex':
case 'testURL':
Expand All @@ -492,6 +493,8 @@ function normalize(options: InitialOptions, argv: Argv) {
newOptions.json = argv.json;
newOptions.lastCommit = argv.lastCommit;

newOptions.testFailureExitCode = parseInt(newOptions.testFailureExitCode, 10);

if (argv.all || newOptions.testPathPattern) {
newOptions.onlyChanged = false;
}
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/valid_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ module.exports = ({
skipNodeResolution: false,
snapshotSerializers: ['my-serializer-module'],
testEnvironment: 'jest-environment-jsdom',
testFailureExitCode: 1,
testMatch: ['**/__tests__/**/*.js?(x)', '**/?(*.)(spec|test).js?(x)'],
testNamePattern: 'test signature',
testPathIgnorePatterns: [NODE_MODULES_REGEXP],
Expand Down
1 change: 1 addition & 0 deletions types/Argv.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export type Argv = {|
silent: boolean,
snapshotSerializers: Array<string>,
testEnvironment: string,
testFailureExitCode: ?string,
testMatch: Array<string>,
testNamePattern: string,
testPathIgnorePatterns: Array<string>,
Expand Down
3 changes: 3 additions & 0 deletions types/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export type DefaultOptions = {|
resetModules: boolean,
snapshotSerializers: Array<Path>,
testEnvironment: string,
testFailureExitCode: string | number,
testMatch: Array<Glob>,
testPathIgnorePatterns: Array<string>,
testRegex: string,
Expand Down Expand Up @@ -109,6 +110,7 @@ export type InitialOptions = {|
skipNodeResolution: boolean,
snapshotSerializers?: Array<Path>,
testEnvironment?: string,
testFailureExitCode?: string | number,
testMatch?: Array<Glob>,
testNamePattern?: string,
testPathIgnorePatterns?: Array<string>,
Expand Down Expand Up @@ -157,6 +159,7 @@ export type GlobalConfig = {|
reporters: Array<ReporterConfig>,
rootDir: Path,
silent: boolean,
testFailureExitCode: number,
testNamePattern: string,
testPathPattern: string,
testResultsProcessor: ?string,
Expand Down

0 comments on commit 200b032

Please sign in to comment.