From 314cf639d69c5f8bb4c6f719a28a5d2f71c01ae7 Mon Sep 17 00:00:00 2001 From: AyushShende2679 Date: Thu, 1 Oct 2026 20:17:21 +0530 Subject: [PATCH] test: treat empty tests as todo Signed-off-by: AyushShende2679 --- lib/internal/test_runner/test.js | 48 ++++++++++++-------- test/parallel/test-runner-todo-skip-tests.js | 16 +++++-- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index 34f3dfaae9df..c2ea111322f7 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -582,6 +582,8 @@ class Test extends AsyncResource { const { concurrency, entryFile, expectFailure, loc, only, timeout, todo, skip, signal, plan } = options; const rawTags = options.tags; + const isTodo = fn === undefined; + if (typeof fn !== 'function') { fn = noop; } @@ -744,7 +746,9 @@ class Test extends AsyncResource { this.cancelled = false; this.expectFailure = parseExpectFailure(expectFailure) || this.parent?.expectFailure; this.skipped = skip !== undefined && skip !== false; - this.isTodo = (todo !== undefined && todo !== false) || this.parent?.isTodo; + this.isTodo = isTodo || + (todo !== undefined && todo !== false) || + this.parent?.isTodo; this.startTime = null; this.endTime = null; this.passed = false; @@ -871,8 +875,8 @@ class Test extends AsyncResource { if (this.root.harness.isFilteringByOnly && !this.only && !this.hasOnlyTests) { if (this.parent.runOnlySubtests || - this.parent.hasOnlyTests || - this.only === false) { + this.parent.hasOnlyTests || + this.only === false) { this.filtered = true; return; } @@ -985,7 +989,7 @@ class Test extends AsyncResource { this.readySubtests.set(subtest.reportOrder, subtest); if (this.unfinishedSubtests.delete(subtest) && - this.unfinishedSubtests.size === 0) { + this.unfinishedSubtests.size === 0) { this.subtestsPromise.resolve(); } } @@ -1138,7 +1142,7 @@ class Test extends AsyncResource { if (this.expectFailure) { if (typeof this.expectFailure === 'object' && - this.expectFailure.match !== undefined) { + this.expectFailure.match !== undefined) { const { match: validation } = this.expectFailure; try { const errorToCheck = ( @@ -1215,7 +1219,7 @@ class Test extends AsyncResource { log(message, data) { validateString(message, 'message'); this.reporter.log(this.nesting, this.loc, message, data, - this.name, this.testId, this.parent?.testId); + this.name, this.testId, this.parent?.testId); } start() { @@ -1234,7 +1238,7 @@ class Test extends AsyncResource { // pending for later execution. this.parent.unfinishedSubtests.add(this); this.reporter.enqueue(this.nesting, this.loc, this.name, this.reportedType, - this.testId, this.parent?.testId, this.tags); + this.testId, this.parent?.testId, this.tags); if (this.root.harness.buildPromise || !this.parent.hasConcurrency()) { const deferred = PromiseWithResolvers(); @@ -1258,7 +1262,7 @@ class Test extends AsyncResource { this.parent.assignReportOrder(this); this.reporter.dequeue(this.nesting, this.loc, this.name, this.reportedType, - this.testId, this.parent?.testId, this.tags); + this.testId, this.parent?.testId, this.tags); return this.run(); } @@ -1571,14 +1575,20 @@ class Test extends AsyncResource { if (coverage) { const coverages = [ - { __proto__: null, actual: coverage.totals.coveredLinePercent, - threshold: this.config.lineCoverage, name: 'line' }, - - { __proto__: null, actual: coverage.totals.coveredBranchPercent, - threshold: this.config.branchCoverage, name: 'branch' }, - - { __proto__: null, actual: coverage.totals.coveredFunctionPercent, - threshold: this.config.functionCoverage, name: 'function' }, + { + __proto__: null, actual: coverage.totals.coveredLinePercent, + threshold: this.config.lineCoverage, name: 'line' + }, + + { + __proto__: null, actual: coverage.totals.coveredBranchPercent, + threshold: this.config.branchCoverage, name: 'branch' + }, + + { + __proto__: null, actual: coverage.totals.coveredFunctionPercent, + threshold: this.config.functionCoverage, name: 'function' + }, ]; for (let i = 0; i < coverages.length; i++) { @@ -1631,7 +1641,7 @@ class Test extends AsyncResource { this.finished = true; if (this.parent === this.root && - this.root.waitingOn > this.root.subtests.length) { + this.root.waitingOn > this.root.subtests.length) { // At this point all of the tests have finished running. However, there // might be ref'ed handles keeping the event loop alive. This gives the // global after() hook a chance to clean them up. The user may also @@ -1795,8 +1805,8 @@ class Suite extends Test { } if (this.config.testNamePatterns !== null && - this.config.testSkipPatterns !== null && - !options.skip) { + this.config.testSkipPatterns !== null && + !options.skip) { this.fn = options.fn || this.fn; this.skipped = false; } diff --git a/test/parallel/test-runner-todo-skip-tests.js b/test/parallel/test-runner-todo-skip-tests.js index 3cabe55723b5..79939d01b312 100644 --- a/test/parallel/test-runner-todo-skip-tests.js +++ b/test/parallel/test-runner-todo-skip-tests.js @@ -1,4 +1,5 @@ 'use strict'; + const common = require('../common'); const assert = require('node:assert'); const { run, suite, test } = require('node:test'); @@ -7,10 +8,15 @@ if (!process.env.NODE_TEST_CONTEXT) { const stream = run({ files: [__filename] }); stream.on('test:fail', common.mustNotCall()); + stream.on('test:pass', common.mustCall((event) => { - assert.strictEqual(event.skip, true); - assert.strictEqual(event.todo, undefined); - }, 4)); + if (event.name === 'test with no callback') { + assert.strictEqual(event.todo, true); + } else { + assert.strictEqual(event.skip, true); + assert.strictEqual(event.todo, undefined); + } + }, 5)); } else { test('test options only', { skip: true, todo: true }, common.mustNotCall()); @@ -23,10 +29,12 @@ if (!process.env.NODE_TEST_CONTEXT) { t.skip(); })); + test('test with no callback'); + // Note - there is no test for the skip option and t.todo() because the skip // option prevents the test from running at all. This is verified by other // tests. // Suites don't have the context methods, so only test the options combination. suite('suite options only', { skip: true, todo: true }, common.mustNotCall()); -} +} \ No newline at end of file