@@ -452,6 +452,12 @@ declare module "node:test" {
452452 * @since v18.0.0, v16.17.0
453453 */
454454 class TestContext {
455+ /**
456+ * An object containing assertion methods bound to the test context.
457+ * The top-level functions from the `node:assert` module are exposed here for the purpose of creating test plans.
458+ * @since v20.15.0
459+ */
460+ readonly assert : TestContextAssert ;
455461 /**
456462 * This function is used to create a hook running before subtest of the current test.
457463 * @param fn The hook function. If the hook uses callbacks, the callback function is passed as the second argument.
@@ -499,6 +505,42 @@ declare module "node:test" {
499505 * @since v18.8.0, v16.18.0
500506 */
501507 readonly name : string ;
508+ /**
509+ * Used to set the number of assertions and subtests that are expected to run within the test.
510+ * If the number of assertions and subtests that run does not match the expected count, the test will fail.
511+ *
512+ * To make sure assertions are tracked, the assert functions on `context.assert` must be used,
513+ * instead of importing from the `node:assert` module.
514+ * ```js
515+ * test('top level test', (t) => {
516+ * t.plan(2);
517+ * t.assert.ok('some relevant assertion here');
518+ * t.test('subtest', () => {});
519+ * });
520+ * ```
521+ *
522+ * When working with asynchronous code, the `plan` function can be used to ensure that the correct number of assertions are run:
523+ * ```js
524+ * test('planning with streams', (t, done) => {
525+ * function* generate() {
526+ * yield 'a';
527+ * yield 'b';
528+ * yield 'c';
529+ * }
530+ * const expected = ['a', 'b', 'c'];
531+ * t.plan(expected.length);
532+ * const stream = Readable.from(generate());
533+ * stream.on('data', (chunk) => {
534+ * t.assert.strictEqual(chunk, expected.shift());
535+ * });
536+ * stream.on('end', () => {
537+ * done();
538+ * });
539+ * });
540+ * ```
541+ * @since v20.15.0
542+ */
543+ plan ( count : number ) : void ;
502544 /**
503545 * If `shouldRunOnlyTests` is truthy, the test context will only run tests that
504546 * have the `only` option set. Otherwise, all tests are run. If Node.js was not
@@ -575,6 +617,76 @@ declare module "node:test" {
575617 */
576618 readonly mock : MockTracker ;
577619 }
620+ interface TestContextAssert {
621+ /**
622+ * Identical to the `deepEqual` function from the `node:assert` module, but bound to the test context.
623+ */
624+ deepEqual : typeof import ( "node:assert" ) . deepEqual ;
625+ /**
626+ * Identical to the `deepStrictEqual` function from the `node:assert` module, but bound to the test context.
627+ */
628+ deepStrictEqual : typeof import ( "node:assert" ) . deepStrictEqual ;
629+ /**
630+ * Identical to the `doesNotMatch` function from the `node:assert` module, but bound to the test context.
631+ */
632+ doesNotMatch : typeof import ( "node:assert" ) . doesNotMatch ;
633+ /**
634+ * Identical to the `doesNotReject` function from the `node:assert` module, but bound to the test context.
635+ */
636+ doesNotReject : typeof import ( "node:assert" ) . doesNotReject ;
637+ /**
638+ * Identical to the `doesNotThrow` function from the `node:assert` module, but bound to the test context.
639+ */
640+ doesNotThrow : typeof import ( "node:assert" ) . doesNotThrow ;
641+ /**
642+ * Identical to the `equal` function from the `node:assert` module, but bound to the test context.
643+ */
644+ equal : typeof import ( "node:assert" ) . equal ;
645+ /**
646+ * Identical to the `fail` function from the `node:assert` module, but bound to the test context.
647+ */
648+ fail : typeof import ( "node:assert" ) . fail ;
649+ /**
650+ * Identical to the `ifError` function from the `node:assert` module, but bound to the test context.
651+ */
652+ ifError : typeof import ( "node:assert" ) . ifError ;
653+ /**
654+ * Identical to the `match` function from the `node:assert` module, but bound to the test context.
655+ */
656+ match : typeof import ( "node:assert" ) . match ;
657+ /**
658+ * Identical to the `notDeepEqual` function from the `node:assert` module, but bound to the test context.
659+ */
660+ notDeepEqual : typeof import ( "node:assert" ) . notDeepEqual ;
661+ /**
662+ * Identical to the `notDeepStrictEqual` function from the `node:assert` module, but bound to the test context.
663+ */
664+ notDeepStrictEqual : typeof import ( "node:assert" ) . notDeepStrictEqual ;
665+ /**
666+ * Identical to the `notEqual` function from the `node:assert` module, but bound to the test context.
667+ */
668+ notEqual : typeof import ( "node:assert" ) . notEqual ;
669+ /**
670+ * Identical to the `notStrictEqual` function from the `node:assert` module, but bound to the test context.
671+ */
672+ notStrictEqual : typeof import ( "node:assert" ) . notStrictEqual ;
673+ /**
674+ * Identical to the `ok` function from the `node:assert` module, but bound to the test context.
675+ */
676+ ok : typeof import ( "node:assert" ) . ok ;
677+ /**
678+ * Identical to the `rejects` function from the `node:assert` module, but bound to the test context.
679+ */
680+ rejects : typeof import ( "node:assert" ) . rejects ;
681+ /**
682+ * Identical to the `strictEqual` function from the `node:assert` module, but bound to the test context.
683+ */
684+ strictEqual : typeof import ( "node:assert" ) . strictEqual ;
685+ /**
686+ * Identical to the `throws` function from the `node:assert` module, but bound to the test context.
687+ */
688+ throws : typeof import ( "node:assert" ) . throws ;
689+ }
578690
579691 /**
580692 * An instance of `SuiteContext` is passed to each suite function in order to
@@ -634,6 +746,14 @@ declare module "node:test" {
634746 * @default false
635747 */
636748 todo ?: boolean | string | undefined ;
749+ /**
750+ * The number of assertions and subtests expected to be run in the test.
751+ * If the number of assertions run in the test does not match the number
752+ * specified in the plan, the test will fail.
753+ * @default undefined
754+ * @since v20.15.0
755+ */
756+ plan ?: number | undefined ;
637757 }
638758 /**
639759 * This function creates a hook that runs before executing a suite.
0 commit comments