Skip to content

Commit 3e805bc

Browse files
bookman25rickhanlonii
authored andcommitted
allow bail setting to control when to bail out of a failing test run (#7335)
1 parent 6a2237d commit 3e805bc

File tree

18 files changed

+108
-26
lines changed

18 files changed

+108
-26
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
- `[jest-config]` Add `haste.computeSha1` option to compute the sha-1 of the files in the haste map ([#7345](https://github.com/facebook/jest/pull/7345))
3535
- `[expect]` `expect(Infinity).toBeCloseTo(Infinity)` Treats `Infinity` as equal in toBeCloseTo matcher ([#7405](https://github.com/facebook/jest/pull/7405))
3636
- `[jest-worker]` Add node worker-thread support to jest-worker ([#7408](https://github.com/facebook/jest/pull/7408))
37+
- `[jest-config]` Allow `bail` setting to be configured with a number allowing tests to abort after `n` of failures ([#7335](https://github.com/facebook/jest/pull/7335))
3738

3839
### Fixes
3940

TestUtils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import type {GlobalConfig, ProjectConfig} from 'types/Config';
1313

1414
const DEFAULT_GLOBAL_CONFIG: GlobalConfig = {
15-
bail: false,
15+
bail: 0,
1616
changedFilesWithAncestor: false,
1717
changedSince: '',
1818
collectCoverage: false,

docs/CLI.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ When you run `jest` with an argument, that argument is treated as a regular expr
9797

9898
### `--bail`
9999

100-
Alias: `-b`. Exit the test suite immediately upon the first failing test suite.
100+
Alias: `-b`. Exit the test suite immediately upon `n` number of failing test suite. Defaults to `1`.
101101

102102
### `--cache`
103103

docs/Configuration.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ When using the `--config` option, the JSON file must not contain a "jest" key:
2929

3030
```json
3131
{
32-
"bail": true,
32+
"bail": 1,
3333
"verbose": true
3434
}
3535
```
@@ -99,11 +99,11 @@ _Note: Core modules, like `fs`, are not mocked by default. They can be mocked ex
9999

100100
_Note: Automocking has a performance cost most noticeable in large projects. See [here](troubleshooting.html#tests-are-slow-when-leveraging-automocking) for details and a workaround._
101101

102-
### `bail` [boolean]
102+
### `bail` [number | boolean]
103103

104-
Default: `false`
104+
Default: `0`
105105

106-
By default, Jest runs all tests and produces all errors into the console upon completion. The bail config option can be used here to have Jest stop running tests after the first failure.
106+
By default, Jest runs all tests and produces all errors into the console upon completion. The bail config option can be used here to have Jest stop running tests after `n` failures. Setting bail to `true` is the same as setting bail to `1`.
107107

108108
### `browser` [boolean]
109109

docs/WatchPlugins.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
---
22
id: watch-plugins
33
title: Watch Plugins
4-
original_id: watch-plugins
54
---
65

76
The Jest watch plugin system provides a way to hook into specific parts of Jest and to define watch mode menu prompts that execute code on key press. Combined, these features allow you to develop interactive experiences custom for your workflow.
@@ -155,7 +154,7 @@ class MyWatchPlugin {
155154

156155
For stability and safety reasons, only part of the global configuration keys can be updated with `updateConfigAndRun`. The current white list is as follows:
157156

158-
- [`bail`](configuration.html#bail-boolean)
157+
- [`bail`](configuration.html#bail-number-boolean)
159158
- [`collectCoverage`](configuration.html#collectcoverage-boolean)
160159
- [`collectCoverageFrom`](configuration.html#collectcoveragefrom-array)
161160
- [`collectCoverageOnlyFrom`](configuration.html#collectcoverageonlyfrom-array)

e2e/__tests__/__snapshots__/show_config.test.js.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ exports[`--showConfig outputs config info and exits 1`] = `
7777
}
7878
],
7979
\\"globalConfig\\": {
80-
\\"bail\\": false,
80+
\\"bail\\": 0,
8181
\\"changedFilesWithAncestor\\": false,
8282
\\"collectCoverage\\": false,
8383
\\"collectCoverageFrom\\": null,

packages/jest-cli/src/TestScheduler.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,10 @@ export default class TestScheduler {
351351
aggregatedResults: AggregatedResult,
352352
watcher: TestWatcher,
353353
): Promise<void> {
354-
if (this._globalConfig.bail && aggregatedResults.numFailedTests !== 0) {
354+
if (
355+
this._globalConfig.bail !== 0 &&
356+
aggregatedResults.numFailedTests >= this._globalConfig.bail
357+
) {
355358
if (watcher.isWatchMode()) {
356359
watcher.setState({interrupted: true});
357360
} else {

packages/jest-cli/src/__tests__/TestScheduler.test.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ jest.mock('jest-runner-parallel', () => jest.fn(() => mockParallelRunner), {
2727
virtual: true,
2828
});
2929

30+
beforeEach(() => {
31+
mockSerialRunner.runTests.mockClear();
32+
});
33+
3034
test('config for reporters supports `default`', () => {
3135
const undefinedReportersScheduler = new TestScheduler(
3236
{
@@ -116,3 +120,63 @@ test('schedule tests run in serial if the runner flags them', async () => {
116120
expect(mockSerialRunner.runTests).toHaveBeenCalled();
117121
expect(mockSerialRunner.runTests.mock.calls[0][5].serial).toBeTruthy();
118122
});
123+
124+
test('should bail after `n` failures', async () => {
125+
const scheduler = new TestScheduler({bail: 2}, {});
126+
const test = {
127+
context: {
128+
config: {
129+
rootDir: './',
130+
runner: 'jest-runner-serial',
131+
},
132+
hasteFS: {
133+
matchFiles: jest.fn(() => []),
134+
},
135+
},
136+
path: './test/path.js',
137+
};
138+
139+
const tests = [test];
140+
const setState = jest.fn();
141+
await scheduler.scheduleTests(tests, {
142+
isInterrupted: jest.fn(),
143+
isWatchMode: () => true,
144+
setState,
145+
});
146+
await mockSerialRunner.runTests.mock.calls[0][3](test, {
147+
numFailingTests: 2,
148+
snapshot: {},
149+
testResults: [{}],
150+
});
151+
expect(setState).toBeCalledWith({interrupted: true});
152+
});
153+
154+
test('should not bail if less than `n` failures', async () => {
155+
const scheduler = new TestScheduler({bail: 2}, {});
156+
const test = {
157+
context: {
158+
config: {
159+
rootDir: './',
160+
runner: 'jest-runner-serial',
161+
},
162+
hasteFS: {
163+
matchFiles: jest.fn(() => []),
164+
},
165+
},
166+
path: './test/path.js',
167+
};
168+
169+
const tests = [test];
170+
const setState = jest.fn();
171+
await scheduler.scheduleTests(tests, {
172+
isInterrupted: jest.fn(),
173+
isWatchMode: () => true,
174+
setState,
175+
});
176+
await mockSerialRunner.runTests.mock.calls[0][3](test, {
177+
numFailingTests: 1,
178+
snapshot: {},
179+
testResults: [{}],
180+
});
181+
expect(setState).not.toBeCalled();
182+
});

packages/jest-cli/src/cli/args.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ export const options = {
8585
bail: {
8686
alias: 'b',
8787
default: undefined,
88-
description: 'Exit the test suite immediately upon the first failing test.',
89-
type: 'boolean',
88+
description:
89+
'Exit the test suite immediately after `n` number of failing tests.',
9090
},
9191
browser: {
9292
default: undefined,

packages/jest-cli/src/lib/__tests__/__snapshots__/init.test.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ module.exports = {
2626
// All imported modules in your tests should be mocked automatically
2727
// automock: false,
2828
29-
// Stop running tests after the first failure
30-
// bail: false,
29+
// Stop running tests after \`n\` failures
30+
// bail: 0,
3131
3232
// Respect \\"browser\\" field in package.json when resolving modules
3333
// browser: false,

packages/jest-cli/src/lib/update_global_config.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@ export default (globalConfig: GlobalConfig, options: Options): GlobalConfig => {
6666
!newConfig.testNamePattern &&
6767
!newConfig.testPathPattern;
6868

69-
if (options.bail !== undefined) {
70-
newConfig.bail = options.bail || false;
69+
if (typeof options.bail === 'boolean') {
70+
newConfig.bail = options.bail ? 1 : 0;
71+
} else if (options.bail !== undefined) {
72+
newConfig.bail = options.bail;
7173
}
7274

7375
if (options.changedSince !== undefined) {

packages/jest-config/src/Defaults.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const NODE_MODULES_REGEXP = replacePathSepForRegex(NODE_MODULES);
1717

1818
export default ({
1919
automock: false,
20-
bail: false,
20+
bail: 0,
2121
browser: false,
2222
cache: true,
2323
cacheDirectory: getCacheDirectory(),

packages/jest-config/src/Descriptions.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
export default ({
1111
automock: 'All imported modules in your tests should be mocked automatically',
12-
bail: 'Stop running tests after the first failure',
12+
bail: 'Stop running tests after `n` failures',
1313
browser: 'Respect "browser" field in package.json when resolving modules',
1414
cacheDirectory:
1515
'The directory where Jest should store its cached dependency information',

packages/jest-config/src/ValidConfig.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const NODE_MODULES_REGEXP = replacePathSepForRegex(NODE_MODULES);
1717

1818
export default ({
1919
automock: false,
20-
bail: false,
20+
bail: (multipleValidOptions(false, 0): any),
2121
browser: false,
2222
cache: true,
2323
cacheDirectory: '/tmp/user/jest',

packages/jest-config/src/normalize.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,8 +617,21 @@ export default function normalize(options: InitialOptions, argv: Argv) {
617617

618618
break;
619619
}
620+
case 'bail': {
621+
if (typeof options[key] === 'boolean') {
622+
value = options[key] ? 1 : 0;
623+
} else if (typeof options[key] === 'string') {
624+
value = 1;
625+
// If Jest is invoked as `jest --bail someTestPattern` then need to
626+
// move the pattern from the `bail` configuration and into `argv._`
627+
// to be processed as an extra parameter
628+
argv._.push(options[key]);
629+
} else {
630+
value = options[key];
631+
}
632+
break;
633+
}
620634
case 'automock':
621-
case 'bail':
622635
case 'browser':
623636
case 'cache':
624637
case 'changedSince':

packages/jest-validate/src/__tests__/fixtures/jestConfig.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const NODE_MODULES_REGEXP = replacePathSepForRegex(NODE_MODULES);
2222

2323
const defaultConfig = {
2424
automock: false,
25-
bail: false,
25+
bail: 0,
2626
browser: false,
2727
cacheDirectory: path.join(os.tmpdir(), 'jest'),
2828
clearMocks: false,
@@ -62,7 +62,7 @@ const defaultConfig = {
6262

6363
const validConfig = {
6464
automock: false,
65-
bail: false,
65+
bail: 0,
6666
browser: false,
6767
cache: true,
6868
cacheDirectory: '/tmp/user/jest',

types/Argv.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type Argv = {|
1313
$0: string,
1414
all: boolean,
1515
automock: boolean,
16-
bail: boolean,
16+
bail: boolean | number,
1717
browser: boolean,
1818
cache: boolean,
1919
cacheDirectory: string,

types/Config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export type ConfigGlobals = Object;
2424

2525
export type DefaultOptions = {|
2626
automock: boolean,
27-
bail: boolean,
27+
bail: number,
2828
browser: boolean,
2929
cache: boolean,
3030
cacheDirectory: Path,
@@ -92,7 +92,7 @@ export type DefaultOptions = {|
9292

9393
export type InitialOptions = {
9494
automock?: boolean,
95-
bail?: boolean,
95+
bail?: boolean | number,
9696
browser?: boolean,
9797
cache?: boolean,
9898
cacheDirectory?: Path,
@@ -190,7 +190,7 @@ export type InitialOptions = {
190190
export type SnapshotUpdateState = 'all' | 'new' | 'none';
191191

192192
export type GlobalConfig = {|
193-
bail: boolean,
193+
bail: number,
194194
changedSince: string,
195195
changedFilesWithAncestor: boolean,
196196
collectCoverage: boolean,

0 commit comments

Comments
 (0)