UNPKG

@augment-vir/test

Version:

A universal testing suite that works with Mocha style test runners _and_ Node.js's built-in test runner.

104 lines (103 loc) 3.71 kB
import { assert, check, } from '@augment-vir/assert'; import { ensureErrorAndPrependMessage, } from '@augment-vir/core'; import { it } from './universal-it.js'; const unsetError = Symbol('unset-error'); /** * Succinctly run many input / output tests for a pure function without repeating `it` boilerplate. * Compatible with both [Node.js's test runner](https://nodejs.org/api/test.html) and * [web-test-runner](https://modern-web.dev/docs/test-runner/overview/) or other Mocha-style test * runners. * * @category Test * @category Package : @augment-vir/test * @example * * ```ts * import {itCases, describe} from '@augment-vir/test'; * * function myFunctionToTest(a: number, b: number) { * return a + b; * } * * describe(myFunctionToTest.name, () => { * itCases(myFunctionToTest, [ * { * it: 'handles negative numbers', * inputs: [ * -1, * -2, * ], * expect: -3, * }, * { * it: 'handles 0', * inputs: [ * 0, * 0, * ], * expect: 0, * }, * { * it: 'adds', * inputs: [ * 3, * 5, * ], * expect: 8, * }, * ]); * }); * ``` * * @package [`@augment-vir/test`](https://www.npmjs.com/package/@augment-vir/test) */ export function itCases(functionToTest, testCasesOrCustomAsserter, maybeTestCases) { const testCases = (maybeTestCases || testCasesOrCustomAsserter); if (!check.isArray(testCases)) { throw new TypeError('expected an array of test cases'); } const asserter = maybeTestCases ? testCasesOrCustomAsserter : assert.deepEquals; if (typeof asserter !== 'function') { throw new TypeError('expected a function for the custom asserter'); } return testCases.map((testCase) => { const itFunction = testCase.only ? it.only : testCase.skip ? it.skip : it; return itFunction(testCase.it, async () => { const functionInputs = 'input' in testCase ? [testCase.input] : 'inputs' in testCase ? testCase.inputs : // as cast here to cover the case where the input has NO inputs []; if ('expect' in testCase) { await assert.output(asserter, functionToTest, functionInputs, testCase.expect, testCase.it); } else { let caughtError = unsetError; try { await functionToTest(...functionInputs); } catch (thrownError) { caughtError = thrownError; } const errorThrower = () => { if (caughtError !== unsetError) { throw caughtError; } }; // give a better name if possible Object.defineProperty(errorThrower, 'name', { value: functionToTest.name, }); const expectsAnError = !!(testCase.throws?.matchConstructor || testCase.throws?.matchMessage); if (caughtError !== unsetError && !expectsAnError) { throw ensureErrorAndPrependMessage(caughtError, `${functionToTest.name} threw an unexpected error`); } else if (expectsAnError) { assert.throws(errorThrower, testCase.throws, 'Caught error did not match expectations'); } } }); }); }