Skip to content

Commit b03a866

Browse files
committed
test_runner: propogate only to work without --test-only
1 parent f842b8b commit b03a866

10 files changed

+141
-124
lines changed

lib/internal/test_runner/test.js

+24-15
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ const kHookNames = ObjectSeal(['before', 'after', 'beforeEach', 'afterEach']);
7272
const kUnwrapErrors = new SafeSet()
7373
.add(kTestCodeFailure).add(kHookFailure)
7474
.add('uncaughtException').add('unhandledRejection');
75-
const { testNamePatterns, testOnlyFlag } = parseCommandLine();
75+
const { testNamePatterns } = parseCommandLine();
7676
let kResistStopPropagation;
7777

7878
function stopTest(timeout, signal) {
@@ -193,9 +193,7 @@ class Test extends AsyncResource {
193193
if (parent === null) {
194194
this.concurrency = 1;
195195
this.nesting = 0;
196-
this.only = testOnlyFlag;
197196
this.reporter = new TestsStream();
198-
this.runOnlySubtests = this.only;
199197
this.testNumber = 0;
200198
this.timeout = kDefaultTimeout;
201199
this.root = this;
@@ -212,9 +210,7 @@ class Test extends AsyncResource {
212210

213211
this.concurrency = parent.concurrency;
214212
this.nesting = nesting;
215-
this.only = only ?? !parent.runOnlySubtests;
216213
this.reporter = parent.reporter;
217-
this.runOnlySubtests = !this.only;
218214
this.testNumber = parent.subtests.length + 1;
219215
this.timeout = parent.timeout;
220216
this.root = parent.root;
@@ -259,10 +255,6 @@ class Test extends AsyncResource {
259255
skip = 'test name does not match pattern';
260256
}
261257

262-
if (testOnlyFlag && !this.only) {
263-
skip = '\'only\' option not set';
264-
}
265-
266258
if (skip) {
267259
fn = noop;
268260
}
@@ -301,12 +293,20 @@ class Test extends AsyncResource {
301293
this.subtests = [];
302294
this.waitingOn = 0;
303295
this.finished = false;
296+
this.only = only;
297+
this.runOnlySubtests = false;
298+
299+
if (only && parent !== null) {
300+
parent.markOnly();
301+
}
302+
}
304303

305-
if (!testOnlyFlag && (only || this.runOnlySubtests)) {
306-
const warning =
307-
"'only' and 'runOnly' require the --test-only command-line option.";
308-
this.diagnostic(warning);
304+
markOnly() {
305+
if (this.runOnlySubtests) {
306+
return;
309307
}
308+
this.runOnlySubtests = true;
309+
this.parent?.markOnly();
310310
}
311311

312312
matchesTestNamePatterns() {
@@ -539,9 +539,18 @@ class Test extends AsyncResource {
539539
}
540540
}
541541

542+
get runOnlySibling() {
543+
return this.parent?.runOnlySubtests && !this.only && !this.hasOnlySubtests;
544+
}
545+
542546
async run() {
543547
this.startTime = hrtime();
544548

549+
if (this.runOnlySibling || this.only === false) {
550+
this.fn = noop;
551+
this.skip('\'only\' option not set');
552+
}
553+
545554
if (this[kShouldAbort]()) {
546555
this.postRun();
547556
return;
@@ -794,7 +803,6 @@ class Suite extends Test {
794803
this.fn = options.fn || this.fn;
795804
this.skipped = false;
796805
}
797-
this.runOnlySubtests = testOnlyFlag;
798806

799807
try {
800808
const { ctx, args } = this.getRunArgs();
@@ -815,7 +823,7 @@ class Suite extends Test {
815823
this.fail(new ERR_TEST_FAILURE(err, kTestCodeFailure));
816824
this.buildPhaseFinished = this.parent !== null;
817825
}
818-
this.fn = () => {};
826+
this.fn = noop;
819827
}
820828

821829
getRunArgs() {
@@ -825,6 +833,7 @@ class Suite extends Test {
825833

826834
async run() {
827835
const hookArgs = this.getRunArgs();
836+
this.runOnlySubtests ||= this.runOnlySibling;
828837

829838
try {
830839
await this.buildSuite;

lib/internal/test_runner/utils.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const {
2222
const { relative } = require('path');
2323
const { createWriteStream } = require('fs');
2424
const { pathToFileURL } = require('internal/url');
25-
const { createDeferredPromise } = require('internal/util');
25+
const { createDeferredPromise, deprecate } = require('internal/util');
2626
const { getOptionValue } = require('internal/options');
2727
const { green, yellow, red, white, shouldColorize } = require('internal/util/colors');
2828

@@ -185,7 +185,6 @@ function parseCommandLine() {
185185
let destinations;
186186
let reporters;
187187
let testNamePatterns;
188-
let testOnlyFlag;
189188

190189
if (isChildProcessV8) {
191190
kBuiltinReporters.set('v8-serializer', 'internal/test_runner/reporter/v8-serializer');
@@ -214,12 +213,14 @@ function parseCommandLine() {
214213
}
215214
}
216215

216+
if (getOptionValue('--test-only') && !isChildProcess && !isChildProcessV8) {
217+
deprecate(() => {}, 'The --test-only flag is deprecated.', '111')();
218+
}
219+
217220
if (isTestRunner) {
218-
testOnlyFlag = false;
219221
testNamePatterns = null;
220222
} else {
221223
const testNamePatternFlag = getOptionValue('--test-name-pattern');
222-
testOnlyFlag = getOptionValue('--test-only');
223224
testNamePatterns = testNamePatternFlag?.length > 0 ?
224225
ArrayPrototypeMap(
225226
testNamePatternFlag,
@@ -231,7 +232,6 @@ function parseCommandLine() {
231232
__proto__: null,
232233
isTestRunner,
233234
coverage,
234-
testOnlyFlag,
235235
testNamePatterns,
236236
reporters,
237237
destinations,

test/fixtures/test-runner/output/name_pattern_with_only.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Flags: --no-warnings --test-only --test-name-pattern=enabled
1+
// Flags: --no-warnings --test-name-pattern=enabled
22
'use strict';
33
const common = require('../../../common');
44
const { test } = require('node:test');
+58-62
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,96 @@
1-
// Flags: --no-warnings --test-only
1+
// Flags: --no-warnings
22
'use strict';
3-
require('../../../common');
3+
const common = require('../../../common');
44
const { test, describe, it } = require('node:test');
55

66
// These tests should be skipped based on the 'only' option.
7-
test('only = undefined');
8-
test('only = undefined, skip = string', { skip: 'skip message' });
9-
test('only = undefined, skip = true', { skip: true });
10-
test('only = undefined, skip = false', { skip: false });
11-
test('only = false', { only: false });
12-
test('only = false, skip = string', { only: false, skip: 'skip message' });
13-
test('only = false, skip = true', { only: false, skip: true });
14-
test('only = false, skip = false', { only: false, skip: false });
7+
test('only = undefined', common.mustNotCall());
8+
test('only = undefined, skip = string', { skip: 'skip message' }, common.mustNotCall());
9+
test('only = undefined, skip = true', { skip: true }, common.mustNotCall());
10+
test('only = undefined, skip = false', { skip: false }, common.mustNotCall());
11+
test('only = false', { only: false }, common.mustNotCall());
12+
test('only = false, skip = string', { only: false, skip: 'skip message' }, common.mustNotCall());
13+
test('only = false, skip = true', { only: false, skip: true }, common.mustNotCall());
14+
test('only = false, skip = false', { only: false, skip: false }, common.mustNotCall());
1515

1616
// These tests should be skipped based on the 'skip' option.
17-
test('only = true, skip = string', { only: true, skip: 'skip message' });
18-
test('only = true, skip = true', { only: true, skip: true });
17+
test('only = true, skip = string', { only: true, skip: 'skip message' }, common.mustNotCall());
18+
test('only = true, skip = true', { only: true, skip: true }, common.mustNotCall());
1919

2020
// An 'only' test with subtests.
21-
test('only = true, with subtests', { only: true }, async (t) => {
21+
test('only = true, with subtests', { only: true }, common.mustCall(async (t) => {
2222
// These subtests should run.
23-
await t.test('running subtest 1');
24-
await t.test('running subtest 2');
23+
await t.test('running subtest 1', common.mustCall());
24+
await t.test('running subtest 2', common.mustCall());
2525

2626
// Switch the context to only execute 'only' tests.
2727
t.runOnly(true);
28-
await t.test('skipped subtest 1');
29-
await t.test('skipped subtest 2');
30-
await t.test('running subtest 3', { only: true });
28+
await t.test('skipped subtest 1', common.mustNotCall());
29+
await t.test('skipped subtest 2'), common.mustNotCall();
30+
await t.test('running subtest 3', { only: true }, common.mustCall());
3131

3232
// Switch the context back to execute all tests.
3333
t.runOnly(false);
34-
await t.test('running subtest 4', async (t) => {
34+
await t.test('running subtest 4', common.mustCall(async (t) => {
3535
// These subtests should run.
36-
await t.test('running sub-subtest 1');
37-
await t.test('running sub-subtest 2');
36+
await t.test('running sub-subtest 1', common.mustCall());
37+
await t.test('running sub-subtest 2', common.mustCall());
3838

3939
// Switch the context to only execute 'only' tests.
4040
t.runOnly(true);
41-
await t.test('skipped sub-subtest 1');
42-
await t.test('skipped sub-subtest 2');
43-
});
41+
await t.test('skipped sub-subtest 1', common.mustNotCall());
42+
await t.test('skipped sub-subtest 2', common.mustNotCall());
43+
}));
4444

4545
// Explicitly do not run these tests.
46-
await t.test('skipped subtest 3', { only: false });
47-
await t.test('skipped subtest 4', { skip: true });
48-
});
46+
await t.test('skipped subtest 3', { only: false }, common.mustNotCall());
47+
await t.test('skipped subtest 4', { skip: true }, common.mustNotCall());
48+
}));
4949

50-
describe.only('describe only = true, with subtests', () => {
51-
it.only('`it` subtest 1 should run', () => {});
50+
describe.only('describe only = true, with subtests', common.mustCall(() => {
51+
it.only('`it` subtest 1 should run', common.mustCall());
5252

53-
it('`it` subtest 2 should not run', async () => {});
54-
});
53+
it('`it` subtest 2 should not run', common.mustNotCall());
54+
}));
5555

56-
describe.only('describe only = true, with a mixture of subtests', () => {
57-
it.only('`it` subtest 1', () => {});
56+
describe.only('describe only = true, with a mixture of subtests', common.mustCall(() => {
57+
it.only('`it` subtest 1', common.mustCall());
5858

59-
it.only('`it` async subtest 1', async () => {});
59+
it.only('`it` async subtest 1', common.mustCall(async () => {}));
6060

61-
it('`it` subtest 2 only=true', { only: true });
61+
it('`it` subtest 2 only=true', { only: true }, common.mustCall());
6262

63-
it('`it` subtest 2 only=false', { only: false }, () => {
64-
throw new Error('This should not run');
65-
});
63+
it('`it` subtest 2 only=false', { only: false }, common.mustNotCall());
6664

67-
it.skip('`it` subtest 3 skip', () => {
68-
throw new Error('This should not run');
69-
});
65+
it.skip('`it` subtest 3 skip', common.mustNotCall());
7066

71-
it.todo('`it` subtest 4 todo', { only: false }, () => {
72-
throw new Error('This should not run');
73-
});
67+
it.todo('`it` subtest 4 todo', { only: false }, common.mustNotCall());
7468

75-
test.only('`test` subtest 1', () => {});
69+
test.only('`test` subtest 1', common.mustCall());
7670

77-
test.only('`test` async subtest 1', async () => {});
71+
test.only('`test` async subtest 1', common.mustCall(async () => {}));
7872

79-
test('`test` subtest 2 only=true', { only: true });
73+
test('`test` subtest 2 only=true', { only: true }, common.mustCall());
8074

81-
test('`test` subtest 2 only=false', { only: false }, () => {
82-
throw new Error('This should not run');
83-
});
75+
test('`test` subtest 2 only=false', { only: false }, common.mustNotCall());
8476

85-
test.skip('`test` subtest 3 skip', () => {
86-
throw new Error('This should not run');
87-
});
77+
test.skip('`test` subtest 3 skip', common.mustNotCall());
8878

89-
test.todo('`test` subtest 4 todo', { only: false }, () => {
90-
throw new Error('This should not run');
91-
});
92-
});
79+
test.todo('`test` subtest 4 todo', { only: false }, common.mustNotCall());
80+
}));
9381

94-
describe.only('describe only = true, with subtests', () => {
95-
test.only('subtest should run', () => {});
82+
describe.only('describe only = true, with subtests', common.mustCall(() => {
83+
test.only('subtest should run', common.mustCall());
9684

97-
test('async subtest should not run', async () => {});
85+
test('async subtest should not run', common.mustNotCall());
9886

99-
test('subtest should be skipped', { only: false }, () => {});
100-
});
87+
test('subtest should be skipped', { only: false }, common.mustNotCall());
88+
}));
89+
90+
describe('describe only = undefined, with subtests', common.mustCall(() => {
91+
test('async subtest should not run', common.mustNotCall());
92+
}));
93+
94+
describe('describe only = false, with subtests', { only: false }, common.mustCall(() => {
95+
test('async subtest should not run', common.mustNotCall());
96+
}));

test/fixtures/test-runner/output/only_tests.snapshot

+28-4
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,36 @@ ok 14 - describe only = true, with subtests
222222
duration_ms: *
223223
type: 'suite'
224224
...
225-
1..14
226-
# tests 40
227-
# suites 3
225+
# Subtest: describe only = undefined, with subtests
226+
# Subtest: async subtest should not run
227+
ok 1 - async subtest should not run # SKIP 'only' option not set
228+
---
229+
duration_ms: *
230+
...
231+
1..1
232+
ok 15 - describe only = undefined, with subtests
233+
---
234+
duration_ms: *
235+
type: 'suite'
236+
...
237+
# Subtest: describe only = false, with subtests
238+
# Subtest: async subtest should not run
239+
ok 1 - async subtest should not run # SKIP 'only' option not set
240+
---
241+
duration_ms: *
242+
...
243+
1..1
244+
ok 16 - describe only = false, with subtests
245+
---
246+
duration_ms: *
247+
type: 'suite'
248+
...
249+
1..16
250+
# tests 42
251+
# suites 5
228252
# pass 15
229253
# fail 0
230254
# cancelled 0
231-
# skipped 25
255+
# skipped 27
232256
# todo 0
233257
# duration_ms *

test/fixtures/test-runner/output/output.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,11 @@ test('callback async throw after done', (t, done) => {
288288
done();
289289
});
290290

291-
test('only is set but not in only mode', { only: true }, async (t) => {
292-
// All of these subtests should run.
291+
test('runOnly is set', async (t) => {
292+
// Subtests should run only outside of a runOnly block, unless they have only: true.
293293
await t.test('running subtest 1');
294294
t.runOnly(true);
295-
await t.test('running subtest 2');
295+
await t.test('skipped subtest 2');
296296
await t.test('running subtest 3', { only: true });
297297
t.runOnly(false);
298298
await t.test('running subtest 4');

0 commit comments

Comments
 (0)