UNPKG

@assertive-ts/core

Version:

A type-safe fluent assertion library

279 lines (278 loc) 8.09 kB
/// <reference types="node" /> import { type TypeFactory } from "./helpers/TypeFactories"; import { AssertionError } from "assert"; export interface Constructor<T> extends Function { prototype: T; } export type DataType = "array" | "bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined"; export interface ExecuteOptions { /** * The condition for when the assertion should pass. The negation of this * condition is also used for the `.not` case of the assertion */ assertWhen: boolean; /** * The assertion error to throw when the condition is not fullfiled */ error: AssertionError; /** * The assertion error to throw given the condition was inverted (`.not`), * and it is also not fullfilled */ invertedError: AssertionError; } /** * Base class for all assertions. * * @param T the type of the `actual` value */ export declare class Assertion<T> { protected readonly actual: T; protected readonly inverted: boolean; readonly not: this; constructor(actual: T); /** * A convenience method to normalize the assertion instance. If it was * inverted with `.not`, it'll return it back to the previous non-inverted * state. Otherwise, it returns the same instance. * * @returns the normalized assertion instance */ protected normalized(): this; /** * A convenience method to execute the assertion. The inversion logic for * `.not` is already embedded in this method, so this should always be used * in assertions to keep the negation system working * * @param options the execution options for the assertion * @returns the Assertion instance if no error was thrown */ protected execute(options: ExecuteOptions): this; /** * Check if the value matches the given predicate. * * @param matcher a matcher predicate * @returns the assertion instance */ toMatch(matcher: (actual: T) => boolean): this; /** * Check if the value exists. This means that the value should be neither * `null` nor `undefined`. * * @example * ``` * expect(planetEarth).toExist(); * ``` * * @returns the assertion instance */ toExist(): this; /** * Check if the value is `undefined` * * @example * ``` * expect(myUndefinedValue).toBeUndefined() * ``` * * @returns the assertion instance */ toBeUndefined(): this; /** * Check if the value is `null`. * * @example * ``` * expect(myNullValue).toBeNull(); * ``` * * @returns the assertion instance */ toBeNull(): this; /** * Check if the value is present. This means that the value should not be * `undefined`. * * @example * ``` * expect(PI).toBePresent(); * ``` * * @returns the assertion instance */ toBePresent(): this; /** * Check if the value is a truthy value. There are six falsy values in * JavaScript: `null`, `undefined`, `0`, `""`, `false`, `NaN`. Everything * else is truthy. * * @example * ``` * expect("hello world").toBeTruthy(); * expect(128).toBeTruthy(); * ``` * * @returns the assertion instance */ toBeTruthy(): this; /** * Check if the value is a falsy value. There are six falsy values in * JavaScript: `null`, `undefined`, `0`, `""`, `false`, `NaN`. Everything * else is truthy. * * @example * ``` * expect(0).toBeFalsy(); * expect("").toBeFalsy(); * ``` * @returns the assertion instance */ toBeFalsy(): this; /** * Check if the value is an instance of the provided constructor. * * @example * ``` * expect(pontiac).toBeInstanceOf(Car); * * expect(today).toBeInstanceOf(Date); * ``` * * @param Expected the constructor the value should be an instance * @returns the assertion instance */ toBeInstanceOf(Expected: Constructor<unknown>): this; /** * Check if the value is deep strict equal to another value. * * @example * ``` * expect(3 + 2).toBeEqual(5); * expect({ a: { b: 1 } }).toBeEqual({ a: { b: 1 } }); * expect(today).toBeEqual(new Date(today.toISOString())); * ``` * * @param expected the value to compare for deep equality * @returns the assertion instance */ toBeEqual(expected: T): this; /** * Check if the value is shallow equal to another value. * * @example * ``` * expect(3 + 2).toBeSimilar(5); * expect({ a: 1 }).toBeSimilar({ a: 1 }); * * expect({ a: { b: 1 } }).not.toBeSimilar({ a: {b: 1} }); * ``` * * @param expected the value to compare for shallow equality * @returns the assertion instance */ toBeSimilar(expected: T): this; /** * Check if the value is the same as another value. * * @example * ``` * const x = { a: 1 }; * const y = x; * * expect(x).toBeSame(x); * expect(x).toBeSame(y); * * expect(x).not.toBeSame({ ...x }); * ``` * * @param expected the value to compare for referential equality * @returns the assertion instance */ toBeSame(expected: T): this; /** * Alias of `.toBeSame(..)` assertion. * * @example * ``` * const x = { a: 1 }; * const y = x; * * expect(x).toBeSameAs(x); * expect(x).toBeSameAs(y); * * expect(x).not.toBeSameAs({ ...x }); * ``` * * @param expected the value to compare for referential equality * @returns the assertion instance */ toBeSameAs(expected: T): this; /** * Another alias of `.toBeSame(..)` assertion. * * @example * ``` * const x = { a: 1 }; * const y = x; * * expect(x).toBe(x); * expect(x).toBe(y); * * expect(x).not.toBe({ ...x }); * ``` * * @param expected the value to compare for referential equality * @returns the assertion instance */ toBe(expected: T): this; /** * Checks if the value is of a specific data type. The supported data types * are the same as the `typeof` operator, plus an additional `array` which * allows desabiguation between `object` (which can also be an array). * * @example * ``` * const arr = [1, 2, 3]; * * expect(arr).toBeOfType("array"); * expect(arr[0]).toBeOfType("number"); * expect(arr[9]).toBeOfType("undefined"); * ``` * * @param expected the expected data type * @returns the assertion instance */ toBeOfType(expected: DataType): this; /** * Check first if the value is of some specific type, in which case returns * an assertion instance for that specific type. The new assertion is built * from a factory that should extend from the base {@link Assertion} class. * * We provide some basic factories in `TypeFactories`. If you need some * other factory for a custom assertion for instance, you can easily create * one from a Factory reference and a predicate. * * @example * ``` * expect(unknownValue) * .asType(TypeFactories.STRING) * .toStartWith("/api/"); * * expect(uuid) * .asType({ * Factory: UUIDAssertion, // a custom UUID assertion * predicate: (value): value is UUID => { * return typeof value === "string" && UUID.PATTER.test(value); * }, * }) * .isValid(); * ``` * * @typeParam S the type of the factory's value * @typeParam A the type of the assertion factory * @param typeFactory a factory to assert the type and create an assertion * @returns a more specific assertion based on the factory type */ asType<S, A extends Assertion<S>>(typeFactory: TypeFactory<S, A>): A; private proxyInverter; }