From 77308d505623e34c99718b6f6e288317ba051a3b Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Thu, 15 Dec 2022 12:24:46 +0100 Subject: [PATCH 1/4] fix: improve types --- lib/test.d.ts | 139 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 120 insertions(+), 19 deletions(-) diff --git a/lib/test.d.ts b/lib/test.d.ts index 29e794b..8b3344f 100644 --- a/lib/test.d.ts +++ b/lib/test.d.ts @@ -1,25 +1,31 @@ interface TestOptions { /** - * The number of tests that can be run at the same time. If unspecified, subtests inherit this value from their parent. - * Default: 1. + * If a number is provided, then that many tests would run in parallel. If truthy, it would run (number of cpu cores - 1) tests in parallel. For subtests, it will be Infinity tests in parallel. If falsy, it would only run one test at a time. If unspecified, subtests inherit this value from their parent. + * @default false. */ concurrency?: boolean | number; + /** + * If truthy, and the test context is configured to run only tests, then this test will be run. Otherwise, the test is skipped. + * @default false. + */ + only?: boolean; + /** * If truthy, the test is skipped. If a string is provided, that string is displayed in the test results as the reason for skipping the test. - * Default: false. + * @default false. */ skip?: boolean | string; /** * If truthy, the test marked as TODO. If a string is provided, that string is displayed in the test results as the reason why the test is TODO. - * Default: false. + * @default false. */ todo?: boolean | string; /** * A number of milliseconds the test will fail after. If unspecified, subtests inherit this value from their parent. - * Default: Infinity + * @default Infinity */ timeout?: number; @@ -29,40 +35,114 @@ interface TestOptions { signal?: AbortSignal; } -type TestFn = (t: TestContext) => any | Promise; +type TestFn = (t: TestContext, done: (result?: any) => void) => any; export default test; -export function test(name: string, options: TestOptions, fn: TestFn): void; -export function test(name: string, fn: TestFn): void; -export function test(options: TestOptions, fn: TestFn): void; -export function test(fn: TestFn): void; +/** + * @param name The name of the test, which is displayed when reporting test results. + * Default: The name property of fn, or '' if fn does not have a name. + * @param options Configuration options for the test. + * @param fn 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 function. + * @returns A {@link Promise} resolved with `undefined` once the test completes. + */ +export function test( + name: string, + options: TestOptions, + fn: TestFn +): Promise; +export function test(name: string, fn: TestFn): Promise; +export function test(options: TestOptions, fn: TestFn): Promise; +export function test(fn: TestFn): Promise; type SuiteFn = (t: SuiteContext) => void; +/** + * @param name The name of the suite, which is displayed when reporting test results. + * Default: The name property of fn, or '' if fn does not have a name. + * @param options Configuration options for the suite. supports the same options as test([name][, options][, fn]). + * @param fn The function under suite declaring all subtests and subsuites. The first argument to this function is a SuiteContext object. + * Default: A no-op function. + * @returns `undefined` + */ export function describe(name: string, options: TestOptions, fn: SuiteFn): void; export function describe(name: string, fn: SuiteFn): void; export function describe(options: TestOptions, fn: SuiteFn): void; export function describe(fn: SuiteFn): void; -type ItFn = (t: ItContext) => any | Promise; +type ItFn = (done: (result?: any) => void) => any; +/** + * @param name The name of the test, which is displayed when reporting test results. + * Default: The name property of fn, or '' if fn does not have a name. + * @param options Configuration options for the suite. supports the same options as test([name][, options][, fn]). + * @param fn The function under test. If the test uses callbacks, the callback function is passed as an argument. + * Default: A no-op function. + * @returns `undefined` + */ export function it(name: string, options: TestOptions, fn: ItFn): void; export function it(name: string, fn: ItFn): void; export function it(options: TestOptions, fn: ItFn): void; export function it(fn: ItFn): void; +type HookFn = (done: (result?: any) => void) => any; + +/** + * This function is used to create a hook running before running a suite. + * + * @param fn The hook function. If the hook uses callbacks, the callback function is passed as the second argument. + * Default: A no-op function. + * @param options Configuration options for the hook. + */ +export function before(fn?: HookFn, options?: HookOptions): void; + +/** + * This function is used to create a hook running after running a suite. + * + * @param fn The hook function. If the hook uses callbacks, the callback function is passed as the second argument. + * Default: A no-op function. + * @param options Configuration options for the hook. + */ +export function after(fn?: HookFn, options?: HookOptions): void; + +/** + * This function is used to create a hook running before each subtest of the current suite. + * + * @param fn The hook function. If the hook uses callbacks, the callback function is passed as the second argument. + * Default: A no-op function. + * @param options Configuration options for the hook. + */ +export function beforeEach(fn?: HookFn, options?: HookOptions): void; + +/** + * This function is used to create a hook running after each subtest of the current test. + * + * @param fn The hook function. If the hook uses callbacks, the callback function is passed as the second argument. + * Default: A no-op function. + * @param options Configuration options for the hook. + */ +export function afterEach(fn?: HookFn, options?: HookOptions): void; + /** * An instance of TestContext is passed to each test function in order to interact with the test runner. * However, the TestContext constructor is not exposed as part of the API. */ declare class TestContext { + /** + * This function is used to create a hook running before each subtest of the current test. + */ + public beforeEach: typeof beforeEach; + + /** + * This function is used to create a hook running after each subtest of the current test. + */ + public afterEach: typeof afterEach; + /** * This function is used to create subtests under the current test. This function behaves in the same fashion as the top level test() function. */ - public test(name: string, options: TestOptions, fn: TestFn): Promise; - public test(name: string, fn: TestFn): Promise; - public test(fn: TestFn): Promise; + public test: typeof test; /** * This function is used to write TAP diagnostics to the output. @@ -72,6 +152,20 @@ declare class TestContext { */ public diagnostic(message: string): void; + /** + * The name of the test. + */ + public name: string; + + /** + * If `shouldRunOnlyTests` is truthy, the test context will only run tests that have the `only` + * option set. Otherwise, all tests are run. If Node.js was not started with the `--test-only` + * command-line option, this function is a no-op. + * + * @param shouldRunOnlyTests Whether or not to run `only` tests. + */ + public runOnly(shouldRunOnlyTests: boolean): void; + /** * This function causes the test's output to indicate the test as skipped. * If message is provided, it is included in the TAP output. @@ -108,12 +202,19 @@ declare class SuiteContext { } /** - * An instance of ItContext is passed to each suite function in order to interact with the test runner. - * However, the ItContext constructor is not exposed as part of the API. + * Configuration options for hooks. */ -declare class ItContext { +interface HookOptions { /** - * Can be used to abort test subtasks when the test has been aborted. + * Allows aborting an in-progress hook. */ - public signal: AbortSignal; + signal?: AbortSignal; + + /** + * A number of milliseconds the hook will fail after. If unspecified, subtests inherit this + * value from their parent. + * + * @default Infinity + */ + timeout?: number; } From 29c3de0a8fa89ddbfcaee7dc71f8a2a28c3e1e63 Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Fri, 16 Dec 2022 10:24:25 +0100 Subject: [PATCH 2/4] chore: format with prettier Using .prettierrc: ```json { "plugins": ["prettier-plugin-jsdoc"] } ``` --- lib/test.d.ts | 161 ++++++++++++++++++++++++++++---------------------- 1 file changed, 90 insertions(+), 71 deletions(-) diff --git a/lib/test.d.ts b/lib/test.d.ts index 8b3344f..e8e8a7b 100644 --- a/lib/test.d.ts +++ b/lib/test.d.ts @@ -1,37 +1,48 @@ interface TestOptions { /** - * If a number is provided, then that many tests would run in parallel. If truthy, it would run (number of cpu cores - 1) tests in parallel. For subtests, it will be Infinity tests in parallel. If falsy, it would only run one test at a time. If unspecified, subtests inherit this value from their parent. - * @default false. + * If a number is provided, then that many tests would run in parallel. If + * truthy, it would run (number of cpu cores - 1) tests in parallel. For + * subtests, it will be Infinity tests in parallel. If falsy, it would only + * run one test at a time. If unspecified, subtests inherit this value from + * their parent. + * + * @default false */ concurrency?: boolean | number; /** - * If truthy, and the test context is configured to run only tests, then this test will be run. Otherwise, the test is skipped. - * @default false. + * If truthy, and the test context is configured to run only tests, then this + * test will be run. Otherwise, the test is skipped. + * + * @default false */ only?: boolean; /** - * If truthy, the test is skipped. If a string is provided, that string is displayed in the test results as the reason for skipping the test. - * @default false. + * If truthy, the test is skipped. If a string is provided, that string is + * displayed in the test results as the reason for skipping the test. + * + * @default false */ skip?: boolean | string; /** - * If truthy, the test marked as TODO. If a string is provided, that string is displayed in the test results as the reason why the test is TODO. - * @default false. + * If truthy, the test marked as TODO. If a string is provided, that string is + * displayed in the test results as the reason why the test is TODO. + * + * @default false */ todo?: boolean | string; /** - * A number of milliseconds the test will fail after. If unspecified, subtests inherit this value from their parent. + * A number of milliseconds the test will fail after. If unspecified, subtests + * inherit this value from their parent. + * * @default Infinity */ timeout?: number; - /** - * Allows aborting an in-progress test - */ + /** Allows aborting an in-progress test */ signal?: AbortSignal; } @@ -40,11 +51,13 @@ type TestFn = (t: TestContext, done: (result?: any) => void) => any; export default test; /** - * @param name The name of the test, which is displayed when reporting test results. - * Default: The name property of fn, or '' if fn does not have a name. + * @param name The name of the test, which is displayed when reporting test + * results. Default: The name property of fn, or '' if fn does not + * have a name. * @param options Configuration options for the test. - * @param fn 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 function. + * @param fn 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 function. * @returns A {@link Promise} resolved with `undefined` once the test completes. */ export function test( @@ -59,11 +72,14 @@ export function test(fn: TestFn): Promise; type SuiteFn = (t: SuiteContext) => void; /** - * @param name The name of the suite, which is displayed when reporting test results. - * Default: The name property of fn, or '' if fn does not have a name. - * @param options Configuration options for the suite. supports the same options as test([name][, options][, fn]). - * @param fn The function under suite declaring all subtests and subsuites. The first argument to this function is a SuiteContext object. - * Default: A no-op function. + * @param name The name of the suite, which is displayed when reporting test + * results. Default: The name property of fn, or '' if fn does not + * have a name. + * @param options Configuration options for the suite. supports the same options + * as test([name][, options][, fn]). + * @param fn The function under suite declaring all subtests and subsuites. The + * first argument to this function is a SuiteContext object. Default: A no-op + * function. * @returns `undefined` */ export function describe(name: string, options: TestOptions, fn: SuiteFn): void; @@ -74,11 +90,13 @@ export function describe(fn: SuiteFn): void; type ItFn = (done: (result?: any) => void) => any; /** - * @param name The name of the test, which is displayed when reporting test results. - * Default: The name property of fn, or '' if fn does not have a name. - * @param options Configuration options for the suite. supports the same options as test([name][, options][, fn]). - * @param fn The function under test. If the test uses callbacks, the callback function is passed as an argument. - * Default: A no-op function. + * @param name The name of the test, which is displayed when reporting test + * results. Default: The name property of fn, or '' if fn does not + * have a name. + * @param options Configuration options for the suite. supports the same options + * as test([name][, options][, fn]). + * @param fn The function under test. If the test uses callbacks, the callback + * function is passed as an argument. Default: A no-op function. * @returns `undefined` */ export function it(name: string, options: TestOptions, fn: ItFn): void; @@ -91,8 +109,8 @@ type HookFn = (done: (result?: any) => void) => any; /** * This function is used to create a hook running before running a suite. * - * @param fn The hook function. If the hook uses callbacks, the callback function is passed as the second argument. - * Default: A no-op function. + * @param fn The hook function. If the hook uses callbacks, the callback + * function is passed as the second argument. Default: A no-op function. * @param options Configuration options for the hook. */ export function before(fn?: HookFn, options?: HookOptions): void; @@ -100,119 +118,120 @@ export function before(fn?: HookFn, options?: HookOptions): void; /** * This function is used to create a hook running after running a suite. * - * @param fn The hook function. If the hook uses callbacks, the callback function is passed as the second argument. - * Default: A no-op function. + * @param fn The hook function. If the hook uses callbacks, the callback + * function is passed as the second argument. Default: A no-op function. * @param options Configuration options for the hook. */ export function after(fn?: HookFn, options?: HookOptions): void; /** - * This function is used to create a hook running before each subtest of the current suite. + * This function is used to create a hook running before each subtest of the + * current suite. * - * @param fn The hook function. If the hook uses callbacks, the callback function is passed as the second argument. - * Default: A no-op function. + * @param fn The hook function. If the hook uses callbacks, the callback + * function is passed as the second argument. Default: A no-op function. * @param options Configuration options for the hook. */ export function beforeEach(fn?: HookFn, options?: HookOptions): void; /** - * This function is used to create a hook running after each subtest of the current test. + * This function is used to create a hook running after each subtest of the + * current test. * - * @param fn The hook function. If the hook uses callbacks, the callback function is passed as the second argument. - * Default: A no-op function. + * @param fn The hook function. If the hook uses callbacks, the callback + * function is passed as the second argument. Default: A no-op function. * @param options Configuration options for the hook. */ export function afterEach(fn?: HookFn, options?: HookOptions): void; /** - * An instance of TestContext is passed to each test function in order to interact with the test runner. - * However, the TestContext constructor is not exposed as part of the API. + * An instance of TestContext is passed to each test function in order to + * interact with the test runner. However, the TestContext constructor is not + * exposed as part of the API. */ declare class TestContext { /** - * This function is used to create a hook running before each subtest of the current test. + * This function is used to create a hook running before each subtest of the + * current test. */ public beforeEach: typeof beforeEach; /** - * This function is used to create a hook running after each subtest of the current test. + * This function is used to create a hook running after each subtest of the + * current test. */ public afterEach: typeof afterEach; /** - * This function is used to create subtests under the current test. This function behaves in the same fashion as the top level test() function. + * This function is used to create subtests under the current test. This + * function behaves in the same fashion as the top level test() function. */ public test: typeof test; /** - * This function is used to write TAP diagnostics to the output. - * Any diagnostic information is included at the end of the test's results. This function does not return a value. + * This function is used to write TAP diagnostics to the output. Any + * diagnostic information is included at the end of the test's results. This + * function does not return a value. * * @param message Message to be displayed as a TAP diagnostic. */ public diagnostic(message: string): void; - /** - * The name of the test. - */ + /** The name of the test. */ public name: string; /** - * If `shouldRunOnlyTests` is truthy, the test context will only run tests that have the `only` - * option set. Otherwise, all tests are run. If Node.js was not started with the `--test-only` - * command-line option, this function is a no-op. + * If `shouldRunOnlyTests` is truthy, the test context will only run tests + * that have the `only` option set. Otherwise, all tests are run. If Node.js + * was not started with the `--test-only` command-line option, this function + * is a no-op. * * @param shouldRunOnlyTests Whether or not to run `only` tests. */ public runOnly(shouldRunOnlyTests: boolean): void; /** - * This function causes the test's output to indicate the test as skipped. - * If message is provided, it is included in the TAP output. - * Calling skip() does not terminate execution of the test function. This function does not return a value. + * This function causes the test's output to indicate the test as skipped. If + * message is provided, it is included in the TAP output. Calling skip() does + * not terminate execution of the test function. This function does not return + * a value. * * @param message Optional skip message to be displayed in TAP output. */ public skip(message?: string): void; /** - * This function adds a TODO directive to the test's output. - * If message is provided, it is included in the TAP output. - * Calling todo() does not terminate execution of the test function. This function does not return a value. + * This function adds a TODO directive to the test's output. If message is + * provided, it is included in the TAP output. Calling todo() does not + * terminate execution of the test function. This function does not return a + * value. * * @param message Optional TODO message to be displayed in TAP output. */ public todo(message?: string): void; - /** - * Can be used to abort test subtasks when the test has been aborted. - */ + /** Can be used to abort test subtasks when the test has been aborted. */ public signal: AbortSignal; } /** - * An instance of SuiteContext is passed to each suite function in order to interact with the test runner. - * However, the SuiteContext constructor is not exposed as part of the API. + * An instance of SuiteContext is passed to each suite function in order to + * interact with the test runner. However, the SuiteContext constructor is not + * exposed as part of the API. */ declare class SuiteContext { - /** - * Can be used to abort test subtasks when the test has been aborted. - */ + /** Can be used to abort test subtasks when the test has been aborted. */ public signal: AbortSignal; } -/** - * Configuration options for hooks. - */ +/** Configuration options for hooks. */ interface HookOptions { - /** - * Allows aborting an in-progress hook. - */ + /** Allows aborting an in-progress hook. */ signal?: AbortSignal; /** - * A number of milliseconds the hook will fail after. If unspecified, subtests inherit this - * value from their parent. + * A number of milliseconds the hook will fail after. If unspecified, subtests + * inherit this value from their parent. * * @default Infinity */ From 54dc7d87a87756b99f9b9f8d642f723410d385f5 Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Fri, 16 Dec 2022 10:28:21 +0100 Subject: [PATCH 3/4] fix: make all exported fn params optional --- lib/test.d.ts | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/test.d.ts b/lib/test.d.ts index e8e8a7b..6f806cd 100644 --- a/lib/test.d.ts +++ b/lib/test.d.ts @@ -61,13 +61,13 @@ export default test; * @returns A {@link Promise} resolved with `undefined` once the test completes. */ export function test( - name: string, - options: TestOptions, - fn: TestFn + name?: string, + options?: TestOptions, + fn?: TestFn ): Promise; -export function test(name: string, fn: TestFn): Promise; -export function test(options: TestOptions, fn: TestFn): Promise; -export function test(fn: TestFn): Promise; +export function test(name?: string, fn?: TestFn): Promise; +export function test(options?: TestOptions, fn?: TestFn): Promise; +export function test(fn?: TestFn): Promise; type SuiteFn = (t: SuiteContext) => void; @@ -82,10 +82,14 @@ type SuiteFn = (t: SuiteContext) => void; * function. * @returns `undefined` */ -export function describe(name: string, options: TestOptions, fn: SuiteFn): void; -export function describe(name: string, fn: SuiteFn): void; -export function describe(options: TestOptions, fn: SuiteFn): void; -export function describe(fn: SuiteFn): void; +export function describe( + name?: string, + options?: TestOptions, + fn?: SuiteFn +): void; +export function describe(name?: string, fn?: SuiteFn): void; +export function describe(options?: TestOptions, fn?: SuiteFn): void; +export function describe(fn?: SuiteFn): void; type ItFn = (done: (result?: any) => void) => any; @@ -99,10 +103,10 @@ type ItFn = (done: (result?: any) => void) => any; * function is passed as an argument. Default: A no-op function. * @returns `undefined` */ -export function it(name: string, options: TestOptions, fn: ItFn): void; -export function it(name: string, fn: ItFn): void; -export function it(options: TestOptions, fn: ItFn): void; -export function it(fn: ItFn): void; +export function it(name?: string, options?: TestOptions, fn?: ItFn): void; +export function it(name?: string, fn?: ItFn): void; +export function it(options?: TestOptions, fn?: ItFn): void; +export function it(fn?: ItFn): void; type HookFn = (done: (result?: any) => void) => any; From 9225f9ee9577cd0b8778c9f4664b0564a74fe53a Mon Sep 17 00:00:00 2001 From: Joram van den Boezem Date: Fri, 16 Dec 2022 12:00:13 +0100 Subject: [PATCH 4/4] fix: make 2nd+ params optional in overloads --- lib/test.d.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/test.d.ts b/lib/test.d.ts index 6f806cd..69d70d0 100644 --- a/lib/test.d.ts +++ b/lib/test.d.ts @@ -65,9 +65,9 @@ export function test( options?: TestOptions, fn?: TestFn ): Promise; -export function test(name?: string, fn?: TestFn): Promise; -export function test(options?: TestOptions, fn?: TestFn): Promise; -export function test(fn?: TestFn): Promise; +export function test(name: string, fn?: TestFn): Promise; +export function test(options: TestOptions, fn?: TestFn): Promise; +export function test(fn: TestFn): Promise; type SuiteFn = (t: SuiteContext) => void; @@ -87,9 +87,9 @@ export function describe( options?: TestOptions, fn?: SuiteFn ): void; -export function describe(name?: string, fn?: SuiteFn): void; -export function describe(options?: TestOptions, fn?: SuiteFn): void; -export function describe(fn?: SuiteFn): void; +export function describe(name: string, fn?: SuiteFn): void; +export function describe(options: TestOptions, fn?: SuiteFn): void; +export function describe(fn: SuiteFn): void; type ItFn = (done: (result?: any) => void) => any; @@ -104,9 +104,9 @@ type ItFn = (done: (result?: any) => void) => any; * @returns `undefined` */ export function it(name?: string, options?: TestOptions, fn?: ItFn): void; -export function it(name?: string, fn?: ItFn): void; -export function it(options?: TestOptions, fn?: ItFn): void; -export function it(fn?: ItFn): void; +export function it(name: string, fn?: ItFn): void; +export function it(options: TestOptions, fn?: ItFn): void; +export function it(fn: ItFn): void; type HookFn = (done: (result?: any) => void) => any;