Skip to content

Commit bee587f

Browse files
authored
[node] Harden TestContext's assert against missing methods, add missing v22 method (DefinitelyTyped#71902)
1 parent 50d34f9 commit bee587f

File tree

4 files changed

+91
-267
lines changed

4 files changed

+91
-267
lines changed

types/node/test.d.ts

Lines changed: 40 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,23 @@ declare module "node:test" {
564564
/**
565565
* An object containing assertion methods bound to the test context.
566566
* The top-level functions from the `node:assert` module are exposed here for the purpose of creating test plans.
567+
*
568+
* **Note:** Some of the functions from `node:assert` contain type assertions. If these are called via the
569+
* TestContext `assert` object, then the context parameter in the test's function signature **must be explicitly typed**
570+
* (ie. the parameter must have a type annotation), otherwise an error will be raised by the TypeScript compiler:
571+
* ```ts
572+
* import { test, type TestContext } from 'node:test';
573+
*
574+
* // The test function's context parameter must have a type annotation.
575+
* test('example', (t: TestContext) => {
576+
* t.assert.deepStrictEqual(actual, expected);
577+
* });
578+
*
579+
* // Omitting the type annotation will result in a compilation error.
580+
* test('example', t => {
581+
* t.assert.deepStrictEqual(actual, expected); // Error: 't' needs an explicit type annotation.
582+
* });
583+
* ```
567584
* @since v22.2.0, v20.15.0
568585
*/
569586
readonly assert: TestContextAssert;
@@ -741,139 +758,29 @@ declare module "node:test" {
741758
*/
742759
readonly mock: MockTracker;
743760
}
744-
interface TestContextAssert {
745-
/**
746-
* Identical to the `deepEqual` function from the `node:assert` module, but bound to the test context.
747-
*/
748-
deepEqual: typeof import("node:assert").deepEqual;
749-
/**
750-
* Identical to the `deepStrictEqual` function from the `node:assert` module, but bound to the test context.
751-
*
752-
* **Note:** as this method returns a type assertion, the context parameter in the callback signature must have a
753-
* type annotation, otherwise an error will be raised by the TypeScript compiler:
754-
* ```ts
755-
* import { test, type TestContext } from 'node:test';
756-
*
757-
* // The test function's context parameter must have a type annotation.
758-
* test('example', (t: TestContext) => {
759-
* t.assert.deepStrictEqual(actual, expected);
760-
* });
761-
*
762-
* // Omitting the type annotation will result in a compilation error.
763-
* test('example', t => {
764-
* t.assert.deepStrictEqual(actual, expected); // Error: 't' needs an explicit type annotation.
765-
* });
766-
* ```
767-
*/
768-
deepStrictEqual: typeof import("node:assert").deepStrictEqual;
769-
/**
770-
* Identical to the `doesNotMatch` function from the `node:assert` module, but bound to the test context.
771-
*/
772-
doesNotMatch: typeof import("node:assert").doesNotMatch;
773-
/**
774-
* Identical to the `doesNotReject` function from the `node:assert` module, but bound to the test context.
775-
*/
776-
doesNotReject: typeof import("node:assert").doesNotReject;
777-
/**
778-
* Identical to the `doesNotThrow` function from the `node:assert` module, but bound to the test context.
779-
*/
780-
doesNotThrow: typeof import("node:assert").doesNotThrow;
781-
/**
782-
* Identical to the `equal` function from the `node:assert` module, but bound to the test context.
783-
*/
784-
equal: typeof import("node:assert").equal;
785-
/**
786-
* Identical to the `fail` function from the `node:assert` module, but bound to the test context.
787-
*/
788-
fail: typeof import("node:assert").fail;
789-
/**
790-
* Identical to the `ifError` function from the `node:assert` module, but bound to the test context.
791-
*
792-
* **Note:** as this method returns a type assertion, the context parameter in the callback signature must have a
793-
* type annotation, otherwise an error will be raised by the TypeScript compiler:
794-
* ```ts
795-
* import { test, type TestContext } from 'node:test';
796-
*
797-
* // The test function's context parameter must have a type annotation.
798-
* test('example', (t: TestContext) => {
799-
* t.assert.ifError(err);
800-
* });
801-
*
802-
* // Omitting the type annotation will result in a compilation error.
803-
* test('example', t => {
804-
* t.assert.ifError(err); // Error: 't' needs an explicit type annotation.
805-
* });
806-
* ```
807-
*/
808-
ifError: typeof import("node:assert").ifError;
809-
/**
810-
* Identical to the `match` function from the `node:assert` module, but bound to the test context.
811-
*/
812-
match: typeof import("node:assert").match;
813-
/**
814-
* Identical to the `notDeepEqual` function from the `node:assert` module, but bound to the test context.
815-
*/
816-
notDeepEqual: typeof import("node:assert").notDeepEqual;
817-
/**
818-
* Identical to the `notDeepStrictEqual` function from the `node:assert` module, but bound to the test context.
819-
*/
820-
notDeepStrictEqual: typeof import("node:assert").notDeepStrictEqual;
821-
/**
822-
* Identical to the `notEqual` function from the `node:assert` module, but bound to the test context.
823-
*/
824-
notEqual: typeof import("node:assert").notEqual;
825-
/**
826-
* Identical to the `notStrictEqual` function from the `node:assert` module, but bound to the test context.
827-
*/
828-
notStrictEqual: typeof import("node:assert").notStrictEqual;
829-
/**
830-
* Identical to the `ok` function from the `node:assert` module, but bound to the test context.
831-
*
832-
* **Note:** as this method returns a type assertion, the context parameter in the callback signature must have a
833-
* type annotation, otherwise an error will be raised by the TypeScript compiler:
834-
* ```ts
835-
* import { test, type TestContext } from 'node:test';
836-
*
837-
* // The test function's context parameter must have a type annotation.
838-
* test('example', (t: TestContext) => {
839-
* t.assert.ok(condition);
840-
* });
841-
*
842-
* // Omitting the type annotation will result in a compilation error.
843-
* test('example', t => {
844-
* t.assert.ok(condition)); // Error: 't' needs an explicit type annotation.
845-
* });
846-
* ```
847-
*/
848-
ok: typeof import("node:assert").ok;
849-
/**
850-
* Identical to the `rejects` function from the `node:assert` module, but bound to the test context.
851-
*/
852-
rejects: typeof import("node:assert").rejects;
853-
/**
854-
* Identical to the `strictEqual` function from the `node:assert` module, but bound to the test context.
855-
*
856-
* **Note:** as this method returns a type assertion, the context parameter in the callback signature must have a
857-
* type annotation, otherwise an error will be raised by the TypeScript compiler:
858-
* ```ts
859-
* import { test, type TestContext } from 'node:test';
860-
*
861-
* // The test function's context parameter must have a type annotation.
862-
* test('example', (t: TestContext) => {
863-
* t.assert.strictEqual(actual, expected);
864-
* });
865-
*
866-
* // Omitting the type annotation will result in a compilation error.
867-
* test('example', t => {
868-
* t.assert.strictEqual(actual, expected); // Error: 't' needs an explicit type annotation.
869-
* });
870-
* ```
871-
*/
872-
strictEqual: typeof import("node:assert").strictEqual;
873-
/**
874-
* Identical to the `throws` function from the `node:assert` module, but bound to the test context.
875-
*/
876-
throws: typeof import("node:assert").throws;
761+
interface TestContextAssert extends
762+
Pick<
763+
typeof import("assert"),
764+
| "deepEqual"
765+
| "deepStrictEqual"
766+
| "doesNotMatch"
767+
| "doesNotReject"
768+
| "doesNotThrow"
769+
| "equal"
770+
| "fail"
771+
| "ifError"
772+
| "match"
773+
| "notDeepEqual"
774+
| "notDeepStrictEqual"
775+
| "notEqual"
776+
| "notStrictEqual"
777+
| "ok"
778+
| "partialDeepStrictEqual"
779+
| "rejects"
780+
| "strictEqual"
781+
| "throws"
782+
>
783+
{
877784
/**
878785
* This function implements assertions for snapshot testing.
879786
* ```js

types/node/test/test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,12 @@ const invalidTestContext = new TestContext();
998998
// @ts-expect-error Should not be able to instantiate a SuiteContext
999999
const invalidSuiteContext = new SuiteContext();
10001000

1001+
test("check all assertion functions are re-exported", t => {
1002+
type AssertModuleExports = keyof typeof import("assert");
1003+
const keys: keyof { [K in keyof typeof t.assert as K extends AssertModuleExports ? K : never]: any } =
1004+
{} as Exclude<AssertModuleExports, "AssertionError" | "CallTracker" | "strict">;
1005+
});
1006+
10011007
test("planning with streams", (t: TestContext, done) => {
10021008
function* generate() {
10031009
yield "a";

types/node/v20/test.d.ts

Lines changed: 39 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,23 @@ declare module "node:test" {
455455
/**
456456
* An object containing assertion methods bound to the test context.
457457
* The top-level functions from the `node:assert` module are exposed here for the purpose of creating test plans.
458+
*
459+
* **Note:** Some of the functions from `node:assert` contain type assertions. If these are called via the
460+
* TestContext `assert` object, then the context parameter in the test's function signature **must be explicitly typed**
461+
* (ie. the parameter must have a type annotation), otherwise an error will be raised by the TypeScript compiler:
462+
* ```ts
463+
* import { test, type TestContext } from 'node:test';
464+
*
465+
* // The test function's context parameter must have a type annotation.
466+
* test('example', (t: TestContext) => {
467+
* t.assert.deepStrictEqual(actual, expected);
468+
* });
469+
*
470+
* // Omitting the type annotation will result in a compilation error.
471+
* test('example', t => {
472+
* t.assert.deepStrictEqual(actual, expected); // Error: 't' needs an explicit type annotation.
473+
* });
474+
* ```
458475
* @since v20.15.0
459476
*/
460477
readonly assert: TestContextAssert;
@@ -626,140 +643,28 @@ declare module "node:test" {
626643
*/
627644
readonly mock: MockTracker;
628645
}
629-
interface TestContextAssert {
630-
/**
631-
* Identical to the `deepEqual` function from the `node:assert` module, but bound to the test context.
632-
*/
633-
deepEqual: typeof import("node:assert").deepEqual;
634-
/**
635-
* Identical to the `deepStrictEqual` function from the `node:assert` module, but bound to the test context.
636-
*
637-
* **Note:** as this method returns a type assertion, the context parameter in the callback signature must have a
638-
* type annotation, otherwise an error will be raised by the TypeScript compiler:
639-
* ```ts
640-
* import { test, type TestContext } from 'node:test';
641-
*
642-
* // The test function's context parameter must have a type annotation.
643-
* test('example', (t: TestContext) => {
644-
* t.assert.deepStrictEqual(actual, expected);
645-
* });
646-
*
647-
* // Omitting the type annotation will result in a compilation error.
648-
* test('example', t => {
649-
* t.assert.deepStrictEqual(actual, expected); // Error: 't' needs an explicit type annotation.
650-
* });
651-
* ```
652-
*/
653-
deepStrictEqual: typeof import("node:assert").deepStrictEqual;
654-
/**
655-
* Identical to the `doesNotMatch` function from the `node:assert` module, but bound to the test context.
656-
*/
657-
doesNotMatch: typeof import("node:assert").doesNotMatch;
658-
/**
659-
* Identical to the `doesNotReject` function from the `node:assert` module, but bound to the test context.
660-
*/
661-
doesNotReject: typeof import("node:assert").doesNotReject;
662-
/**
663-
* Identical to the `doesNotThrow` function from the `node:assert` module, but bound to the test context.
664-
*/
665-
doesNotThrow: typeof import("node:assert").doesNotThrow;
666-
/**
667-
* Identical to the `equal` function from the `node:assert` module, but bound to the test context.
668-
*/
669-
equal: typeof import("node:assert").equal;
670-
/**
671-
* Identical to the `fail` function from the `node:assert` module, but bound to the test context.
672-
*/
673-
fail: typeof import("node:assert").fail;
674-
/**
675-
* Identical to the `ifError` function from the `node:assert` module, but bound to the test context.
676-
*
677-
* **Note:** as this method returns a type assertion, the context parameter in the callback signature must have a
678-
* type annotation, otherwise an error will be raised by the TypeScript compiler:
679-
* ```ts
680-
* import { test, type TestContext } from 'node:test';
681-
*
682-
* // The test function's context parameter must have a type annotation.
683-
* test('example', (t: TestContext) => {
684-
* t.assert.ifError(err);
685-
* });
686-
*
687-
* // Omitting the type annotation will result in a compilation error.
688-
* test('example', t => {
689-
* t.assert.ifError(err); // Error: 't' needs an explicit type annotation.
690-
* });
691-
* ```
692-
*/
693-
ifError: typeof import("node:assert").ifError;
694-
/**
695-
* Identical to the `match` function from the `node:assert` module, but bound to the test context.
696-
*/
697-
match: typeof import("node:assert").match;
698-
/**
699-
* Identical to the `notDeepEqual` function from the `node:assert` module, but bound to the test context.
700-
*/
701-
notDeepEqual: typeof import("node:assert").notDeepEqual;
702-
/**
703-
* Identical to the `notDeepStrictEqual` function from the `node:assert` module, but bound to the test context.
704-
*/
705-
notDeepStrictEqual: typeof import("node:assert").notDeepStrictEqual;
706-
/**
707-
* Identical to the `notEqual` function from the `node:assert` module, but bound to the test context.
708-
*/
709-
notEqual: typeof import("node:assert").notEqual;
710-
/**
711-
* Identical to the `notStrictEqual` function from the `node:assert` module, but bound to the test context.
712-
*/
713-
notStrictEqual: typeof import("node:assert").notStrictEqual;
714-
/**
715-
* Identical to the `ok` function from the `node:assert` module, but bound to the test context.
716-
*
717-
* **Note:** as this method returns a type assertion, the context parameter in the callback signature must have a
718-
* type annotation, otherwise an error will be raised by the TypeScript compiler:
719-
* ```ts
720-
* import { test, type TestContext } from 'node:test';
721-
*
722-
* // The test function's context parameter must have a type annotation.
723-
* test('example', (t: TestContext) => {
724-
* t.assert.ok(condition);
725-
* });
726-
*
727-
* // Omitting the type annotation will result in a compilation error.
728-
* test('example', t => {
729-
* t.assert.ok(condition)); // Error: 't' needs an explicit type annotation.
730-
* });
731-
* ```
732-
*/
733-
ok: typeof import("node:assert").ok;
734-
/**
735-
* Identical to the `rejects` function from the `node:assert` module, but bound to the test context.
736-
*/
737-
rejects: typeof import("node:assert").rejects;
738-
/**
739-
* Identical to the `strictEqual` function from the `node:assert` module, but bound to the test context.
740-
*
741-
* **Note:** as this method returns a type assertion, the context parameter in the callback signature must have a
742-
* type annotation, otherwise an error will be raised by the TypeScript compiler:
743-
* ```ts
744-
* import { test, type TestContext } from 'node:test';
745-
*
746-
* // The test function's context parameter must have a type annotation.
747-
* test('example', (t: TestContext) => {
748-
* t.assert.strictEqual(actual, expected);
749-
* });
750-
*
751-
* // Omitting the type annotation will result in a compilation error.
752-
* test('example', t => {
753-
* t.assert.strictEqual(actual, expected); // Error: 't' needs an explicit type annotation.
754-
* });
755-
* ```
756-
*/
757-
strictEqual: typeof import("node:assert").strictEqual;
758-
/**
759-
* Identical to the `throws` function from the `node:assert` module, but bound to the test context.
760-
*/
761-
throws: typeof import("node:assert").throws;
762-
}
646+
interface TestContextAssert extends
647+
Pick<
648+
typeof import("assert"),
649+
| "deepEqual"
650+
| "deepStrictEqual"
651+
| "doesNotMatch"
652+
| "doesNotReject"
653+
| "doesNotThrow"
654+
| "equal"
655+
| "fail"
656+
| "ifError"
657+
| "match"
658+
| "notDeepEqual"
659+
| "notDeepStrictEqual"
660+
| "notEqual"
661+
| "notStrictEqual"
662+
| "ok"
663+
| "rejects"
664+
| "strictEqual"
665+
| "throws"
666+
>
667+
{}
763668

764669
/**
765670
* An instance of `SuiteContext` is passed to each suite function in order to

types/node/v20/test/test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,12 @@ const invalidTestContext = new TestContext();
952952
// @ts-expect-error Should not be able to instantiate a SuiteContext
953953
const invalidSuiteContext = new SuiteContext();
954954

955+
test("check all assertion functions are re-exported", t => {
956+
type AssertModuleExports = keyof typeof import("assert");
957+
const keys: keyof { [K in keyof typeof t.assert as K extends AssertModuleExports ? K : never]: any } =
958+
{} as Exclude<AssertModuleExports, "AssertionError" | "CallTracker" | "strict">;
959+
});
960+
955961
test("planning with streams", (t: TestContext, done) => {
956962
function* generate() {
957963
yield "a";

0 commit comments

Comments
 (0)