UNPKG

@typed/test

Version:
77 lines (64 loc) 2.31 kB
import { Assertions, Test, TestFn, TestResult } from '../types' import { blue } from 'typed-colors' import { createAssertionsEnvironment } from '../assertions' export function it(does: string, test: TestFn): Test { return new It(does, test) } class It implements Test { public name: string protected test: TestFn constructor(name: string, test: TestFn) { this.name = `${blue('it')} ${name}` this.test = test } run(timeout: number = 2000): Promise<TestResult> { const { test } = this const { assertions, stats } = createAssertionsEnvironment() return failAfterGivenTimeout(timeout, runTest(test, assertions)) .then((): TestResult => { if (stats.count === 0) throw new Error(`No assertions have been made`) return { passed: true, error: void 0 } }) .catch((error): TestResult => ({ passed: false, error })) } } function runTest(test: TestFn, assertions: Assertions): Promise<any> { switch (test.length) { // not using assertions passed in -- always fail case 0: return Promise.reject(new Error(`No assertions have been made`)) // synchronous test or returning promise -- promise will reject if test throws case 1: return new Promise(resolve => resolve(test(assertions, Function.prototype as any))) // is using done() callback to signal test completion default: { return new Promise((resolve, reject) => { try { const result = test(assertions, (error?: Error) => { // use promise to ensure test returns first new Promise(res => setTimeout(res, 0, error)).then((err?: Error) => { if (err) return reject(err) resolve() }) }) if (result && typeof result.then === 'function') reject(new Error(`A promise-returning test should not use 'done' callback`)) } catch (err) { reject(err) } }) } } } function failAfterGivenTimeout(time: number, promise: Promise<any>): Promise<any> { return new Promise((resolve, reject) => { const id = setTimeout(() => { reject(new Error(`Timed out after ${time} ms`)) clearTimeout(id) }, time) promise.then((value: any) => { clearTimeout(id) resolve(value) }, reject) }) }