/** * Provides assertion helpers used by `@effect/vitest` tests. * * This module defines small assertion functions built on Node's `assert`, * Vitest's instance checks, and Effect's equality support. The helpers cover * basic equality, thrown errors, defined and undefined values, strings, regular * expressions, class instances, `Option`, `Result`, and `Exit`. Most helpers are * synchronous; `throwsAsync` handles rejected promises. * * @since 4.0.0 */ import type * as Cause from "effect/Cause" import * as Equal from "effect/Equal" import * as Exit from "effect/Exit" import * as Option from "effect/Option" import * as Predicate from "effect/Predicate" import * as Result from "effect/Result" import * as assert from "node:assert" import { assert as vassert } from "vitest" // ---------------------------- // Primitives // ---------------------------- /** * Fails the current test with the provided error message. * * @category testing * @since 4.0.0 */ export function fail(message: string) { assert.fail(message) } /** * Asserts that `actual` is deeply strictly equal to `expected` using Node's `assert.deepStrictEqual`. * * @category testing * @since 4.0.0 */ export function deepStrictEqual(actual: A, expected: A, message?: string, ..._: Array) { assert.deepStrictEqual(actual, expected, message as string) } /** * Asserts that `actual` is not deeply strictly equal to `expected` using Node's `assert.notDeepStrictEqual`. * * @category testing * @since 4.0.0 */ export function notDeepStrictEqual(actual: A, expected: A, message?: string, ..._: Array) { assert.notDeepStrictEqual(actual, expected, message as string) } /** * Asserts that `actual` is strictly equal to `expected` using Node's `assert.strictEqual`. * * @category testing * @since 4.0.0 */ export function strictEqual(actual: A, expected: A, message?: string, ..._: Array) { assert.strictEqual(actual, expected, message as string) } /** * Asserts that `actual` is equal to `expected` using the `Equal.equals` trait. * * @category testing * @since 4.0.0 */ export function assertEquals(actual: A, expected: A, message?: string, ..._: Array) { if (!Equal.equals(actual, expected)) { deepStrictEqual(actual, expected, message) // show diff fail(message ?? "Expected values to be Equal.equals") } } /** * Asserts that `thunk` does not throw an error. * * @category testing * @since 4.0.0 */ export function doesNotThrow(thunk: () => void, message?: string, ..._: Array) { assert.doesNotThrow(thunk, message) } // ---------------------------- // Derived // ---------------------------- /** * Asserts that `value` is an instance of `constructor`. * * @category testing * @since 4.0.0 */ export function assertInstanceOf any>( value: unknown, constructor: C, message?: string, ..._: Array ): asserts value is InstanceType { vassert.instanceOf(value, constructor as any, message) } /** * Asserts that `self` is `true`. * * @category testing * @since 4.0.0 */ export function assertTrue(self: unknown, message?: string, ..._: Array): asserts self { strictEqual(self, true, message) } /** * Asserts that `self` is `false`. * * @category testing * @since 4.0.0 */ export function assertFalse(self: boolean, message?: string, ..._: Array) { strictEqual(self, false, message) } /** * Asserts that `actual` includes `expected`. * * @category testing * @since 4.0.0 */ export function assertInclude(actual: string | undefined, expected: string, ..._: Array) { if (typeof expected === "string") { if (!actual?.includes(expected)) { fail(`Expected\n\n${actual}\n\nto include\n\n${expected}`) } } } /** * Asserts that `actual` matches `regExp`. * * @category testing * @since 4.0.0 */ export function assertMatch(actual: string, regExp: RegExp, ..._: Array) { if (!regExp.test(actual)) { fail(`Expected\n\n${actual}\n\nto match\n\n${regExp}`) } } /** * Asserts that `thunk` throws, optionally checking the thrown value against an expected `Error` or validation function. * * @category testing * @since 4.0.0 */ export function throws(thunk: () => void, error?: Error | ((u: unknown) => undefined), ..._: Array) { try { thunk() fail("Expected to throw an error") } catch (e) { if (error !== undefined) { if (Predicate.isFunction(error)) { error(e) } else if (error) { deepStrictEqual(e, error) } else { throw e } } } } /** * Asserts that `thunk` throws or returns a rejected promise, optionally checking the failure value against an expected `Error` or validation function. * * @category testing * @since 4.0.0 */ export async function throwsAsync( thunk: () => Promise, error?: Error | ((u: unknown) => undefined), ..._: Array ) { try { await thunk() fail("Expected to throw an error") } catch (e) { if (error !== undefined) { if (Predicate.isFunction(error)) { error(e) } else { deepStrictEqual(e, error) } } } } // ---------------------------- // Option // ---------------------------- /** * Asserts that `option` is `None`. * * @category testing * @since 4.0.0 */ export function assertNone(option: Option.Option, ..._: Array): asserts option is Option.None { deepStrictEqual(option, Option.none()) } /** * Asserts that `a` is not `undefined`. * * @category testing * @since 4.0.0 */ export function assertDefined( a: A | undefined, ..._: Array ): asserts a is Exclude { if (a === undefined) { fail("Expected value to be defined") } } /** * Asserts that `a` is `undefined`. * * @category testing * @since 4.0.0 */ export function assertUndefined( a: A | undefined, ..._: Array ): asserts a is undefined { if (a !== undefined) { fail("Expected value to be undefined") } } /** * Asserts that `option` is `Some` and contains a value equal to `expected`. * * @category testing * @since 4.0.0 */ export function assertSome( option: Option.Option, expected: A, ..._: Array ): asserts option is Option.Some { deepStrictEqual(option, Option.some(expected)) } // ---------------------------- // Result // ---------------------------- /** * Asserts that `result` is `Success` and contains a value equal to `expected`. * * @category testing * @since 4.0.0 */ export function assertSuccess( result: Result.Result, expected: A, ..._: Array ): asserts result is Result.Success { deepStrictEqual(result, Result.succeed(expected)) } /** * Asserts that `result` is `Failure` and contains an error equal to `expected`. * * @category testing * @since 4.0.0 */ export function assertFailure( result: Result.Result, expected: E, ..._: Array ): asserts result is Result.Failure { deepStrictEqual(result, Result.fail(expected)) } // ---------------------------- // Exit // ---------------------------- /** * Asserts that `exit` is a failure with a cause equal to `expected`. * * @category testing * @since 4.0.0 */ export function assertExitFailure( exit: Exit.Exit, expected: Cause.Cause, ..._: Array ): asserts exit is Exit.Failure { deepStrictEqual(exit, Exit.failCause(expected)) } /** * Asserts that `exit` is a success with a value equal to `expected`. * * @category testing * @since 4.0.0 */ export function assertExitSuccess( exit: Exit.Exit, expected: A, ..._: Array ): asserts exit is Exit.Success { deepStrictEqual(exit, Exit.succeed(expected)) }