-
-
Notifications
You must be signed in to change notification settings - Fork 33.4k
test_runner: add bail out #56490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
test_runner: add bail out #56490
Changes from all commits
28c4e69
0b78797
ba4b376
5ec7d65
6eed90f
24d8a0d
10985fa
ae40aca
4824fbf
24eb106
439a5ee
26ebbb2
791fb5e
1183d02
524ffe8
a32f885
4e93338
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -990,6 +990,22 @@ exports[`suite of snapshot tests > snapshot test 2`] = ` | |||||
Once the snapshot file is created, run the tests again without the | ||||||
`--test-update-snapshots` flag. The tests should pass now. | ||||||
|
||||||
## Bailing out | ||||||
|
||||||
<!-- YAML | ||||||
added: | ||||||
- REPLACEME | ||||||
--> | ||||||
|
||||||
> Stability: 1 - Experimental | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
The `--test-bail` flag provides a way to stop test execution | ||||||
as soon as a test fails. | ||||||
By enabling this flag, the test runner will cancel all remaining tests | ||||||
when it encounters the first failing test. | ||||||
|
||||||
Note: The bail option is not currently supported in watch mode. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
## Test reporters | ||||||
|
||||||
<!-- YAML | ||||||
|
@@ -1077,6 +1093,9 @@ const customReporter = new Transform({ | |||||
case 'test:fail': | ||||||
callback(null, `test ${event.data.name} failed`); | ||||||
break; | ||||||
case 'test:bail': | ||||||
callback(null, `test ${event.data.name} bailed out`); | ||||||
break; | ||||||
case 'test:plan': | ||||||
callback(null, 'test plan'); | ||||||
break; | ||||||
|
@@ -1122,6 +1141,9 @@ const customReporter = new Transform({ | |||||
case 'test:fail': | ||||||
callback(null, `test ${event.data.name} failed`); | ||||||
break; | ||||||
case 'test:bail': | ||||||
callback(null, `test ${event.data.name} bailed out`); | ||||||
break; | ||||||
case 'test:plan': | ||||||
callback(null, 'test plan'); | ||||||
break; | ||||||
|
@@ -1166,6 +1188,9 @@ export default async function * customReporter(source) { | |||||
case 'test:fail': | ||||||
yield `test ${event.data.name} failed\n`; | ||||||
break; | ||||||
case 'test:bail': | ||||||
yield `test ${event.data.name} bailed out\n`; | ||||||
break; | ||||||
case 'test:plan': | ||||||
yield 'test plan\n'; | ||||||
break; | ||||||
|
@@ -1206,6 +1231,9 @@ module.exports = async function * customReporter(source) { | |||||
case 'test:fail': | ||||||
yield `test ${event.data.name} failed\n`; | ||||||
break; | ||||||
case 'test:bail': | ||||||
yield `test ${event.data.name} bailed out\n`; | ||||||
break; | ||||||
case 'test:plan': | ||||||
yield 'test plan\n'; | ||||||
break; | ||||||
|
@@ -1289,6 +1317,10 @@ changes: | |||||
parallel. | ||||||
If `false`, it would only run one test file at a time. | ||||||
**Default:** `false`. | ||||||
* `bail`: {boolean} Determines whether the test runner stops execution after the first test failure. | ||||||
If set to `true`, the runner cancels all remaining tests immediately upon encountering a failure, | ||||||
following the [bailing out][] behavior. | ||||||
**Default:** `false`. | ||||||
* `cwd`: {string} Specifies the current working directory to be used by the test runner. | ||||||
Serves as the base path for resolving files according to the [test runner execution model][]. | ||||||
**Default:** `process.cwd()`. | ||||||
|
@@ -1316,8 +1348,7 @@ changes: | |||||
and can be used to setup listeners before any tests are run. | ||||||
**Default:** `undefined`. | ||||||
* `execArgv` {Array} An array of CLI flags to pass to the `node` executable when | ||||||
spawning the subprocesses. This option has no effect when `isolation` is `'none`'. | ||||||
**Default:** `[]` | ||||||
spawning the subprocesses. This option has no effect when `isolation` is `'none''. **Default:** `\[]\` | ||||||
* `argv` {Array} An array of CLI flags to pass to each test file when spawning the | ||||||
subprocesses. This option has no effect when `isolation` is `'none'`. | ||||||
**Default:** `[]`. | ||||||
|
@@ -3124,6 +3155,22 @@ generated for each test file in addition to a final cumulative summary. | |||||
|
||||||
Emitted when no more tests are queued for execution in watch mode. | ||||||
|
||||||
### Event: `'test:bail'` | ||||||
|
||||||
* `data` {Object} | ||||||
* `column` {number|undefined} The column number where the test is defined, or | ||||||
`undefined` if the test was run through the REPL. | ||||||
* `file` {string|undefined} The path of the test file, | ||||||
`undefined` if test was run through the REPL. | ||||||
* `line` {number|undefined} The line number where the test is defined, or | ||||||
`undefined` if the test was run through the REPL. | ||||||
* `name` {string} The test name. | ||||||
* `nesting` {number} The nesting level of the test. | ||||||
|
||||||
Emitted when the test runner stops executing tests due to the [`--test-bail`][] flag. | ||||||
This event signals that the first failing test caused the suite to bail out, | ||||||
canceling all pending and currently running tests. | ||||||
|
||||||
## Class: `TestContext` | ||||||
|
||||||
<!-- YAML | ||||||
|
@@ -3678,6 +3725,7 @@ Can be used to abort test subtasks when the test has been aborted. | |||||
[`--experimental-test-module-mocks`]: cli.md#--experimental-test-module-mocks | ||||||
[`--import`]: cli.md#--importmodule | ||||||
[`--no-experimental-strip-types`]: cli.md#--no-experimental-strip-types | ||||||
[`--test-bail`]: cli.md#--test-bail | ||||||
[`--test-concurrency`]: cli.md#--test-concurrency | ||||||
[`--test-coverage-exclude`]: cli.md#--test-coverage-exclude | ||||||
[`--test-coverage-include`]: cli.md#--test-coverage-include | ||||||
|
@@ -3704,6 +3752,7 @@ Can be used to abort test subtasks when the test has been aborted. | |||||
[`run()`]: #runoptions | ||||||
[`suite()`]: #suitename-options-fn | ||||||
[`test()`]: #testname-options-fn | ||||||
[bailing out]: #bailing-out | ||||||
[code coverage]: #collecting-code-coverage | ||||||
[describe options]: #describename-options-fn | ||||||
[it options]: #testname-options-fn | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ const { | |
const assert = require('assert'); | ||
const Transform = require('internal/streams/transform'); | ||
const colors = require('internal/util/colors'); | ||
const { kSubtestsFailed } = require('internal/test_runner/test'); | ||
const { kSubtestsFailed, kTestBailedOut } = require('internal/test_runner/test'); | ||
const { getCoverageReport } = require('internal/test_runner/utils'); | ||
const { relative } = require('path'); | ||
const { | ||
|
@@ -57,6 +57,7 @@ class SpecReporter extends Transform { | |
#handleEvent({ type, data }) { | ||
switch (type) { | ||
case 'test:fail': | ||
if (data.details?.error?.failureType === kTestBailedOut) break; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a big fan of needing to check this for every failure, even if bail out mode is not enabled. Couldn't we break out in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could, but in that case, we would lose the "report' section.
Specifically, how would you do that? Would you finalise the reporter, or propagate the abort up to the test runner root? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pmarchini we need to also account for the fact these changes impact custom reporters There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @atlowChemi, I think the most expressive approach would be to avoid interrupting the test stream (or taking any action that has a similar effect), as users might still want to list the tests that were not executed because of the bail. @cjihrig regarding avoiding unnecessary controls: I was thinking about using a set of functions "decorating" the |
||
if (data.details?.error?.failureType !== kSubtestsFailed) { | ||
ArrayPrototypePush(this.#failedTests, data); | ||
} | ||
|
@@ -74,6 +75,8 @@ class SpecReporter extends Transform { | |
case 'test:coverage': | ||
return getCoverageReport(indent(data.nesting), data.summary, | ||
reporterUnicodeSymbolMap['test:coverage'], colors.blue, true); | ||
case 'test:bail': | ||
return `${reporterColorMap[type]}${reporterUnicodeSymbolMap[type]}Bail out!${colors.white}\n`; | ||
} | ||
} | ||
_transform({ type, data }, encoding, callback) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,7 @@ async function * tapReporter(source) { | |
for await (const { type, data } of source) { | ||
switch (type) { | ||
case 'test:fail': { | ||
if (data.details?.error?.failureType === lazyLoadTest().kTestBailedOut) break; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment here. Also, why is bailing out only supported in the spec and tap reporters? What about the dot reporter for example? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I haven't implemented all the reporters yet, as I'm still not convinced by the bail implementation itself. |
||
yield reportTest(data.nesting, data.testNumber, 'not ok', data.name, data.skip, data.todo); | ||
const location = data.file ? `${data.file}:${data.line}:${data.column}` : null; | ||
yield reportDetails(data.nesting, data.details, location); | ||
|
@@ -61,6 +62,9 @@ async function * tapReporter(source) { | |
case 'test:coverage': | ||
yield getCoverageReport(indent(data.nesting), data.summary, '# ', '', true); | ||
break; | ||
case 'test:bail': | ||
yield `${indent(data.nesting)}Bail out!\n`; | ||
break; | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.