Skip to content

Commit 949228d

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 7bd2fea commit 949228d

4 files changed

Lines changed: 42 additions & 8 deletions

File tree

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`
@@ -1683,6 +1687,9 @@ changes:
16831687
thread. If `false`, only one test runs at a time.
16841688
If unspecified, subtests inherit this value from their parent.
16851689
**Default:** `false`.
1690+
* `expectFailure` {boolean|string} If truthy, the test is expected to fail.
1691+
If a string is provided, that string is displayed in the test results as the
1692+
reason why the test is expected to fail. **Default:** `false`.
16861693
* `only` {boolean} If truthy, and the test context is configured to run
16871694
`only` tests, then this test will be run. Otherwise, the test is skipped.
16881695
**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
@@ -636,7 +636,13 @@ class Test extends AsyncResource {
636636
this.plan = null;
637637
this.expectedAssertions = plan;
638638
this.cancelled = false;
639-
this.expectFailure = expectFailure !== undefined && expectFailure !== false;
639+
if (expectFailure === undefined || expectFailure === false) {
640+
this.expectFailure = false;
641+
} else if (typeof expectFailure === 'string') {
642+
this.expectFailure = expectFailure;
643+
} else {
644+
this.expectFailure = true;
645+
}
640646
this.skipped = skip !== undefined && skip !== false;
641647
this.isTodo = (todo !== undefined && todo !== false) || this.parent?.isTodo;
642648
this.startTime = null;
@@ -948,11 +954,7 @@ class Test extends AsyncResource {
948954
return;
949955
}
950956

951-
if (this.expectFailure === true) {
952-
this.passed = true;
953-
} else {
954-
this.passed = false;
955-
}
957+
this.passed = this.expectFailure;
956958

957959
this.error = err;
958960
}
@@ -1359,7 +1361,7 @@ class Test extends AsyncResource {
13591361
} else if (this.isTodo) {
13601362
directive = this.reporter.getTodo(this.message);
13611363
} else if (this.expectFailure) {
1362-
directive = this.reporter.getXFail(this.expectFailure); // TODO(@JakobJingleheimer): support specifying failure
1364+
directive = this.reporter.getXFail(this.expectFailure);
13631365
}
13641366

13651367
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)