UNPKG

@augment-vir/assert

Version:

A collection of assertions for test and production code alike.

782 lines (781 loc) 29.5 kB
import { stringify } from '@augment-vir/core'; import { AssertionError } from '../augments/assertion.error.js'; import { createWaitUntil } from '../guard-types/wait-until-function.js'; const assertions = { /** * Asserts that a value is a `PromiseLike`. * * `PromiseLike` is TypeScript built-in type that has a `.then` method and thus behaves like a * promise. This is also referred to as a "thenable". This enables the use of third-party * promise implementations that aren't instances of the built-in `Promise` class. * * Type guards the value. * * @example * * ```ts * import {assert} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable(onFulfilled ? onFulfilled(this.value) : this.value); * } * } * * assert.isPromiseLike(Promise.resolve(5)); // passes * assert.isPromiseLike(new CustomThenable(5)); // passes * assert.isPromiseLike(5); // fails * ``` * * @throws {@link AssertionError} If the assertion fails. * @see * - {@link assert.isNotPromiseLike} : the opposite assertion. * - {@link assert.isPromise} : the more precise assertion. */ isPromiseLike(actual, failureMessage) { if (!(actual instanceof Promise) && !(actual && typeof actual === 'object' && 'then' in actual && typeof actual.then === 'function')) { throw new AssertionError(`'${stringify(actual)}' is not a PromiseLike.`, failureMessage); } }, /** * Asserts that a value is _not_ a `PromiseLike`. * * `PromiseLike` is TypeScript built-in type that has a `.then` method and thus behaves like a * promise. This is also referred to as a "thenable". This enables the use of third-party * promise implementations that aren't instances of the built-in `Promise` class. * * Type guards the value. * * @example * * ```ts * import {assert} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable(onFulfilled ? onFulfilled(this.value) : this.value); * } * } * * assert.isNotPromiseLike(Promise.resolve(5)); // fails * assert.isNotPromiseLike(new CustomThenable(5)); // fails * assert.isNotPromiseLike(5); // passes * ``` * * @throws {@link AssertionError} If the assertion fails. * @see * - {@link assert.isPromiseLike} : the opposite assertion. * - {@link assert.isNotPromise} : the more precise assertion. */ isNotPromiseLike(actual, failureMessage) { if (actual instanceof Promise || (actual && typeof actual === 'object' && 'then' in actual && typeof actual.then === 'function')) { throw new AssertionError(`'${stringify(actual)}' is a PromiseLike.`, failureMessage); } }, /** * Asserts that a value is a `Promise` instance. * * Type guards the value. * * @example * * ```ts * import {assert} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable(onFulfilled ? onFulfilled(this.value) : this.value); * } * } * * assert.isPromise(Promise.resolve(5)); // passes * assert.isPromise(new CustomThenable(5)); // fails * assert.isPromise(5); // fails * ``` * * @throws {@link AssertionError} If the assertion fails. * @see * - {@link assert.isNotPromise} : the opposite assertion. * - {@link assert.isPromiseLike} : the more lenient assertion. */ isPromise(actual, failureMessage) { if (!(actual instanceof Promise)) { throw new AssertionError(`'${stringify(actual)}' is not a Promise.`, failureMessage); } }, /** * Asserts that a value is a _not_ `Promise` instance. * * Type guards the value. * * @example * * ```ts * import {assert} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable(onFulfilled ? onFulfilled(this.value) : this.value); * } * } * * assert.isNotPromise(Promise.resolve(5)); // fails * assert.isNotPromise(new CustomThenable(5)); // passes * assert.isNotPromise(5); // passes * ``` * * @throws {@link AssertionError} If the assertion fails. * @see * - {@link assert.isPromise} : the opposite assertion. * - {@link assert.isNotPromiseLike} : the more lenient assertion. */ isNotPromise(actual, failureMessage) { if (actual instanceof Promise) { throw new AssertionError(`'${stringify(actual)}' is a Promise.`, failureMessage); } }, }; export const promiseGuards = { assert: assertions, check: { /** * Checks that a value is a `PromiseLike`. * * `PromiseLike` is TypeScript built-in type that has a `.then` method and thus behaves like * a promise. This is also referred to as a "thenable". This enables the use of third-party * promise implementations that aren't instances of the built-in `Promise` class. * * Type guards the value. * * @example * * ```ts * import {check} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * check.isPromiseLike(Promise.resolve(5)); // returns `true` * check.isPromiseLike(new CustomThenable(5)); // returns `true` * check.isPromiseLike(5); // returns `false` * ``` * * @see * - {@link check.isNotPromiseLike} : the opposite check. * - {@link check.isPromise} : the more precise check. */ isPromiseLike(actual) { return (actual instanceof Promise || (actual && typeof actual === 'object' && 'then' in actual && typeof actual.then === 'function')); }, /** * Checks that a value is _not_ a `PromiseLike`. * * `PromiseLike` is TypeScript built-in type that has a `.then` method and thus behaves like * a promise. This is also referred to as a "thenable". This enables the use of third-party * promise implementations that aren't instances of the built-in `Promise` class. * * Type guards the value. * * @example * * ```ts * import {check} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * check.isNotPromiseLike(Promise.resolve(5)); // returns `false` * check.isNotPromiseLike(new CustomThenable(5)); // returns `false` * check.isNotPromiseLike(5); // returns `true` * ``` * * @see * - {@link check.isPromiseLike} : the opposite check. * - {@link check.isNotPromise} : the more precise check. */ isNotPromiseLike(actual) { return !(actual instanceof Promise || (actual && typeof actual === 'object' && 'then' in actual && typeof actual.then === 'function')); }, /** * Checks that a value is a `Promise` instance. * * Type guards the value. * * @example * * ```ts * import {check} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * check.isPromise(Promise.resolve(5)); // returns `true` * check.isPromise(new CustomThenable(5)); // returns `false` * check.isPromise(5); // returns `false` * ``` * * @see * - {@link check.isNotPromise} : the opposite check. * - {@link check.isPromiseLike} : the more lenient check. */ isPromise(actual) { return actual instanceof Promise; }, /** * Checks that a value is a _not_ `Promise` instance. * * Type guards the value. * * @example * * ```ts * import {check} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * check.isNotPromise(Promise.resolve(5)); // returns `false` * check.isNotPromise(new CustomThenable(5)); // returns `true` * check.isNotPromise(5); // returns `true` * ``` * * @see * - {@link check.isPromise} : the opposite check. * - {@link check.isNotPromiseLike} : the more lenient check. */ isNotPromise(actual) { return !(actual instanceof Promise); }, }, assertWrap: { /** * Asserts that a value is a `PromiseLike`. Returns the value if the assertion passes. * * `PromiseLike` is TypeScript built-in type that has a `.then` method and thus behaves like * a promise. This is also referred to as a "thenable". This enables the use of third-party * promise implementations that aren't instances of the built-in `Promise` class. * * Type guards the value. * * @example * * ```ts * import {assertWrap} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * assertWrap.isPromiseLike(Promise.resolve(5)); // returns the `Promise` instance * assertWrap.isPromiseLike(new CustomThenable(5)); // returns the `CustomThenable` instance * assertWrap.isPromiseLike(5); // throws an error * ``` * * @returns The value if the assertion passes. * @throws {@link AssertionError} If the assertion fails. * @see * - {@link assertWrap.isNotPromiseLike} : the opposite assertion. * - {@link assertWrap.isPromise} : the more precise assertion. */ isPromiseLike(actual, failureMessage) { if (!(actual instanceof Promise) && !(actual && typeof actual === 'object' && 'then' in actual && typeof actual.then === 'function')) { throw new AssertionError(`'${stringify(actual)}' is not a PromiseLike.`, failureMessage); } return actual; }, /** * Asserts that a value is _not_ a `PromiseLike`. Returns the value if the assertion passes. * * `PromiseLike` is TypeScript built-in type that has a `.then` method and thus behaves like * a promise. This is also referred to as a "thenable". This enables the use of third-party * promise implementations that aren't instances of the built-in `Promise` class. * * Type guards the value. * * @example * * ```ts * import {assertWrap} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * assertWrap.isNotPromiseLike(Promise.resolve(5)); // throws an error * assertWrap.isNotPromiseLike(new CustomThenable(5)); // throws an error * assertWrap.isNotPromiseLike(5); // returns `5` * ``` * * @returns The value if the assertion passes. * @throws {@link AssertionError} If the assertion fails. * @see * - {@link assertWrap.isPromiseLike} : the opposite assertion. * - {@link assertWrap.isNotPromise} : the more precise assertion. */ isNotPromiseLike(actual, failureMessage) { if (actual instanceof Promise || (actual && typeof actual === 'object' && 'then' in actual && typeof actual.then === 'function')) { throw new AssertionError(`'${stringify(actual)}' is a PromiseLike.`, failureMessage); } return actual; }, /** * Asserts that a value is a `Promise` instance. Returns the value if the assertion passes. * * Type guards the value. * * @example * * ```ts * import {assertWrap} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * assertWrap.isPromise(Promise.resolve(5)); // returns the `Promise` instance * assertWrap.isPromise(new CustomThenable(5)); // throws an error * assertWrap.isPromise(5); // throws an error * ``` * * @returns The value if the assertion passes. * @throws {@link AssertionError} If the assertion fails. * @see * - {@link assertWrap.isNotPromise} : the opposite assertion. * - {@link assertWrap.isPromiseLike} : the more lenient assertion. */ isPromise(actual, failureMessage) { if (!(actual instanceof Promise)) { throw new AssertionError(`'${stringify(actual)}' is not a Promise.`, failureMessage); } return actual; }, /** * Asserts that a value is a _not_ `Promise` instance. Returns the value if the assertion * passes. * * Type guards the value. * * @example * * ```ts * import {assertWrap} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * assertWrap.isNotPromise(Promise.resolve(5)); // throws an error * assertWrap.isNotPromise(new CustomThenable(5)); // returns the `CustomThenable` promise * assertWrap.isNotPromise(5); // returns `5` * ``` * * @returns The value if the assertion passes. * @throws {@link AssertionError} If the assertion fails. * @see * - {@link assertWrap.isPromise} : the opposite assertion. * - {@link assertWrap.isNotPromiseLike} : the more lenient assertion. */ isNotPromise(actual, failureMessage) { if (actual instanceof Promise) { throw new AssertionError(`'${stringify(actual)}' is a Promise.`, failureMessage); } return actual; }, }, checkWrap: { /** * Checks that a value is a `PromiseLike`. Returns the value if the check passes, otherwise * `undefined`. * * `PromiseLike` is TypeScript built-in type that has a `.then` method and thus behaves like * a promise. This is also referred to as a "thenable". This enables the use of third-party * promise implementations that aren't instances of the built-in `Promise` class. * * Type guards the value. * * @example * * ```ts * import {checkWrap} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * checkWrap.isPromiseLike(Promise.resolve(5)); // returns `true` * checkWrap.isPromiseLike(new CustomThenable(5)); // returns `true` * checkWrap.isPromiseLike(5); // returns `false` * ``` * * @see * - {@link checkWrap.isNotPromiseLike} : the opposite check. * - {@link checkWrap.isPromise} : the more precise check. */ isPromiseLike(actual) { if (actual instanceof Promise || (actual && typeof actual === 'object' && 'then' in actual && typeof actual.then === 'function')) { return actual; } else { return undefined; } }, /** * Checks that a value is _not_ a `PromiseLike`. Returns the value if the check passes, * otherwise `undefined`. * * `PromiseLike` is TypeScript built-in type that has a `.then` method and thus behaves like * a promise. This is also referred to as a "thenable". This enables the use of third-party * promise implementations that aren't instances of the built-in `Promise` class. * * Type guards the value. * * @example * * ```ts * import {checkWrap} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * checkWrap.isNotPromiseLike(Promise.resolve(5)); // returns `false` * checkWrap.isNotPromiseLike(new CustomThenable(5)); // returns `false` * checkWrap.isNotPromiseLike(5); // returns `true` * ``` * * @see * - {@link checkWrap.isPromiseLike} : the opposite check. * - {@link checkWrap.isNotPromise} : the more precise check. */ isNotPromiseLike(actual) { if (actual instanceof Promise || (actual && typeof actual === 'object' && 'then' in actual && typeof actual.then === 'function')) { return undefined; } else { return actual; } }, /** * Checks that a value is a `Promise` instance. Returns the value if the check passes, * otherwise `undefined`. * * Type guards the value. * * @example * * ```ts * import {checkWrap} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * checkWrap.isPromise(Promise.resolve(5)); // returns `true` * checkWrap.isPromise(new CustomThenable(5)); // returns `false` * checkWrap.isPromise(5); // returns `false` * ``` * * @see * - {@link checkWrap.isNotPromise} : the opposite check. * - {@link checkWrap.isPromiseLike} : the more lenient check. */ isPromise(actual) { if (actual instanceof Promise) { return actual; } else { return undefined; } }, /** * Checks that a value is a _not_ `Promise` instance. Returns the value if the check passes, * otherwise `undefined`. * * Type guards the value. * * @example * * ```ts * import {checkWrap} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * checkWrap.isNotPromise(Promise.resolve(5)); // returns `false` * checkWrap.isNotPromise(new CustomThenable(5)); // returns `true` * checkWrap.isNotPromise(5); // returns `true` * ``` * * @see * - {@link checkWrap.isPromise} : the opposite check. * - {@link checkWrap.isNotPromiseLike} : the more lenient check. */ isNotPromise(actual) { if (actual instanceof Promise) { return undefined; } else { return actual; } }, }, waitUntil: { /** * Repeatedly calls a callback until its output is a `PromiseLike`. Once the callback output * passes, it is returned. If the attempts time out, an error is thrown. * * `PromiseLike` is TypeScript built-in type that has a `.then` method and thus behaves like * a promise. This is also referred to as a "thenable". This enables the use of third-party * promise implementations that aren't instances of the built-in `Promise` class. * * Type guards the value. * * @example * * ```ts * import {waitUntil} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * await waitUntil.isPromiseLike(() => Promise.resolve(5)); // returns the resolved `5` * await waitUntil.isPromiseLike(() => new CustomThenable(5)); // returns the resolved `5` * await waitUntil.isPromiseLike(() => 5); // throws an error * ``` * * @returns The callback output once it passes. * @throws {@link AssertionError} If the assertion fails. * @see * - {@link waitUntil.isNotPromiseLike} : the opposite assertion. * - {@link waitUntil.isPromise} : the more precise assertion. */ isPromiseLike: createWaitUntil(assertions.isPromiseLike, true), /** * Repeatedly calls a callback until its output is _not_ a `PromiseLike`. Once the callback * output passes, it is returned. If the attempts time out, an error is thrown. * * `PromiseLike` is TypeScript built-in type that has a `.then` method and thus behaves like * a promise. This is also referred to as a "thenable". This enables the use of third-party * promise implementations that aren't instances of the built-in `Promise` class. * * Type guards the value. * * @example * * ```ts * import {waitUntil} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * await waitUntil.isNotPromiseLike(() => Promise.resolve(5)); // throws an error * await waitUntil.isNotPromiseLike(() => new CustomThenable(5)); // throws an error * await waitUntil.isNotPromiseLike(() => 5); // returns `5` * ``` * * @returns The callback output once it passes. * @throws {@link AssertionError} If the assertion fails. * @see * - {@link waitUntil.isPromiseLike} : the opposite assertion. * - {@link waitUntil.isNotPromise} : the more precise assertion. */ isNotPromiseLike: createWaitUntil(assertions.isNotPromiseLike, true), /** * Repeatedly calls a callback until its output is a `Promise` instance. Once the callback * output passes, it is returned. If the attempts time out, an error is thrown. * * Type guards the value. * * @example * * ```ts * import {waitUntil} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * await waitUntil.isPromise(() => Promise.resolve(5)); // returns the resolved `5` * await waitUntil.isPromise(() => new CustomThenable(5)); // throws an error * await waitUntil.isPromise(() => 5); // throws an error * ``` * * @returns The callback output once it passes. * @throws {@link AssertionError} If the assertion fails. * @see * - {@link waitUntil.isNotPromise} : the opposite assertion. * - {@link waitUntil.isPromiseLike} : the more lenient assertion. */ isPromise: createWaitUntil(assertions.isPromise, true), /** * Repeatedly calls a callback until its output is a _not_ `Promise` instance. Once the * callback output passes, it is returned. If the attempts time out, an error is thrown. * * Type guards the value. * * @example * * ```ts * import {waitUntil} from '@augment-vir/assert'; * * class CustomThenable { * constructor(public value: any) {} * * then(onFulfilled?: AnyFunction, onRejected?: AnyFunction) { * return new CustomThenable( * onFulfilled ? onFulfilled(this.value) : this.value, * ); * } * } * * await waitUntil.isNotPromise(() => Promise.resolve(5)); // throws an error * await waitUntil.isNotPromise(() => new CustomThenable(5)); // returns the resolved `5` * await waitUntil.isNotPromise(() => 5); // returns the resolved `5` * ``` * * @returns The callback output once it passes. * @throws {@link AssertionError} If the assertion fails. * @see * - {@link waitUntil.isPromise} : the opposite assertion. * - {@link waitUntil.isNotPromiseLike} : the more lenient assertion. */ isNotPromise: createWaitUntil(assertions.isNotPromise, true), }, };