diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index 2203bbd3497659..174671e034f49f 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -14,6 +14,7 @@ const { MathMax, Number, NumberPrototypeToFixed, + ObjectAssign, ObjectKeys, ObjectSeal, Promise, @@ -358,7 +359,7 @@ class TestContext { this.#test.todo(message); } - test(name, options, fn) { + #runTest(name, options, fn) { const overrides = { __proto__: null, loc: getCallerLocation(), @@ -377,6 +378,14 @@ class TestContext { return subtest.start(); } + test = ObjectAssign((...args) => this.#runTest(...args), { + __proto__: null, + expectFailure: (name, opts, fn) => this.#runTest(name, { __proto__: null, ...opts, expectFailure: true }, fn), + only: (name, opts, fn) => this.#runTest(name, { __proto__: null, ...opts, only: true }, fn), + skip: (name, opts, fn) => this.#runTest(name, { __proto__: null, ...opts, skip: true }, fn), + todo: (name, opts, fn) => this.#runTest(name, { __proto__: null, ...opts, todo: true }, fn), + }); + before(fn, options) { this.#test.createHook('before', fn, { __proto__: null, diff --git a/test/parallel/test-runner-subtest-methods.js b/test/parallel/test-runner-subtest-methods.js new file mode 100644 index 00000000000000..08ddef85558798 --- /dev/null +++ b/test/parallel/test-runner-subtest-methods.js @@ -0,0 +1,53 @@ +'use strict'; + +require('../common'); +const assert = require('node:assert'); +const { test } = require('node:test'); +const { isPromise } = require('node:util/types'); + +test('subtest context should have test variants', async (t) => { + assert.strictEqual(typeof t.test, 'function'); + assert.strictEqual(typeof t.test.expectFailure, 'function'); + assert.strictEqual(typeof t.test.only, 'function'); + assert.strictEqual(typeof t.test.skip, 'function'); + assert.strictEqual(typeof t.test.todo, 'function'); +}); + +test('subtest should return a promise', async (t) => { + const normal = t.test('normal subtest'); + assert.ok(isPromise(normal)); + await normal; +}); + +test('t.test[variant]() should return a promise', async (t) => { + assert.ok(isPromise( + t.test.expectFailure('expectFailure subtest', () => { throw new Error('This should pass'); }) + )); + assert.ok(isPromise( + t.test.only('only subtest') + )); + assert.ok(isPromise( + t.test.skip('skip subtest') + )); + assert.ok(isPromise( + t.test.todo('todo subtest') + )); +}); + +test('nested subtests should have test variants', async (t) => { + await t.test('level 1', async (t) => { + assert.strictEqual(typeof t.test, 'function'); + assert.strictEqual(typeof t.test.expectFailure, 'function'); + assert.strictEqual(typeof t.test.only, 'function'); + assert.strictEqual(typeof t.test.skip, 'function'); + assert.strictEqual(typeof t.test.todo, 'function'); + + await t.test('level 2', async (t) => { + assert.strictEqual(typeof t.test, 'function'); + assert.strictEqual(typeof t.test.expectFailure, 'function'); + assert.strictEqual(typeof t.test.skip, 'function'); + assert.strictEqual(typeof t.test.todo, 'function'); + assert.strictEqual(typeof t.test.only, 'function'); + }); + }); +});