From 39abeec524cba21c09d5fcb84e3695b5e329af5b Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Wed, 18 May 2022 17:29:40 +1200 Subject: [PATCH 01/11] fix: export type information for node16 module resolution --- index.d.cts | 2 ++ index.d.ts | 10 +++++----- package.json | 20 ++++++++++++++++---- plugin.d.cts | 1 + types/{subscribable.ts => subscribable.d.ts} | 0 types/test-fn.d.ts | 6 +++--- types/try-fn.d.ts | 2 +- 7 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 index.d.cts create mode 100644 plugin.d.cts rename types/{subscribable.ts => subscribable.d.ts} (100%) diff --git a/index.d.cts b/index.d.cts new file mode 100644 index 000000000..fc433503e --- /dev/null +++ b/index.d.cts @@ -0,0 +1,2 @@ +import Ava from "./index.js"; +export = Ava; diff --git a/index.d.ts b/index.d.ts index 24b722040..50f1570d7 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,9 +1,9 @@ -import type {TestFn} from './types/test-fn'; +import type {TestFn} from './types/test-fn.js'; -export * from './types/assertions'; -export * from './types/try-fn'; -export * from './types/test-fn'; -export * from './types/subscribable'; +export * from './types/assertions.js'; +export * from './types/try-fn.js'; +export * from './types/test-fn.js'; +export * from './types/subscribable.js'; /** Call to declare a test, or chain to declare hooks or test modifiers */ declare const test: TestFn; diff --git a/package.json b/package.json index cb2c85406..802dbf9f2 100644 --- a/package.json +++ b/package.json @@ -10,13 +10,25 @@ }, "exports": { ".": { - "import": "./entrypoints/main.mjs", - "require": "./entrypoints/main.cjs" + "import": { + "types": "./index.d.ts", + "default": "./entrypoints/main.mjs" + }, + "require": { + "types": "./index.d.cts", + "default": "./entrypoints/main.cjs" + } }, "./eslint-plugin-helper": "./entrypoints/eslint-plugin-helper.cjs", "./plugin": { - "import": "./entrypoints/plugin.mjs", - "require": "./entrypoints/plugin.cjs" + "import": { + "types": "./plugin.d.ts", + "default": "./entrypoints/plugin.mjs" + }, + "require": { + "types": "./plugin.d.cts", + "default": "./entrypoints/plugin.cjs" + } } }, "type": "module", diff --git a/plugin.d.cts b/plugin.d.cts new file mode 100644 index 000000000..0cfae42ba --- /dev/null +++ b/plugin.d.cts @@ -0,0 +1 @@ +export * from "./plugin.js"; diff --git a/types/subscribable.ts b/types/subscribable.d.ts similarity index 100% rename from types/subscribable.ts rename to types/subscribable.d.ts diff --git a/types/test-fn.d.ts b/types/test-fn.d.ts index bcb9778ab..62b831f0a 100644 --- a/types/test-fn.d.ts +++ b/types/test-fn.d.ts @@ -1,6 +1,6 @@ -import type {Assertions} from './assertions'; -import type {Subscribable} from './subscribable'; -import type {TryFn} from './try-fn'; +import type {Assertions} from './assertions.js'; +import type {Subscribable} from './subscribable.js'; +import type {TryFn} from './try-fn.js'; /** The `t` value passed to test & hook implementations. */ export interface ExecutionContext extends Assertions { diff --git a/types/try-fn.d.ts b/types/try-fn.d.ts index 41a1664d5..8009df0c9 100644 --- a/types/try-fn.d.ts +++ b/types/try-fn.d.ts @@ -1,4 +1,4 @@ -import type {Implementation} from './test-fn'; +import type {Implementation} from './test-fn.js'; export type CommitDiscardOptions = { /** From 484fe31410b91daa4407ae7b38fe137fe2c3b2db Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Sun, 22 May 2022 17:14:54 +0200 Subject: [PATCH 02/11] Test type definitions with TS 4.6 and 4.7 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a52c69565..502f1e5dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ts-version: [~4.4, ~4.5] + ts-version: [~4.4, ~4.5, ~4.6, 4.7.1-rc] steps: - uses: actions/checkout@v2 - run: rm .npmrc From 7ed3a5a24aaeba1b61b0635c6bf67d349cbd7be0 Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Sun, 29 May 2022 17:18:48 +0200 Subject: [PATCH 03/11] Test with official TS 4.7 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 502f1e5dd..31320044b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ts-version: [~4.4, ~4.5, ~4.6, 4.7.1-rc] + ts-version: [~4.4, ~4.5, ~4.6, ~4.7] steps: - uses: actions/checkout@v2 - run: rm .npmrc From f815557acc5d9605364c1b6a1214be5369e0c99f Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Sun, 29 May 2022 18:44:20 +0200 Subject: [PATCH 04/11] Place .d.cts files in types/ This is both tidier and ensures they're included in the package. Also rename the import in main.d.cts. --- index.d.cts | 2 -- plugin.d.cts | 1 - types/main.d.cts | 3 +++ types/plugin.d.cts | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 index.d.cts delete mode 100644 plugin.d.cts create mode 100644 types/main.d.cts create mode 100644 types/plugin.d.cts diff --git a/index.d.cts b/index.d.cts deleted file mode 100644 index fc433503e..000000000 --- a/index.d.cts +++ /dev/null @@ -1,2 +0,0 @@ -import Ava from "./index.js"; -export = Ava; diff --git a/plugin.d.cts b/plugin.d.cts deleted file mode 100644 index 0cfae42ba..000000000 --- a/plugin.d.cts +++ /dev/null @@ -1 +0,0 @@ -export * from "./plugin.js"; diff --git a/types/main.d.cts b/types/main.d.cts new file mode 100644 index 000000000..340ce6bd7 --- /dev/null +++ b/types/main.d.cts @@ -0,0 +1,3 @@ +// FIXME: Self-refencing "ava" should work, but seems to fail. +import test from "../index.js"; +export = test diff --git a/types/plugin.d.cts b/types/plugin.d.cts new file mode 100644 index 000000000..14497324d --- /dev/null +++ b/types/plugin.d.cts @@ -0,0 +1,2 @@ +// FIXME: Self-refencing "ava/plugin" should work, but seems to fail. +export * from "../plugin.js"; From fdb302a72752d91c9e4543fcc9134cdaec1747a4 Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Sun, 29 May 2022 18:50:58 +0200 Subject: [PATCH 05/11] Point at correct files --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index cc7c318f5..454caa56c 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "default": "./entrypoints/main.mjs" }, "require": { - "types": "./index.d.cts", + "types": "./entrypoints/main.d.cts", "default": "./entrypoints/main.cjs" } }, @@ -26,7 +26,7 @@ "default": "./entrypoints/plugin.mjs" }, "require": { - "types": "./plugin.d.cts", + "types": "./entrypoints/plugin.d.cts", "default": "./entrypoints/plugin.cjs" } } From f391df11132036925fdf9247be16973005b0f67f Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Mon, 30 May 2022 19:42:23 +1200 Subject: [PATCH 06/11] fix: provide both cts and mts types --- .c8rc.json | 2 +- .xo-config.cjs | 2 +- index.d.cts | 7 + package.json | 6 +- plugin.d.cts | 77 +++++++++ types/assertions.d.cts | 339 +++++++++++++++++++++++++++++++++++++++ types/main.d.cts | 3 - types/plugin.d.cts | 2 - types/subscribable.d.cts | 6 + types/test-fn.d.cts | 231 ++++++++++++++++++++++++++ types/try-fn.d.cts | 58 +++++++ 11 files changed, 724 insertions(+), 9 deletions(-) create mode 100644 index.d.cts create mode 100644 plugin.d.cts create mode 100644 types/assertions.d.cts delete mode 100644 types/main.d.cts delete mode 100644 types/plugin.d.cts create mode 100644 types/subscribable.d.cts create mode 100644 types/test-fn.d.cts create mode 100644 types/try-fn.d.cts diff --git a/.c8rc.json b/.c8rc.json index af0d00eac..3409cc347 100644 --- a/.c8rc.json +++ b/.c8rc.json @@ -3,7 +3,7 @@ "exclude": [ "{coverage,examples,media,test,test-d,test-tap,types}/**", "*.config.cjs", - "*.d.ts" + "*.d.*(c|m)ts" ], "reporter": [ "html", diff --git a/.xo-config.cjs b/.xo-config.cjs index 97c38e53d..74b2df577 100644 --- a/.xo-config.cjs +++ b/.xo-config.cjs @@ -28,7 +28,7 @@ module.exports = { }, overrides: [ { - files: '**/*.d.ts', + files: '**/*.d.*(c|m)ts', rules: { 'import/extensions': 'off', }, diff --git a/index.d.cts b/index.d.cts new file mode 100644 index 000000000..4205f6cdb --- /dev/null +++ b/index.d.cts @@ -0,0 +1,7 @@ +import type {TestFn} from './types/test-fn.cjs'; + +/** Call to declare a test, or chain to declare hooks or test modifiers */ +declare const test: TestFn; + +/** Call to declare a test, or chain to declare hooks or test modifiers */ +export = test; diff --git a/package.json b/package.json index 454caa56c..abef0080c 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "default": "./entrypoints/main.mjs" }, "require": { - "types": "./entrypoints/main.d.cts", + "types": "./index.d.cts", "default": "./entrypoints/main.cjs" } }, @@ -26,7 +26,7 @@ "default": "./entrypoints/plugin.mjs" }, "require": { - "types": "./entrypoints/plugin.d.cts", + "types": "./plugin.d.cts", "default": "./entrypoints/plugin.cjs" } } @@ -43,7 +43,9 @@ "entrypoints", "lib", "types", + "index.d.cts", "index.d.ts", + "plugin.d.cts", "plugin.d.ts" ], "keywords": [ diff --git a/plugin.d.cts b/plugin.d.cts new file mode 100644 index 000000000..a2f68e179 --- /dev/null +++ b/plugin.d.cts @@ -0,0 +1,77 @@ +import {URL} from 'node:url'; + +export namespace SharedWorker { + export type ProtocolIdentifier = 'ava-4'; + + export type FactoryOptions = { + negotiateProtocol (supported: readonly ['ava-4']): Protocol; + // Add overloads for additional protocols. + }; + + export type Factory = (options: FactoryOptions) => void; + + export type Protocol = { + readonly initialData: Data; + readonly protocol: 'ava-4'; + broadcast: (data: Data) => BroadcastMessage; + ready: () => Protocol; + subscribe: () => AsyncIterableIterator>; + testWorkers: () => AsyncIterableIterator>; + }; + + export type BroadcastMessage = { + readonly id: string; + replies: () => AsyncIterableIterator>; + }; + + export type PublishedMessage = { + readonly id: string; + replies: () => AsyncIterableIterator>; + }; + + export type ReceivedMessage = { + readonly data: Data; + readonly id: string; + readonly testWorker: TestWorker; + reply: (data: Data) => PublishedMessage; + }; + + export type TestWorker = { + readonly id: string; + readonly file: string; + publish: (data: Data) => PublishedMessage; + subscribe: () => AsyncIterableIterator>; + teardown: (fn: (() => Promise) | (() => void)) => () => Promise; + }; + + export namespace Plugin { + export type RegistrationOptions = { + readonly filename: string | URL; + readonly initialData?: Data; + readonly supportedProtocols: readonly Identifier[]; + readonly teardown?: () => void; + }; + + export type Protocol = { + readonly available: Promise; + readonly currentlyAvailable: boolean; + readonly protocol: 'ava-4'; + publish: (data: Data) => PublishedMessage; + subscribe: () => AsyncIterableIterator>; + }; + + export type PublishedMessage = { + readonly id: string; + replies: () => AsyncIterableIterator>; + }; + + export type ReceivedMessage = { + readonly data: Data; + readonly id: string; + reply: (data: Data) => PublishedMessage; + }; + } +} + +export function registerSharedWorker(options: SharedWorker.Plugin.RegistrationOptions<'ava-4', Data>): SharedWorker.Plugin.Protocol; +// Add overloads for additional protocols. diff --git a/types/assertions.d.cts b/types/assertions.d.cts new file mode 100644 index 000000000..0d2c8506b --- /dev/null +++ b/types/assertions.d.cts @@ -0,0 +1,339 @@ +export type ErrorConstructor = new (...args: any[]) => Error; + +/** Specify one or more expectations the thrown error must satisfy. */ +export type ThrowsExpectation = { + /** The thrown error must have a code that equals the given string or number. */ + code?: string | number; + + /** The thrown error must be an instance of this constructor. */ + instanceOf?: ErrorConstructor; + + /** The thrown error must be strictly equal to this value. */ + is?: Error; + + /** The thrown error must have a message that equals the given string, or matches the regular expression. */ + message?: string | RegExp | ((message: string) => boolean); + + /** The thrown error must have a name that equals the given string. */ + name?: string; +}; + +export interface Assertions { + /** + * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean + * indicating whether the assertion passed. + */ + assert: AssertAssertion; + + /** + * Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning a boolean indicating whether the assertion passed. + */ + deepEqual: DeepEqualAssertion; + + /** + * Assert that `value` is like `selector`, returning a boolean indicating whether the assertion passed. + */ + like: LikeAssertion; + + /** Fail the test, always returning `false`. */ + fail: FailAssertion; + + /** + * Assert that `actual` is strictly false, returning a boolean indicating whether the assertion passed. + */ + false: FalseAssertion; + + /** + * Assert that `actual` is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), returning a boolean + * indicating whether the assertion passed. + */ + falsy: FalsyAssertion; + + /** + * Assert that `actual` is [the same + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, + * returning a boolean indicating whether the assertion passed. + */ + is: IsAssertion; + + /** + * Assert that `actual` is not [the same + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, + * returning a boolean indicating whether the assertion passed. + */ + not: NotAssertion; + + /** + * Assert that `actual` is not [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning a boolean indicating whether the assertion passed. + */ + notDeepEqual: NotDeepEqualAssertion; + + /** + * Assert that `string` does not match the regular expression, returning a boolean indicating whether the assertion + * passed. + */ + notRegex: NotRegexAssertion; + + /** Assert that the function does not throw. */ + notThrows: NotThrowsAssertion; + + /** Assert that the async function does not throw, or that the promise does not reject. Must be awaited. */ + notThrowsAsync: NotThrowsAsyncAssertion; + + /** Count a passing assertion, always returning `true`. */ + pass: PassAssertion; + + /** + * Assert that `string` matches the regular expression, returning a boolean indicating whether the assertion passed. + */ + regex: RegexAssertion; + + /** + * Assert that `expected` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to a + * previously recorded [snapshot](https://github.com/concordancejs/concordance#serialization-details), or if + * necessary record a new snapshot. + */ + snapshot: SnapshotAssertion; + + /** + * Assert that the function throws [an error](https://www.npmjs.com/package/is-error). If so, returns the error value. + */ + throws: ThrowsAssertion; + + /** + * Assert that the async function throws [an error](https://www.npmjs.com/package/is-error), or the promise rejects + * with one. If so, returns a promise for the error value, which must be awaited. + */ + throwsAsync: ThrowsAsyncAssertion; + + /** + * Assert that `actual` is strictly true, returning a boolean indicating whether the assertion passed. + */ + true: TrueAssertion; + + /** + * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean + * indicating whether the assertion passed. + */ + truthy: TruthyAssertion; +} + +export interface AssertAssertion { + /** + * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean + * indicating whether the assertion passed. + */ + (actual: any, message?: string): boolean; + + /** Skip this assertion. */ + skip(actual: any, message?: string): void; +} + +export interface DeepEqualAssertion { + /** + * Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning a boolean indicating whether the assertion passed. + */ + (actual: Actual, expected: Expected, message?: string): actual is Expected; + + /** + * Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning a boolean indicating whether the assertion passed. + */ + (actual: Actual, expected: Expected, message?: string): expected is Actual; + + /** + * Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning a boolean indicating whether the assertion passed. + */ + (actual: Actual, expected: Expected, message?: string): boolean; + + /** Skip this assertion. */ + skip(actual: any, expected: any, message?: string): void; +} + +export interface LikeAssertion { + /** + * Assert that `value` is like `selector`, returning a boolean indicating whether the assertion passed. + */ + >(value: any, selector: Expected, message?: string): value is Expected; + + /** Skip this assertion. */ + skip(value: any, selector: any, message?: string): void; +} + +export interface FailAssertion { + /** Fail the test, always returning `false`. */ + (message?: string): boolean; + + /** Skip this assertion. */ + skip(message?: string): void; +} + +export interface FalseAssertion { + /** + * Assert that `actual` is strictly false, returning a boolean indicating whether the assertion passed. + */ + (actual: any, message?: string): actual is false; + + /** Skip this assertion. */ + skip(actual: any, message?: string): void; +} + +export interface FalsyAssertion { + /** + * Assert that `actual` is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), returning a boolean + * indicating whether the assertion passed. + */ + (actual: any, message?: string): boolean; + + /** Skip this assertion. */ + skip(actual: any, message?: string): void; +} + +export interface IsAssertion { + /** + * Assert that `actual` is [the same + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, + * returning a boolean indicating whether the assertion passed. + */ + (actual: Actual, expected: Expected, message?: string): actual is Expected; + + /** Skip this assertion. */ + skip(actual: any, expected: any, message?: string): void; +} + +export interface NotAssertion { + /** + * Assert that `actual` is not [the same + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, + * returning a boolean indicating whether the assertion passed. + */ + (actual: Actual, expected: Expected, message?: string): boolean; + + /** Skip this assertion. */ + skip(actual: any, expected: any, message?: string): void; +} + +export interface NotDeepEqualAssertion { + /** + * Assert that `actual` is not [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning a boolean indicating whether the assertion passed. + */ + (actual: Actual, expected: Expected, message?: string): boolean; + + /** Skip this assertion. */ + skip(actual: any, expected: any, message?: string): void; +} + +export interface NotRegexAssertion { + /** + * Assert that `string` does not match the regular expression, returning a boolean indicating whether the assertion + * passed. + */ + (string: string, regex: RegExp, message?: string): boolean; + + /** Skip this assertion. */ + skip(string: string, regex: RegExp, message?: string): void; +} + +export interface NotThrowsAssertion { + /** Assert that the function does not throw. */ + (fn: () => any, message?: string): void; + + /** Skip this assertion. */ + skip(fn: () => any, message?: string): void; +} + +export interface NotThrowsAsyncAssertion { + /** Assert that the async function does not throw. You must await the result. */ + (fn: () => PromiseLike, message?: string): Promise; + + /** Assert that the promise does not reject. You must await the result. */ + (promise: PromiseLike, message?: string): Promise; // eslint-disable-line @typescript-eslint/unified-signatures + + /** Skip this assertion. */ + skip(nonThrower: any, message?: string): void; +} + +export interface PassAssertion { + /** Count a passing assertion, always returning `true`. */ + (message?: string): boolean; + + /** Skip this assertion. */ + skip(message?: string): void; +} + +export interface RegexAssertion { + /** + * Assert that `string` matches the regular expression, returning a boolean indicating whether the assertion passed. + */ + (string: string, regex: RegExp, message?: string): boolean; + + /** Skip this assertion. */ + skip(string: string, regex: RegExp, message?: string): void; +} + +export interface SnapshotAssertion { + /** + * Assert that `expected` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to a + * previously recorded [snapshot](https://github.com/concordancejs/concordance#serialization-details), or if + * necessary record a new snapshot. + */ + (expected: any, message?: string): void; + + /** Skip this assertion. */ + skip(expected: any, message?: string): void; +} + +export interface ThrowsAssertion { + /** + * Assert that the function throws [an error](https://www.npmjs.com/package/is-error). If so, returns the error value. + * The error must satisfy all expectations. Returns undefined when the assertion fails. + */ + (fn: () => any, expectations?: ThrowsExpectation, message?: string): ThrownError | undefined; + + /** Skip this assertion. */ + skip(fn: () => any, expectations?: any, message?: string): void; +} + +export interface ThrowsAsyncAssertion { + /** + * Assert that the async function throws [an error](https://www.npmjs.com/package/is-error). If so, returns the error + * value. Returns undefined when the assertion fails. You must await the result. The error must satisfy all expectations. + */ + (fn: () => PromiseLike, expectations?: ThrowsExpectation, message?: string): Promise; + + /** + * Assert that the promise rejects with [an error](https://www.npmjs.com/package/is-error). If so, returns the + * rejection reason. Returns undefined when the assertion fails. You must await the result. The error must satisfy all + * expectations. + */ + (promise: PromiseLike, expectations?: ThrowsExpectation, message?: string): Promise; // eslint-disable-line @typescript-eslint/unified-signatures + + /** Skip this assertion. */ + skip(thrower: any, expectations?: any, message?: string): void; +} + +export interface TrueAssertion { + /** + * Assert that `actual` is strictly true, returning a boolean indicating whether the assertion passed. + */ + (actual: any, message?: string): actual is true; + + /** Skip this assertion. */ + skip(actual: any, message?: string): void; +} + +export interface TruthyAssertion { + /** + * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean + * indicating whether the assertion passed. + */ + (actual: any, message?: string): boolean; + + /** Skip this assertion. */ + skip(actual: any, message?: string): void; +} diff --git a/types/main.d.cts b/types/main.d.cts deleted file mode 100644 index 340ce6bd7..000000000 --- a/types/main.d.cts +++ /dev/null @@ -1,3 +0,0 @@ -// FIXME: Self-refencing "ava" should work, but seems to fail. -import test from "../index.js"; -export = test diff --git a/types/plugin.d.cts b/types/plugin.d.cts deleted file mode 100644 index 14497324d..000000000 --- a/types/plugin.d.cts +++ /dev/null @@ -1,2 +0,0 @@ -// FIXME: Self-refencing "ava/plugin" should work, but seems to fail. -export * from "../plugin.js"; diff --git a/types/subscribable.d.cts b/types/subscribable.d.cts new file mode 100644 index 000000000..3a3399bca --- /dev/null +++ b/types/subscribable.d.cts @@ -0,0 +1,6 @@ +export interface Subscribable { + subscribe(observer: { + error(error: any): void; + complete(): void; + }): void; +} diff --git a/types/test-fn.d.cts b/types/test-fn.d.cts new file mode 100644 index 000000000..ee117ff72 --- /dev/null +++ b/types/test-fn.d.cts @@ -0,0 +1,231 @@ +import type {Assertions} from './assertions.cjs'; +import type {Subscribable} from './subscribable.cjs'; +import type {TryFn} from './try-fn.cjs'; + +/** The `t` value passed to test & hook implementations. */ +export interface ExecutionContext extends Assertions { + /** Test context, shared with hooks. */ + context: Context; + + /** Title of the test or hook. */ + readonly title: string; + + /** Whether the test has passed. Only accurate in afterEach hooks. */ + readonly passed: boolean; + + readonly log: LogFn; + readonly plan: PlanFn; + readonly teardown: TeardownFn; + readonly timeout: TimeoutFn; + readonly try: TryFn; +} + +export interface LogFn { + /** Log one or more values. */ + (...values: any[]): void; + + /** Skip logging. */ + skip(...values: any[]): void; +} + +export interface PlanFn { + /** + * Plan how many assertion there are in the test. The test will fail if the actual assertion count doesn't match the + * number of planned assertions. See [assertion planning](https://github.com/avajs/ava#assertion-planning). + */ + (count: number): void; + + /** Don't plan assertions. */ + skip(count: number): void; +} + +/** + * Set a timeout for the test, in milliseconds. The test will fail if the timeout is exceeded. + * The timeout is reset each time an assertion is made. + */ +export type TimeoutFn = (ms: number, message?: string) => void; + +/** Declare a function to be run after the test has ended. */ +export type TeardownFn = (fn: (() => Promise) | (() => void)) => void; + +export type ImplementationFn = + ((t: ExecutionContext, ...args: Args) => PromiseLike) | + ((t: ExecutionContext, ...args: Args) => Subscribable) | + ((t: ExecutionContext, ...args: Args) => void); + +export type TitleFn = (providedTitle: string | undefined, ...args: Args) => string; + +/** A reusable test or hook implementation. */ +export type Macro = { + /** The function that is executed when the macro is used. */ + readonly exec: ImplementationFn; + + /** Generates a test title when this macro is used. */ + readonly title?: TitleFn; +}; + +/** A test or hook implementation. */ +export type Implementation = ImplementationFn | Macro; + +export interface TestFn { + /** Declare a concurrent test. Additional arguments are passed to the implementation or macro. */ + (title: string, implementation: Implementation, ...args: Args): void; + + /** + * Declare a concurrent test that uses a macro. Additional arguments are passed to the macro. + * The macro is responsible for generating a unique test title. + */ + (macro: Macro, ...args: Args): void; + + after: AfterFn; + afterEach: AfterFn; + before: BeforeFn; + beforeEach: BeforeFn; + failing: FailingFn; + macro: MacroFn; + meta: Meta; + only: OnlyFn; + serial: SerialFn; + skip: SkipFn; + todo: TodoFn; +} + +export interface AfterFn { + /** + * Declare a hook that is run once, after all tests have passed. + * Additional arguments are passed to the implementation or macro. + */ + (title: string, implementation: Implementation, ...args: Args): void; + + /** + * Declare a hook that is run once, after all tests have passed. + * Additional arguments are passed to the implementation or macro. + */ + (implementation: Implementation, ...args: Args): void; + + always: AlwaysInterface; + skip: HookSkipFn; +} + +export interface AlwaysInterface { + /** + * Declare a hook that is run once, after all tests are done. + * Additional arguments are passed to the implementation or macro. + */ + (title: string, implementation: Implementation, ...args: Args): void; + + /** + * Declare a hook that is run once, after all tests are done. + * Additional arguments are passed to the implementation or macro. + */ + (implementation: Implementation, ...args: Args): void; + + skip: HookSkipFn; +} + +export interface BeforeFn { + /** + * Declare a hook that is run once, before all tests. + * Additional arguments are passed to the implementation or macro. + */ + (title: string, implementation: Implementation, ...args: Args): void; + + /** + * Declare a hook that is run once, before all tests. + * Additional arguments are passed to the implementation or macro. + */ + (implementation: Implementation, ...args: Args): void; + + skip: HookSkipFn; +} + +export interface FailingFn { + /** + * Declare a concurrent test that is expected to fail. + * Additional arguments are passed to the implementation or macro. + */ + (title: string, implementation: Implementation, ...args: Args): void; + + /** + * Declare a concurrent test, using a macro, that is expected to fail. + * Additional arguments are passed to the macro. The macro is responsible for generating a unique test title. + */ + (macro: Macro, ...args: Args): void; + + only: OnlyFn; + skip: SkipFn; +} + +export interface HookSkipFn { + /** Skip this hook. */ + (title: string, implementation: Implementation, ...args: Args): void; + + /** Skip this hook. */ + (implementation: Implementation, ...args: Args): void; +} + +export interface OnlyFn { + /** + * Declare a test. Only this test and others declared with `.only()` are run. + * Additional arguments are passed to the implementation or macro. + */ + (title: string, implementation: Implementation, ...args: Args): void; + + /** + * Declare a test that uses a macro. Only this test and others declared with `.only()` are run. + * Additional arguments are passed to the macro. The macro is responsible for generating a unique test title. + */ + (macro: Macro, ...args: Args): void; +} + +export interface SerialFn { + /** Declare a serial test. Additional arguments are passed to the implementation or macro. */ + (title: string, implementation: Implementation, ...args: Args): void; + + /** + * Declare a serial test that uses a macro. The macro is responsible for generating a unique test title. + */ + (macro: Macro, ...args: Args): void; + + after: AfterFn; + afterEach: AfterFn; + before: BeforeFn; + beforeEach: BeforeFn; + failing: FailingFn; + only: OnlyFn; + skip: SkipFn; + todo: TodoFn; +} + +export interface SkipFn { + /** Skip this test. */ + (title: string, implementation: Implementation, ...args: Args): void; + + /** Skip this test. */ + (macro: Macro, ...args: Args): void; +} + +/** Declare a test that should be implemented later. */ +export type TodoFn = (title: string) => void; + +export type MacroDeclarationOptions = { + /** The function that is executed when the macro is used. */ + exec: ImplementationFn; + + /** The function responsible for generating a unique title when the macro is used. */ + title: TitleFn; +}; + +export interface MacroFn { + /** Declare a reusable test implementation. */ + (/** The function that is executed when the macro is used. */ exec: ImplementationFn): Macro; + (declaration: MacroDeclarationOptions): Macro; // eslint-disable-line @typescript-eslint/unified-signatures +} + +export interface Meta { + /** Path to the test file being executed. */ + file: string; + + /** Directory where snapshots are stored. */ + snapshotDirectory: string; +} diff --git a/types/try-fn.d.cts b/types/try-fn.d.cts new file mode 100644 index 000000000..4a168115f --- /dev/null +++ b/types/try-fn.d.cts @@ -0,0 +1,58 @@ +import type {Implementation} from './test-fn.cjs'; + +export type CommitDiscardOptions = { + /** + * Whether the logs should be included in those of the parent test. + */ + retainLogs?: boolean; +}; + +export interface AssertionError extends Error {} + +export interface TryResult { + /** + * Title of the attempt, helping you tell attempts aparts. + */ + title: string; + + /** + * Indicates whether all assertions passed, or at least one failed. + */ + passed: boolean; + + /** + * Errors raised for each failed assertion. + */ + errors: AssertionError[]; + + /** + * Logs created during the attempt using `t.log()`. Contains formatted values. + */ + logs: string[]; + + /** + * Commit the attempt. Counts as one assertion for the plan count. If the + * attempt failed, calling this will also cause your test to fail. + */ + commit(options?: CommitDiscardOptions): void; + + /** + * Discard the attempt. + */ + discard(options?: CommitDiscardOptions): void; +} + +export interface TryFn { + /** + * Attempt to run some assertions. The result must be explicitly committed or discarded or else + * the test will fail. The title may help distinguish attempts from one another. + */ + (title: string, fn: Implementation, ...args: Args): Promise; + + /** + * Attempt to run some assertions. The result must be explicitly committed or discarded or else + * the test will fail. + */ + (fn: Implementation, ...args: Args): Promise; +} + From 254e78d5ac341e60eb1f875ff2fda857375aa18b Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Mon, 30 May 2022 14:33:01 +0200 Subject: [PATCH 07/11] Re-export using ESM syntax --- index.d.cts | 9 +- plugin.d.cts | 78 +-------- types/assertions.d.cts | 339 --------------------------------------- types/subscribable.d.cts | 6 - types/test-fn.d.cts | 231 -------------------------- types/try-fn.d.cts | 58 ------- 6 files changed, 3 insertions(+), 718 deletions(-) delete mode 100644 types/assertions.d.cts delete mode 100644 types/subscribable.d.cts delete mode 100644 types/test-fn.d.cts delete mode 100644 types/try-fn.d.cts diff --git a/index.d.cts b/index.d.cts index 4205f6cdb..1b6640961 100644 --- a/index.d.cts +++ b/index.d.cts @@ -1,7 +1,2 @@ -import type {TestFn} from './types/test-fn.cjs'; - -/** Call to declare a test, or chain to declare hooks or test modifiers */ -declare const test: TestFn; - -/** Call to declare a test, or chain to declare hooks or test modifiers */ -export = test; +export {default} from './index.js'; +export * from './index.js'; diff --git a/plugin.d.cts b/plugin.d.cts index a2f68e179..837235148 100644 --- a/plugin.d.cts +++ b/plugin.d.cts @@ -1,77 +1 @@ -import {URL} from 'node:url'; - -export namespace SharedWorker { - export type ProtocolIdentifier = 'ava-4'; - - export type FactoryOptions = { - negotiateProtocol (supported: readonly ['ava-4']): Protocol; - // Add overloads for additional protocols. - }; - - export type Factory = (options: FactoryOptions) => void; - - export type Protocol = { - readonly initialData: Data; - readonly protocol: 'ava-4'; - broadcast: (data: Data) => BroadcastMessage; - ready: () => Protocol; - subscribe: () => AsyncIterableIterator>; - testWorkers: () => AsyncIterableIterator>; - }; - - export type BroadcastMessage = { - readonly id: string; - replies: () => AsyncIterableIterator>; - }; - - export type PublishedMessage = { - readonly id: string; - replies: () => AsyncIterableIterator>; - }; - - export type ReceivedMessage = { - readonly data: Data; - readonly id: string; - readonly testWorker: TestWorker; - reply: (data: Data) => PublishedMessage; - }; - - export type TestWorker = { - readonly id: string; - readonly file: string; - publish: (data: Data) => PublishedMessage; - subscribe: () => AsyncIterableIterator>; - teardown: (fn: (() => Promise) | (() => void)) => () => Promise; - }; - - export namespace Plugin { - export type RegistrationOptions = { - readonly filename: string | URL; - readonly initialData?: Data; - readonly supportedProtocols: readonly Identifier[]; - readonly teardown?: () => void; - }; - - export type Protocol = { - readonly available: Promise; - readonly currentlyAvailable: boolean; - readonly protocol: 'ava-4'; - publish: (data: Data) => PublishedMessage; - subscribe: () => AsyncIterableIterator>; - }; - - export type PublishedMessage = { - readonly id: string; - replies: () => AsyncIterableIterator>; - }; - - export type ReceivedMessage = { - readonly data: Data; - readonly id: string; - reply: (data: Data) => PublishedMessage; - }; - } -} - -export function registerSharedWorker(options: SharedWorker.Plugin.RegistrationOptions<'ava-4', Data>): SharedWorker.Plugin.Protocol; -// Add overloads for additional protocols. +export * from './plugin.js' diff --git a/types/assertions.d.cts b/types/assertions.d.cts deleted file mode 100644 index 0d2c8506b..000000000 --- a/types/assertions.d.cts +++ /dev/null @@ -1,339 +0,0 @@ -export type ErrorConstructor = new (...args: any[]) => Error; - -/** Specify one or more expectations the thrown error must satisfy. */ -export type ThrowsExpectation = { - /** The thrown error must have a code that equals the given string or number. */ - code?: string | number; - - /** The thrown error must be an instance of this constructor. */ - instanceOf?: ErrorConstructor; - - /** The thrown error must be strictly equal to this value. */ - is?: Error; - - /** The thrown error must have a message that equals the given string, or matches the regular expression. */ - message?: string | RegExp | ((message: string) => boolean); - - /** The thrown error must have a name that equals the given string. */ - name?: string; -}; - -export interface Assertions { - /** - * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean - * indicating whether the assertion passed. - */ - assert: AssertAssertion; - - /** - * Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to - * `expected`, returning a boolean indicating whether the assertion passed. - */ - deepEqual: DeepEqualAssertion; - - /** - * Assert that `value` is like `selector`, returning a boolean indicating whether the assertion passed. - */ - like: LikeAssertion; - - /** Fail the test, always returning `false`. */ - fail: FailAssertion; - - /** - * Assert that `actual` is strictly false, returning a boolean indicating whether the assertion passed. - */ - false: FalseAssertion; - - /** - * Assert that `actual` is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), returning a boolean - * indicating whether the assertion passed. - */ - falsy: FalsyAssertion; - - /** - * Assert that `actual` is [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, - * returning a boolean indicating whether the assertion passed. - */ - is: IsAssertion; - - /** - * Assert that `actual` is not [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, - * returning a boolean indicating whether the assertion passed. - */ - not: NotAssertion; - - /** - * Assert that `actual` is not [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to - * `expected`, returning a boolean indicating whether the assertion passed. - */ - notDeepEqual: NotDeepEqualAssertion; - - /** - * Assert that `string` does not match the regular expression, returning a boolean indicating whether the assertion - * passed. - */ - notRegex: NotRegexAssertion; - - /** Assert that the function does not throw. */ - notThrows: NotThrowsAssertion; - - /** Assert that the async function does not throw, or that the promise does not reject. Must be awaited. */ - notThrowsAsync: NotThrowsAsyncAssertion; - - /** Count a passing assertion, always returning `true`. */ - pass: PassAssertion; - - /** - * Assert that `string` matches the regular expression, returning a boolean indicating whether the assertion passed. - */ - regex: RegexAssertion; - - /** - * Assert that `expected` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to a - * previously recorded [snapshot](https://github.com/concordancejs/concordance#serialization-details), or if - * necessary record a new snapshot. - */ - snapshot: SnapshotAssertion; - - /** - * Assert that the function throws [an error](https://www.npmjs.com/package/is-error). If so, returns the error value. - */ - throws: ThrowsAssertion; - - /** - * Assert that the async function throws [an error](https://www.npmjs.com/package/is-error), or the promise rejects - * with one. If so, returns a promise for the error value, which must be awaited. - */ - throwsAsync: ThrowsAsyncAssertion; - - /** - * Assert that `actual` is strictly true, returning a boolean indicating whether the assertion passed. - */ - true: TrueAssertion; - - /** - * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean - * indicating whether the assertion passed. - */ - truthy: TruthyAssertion; -} - -export interface AssertAssertion { - /** - * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean - * indicating whether the assertion passed. - */ - (actual: any, message?: string): boolean; - - /** Skip this assertion. */ - skip(actual: any, message?: string): void; -} - -export interface DeepEqualAssertion { - /** - * Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to - * `expected`, returning a boolean indicating whether the assertion passed. - */ - (actual: Actual, expected: Expected, message?: string): actual is Expected; - - /** - * Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to - * `expected`, returning a boolean indicating whether the assertion passed. - */ - (actual: Actual, expected: Expected, message?: string): expected is Actual; - - /** - * Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to - * `expected`, returning a boolean indicating whether the assertion passed. - */ - (actual: Actual, expected: Expected, message?: string): boolean; - - /** Skip this assertion. */ - skip(actual: any, expected: any, message?: string): void; -} - -export interface LikeAssertion { - /** - * Assert that `value` is like `selector`, returning a boolean indicating whether the assertion passed. - */ - >(value: any, selector: Expected, message?: string): value is Expected; - - /** Skip this assertion. */ - skip(value: any, selector: any, message?: string): void; -} - -export interface FailAssertion { - /** Fail the test, always returning `false`. */ - (message?: string): boolean; - - /** Skip this assertion. */ - skip(message?: string): void; -} - -export interface FalseAssertion { - /** - * Assert that `actual` is strictly false, returning a boolean indicating whether the assertion passed. - */ - (actual: any, message?: string): actual is false; - - /** Skip this assertion. */ - skip(actual: any, message?: string): void; -} - -export interface FalsyAssertion { - /** - * Assert that `actual` is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), returning a boolean - * indicating whether the assertion passed. - */ - (actual: any, message?: string): boolean; - - /** Skip this assertion. */ - skip(actual: any, message?: string): void; -} - -export interface IsAssertion { - /** - * Assert that `actual` is [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, - * returning a boolean indicating whether the assertion passed. - */ - (actual: Actual, expected: Expected, message?: string): actual is Expected; - - /** Skip this assertion. */ - skip(actual: any, expected: any, message?: string): void; -} - -export interface NotAssertion { - /** - * Assert that `actual` is not [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, - * returning a boolean indicating whether the assertion passed. - */ - (actual: Actual, expected: Expected, message?: string): boolean; - - /** Skip this assertion. */ - skip(actual: any, expected: any, message?: string): void; -} - -export interface NotDeepEqualAssertion { - /** - * Assert that `actual` is not [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to - * `expected`, returning a boolean indicating whether the assertion passed. - */ - (actual: Actual, expected: Expected, message?: string): boolean; - - /** Skip this assertion. */ - skip(actual: any, expected: any, message?: string): void; -} - -export interface NotRegexAssertion { - /** - * Assert that `string` does not match the regular expression, returning a boolean indicating whether the assertion - * passed. - */ - (string: string, regex: RegExp, message?: string): boolean; - - /** Skip this assertion. */ - skip(string: string, regex: RegExp, message?: string): void; -} - -export interface NotThrowsAssertion { - /** Assert that the function does not throw. */ - (fn: () => any, message?: string): void; - - /** Skip this assertion. */ - skip(fn: () => any, message?: string): void; -} - -export interface NotThrowsAsyncAssertion { - /** Assert that the async function does not throw. You must await the result. */ - (fn: () => PromiseLike, message?: string): Promise; - - /** Assert that the promise does not reject. You must await the result. */ - (promise: PromiseLike, message?: string): Promise; // eslint-disable-line @typescript-eslint/unified-signatures - - /** Skip this assertion. */ - skip(nonThrower: any, message?: string): void; -} - -export interface PassAssertion { - /** Count a passing assertion, always returning `true`. */ - (message?: string): boolean; - - /** Skip this assertion. */ - skip(message?: string): void; -} - -export interface RegexAssertion { - /** - * Assert that `string` matches the regular expression, returning a boolean indicating whether the assertion passed. - */ - (string: string, regex: RegExp, message?: string): boolean; - - /** Skip this assertion. */ - skip(string: string, regex: RegExp, message?: string): void; -} - -export interface SnapshotAssertion { - /** - * Assert that `expected` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to a - * previously recorded [snapshot](https://github.com/concordancejs/concordance#serialization-details), or if - * necessary record a new snapshot. - */ - (expected: any, message?: string): void; - - /** Skip this assertion. */ - skip(expected: any, message?: string): void; -} - -export interface ThrowsAssertion { - /** - * Assert that the function throws [an error](https://www.npmjs.com/package/is-error). If so, returns the error value. - * The error must satisfy all expectations. Returns undefined when the assertion fails. - */ - (fn: () => any, expectations?: ThrowsExpectation, message?: string): ThrownError | undefined; - - /** Skip this assertion. */ - skip(fn: () => any, expectations?: any, message?: string): void; -} - -export interface ThrowsAsyncAssertion { - /** - * Assert that the async function throws [an error](https://www.npmjs.com/package/is-error). If so, returns the error - * value. Returns undefined when the assertion fails. You must await the result. The error must satisfy all expectations. - */ - (fn: () => PromiseLike, expectations?: ThrowsExpectation, message?: string): Promise; - - /** - * Assert that the promise rejects with [an error](https://www.npmjs.com/package/is-error). If so, returns the - * rejection reason. Returns undefined when the assertion fails. You must await the result. The error must satisfy all - * expectations. - */ - (promise: PromiseLike, expectations?: ThrowsExpectation, message?: string): Promise; // eslint-disable-line @typescript-eslint/unified-signatures - - /** Skip this assertion. */ - skip(thrower: any, expectations?: any, message?: string): void; -} - -export interface TrueAssertion { - /** - * Assert that `actual` is strictly true, returning a boolean indicating whether the assertion passed. - */ - (actual: any, message?: string): actual is true; - - /** Skip this assertion. */ - skip(actual: any, message?: string): void; -} - -export interface TruthyAssertion { - /** - * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean - * indicating whether the assertion passed. - */ - (actual: any, message?: string): boolean; - - /** Skip this assertion. */ - skip(actual: any, message?: string): void; -} diff --git a/types/subscribable.d.cts b/types/subscribable.d.cts deleted file mode 100644 index 3a3399bca..000000000 --- a/types/subscribable.d.cts +++ /dev/null @@ -1,6 +0,0 @@ -export interface Subscribable { - subscribe(observer: { - error(error: any): void; - complete(): void; - }): void; -} diff --git a/types/test-fn.d.cts b/types/test-fn.d.cts deleted file mode 100644 index ee117ff72..000000000 --- a/types/test-fn.d.cts +++ /dev/null @@ -1,231 +0,0 @@ -import type {Assertions} from './assertions.cjs'; -import type {Subscribable} from './subscribable.cjs'; -import type {TryFn} from './try-fn.cjs'; - -/** The `t` value passed to test & hook implementations. */ -export interface ExecutionContext extends Assertions { - /** Test context, shared with hooks. */ - context: Context; - - /** Title of the test or hook. */ - readonly title: string; - - /** Whether the test has passed. Only accurate in afterEach hooks. */ - readonly passed: boolean; - - readonly log: LogFn; - readonly plan: PlanFn; - readonly teardown: TeardownFn; - readonly timeout: TimeoutFn; - readonly try: TryFn; -} - -export interface LogFn { - /** Log one or more values. */ - (...values: any[]): void; - - /** Skip logging. */ - skip(...values: any[]): void; -} - -export interface PlanFn { - /** - * Plan how many assertion there are in the test. The test will fail if the actual assertion count doesn't match the - * number of planned assertions. See [assertion planning](https://github.com/avajs/ava#assertion-planning). - */ - (count: number): void; - - /** Don't plan assertions. */ - skip(count: number): void; -} - -/** - * Set a timeout for the test, in milliseconds. The test will fail if the timeout is exceeded. - * The timeout is reset each time an assertion is made. - */ -export type TimeoutFn = (ms: number, message?: string) => void; - -/** Declare a function to be run after the test has ended. */ -export type TeardownFn = (fn: (() => Promise) | (() => void)) => void; - -export type ImplementationFn = - ((t: ExecutionContext, ...args: Args) => PromiseLike) | - ((t: ExecutionContext, ...args: Args) => Subscribable) | - ((t: ExecutionContext, ...args: Args) => void); - -export type TitleFn = (providedTitle: string | undefined, ...args: Args) => string; - -/** A reusable test or hook implementation. */ -export type Macro = { - /** The function that is executed when the macro is used. */ - readonly exec: ImplementationFn; - - /** Generates a test title when this macro is used. */ - readonly title?: TitleFn; -}; - -/** A test or hook implementation. */ -export type Implementation = ImplementationFn | Macro; - -export interface TestFn { - /** Declare a concurrent test. Additional arguments are passed to the implementation or macro. */ - (title: string, implementation: Implementation, ...args: Args): void; - - /** - * Declare a concurrent test that uses a macro. Additional arguments are passed to the macro. - * The macro is responsible for generating a unique test title. - */ - (macro: Macro, ...args: Args): void; - - after: AfterFn; - afterEach: AfterFn; - before: BeforeFn; - beforeEach: BeforeFn; - failing: FailingFn; - macro: MacroFn; - meta: Meta; - only: OnlyFn; - serial: SerialFn; - skip: SkipFn; - todo: TodoFn; -} - -export interface AfterFn { - /** - * Declare a hook that is run once, after all tests have passed. - * Additional arguments are passed to the implementation or macro. - */ - (title: string, implementation: Implementation, ...args: Args): void; - - /** - * Declare a hook that is run once, after all tests have passed. - * Additional arguments are passed to the implementation or macro. - */ - (implementation: Implementation, ...args: Args): void; - - always: AlwaysInterface; - skip: HookSkipFn; -} - -export interface AlwaysInterface { - /** - * Declare a hook that is run once, after all tests are done. - * Additional arguments are passed to the implementation or macro. - */ - (title: string, implementation: Implementation, ...args: Args): void; - - /** - * Declare a hook that is run once, after all tests are done. - * Additional arguments are passed to the implementation or macro. - */ - (implementation: Implementation, ...args: Args): void; - - skip: HookSkipFn; -} - -export interface BeforeFn { - /** - * Declare a hook that is run once, before all tests. - * Additional arguments are passed to the implementation or macro. - */ - (title: string, implementation: Implementation, ...args: Args): void; - - /** - * Declare a hook that is run once, before all tests. - * Additional arguments are passed to the implementation or macro. - */ - (implementation: Implementation, ...args: Args): void; - - skip: HookSkipFn; -} - -export interface FailingFn { - /** - * Declare a concurrent test that is expected to fail. - * Additional arguments are passed to the implementation or macro. - */ - (title: string, implementation: Implementation, ...args: Args): void; - - /** - * Declare a concurrent test, using a macro, that is expected to fail. - * Additional arguments are passed to the macro. The macro is responsible for generating a unique test title. - */ - (macro: Macro, ...args: Args): void; - - only: OnlyFn; - skip: SkipFn; -} - -export interface HookSkipFn { - /** Skip this hook. */ - (title: string, implementation: Implementation, ...args: Args): void; - - /** Skip this hook. */ - (implementation: Implementation, ...args: Args): void; -} - -export interface OnlyFn { - /** - * Declare a test. Only this test and others declared with `.only()` are run. - * Additional arguments are passed to the implementation or macro. - */ - (title: string, implementation: Implementation, ...args: Args): void; - - /** - * Declare a test that uses a macro. Only this test and others declared with `.only()` are run. - * Additional arguments are passed to the macro. The macro is responsible for generating a unique test title. - */ - (macro: Macro, ...args: Args): void; -} - -export interface SerialFn { - /** Declare a serial test. Additional arguments are passed to the implementation or macro. */ - (title: string, implementation: Implementation, ...args: Args): void; - - /** - * Declare a serial test that uses a macro. The macro is responsible for generating a unique test title. - */ - (macro: Macro, ...args: Args): void; - - after: AfterFn; - afterEach: AfterFn; - before: BeforeFn; - beforeEach: BeforeFn; - failing: FailingFn; - only: OnlyFn; - skip: SkipFn; - todo: TodoFn; -} - -export interface SkipFn { - /** Skip this test. */ - (title: string, implementation: Implementation, ...args: Args): void; - - /** Skip this test. */ - (macro: Macro, ...args: Args): void; -} - -/** Declare a test that should be implemented later. */ -export type TodoFn = (title: string) => void; - -export type MacroDeclarationOptions = { - /** The function that is executed when the macro is used. */ - exec: ImplementationFn; - - /** The function responsible for generating a unique title when the macro is used. */ - title: TitleFn; -}; - -export interface MacroFn { - /** Declare a reusable test implementation. */ - (/** The function that is executed when the macro is used. */ exec: ImplementationFn): Macro; - (declaration: MacroDeclarationOptions): Macro; // eslint-disable-line @typescript-eslint/unified-signatures -} - -export interface Meta { - /** Path to the test file being executed. */ - file: string; - - /** Directory where snapshots are stored. */ - snapshotDirectory: string; -} diff --git a/types/try-fn.d.cts b/types/try-fn.d.cts deleted file mode 100644 index 4a168115f..000000000 --- a/types/try-fn.d.cts +++ /dev/null @@ -1,58 +0,0 @@ -import type {Implementation} from './test-fn.cjs'; - -export type CommitDiscardOptions = { - /** - * Whether the logs should be included in those of the parent test. - */ - retainLogs?: boolean; -}; - -export interface AssertionError extends Error {} - -export interface TryResult { - /** - * Title of the attempt, helping you tell attempts aparts. - */ - title: string; - - /** - * Indicates whether all assertions passed, or at least one failed. - */ - passed: boolean; - - /** - * Errors raised for each failed assertion. - */ - errors: AssertionError[]; - - /** - * Logs created during the attempt using `t.log()`. Contains formatted values. - */ - logs: string[]; - - /** - * Commit the attempt. Counts as one assertion for the plan count. If the - * attempt failed, calling this will also cause your test to fail. - */ - commit(options?: CommitDiscardOptions): void; - - /** - * Discard the attempt. - */ - discard(options?: CommitDiscardOptions): void; -} - -export interface TryFn { - /** - * Attempt to run some assertions. The result must be explicitly committed or discarded or else - * the test will fail. The title may help distinguish attempts from one another. - */ - (title: string, fn: Implementation, ...args: Args): Promise; - - /** - * Attempt to run some assertions. The result must be explicitly committed or discarded or else - * the test will fail. - */ - (fn: Implementation, ...args: Args): Promise; -} - From 09766a926ffd2ab4ee86c083cd09e65ca00a766c Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Mon, 30 May 2022 14:34:11 +0200 Subject: [PATCH 08/11] Move cts entrypoints --- entrypoints/index.d.cts | 2 ++ entrypoints/plugin.d.cts | 1 + index.d.cts | 2 -- package.json | 4 ++-- plugin.d.cts | 1 - 5 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 entrypoints/index.d.cts create mode 100644 entrypoints/plugin.d.cts delete mode 100644 index.d.cts delete mode 100644 plugin.d.cts diff --git a/entrypoints/index.d.cts b/entrypoints/index.d.cts new file mode 100644 index 000000000..91c40063f --- /dev/null +++ b/entrypoints/index.d.cts @@ -0,0 +1,2 @@ +export {default} from '../index.js'; +export * from '../index.js'; diff --git a/entrypoints/plugin.d.cts b/entrypoints/plugin.d.cts new file mode 100644 index 000000000..b66e07dcb --- /dev/null +++ b/entrypoints/plugin.d.cts @@ -0,0 +1 @@ +export * from '../plugin.js' diff --git a/index.d.cts b/index.d.cts deleted file mode 100644 index 1b6640961..000000000 --- a/index.d.cts +++ /dev/null @@ -1,2 +0,0 @@ -export {default} from './index.js'; -export * from './index.js'; diff --git a/package.json b/package.json index abef0080c..5e9e4d34b 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "default": "./entrypoints/main.mjs" }, "require": { - "types": "./index.d.cts", + "types": "./entrypoints/index.d.cts", "default": "./entrypoints/main.cjs" } }, @@ -26,7 +26,7 @@ "default": "./entrypoints/plugin.mjs" }, "require": { - "types": "./plugin.d.cts", + "types": "./entrypoints/plugin.d.cts", "default": "./entrypoints/plugin.cjs" } } diff --git a/plugin.d.cts b/plugin.d.cts deleted file mode 100644 index 837235148..000000000 --- a/plugin.d.cts +++ /dev/null @@ -1 +0,0 @@ -export * from './plugin.js' From c153ebabe8e91d31701ef58b32f757c0e3df8eb7 Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Tue, 31 May 2022 15:45:07 +0200 Subject: [PATCH 09/11] Update documentation for the test.default property --- lib/create-chain.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/create-chain.js b/lib/create-chain.js index 525fa96d1..2140d85bb 100644 --- a/lib/create-chain.js +++ b/lib/create-chain.js @@ -101,11 +101,13 @@ export default function createChain(fn, defaults, meta) { root.meta = meta; - // Our type definition uses ESM syntax; when using CJS with VSCode, the - // auto-completion assumes the root is accessed through `require('ava').default`. - // Placate VSCode by adding a mostly hidden default property on the root. - // This is available through both CJS and ESM imports. We use a proxy so that - // we don't end up with root.default.default.default chains. + // The ESM and CJS type definitions export the chain (`test()` function) as + // the default. TypeScript's CJS output (when `esModuleInterop` is disabled) + // assume `require('ava').default` is available. The same goes for `import ava + // = require('ava')` syntax. + // + // Add `test.default` to make this work. Use a proxy to avoid + // `test.default.default` chains. Object.defineProperty(root, 'default', { configurable: false, enumerable: false, From ae3c5702c151a434678136f0b510cd3b2203b03a Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Tue, 31 May 2022 15:45:24 +0200 Subject: [PATCH 10/11] Provide more examples on how to import AVA --- docs/recipes/typescript.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/recipes/typescript.md b/docs/recipes/typescript.md index 38fe1d729..6127efc7f 100644 --- a/docs/recipes/typescript.md +++ b/docs/recipes/typescript.md @@ -82,7 +82,7 @@ It's worth noting that with this configuration, tests will fail if there are Typ [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/avajs/ava/tree/main/examples/typescript-basic?file=source%2Ftest.ts&terminal=test&view=editor) -Create a `test.ts` file. +Create a `test.ts` file. ESM syntax works best, even if you're targeting CommonJS. ```ts import test from 'ava'; @@ -94,6 +94,22 @@ test('fn() returns foo', t => { }); ``` +You can use CommonJS syntax as well: + +```ts +const test = require('ava'); +``` + +This works whether `esModuleInterop` is enabled or not. + +`import … = require()` syntax is less elegant. It's best like this: + +```ts +import ava = require('ava') + +const test = ava.default; +``` + ## Using [macros](../01-writing-tests.md#reusing-test-logic-through-macros) Macros can receive additional arguments. AVA can infer these to ensure you're using the macro correctly: From 2a54858803fa5e3c74afa73f9c3dc6e8e529550a Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Tue, 31 May 2022 15:46:24 +0200 Subject: [PATCH 11/11] Remove unnecessary entries from files list --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index 5e9e4d34b..ad36940d3 100644 --- a/package.json +++ b/package.json @@ -43,9 +43,7 @@ "entrypoints", "lib", "types", - "index.d.cts", "index.d.ts", - "plugin.d.cts", "plugin.d.ts" ], "keywords": [