From 2f59529dc50f1d8b0dd69fa22bdf0cf8db4cbaa7 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Thu, 9 May 2024 11:48:13 +0200 Subject: [PATCH] test_runner: support test plans Co-Authored-By: Marco Ippolito PR-URL: https://github.com/nodejs/node/pull/52860 Reviewed-By: Matteo Collina Reviewed-By: Paolo Insogna --- doc/api/test.md | 58 +++++++++- lib/internal/test_runner/runner.js | 3 +- lib/internal/test_runner/test.js | 79 ++++++++++++- .../test-runner/output/test-runner-plan.js | 79 +++++++++++++ .../output/test-runner-plan.snapshot | 105 ++++++++++++++++++ test/parallel/test-runner-output.mjs | 1 + 6 files changed, 321 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/test-runner/output/test-runner-plan.js create mode 100644 test/fixtures/test-runner/output/test-runner-plan.snapshot diff --git a/doc/api/test.md b/doc/api/test.md index d86c2cfc0bfb13..8d1e5a4624ce16 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -1364,6 +1364,10 @@ changes: * `timeout` {number} A number of milliseconds the test will fail after. If unspecified, subtests inherit this value from their parent. **Default:** `Infinity`. + * `plan` {number} The number of assertions and subtests expected to be run in the test. + If the number of assertions run in the test does not match the number + specified in the plan, the test will fail. + **Default:** `undefined`. * `fn` {Function|AsyncFunction} The function under test. The first argument to this function is a [`TestContext`][] object. If the test uses callbacks, the callback function is passed as the second argument. **Default:** A no-op @@ -2965,6 +2969,54 @@ added: The name of the test. +### `context.plan(count)` + + + +> Stability: 1 - Experimental + +* `count` {number} The number of assertions and subtests that are expected to run. + +This function is used to set the number of assertions and subtests that are expected to run +within the test. If the number of assertions and subtests that run does not match the +expected count, the test will fail. + +> Note: To make sure assertions are tracked, `t.assert` must be used instead of `assert` directly. + +```js +test('top level test', (t) => { + t.plan(2); + t.assert.ok('some relevant assertion here'); + t.subtest('subtest', () => {}); +}); +``` + +When working with asynchronous code, the `plan` function can be used to ensure that the +correct number of assertions are run: + +```js +test('planning with streams', (t, done) => { + function* generate() { + yield 'a'; + yield 'b'; + yield 'c'; + } + const expected = ['a', 'b', 'c']; + t.plan(expected.length); + const stream = Readable.from(generate()); + stream.on('data', (chunk) => { + t.assert.strictEqual(chunk, expected.shift()); + }); + + stream.on('end', () => { + done(); + }); +}); +``` + ### `context.runOnly(shouldRunOnlyTests)`