@@ -478,6 +478,82 @@ Test name patterns do not change the set of files that the test runner executes.
478478If both ` --test-name-pattern ` and ` --test-skip-pattern ` are supplied,
479479tests must satisfy ** both** requirements in order to be executed.
480480
481+ ## Test tags
482+
483+ <!-- YAML
484+ added: REPLACEME
485+ -->
486+
487+ > Stability: 1.0 - Early development
488+
489+ Tags annotate tests and suites with arbitrary string labels. The
490+ [ ` --experimental-test-tag-filter ` ] [ ] CLI flag (or the ` testTagFilters `
491+ option on [ ` run() ` ] [ ] ) selects tests whose tag set contains every
492+ provided filter value.
493+
494+ Tags are an alternative to encoding metadata into test names. They are
495+ useful for cross-cutting axes such as subsystem, speed bucket, flakiness,
496+ or environment, where a name pattern would be brittle.
497+
498+ ### Authoring tagged tests
499+
500+ Pass a ` tags ` array on any of ` test() ` , ` it() ` , ` suite() ` , or ` describe() ` .
501+ Tags inherit from a suite to its child tests by union—a test inside a
502+ suite tagged ` ['db'] ` that declares its own ` tags: ['integration'] `
503+ effectively has both tags.
504+
505+ ``` mjs
506+ import { describe , it } from ' node:test' ;
507+
508+ describe (' database' , { tags: [' db' ] }, () => {
509+ it (' reads a row' ); // tags: ['db']
510+ it (' writes a row' , { tags: [' integration' ] }); // tags: ['db', 'integration']
511+ it (' reconnects after disconnect' , { tags: [' flaky' ] }); // tags: ['db', 'flaky']
512+ });
513+ ```
514+
515+ ``` cjs
516+ const { describe , it } = require (' node:test' );
517+
518+ describe (' database' , { tags: [' db' ] }, () => {
519+ it (' reads a row' ); // tags: ['db']
520+ it (' writes a row' , { tags: [' integration' ] }); // tags: ['db', 'integration']
521+ it (' reconnects after disconnect' , { tags: [' flaky' ] }); // tags: ['db', 'flaky']
522+ });
523+ ```
524+
525+ Tag values must be non-empty strings. Tags are matched case-insensitively;
526+ the canonical form is lowercase. Duplicates within a single ` tags ` array
527+ are collapsed on the lowercased form, preserving the first-seen
528+ declaration order.
529+
530+ Hooks (` before ` , ` after ` , ` beforeEach ` , ` afterEach ` ) do not declare their
531+ own tags. They run as part of their owning suite, which carries the
532+ suite's tags.
533+
534+ ### Filtering by tag
535+
536+ Each [ ` --experimental-test-tag-filter ` ] [ ] value is a literal tag name. A
537+ test runs only when its tag set contains that name. The flag may be
538+ specified more than once; tests must match ** every** filter to run. The
539+ same applies to the ` testTagFilters ` array on [ ` run() ` ] [ ] . Filters are
540+ case-insensitive and AND'd with [ ` --test-name-pattern ` ] [ ] ,
541+ [ ` --test-skip-pattern ` ] [ ] , and ` .only ` filtering.
542+
543+ Untagged tests are excluded under any non-empty filter, since the filter
544+ requires the tag to be present.
545+
546+ ### Reading tags from inside a test
547+
548+ The [ ` TestContext ` ] [ ] object exposes the test's tags as a frozen array
549+ through [ ` context.tags ` ] [ ] , so tests can branch on their own metadata.
550+
551+ ### Errors
552+
553+ A tag value that violates the validation rules above throws
554+ ` ERR_INVALID_ARG_VALUE ` at the registration site, before any test runs.
555+ A non-array ` tags ` value throws ` ERR_INVALID_ARG_TYPE ` .
556+
481557## Extraneous asynchronous activity
482558
483559Once a test function finishes executing, the results are reported as quickly
@@ -749,6 +825,8 @@ test runner functionality:
749825
750826* ` --test ` - Prevented to avoid recursive test execution
751827* ` --experimental-test-coverage ` - Managed by the test runner
828+ * ` --experimental-test-tag-filter ` - Filter values are validated by the parent
829+ process and re-emitted to child processes
752830* ` --watch ` - Watch mode is handled at the parent level
753831* ` --experimental-default-config-file ` - Config file loading is handled by the parent
754832* ` --test-reporter ` - Reporting is managed by the parent process
@@ -1570,6 +1648,9 @@ added:
15701648 - v18.9.0
15711649 - v16.19.0
15721650changes:
1651+ - version: REPLACEME
1652+ pr-url: https://github.com/nodejs/node/pull/63221
1653+ description: Added the `testTagFilters` option.
15731654 - version: v24.14.0
15741655 pr-url: https://github.com/nodejs/node/pull/61367
15751656 description: Add the `env` option.
@@ -1656,6 +1737,10 @@ changes:
16561737 For each test that is executed, any corresponding test hooks, such as
16571738 ` beforeEach() ` , are also run.
16581739 ** Default:** ` undefined ` .
1740+ * ` testTagFilters ` {string|string\[ ] } A tag name, or an array of tag names,
1741+ used to filter tests by their declared tags. Tests must contain every
1742+ listed tag to run. Equivalent to passing [ ` --experimental-test-tag-filter ` ] [ ]
1743+ on the command line. See [ Test tags] [ ] . ** Default:** ` undefined ` .
16591744 * ` timeout ` {number} A number of milliseconds the test execution will
16601745 fail after.
16611746 If unspecified, subtests inherit this value from their parent.
@@ -1799,6 +1884,9 @@ added:
17991884 - v18.0.0
18001885 - v16.17.0
18011886changes:
1887+ - version: REPLACEME
1888+ pr-url: https://github.com/nodejs/node/pull/63221
1889+ description: Added the `tags` option.
18021890 - version:
18031891 - v20.2.0
18041892 - v18.17.0
@@ -1842,6 +1930,10 @@ changes:
18421930 * ` skip ` {boolean|string} If truthy, the test is skipped. If a string is
18431931 provided, that string is displayed in the test results as the reason for
18441932 skipping the test. ** Default:** ` false ` .
1933+ * ` tags ` {string\[ ] } An array of string labels associated with the test.
1934+ Used together with [ ` --experimental-test-tag-filter ` ] [ ] to filter which
1935+ tests run. Tags inherit from suites to nested tests by union. See
1936+ [ Test tags] [ ] . ** Default:** ` [] ` .
18451937 * ` todo ` {boolean|string} If truthy, the test marked as ` TODO ` . If a string
18461938 is provided, that string is displayed in the test results as the reason why
18471939 the test is ` TODO ` . ** Default:** ` false ` .
@@ -3425,6 +3517,9 @@ Emitted when code coverage is enabled and all tests have completed.
34253517 ` undefined ` if the test was run through the REPL.
34263518 * ` name ` {string} The test name.
34273519 * ` nesting ` {number} The nesting level of the test.
3520+ * ` tags ` {string\[ ] } The flattened lowercased tags declared on the test
3521+ and its ancestor suites, in declaration order. Empty for untagged tests.
3522+ See [ Test tags] [ ] .
34283523 * ` testId ` {number} A numeric identifier for this test instance, unique
34293524 within the test file's process. Consistent across all events for the same
34303525 test instance, enabling reliable correlation in custom reporters.
@@ -3448,6 +3543,9 @@ The corresponding declaration ordered events are `'test:pass'` and `'test:fail'`
34483543 ` undefined ` if the test was run through the REPL.
34493544 * ` name ` {string} The test name.
34503545 * ` nesting ` {number} The nesting level of the test.
3546+ * ` tags ` {string\[ ] } The flattened lowercased tags declared on the test
3547+ and its ancestor suites, in declaration order. Empty for untagged tests.
3548+ See [ Test tags] [ ] .
34513549 * ` testId ` {number} A numeric identifier for this test instance, unique
34523550 within the test file's process. Consistent across all events for the same
34533551 test instance, enabling reliable correlation in custom reporters.
@@ -3489,6 +3587,9 @@ defined.
34893587 ` undefined ` if the test was run through the REPL.
34903588 * ` name ` {string} The test name.
34913589 * ` nesting ` {number} The nesting level of the test.
3590+ * ` tags ` {string\[ ] } The flattened lowercased tags declared on the test
3591+ and its ancestor suites, in declaration order. Empty for untagged tests.
3592+ See [ Test tags] [ ] .
34923593 * ` testId ` {number} A numeric identifier for this test instance, unique
34933594 within the test file's process. Consistent across all events for the same
34943595 test instance, enabling reliable correlation in custom reporters.
@@ -3515,6 +3616,9 @@ Emitted when a test is enqueued for execution.
35153616 ` undefined ` if the test was run through the REPL.
35163617 * ` name ` {string} The test name.
35173618 * ` nesting ` {number} The nesting level of the test.
3619+ * ` tags ` {string\[ ] } The flattened lowercased tags declared on the test
3620+ and its ancestor suites, in declaration order. Empty for untagged tests.
3621+ See [ Test tags] [ ] .
35183622 * ` testId ` {number} A numeric identifier for this test instance, unique
35193623 within the test file's process. Consistent across all events for the same
35203624 test instance, enabling reliable correlation in custom reporters.
@@ -3572,6 +3676,9 @@ since the parent runner only knows about file-level tests. When using
35723676 ` undefined ` if the test was run through the REPL.
35733677 * ` name ` {string} The test name.
35743678 * ` nesting ` {number} The nesting level of the test.
3679+ * ` tags ` {string\[ ] } The flattened lowercased tags declared on the test
3680+ and its ancestor suites, in declaration order. Empty for untagged tests.
3681+ See [ Test tags] [ ] .
35753682 * ` testId ` {number} A numeric identifier for this test instance, unique
35763683 within the test file's process. Consistent across all events for the same
35773684 test instance, enabling reliable correlation in custom reporters.
@@ -3611,6 +3718,9 @@ defined.
36113718 ` undefined ` if the test was run through the REPL.
36123719 * ` name ` {string} The test name.
36133720 * ` nesting ` {number} The nesting level of the test.
3721+ * ` tags ` {string\[ ] } The flattened lowercased tags declared on the test
3722+ and its ancestor suites, in declaration order. Empty for untagged tests.
3723+ See [ Test tags] [ ] .
36143724 * ` testId ` {number} A numeric identifier for this test instance, unique
36153725 within the test file's process. Consistent across all events for the same
36163726 test instance, enabling reliable correlation in custom reporters.
@@ -4114,6 +4224,20 @@ The attempt number of the test. This value is zero-based, so the first attempt i
41144224the second attempt is ` 1 ` , and so on. This property is useful in conjunction with the
41154225` --test-rerun-failures ` option to determine which attempt the test is currently running.
41164226
4227+ ### ` context.tags `
4228+
4229+ <!-- YAML
4230+ added: REPLACEME
4231+ -->
4232+
4233+ > Stability: 1.0 - Early development
4234+
4235+ * Type: {string\[ ] }
4236+
4237+ A frozen array of the test's flattened lowercased tags, in declaration
4238+ order, including any tags inherited from ancestor suites. Empty when the
4239+ test has no tags. See [ Test tags] [ ] .
4240+
41174241### ` context.workerId `
41184242
41194243<!-- YAML
@@ -4329,6 +4453,9 @@ added:
43294453 - v18.0.0
43304454 - v16.17.0
43314455changes:
4456+ - version: REPLACEME
4457+ pr-url: https://github.com/nodejs/node/pull/63221
4458+ description: Added the `tags` option.
43324459 - version:
43334460 - v18.8.0
43344461 - v16.18.0
@@ -4359,6 +4486,10 @@ changes:
43594486 * ` skip ` {boolean|string} If truthy, the test is skipped. If a string is
43604487 provided, that string is displayed in the test results as the reason for
43614488 skipping the test. ** Default:** ` false ` .
4489+ * ` tags ` {string\[ ] } An array of string labels associated with the subtest.
4490+ Used together with [ ` --experimental-test-tag-filter ` ] [ ] to filter which
4491+ tests run. Tags inherit from the parent test or suite by union. See
4492+ [ Test tags] [ ] . ** Default:** ` [] ` .
43624493 * ` todo ` {boolean|string} If truthy, the test marked as ` TODO ` . If a string
43634494 is provided, that string is displayed in the test results as the reason why
43644495 the test is ` TODO ` . ** Default:** ` false ` .
@@ -4507,8 +4638,10 @@ test.describe('my suite', (suite) => {
45074638```
45084639
45094640[ TAP ] : https://testanything.org/
4641+ [ Test tags ] : #test-tags
45104642[ `--experimental-test-coverage` ] : cli.md#--experimental-test-coverage
45114643[ `--experimental-test-module-mocks` ] : cli.md#--experimental-test-module-mocks
4644+ [ `--experimental-test-tag-filter` ] : cli.md#--experimental-test-tag-filtertag
45124645[ `--import` ] : cli.md#--importmodule
45134646[ `--no-strip-types` ] : cli.md#--no-strip-types
45144647[ `--test-concurrency` ] : cli.md#--test-concurrency
@@ -4534,6 +4667,7 @@ test.describe('my suite', (suite) => {
45344667[ `assert.throws` ] : assert.md#assertthrowsfn-error-message
45354668[ `context.diagnostic` ] : #contextdiagnosticmessage
45364669[ `context.skip` ] : #contextskipmessage
4670+ [ `context.tags` ] : #contexttags
45374671[ `context.todo` ] : #contexttodomessage
45384672[ `describe()` ] : #describename-options-fn
45394673[ `diagnostics_channel` ] : diagnostics_channel.md
0 commit comments