UNPKG

@magic/test

Version:

simple yet powerful unit testing library

103 lines (86 loc) 2.86 kB
import is from '@magic/types' /** @typedef {unknown} SpecValue */ /** * @param {unknown} lib * @param {unknown | unknown[]} spec * @param {string} fullName * @returns {{ fn: boolean, info: string } | { fn: boolean, info: string }[]} */ const createLibTest = (lib, spec, fullName) => { if (is.array(spec)) { return spec.map(type => createLibTest(lib, type, fullName)).flat() } let fn = spec if (!is.fn(spec)) { if (is.string(spec) && is.ownProp(is, spec)) { const isValue = is[/** @type {keyof typeof is} */ (spec)] if (is.fn(isValue)) { fn = isValue } } } if (!is.fn(fn)) { return { fn: false, info: `Spec for ${fullName} is wrong, got: ${spec}, but @magic/types does not have this function.`, } } return { fn: /** @type {Function} */ (fn)(lib), info: `Spec for ${fullName} is wrong, expected: ${spec}, actual type is ${typeof lib}`, } } /** * @param {Record<string, unknown>} [lib={}] * @param {Record<string, SpecValue>} [spec={}] * @param {string} [parent=''] * @returns {({ fn: boolean, info: string } | { fn: boolean, info: string }[])[]} */ export const test = (lib = {}, spec = {}, parent = '') => { return Object.entries(lib) .map(([name, subLib]) => { const fullName = `${parent ? `${parent}.` : ''}${name}` const subSpec = spec[name] if (!subSpec) { return { fn: false, info: `Spec missing for ${fullName}`, } } if (is.array(subSpec)) { const [parentType, subSpecChildren] = subSpec const parentTest = createLibTest(subLib, parentType, fullName) if (subSpecChildren === false) { return parentTest } if (is.object(subLib) && is.object(subSpecChildren)) { const subTests = test( /** @type {Record<string, unknown>} */ (subLib), /** @type {Record<string, SpecValue>} */ (subSpecChildren), `${parent}${name}`, ) return [parentTest, ...subTests].flat() } return parentTest } else if (is.string(subSpec)) { if (subSpec === 'obj' || subSpec === 'object') { return { fn: false, info: `Spec for ${fullName} specifies object, but no children defined. change to an array [parentType, { subName: subType }]`, } } return createLibTest(subLib, subSpec, fullName) } else if (is.function(subSpec)) { return createLibTest(subLib, subSpec, fullName) } return undefined }) .filter(a => !!a) } /** * @param {Record<string, unknown>} [lib] * @param {Record<string, SpecValue>} [spec] * @param {string} [parent] * @returns {{ fn: boolean, info: string }[]} */ export const version = (lib, spec, parent) => test(lib, spec, parent).flat(2000)