From 8858e1ec618d54c41c8d166bf8904fd1b418c2c9 Mon Sep 17 00:00:00 2001 From: Moshe Atlow Date: Sun, 11 Jun 2023 18:02:18 +0300 Subject: [PATCH] test_runner: make `--test-name-pattern` recursive PR-URL: https://github.com/nodejs/node/pull/48382 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Colin Ihrig --- lib/internal/test_runner/test.js | 27 +++--- .../test-runner/output/name_pattern.js | 28 +++++- .../test-runner/output/name_pattern.snapshot | 90 ++++++++++++++++--- .../output/name_pattern_with_only.js | 2 +- .../output/name_pattern_with_only.snapshot | 8 +- 5 files changed, 124 insertions(+), 31 deletions(-) diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index 4dfbdcad0502ba..a6601fe6e79d71 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -246,16 +246,11 @@ class Test extends AsyncResource { this.timeout = timeout; } - if (testNamePatterns !== null) { - // eslint-disable-next-line no-use-before-define - const match = this instanceof TestHook || ArrayPrototypeSome( - testNamePatterns, - (re) => RegExpPrototypeExec(re, name) !== null, - ); + this.name = name; + this.parent = parent; - if (!match) { - skip = 'test name does not match pattern'; - } + if (testNamePatterns !== null && !this.matchesTestNamePatterns()) { + skip = 'test name does not match pattern'; } if (testOnlyFlag && !this.only) { @@ -276,8 +271,6 @@ class Test extends AsyncResource { this.fn = fn; this.harness = null; // Configured on the root test by the test harness. this.mock = null; - this.name = name; - this.parent = parent; this.cancelled = false; this.skipped = !!skip; this.isTodo = !!todo; @@ -302,6 +295,11 @@ class Test extends AsyncResource { } } + matchesTestNamePatterns() { + return ArrayPrototypeSome(testNamePatterns, (re) => RegExpPrototypeExec(re, this.name) !== null) || + this.parent?.matchesTestNamePatterns(); + } + hasConcurrency() { return this.concurrency > this.activeSubtests; } @@ -750,6 +748,9 @@ class TestHook extends Test { getRunArgs() { return this.#args; } + matchesTestNamePatterns() { + return true; + } postRun() { } } @@ -759,6 +760,10 @@ class Suite extends Test { constructor(options) { super(options); + if (testNamePatterns !== null && !options.skip && !options.todo) { + this.fn = options.fn || this.fn; + this.skipped = false; + } this.runOnlySubtests = testOnlyFlag; try { diff --git a/test/fixtures/test-runner/output/name_pattern.js b/test/fixtures/test-runner/output/name_pattern.js index 3c398e626611d0..f183c09057fa33 100644 --- a/test/fixtures/test-runner/output/name_pattern.js +++ b/test/fixtures/test-runner/output/name_pattern.js @@ -1,4 +1,4 @@ -// Flags: --no-warnings --test-name-pattern=enabled --test-name-pattern=/pattern/i +// Flags: --no-warnings --test-name-pattern=enabled --test-name-pattern=yes --test-name-pattern=/pattern/i 'use strict'; const common = require('../../../common'); const { @@ -18,7 +18,7 @@ it('top level it enabled', common.mustCall()); it('top level it disabled', common.mustNotCall()); it.skip('top level skipped it disabled', common.mustNotCall()); it.skip('top level skipped it enabled', common.mustNotCall()); -describe('top level describe disabled', common.mustNotCall()); +describe('top level describe never disabled', common.mustCall()); describe.skip('top level skipped describe disabled', common.mustNotCall()); describe.skip('top level skipped describe enabled', common.mustNotCall()); test('top level runs because name includes PaTtErN', common.mustCall()); @@ -38,10 +38,30 @@ describe('top level describe enabled', () => { afterEach(common.mustCall(3)); after(common.mustCall()); - it('nested it disabled', common.mustNotCall()); + it('nested it not disabled', common.mustCall()); it('nested it enabled', common.mustCall()); - describe('nested describe disabled', common.mustNotCall()); + describe('nested describe not disabled', common.mustCall()); describe('nested describe enabled', common.mustCall(() => { it('is enabled', common.mustCall()); })); }); + +describe('yes', function() { + it('no', () => {}); + it('yes', () => {}); + + describe('maybe', function() { + it('no', () => {}); + it('yes', () => {}); + }); +}); + +describe('no', function() { + it('no', () => {}); + it('yes', () => {}); + + describe('maybe', function() { + it('no', () => {}); + it('yes', () => {}); + }); +}); diff --git a/test/fixtures/test-runner/output/name_pattern.snapshot b/test/fixtures/test-runner/output/name_pattern.snapshot index 36a1da9fbeff11..bd53cc1fd2b89e 100644 --- a/test/fixtures/test-runner/output/name_pattern.snapshot +++ b/test/fixtures/test-runner/output/name_pattern.snapshot @@ -34,8 +34,8 @@ ok 7 - top level skipped it enabled # SKIP --- duration_ms: * ... -# Subtest: top level describe disabled -ok 8 - top level describe disabled # SKIP test name does not match pattern +# Subtest: top level describe never disabled +ok 8 - top level describe never disabled --- duration_ms: * type: 'suite' @@ -69,8 +69,8 @@ ok 12 - top level test enabled duration_ms: * ... # Subtest: top level describe enabled - # Subtest: nested it disabled - ok 1 - nested it disabled # SKIP test name does not match pattern + # Subtest: nested it not disabled + ok 1 - nested it not disabled --- duration_ms: * ... @@ -79,8 +79,8 @@ ok 12 - top level test enabled --- duration_ms: * ... - # Subtest: nested describe disabled - ok 3 - nested describe disabled # SKIP test name does not match pattern + # Subtest: nested describe not disabled + ok 3 - nested describe not disabled --- duration_ms: * type: 'suite' @@ -103,12 +103,80 @@ ok 13 - top level describe enabled duration_ms: * type: 'suite' ... -1..13 -# tests 13 -# suites 6 -# pass 6 +# Subtest: yes + # Subtest: no + ok 1 - no + --- + duration_ms: * + ... + # Subtest: yes + ok 2 - yes + --- + duration_ms: * + ... + # Subtest: maybe + # Subtest: no + ok 1 - no + --- + duration_ms: * + ... + # Subtest: yes + ok 2 - yes + --- + duration_ms: * + ... + 1..2 + ok 3 - maybe + --- + duration_ms: * + type: 'suite' + ... + 1..3 +ok 14 - yes + --- + duration_ms: * + type: 'suite' + ... +# Subtest: no + # Subtest: no + ok 1 - no # SKIP test name does not match pattern + --- + duration_ms: * + ... + # Subtest: yes + ok 2 - yes + --- + duration_ms: * + ... + # Subtest: maybe + # Subtest: no + ok 1 - no # SKIP test name does not match pattern + --- + duration_ms: * + ... + # Subtest: yes + ok 2 - yes + --- + duration_ms: * + ... + 1..2 + ok 3 - maybe + --- + duration_ms: * + type: 'suite' + ... + 1..3 +ok 15 - no + --- + duration_ms: * + type: 'suite' + ... +1..15 +# tests 21 +# suites 10 +# pass 13 # fail 0 # cancelled 0 -# skipped 7 +# skipped 8 # todo 0 # duration_ms * diff --git a/test/fixtures/test-runner/output/name_pattern_with_only.js b/test/fixtures/test-runner/output/name_pattern_with_only.js index 1dc0f362f9be28..a3e2f1be2ad42d 100644 --- a/test/fixtures/test-runner/output/name_pattern_with_only.js +++ b/test/fixtures/test-runner/output/name_pattern_with_only.js @@ -5,7 +5,7 @@ const { test } = require('node:test'); test('enabled and only', { only: true }, common.mustCall(async (t) => { await t.test('enabled', common.mustCall()); - await t.test('disabled', common.mustNotCall()); + await t.test('disabled but parent not', common.mustCall()); })); test('enabled but not only', common.mustNotCall()); diff --git a/test/fixtures/test-runner/output/name_pattern_with_only.snapshot b/test/fixtures/test-runner/output/name_pattern_with_only.snapshot index 35fbbc223c6db0..ddfb29afaa2198 100644 --- a/test/fixtures/test-runner/output/name_pattern_with_only.snapshot +++ b/test/fixtures/test-runner/output/name_pattern_with_only.snapshot @@ -5,8 +5,8 @@ TAP version 13 --- duration_ms: * ... - # Subtest: disabled - ok 2 - disabled # SKIP test name does not match pattern + # Subtest: disabled but parent not + ok 2 - disabled but parent not --- duration_ms: * ... @@ -33,9 +33,9 @@ ok 4 - not only and does not match pattern # SKIP 'only' option not set 1..4 # tests 6 # suites 0 -# pass 2 +# pass 3 # fail 0 # cancelled 0 -# skipped 4 +# skipped 3 # todo 0 # duration_ms *