Skip to content

Commit 5a15080

Browse files
committed
test_runner: support custom message for expectFailure
Update `expectFailure` option to accept a string message and display it in the TAP reporter output. Example output: `# EXPECTED FAILURE <reason>`
1 parent 8c380de commit 5a15080

File tree

4 files changed

+42
-8
lines changed

4 files changed

+42
-8
lines changed

doc/api/test.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,10 @@ it.expectFailure('should do the thing', () => {
245245
it('should do the thing', { expectFailure: true }, () => {
246246
assert.strictEqual(doTheThing(), true);
247247
});
248+
249+
it('should do the thing', { expectFailure: 'flaky test' }, () => {
250+
assert.strictEqual(doTheThing(), true);
251+
});
248252
```
249253

250254
`skip` and/or `todo` are mutually exclusive to `expectFailure`, and `skip` or `todo`
@@ -1677,6 +1681,9 @@ changes:
16771681
thread. If `false`, only one test runs at a time.
16781682
If unspecified, subtests inherit this value from their parent.
16791683
**Default:** `false`.
1684+
* `expectFailure` {boolean|string} If truthy, the test is expected to fail.
1685+
If a string is provided, that string is displayed in the test results as the
1686+
reason why the test is expected to fail. **Default:** `false`.
16801687
* `only` {boolean} If truthy, and the test context is configured to run
16811688
`only` tests, then this test will be run. Otherwise, the test is skipped.
16821689
**Default:** `false`.

lib/internal/test_runner/reporter/tap.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ function reportTest(nesting, testNumber, status, name, skip, todo, expectFailure
7777
} else if (todo !== undefined) {
7878
line += ` # TODO${typeof todo === 'string' && todo.length ? ` ${tapEscape(todo)}` : ''}`;
7979
} else if (expectFailure !== undefined) {
80-
line += ' # EXPECTED FAILURE';
80+
line += ` # EXPECTED FAILURE${typeof expectFailure === 'string' && expectFailure.length ? ` ${tapEscape(expectFailure)}` : ''}`;
8181
}
8282

8383
line += '\n';

lib/internal/test_runner/test.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,13 @@ class Test extends AsyncResource {
635635
this.plan = null;
636636
this.expectedAssertions = plan;
637637
this.cancelled = false;
638-
this.expectFailure = expectFailure !== undefined && expectFailure !== false;
638+
if (expectFailure === undefined || expectFailure === false) {
639+
this.expectFailure = false;
640+
} else if (typeof expectFailure === 'string') {
641+
this.expectFailure = expectFailure;
642+
} else {
643+
this.expectFailure = true;
644+
}
639645
this.skipped = skip !== undefined && skip !== false;
640646
this.isTodo = (todo !== undefined && todo !== false) || this.parent?.isTodo;
641647
this.startTime = null;
@@ -947,11 +953,7 @@ class Test extends AsyncResource {
947953
return;
948954
}
949955

950-
if (this.expectFailure === true) {
951-
this.passed = true;
952-
} else {
953-
this.passed = false;
954-
}
956+
this.passed = this.expectFailure;
955957

956958
this.error = err;
957959
}
@@ -1350,7 +1352,7 @@ class Test extends AsyncResource {
13501352
} else if (this.isTodo) {
13511353
directive = this.reporter.getTodo(this.message);
13521354
} else if (this.expectFailure) {
1353-
directive = this.reporter.getXFail(this.expectFailure); // TODO(@JakobJingleheimer): support specifying failure
1355+
directive = this.reporter.getXFail(this.expectFailure);
13541356
}
13551357

13561358
if (this.reportedType) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
const common = require('../common');
3+
const { test } = require('node:test');
4+
const { spawn } = require('child_process');
5+
const assert = require('node:assert');
6+
7+
if (process.env.CHILD_PROCESS === 'true') {
8+
test('fail with message', { expectFailure: 'flaky test reason' }, () => {
9+
assert.fail('boom');
10+
});
11+
} else {
12+
const child = spawn(process.execPath, ['--test-reporter', 'tap', __filename], {
13+
env: { ...process.env, CHILD_PROCESS: 'true' },
14+
stdio: 'pipe',
15+
});
16+
17+
let stdout = '';
18+
child.stdout.setEncoding('utf8');
19+
child.stdout.on('data', (chunk) => { stdout += chunk; });
20+
21+
child.on('close', common.mustCall((code) => {
22+
assert.strictEqual(code, 0);
23+
assert.match(stdout, /# EXPECTED FAILURE flaky test reason/);
24+
}));
25+
}

0 commit comments

Comments
 (0)