metatests
Version:
Simple to use test engine for Metarhia technology stack
258 lines (212 loc) • 8.06 kB
TypeScript
import { Test, TestContext, TestOptions } from './test';
import { Runner } from './runner';
import { DeclarativeTest } from './declarative-test';
export interface ImperativeTestResult {
type: string;
success: boolean;
message?: string;
expected?: any;
actual?: any;
stack: string;
}
export interface ImperativeTestOptions<
C extends TestContext = {},
R extends Runner = Runner,
> extends TestOptions<C, R> {
run: boolean;
async: boolean;
timeout: number;
parallelSubtests: boolean;
dependentSubtests: boolean;
}
export class BailoutError extends Error {}
export class ImperativeTest<C extends TestContext = {}> extends Test<
ImperativeTestResult,
ImperativeTestOptions<C>
> {
constructor(
caption: string,
func: (test: ImperativeTest) => any | Promise<any>,
options: ImperativeTestOptions,
);
// Mark this test to call end after its subtests are done.
endAfterSubtests(): void;
// Mark this test to call end after its subtests are done.
beforeEach(
func: (
subtest: ImperativeTest,
callback: (context: this['context']) => void,
) => void,
): void;
beforeEach(func: (subtest: ImperativeTest) => Promise<this['context']>): void;
// Set a function to run after each subtest.
afterEach(
func: (subtest: ImperativeTest, callback: () => void) => void,
): void;
afterEach(func: (subtest: ImperativeTest) => Promise<void>): void;
// Create a subtest of this test.
test<C extends TestContext = {}>(
message: string,
func: (test: ImperativeTest<C>) => any | Promise<any>,
options: ImperativeTestOptions<C>,
): ImperativeTest<C>;
// Create an asynchronous subtest of this test.
testAsync<C extends TestContext = {}>(
message: string,
func: (test: ImperativeTest<C>) => any | Promise<any>,
options: ImperativeTestOptions<C>,
): ImperativeTest<C>;
// Create a synchronous subtest of this test
testSync<C extends TestContext = {}>(
message: string,
func: (test: ImperativeTest<C>) => any | Promise<any>,
options: ImperativeTestOptions<C>,
): ImperativeTest<C>;
// Create a declarative `{case()}` subtest of this test.
case(
caption: string,
namespace: Record<string, any>,
list: Record<string, any[]>,
options: TestOptions,
): DeclarativeTest;
// Compare actual and expected for non-strict equality.
equal(actual: any, expected: any, message?: string): void;
// Compare actual and expected for non-strict equality.
same(actual: any, expected: any, message?: string): void;
// Compare actual and expected for non-strict not-equality.
notEqual(actual: any, expected: any, message?: string): void;
// Compare actual and expected for strict equality.
strictEqual(actual: any, expected: any, message?: string): void;
// Compare actual and expected for strict equality.
strictSame(actual: any, expected: any, message?: string): void;
// Compare actual and expected for strict non-equality.
strictNotSame(actual: any, expected: any, message?: string): void;
// Compare actual and expected to have same topology.
sameTopology(obj1: any, obj2: any, message?: string): void;
// Compare actual and expected to not have the same topology.
notSameTopology(obj1: any, obj2: any, message?: string): void;
// Check if value is truthy.
assert(value: any, message?: string): void;
// Check if value is truthy.
ok(value: any, message?: string): void;
// Check if value is falsy.
assertNot(value: any, message?: string): void;
// Check if value is falsy.
notOk(value: any, message?: string): void;
// Fail this test recording failure message.
fail(err: Error): void;
// Fail this test recording failure message.
fail(message: string, err: Error): void;
// Fail if err is instance of Error.
error(err: any, message?: string): void;
// Check if obj is of specified type.
type(obj: any, type: string | (new () => any), message?: string): void;
// Check if actual is equal to expected error.
isError(actual: any, expected: Error, message?: string): void;
// Check that fn throws expected error.
throws(fn: () => void, expected: Error, message?: string): void;
// Check that fn doesn't throw.
doesNotThrow(fn: () => void, message?: string): void;
// Check that fn is called specified amount of times.
mustCall<F extends () => {} = () => {}>(
fn?: F,
count?: number,
name?: string,
): F;
// Check that fn is not called.
mustNotCall<F extends () => {} = () => {}>(fn?: F, name?: string): F;
// Check that actual contains all properties of subObj.
contains<T, A extends Iterable<T>, S extends Iterable<T>>(
actual: A,
subObj: S,
message?: string,
sort?: boolean,
test?: (a: T, b: T) => boolean,
): void;
// Check greedily that actual contains all properties of subObj.
containsGreedy<T, A extends Iterable<T>, S extends Iterable<T>>(
actual: A,
subObj: S,
message?: string,
test?: (a: T, b: T) => boolean,
): void;
// Fail this test and throw an error.
bailout(message: string): void;
// Fail this test and throw an error.
bailout(err: Error, message: string): void;
// Create error-first callback wrapper to perform automatic checks.
cb<F extends (err: Error, ...args: any[]) => {}>(cb: F): F;
// Create error-first callback wrapper to perform automatic checks.
cb<F extends (err: Error, ...args: any[]) => {}>(msg: string, cb: F): F;
// Create error-first callback wrapper to fail test if call fails.
cbFail<A extends any[], R, F extends (err: Error, ...args: A) => R>(
fail: string,
cb: F,
afterAllCb: () => void,
): (...args: A) => R;
// Create error-first callback wrapper to fail test if call fails.
cbFail<A extends any[], R, F extends (err: Error, ...args: A) => R>(
cb: F,
afterAllCb: () => void,
): (...args: A) => R;
// Verify that input resolves.
resolves<T>(input: Promise<T> | (() => Promise<T>), expected?: T): Promise<T>;
// Verify that input resolves.
isResolved<T>(
input: Promise<T> | (() => Promise<T>),
expected?: T,
): Promise<T>;
// Check that input rejects.
rejects<T, E extends Error>(
input: Promise<T> | (() => Promise<T>),
err: Error,
): Promise<E>;
// Check that input rejects.
isRejected<T, E extends Error>(
input: Promise<T> | (() => Promise<T>),
err: Error,
): Promise<E>;
// Check whether `val` satisfies custom `checkFn` condition.
is<T>(checkFn: (val: T) => boolean, val: T, message?: string): void;
// Check if `val` satisfies `Array.isArray`.
isArray(val: any, message?: string): void;
// Check if `val` satisfies `Buffer.isBuffer`.
isBuffer(val: any, message?: string): void;
// Test whether input matches the provided RegExp
regex(regex: RegExp | string, input: string, message?: string): void;
// Plan this test to have exactly n assertions and end test after
// this amount of assertions is reached.
plan(n: number): void;
// Record a passing assertion.
pass(message?: string): void;
// Defer a function call until the 'before' end of test.
defer<F extends () => any | Promise<any> = () => {}>(
fn: F,
options: { ignoreErrors?: boolean },
): void;
on(name: 'done', listener: (test: this) => void): this;
}
// Create a test case.
export function test<C extends TestContext = {}, R extends Runner = Runner>(
caption: string,
func: (test: ImperativeTest) => any | Promise<any>,
options?: ImperativeTestOptions,
runner?: R,
): ImperativeTest<C>;
// Create an asynchronous test
export function testAsync<
C extends TestContext = {},
R extends Runner = Runner,
>(
caption: string,
func: (test: ImperativeTest) => any | Promise<any>,
options?: ImperativeTestOptions,
runner?: R,
): ImperativeTest<C>;
// Create a synchronous test
export function testSync<C extends TestContext = {}, R extends Runner = Runner>(
caption: string,
func: (test: ImperativeTest) => any | Promise<any>,
options?: ImperativeTestOptions,
runner?: R,
): ImperativeTest<C>;