UNPKG

@fast-check/jest

Version:

Property based testing for Jest based on fast-check

96 lines (95 loc) 4.66 kB
import { readConfigureGlobal, record } from "fast-check"; //#region src/internals/TestWithPropRunnerBuilder.ts function wrapProp(prop) { return (...args) => Promise.resolve(prop(...args)); } function buildTestWithPropRunner(testFn, label, arbitraries, prop, params, timeout, jest, fc) { const customParams = { ...params }; if (customParams.seed === void 0) { const seedFromGlobals = readConfigureGlobal().seed; if (seedFromGlobals !== void 0) customParams.seed = seedFromGlobals; else { const seedFromJest = typeof jest.getSeed === "function" ? jest.getSeed() : void 0; if (seedFromJest !== void 0) customParams.seed = seedFromJest; else customParams.seed = Date.now() ^ Math.random() * 4294967296; } } if (customParams.interruptAfterTimeLimit === void 0) customParams.interruptAfterTimeLimit = fc.readConfigureGlobal().interruptAfterTimeLimit; const jestTimeout = timeout !== void 0 ? timeout : extractJestGlobalTimeout(); if (jestTimeout !== void 0) if (customParams.interruptAfterTimeLimit === void 0) customParams.interruptAfterTimeLimit = jestTimeout; else customParams.interruptAfterTimeLimit = Math.min(customParams.interruptAfterTimeLimit, jestTimeout); else console.warn("Unable to get back timeout of Jest, falling back onto Jest for global timeout handling"); const promiseProp = wrapProp(prop); const propertyInstance = fc.asyncProperty(...arbitraries, promiseProp); testFn(`${label} (with seed=${customParams.seed})`, async () => { await fc.assert(propertyInstance, customParams); }, jestTimeout !== void 0 ? 2147483647 : void 0); } function extractJestGlobalTimeout() { const jestTimeout = globalThis[Symbol.for("TEST_TIMEOUT_SYMBOL")]; if (typeof jestTimeout === "number") return jestTimeout; const stateSymbolStringValue = String(Symbol("JEST_STATE_SYMBOL")); for (const key of Object.getOwnPropertySymbols(globalThis)) if (String(key) === stateSymbolStringValue) { const jestState = globalThis[key]; if (jestState !== null && typeof jestState === "object" && typeof jestState.testTimeout === "number") return jestState.testTimeout; } if (typeof jasmine !== "undefined") return jasmine.DEFAULT_TIMEOUT_INTERVAL; } //#endregion //#region src/internals/TestBuilder.ts function adaptParametersForRecord(parameters, originalParamaters) { return { ...parameters, examples: parameters.examples !== void 0 ? parameters.examples.map((example) => example[0]) : void 0, reporter: originalParamaters.reporter, asyncReporter: originalParamaters.asyncReporter }; } function adaptExecutionTreeForRecord(executionSummary) { return executionSummary.map((summary) => ({ ...summary, value: summary.value[0], children: adaptExecutionTreeForRecord(summary.children) })); } function adaptRunDetailsForRecord(runDetails, originalParamaters) { return { ...runDetails, counterexample: runDetails.counterexample !== null ? runDetails.counterexample[0] : null, failures: runDetails.failures.map((failure) => failure[0]), executionSummary: adaptExecutionTreeForRecord(runDetails.executionSummary), runConfiguration: adaptParametersForRecord(runDetails.runConfiguration, originalParamaters) }; } function buildTestProp(testFn, jest, fc) { return (arbitraries, params) => { if (Array.isArray(arbitraries)) return (testName, prop, timeout) => buildTestWithPropRunner(testFn, testName, arbitraries, prop, params, timeout, jest, fc); return (testName, prop, timeout) => { const recordArb = record(arbitraries); const recordParams = params !== void 0 ? { ...params, examples: params.examples !== void 0 ? params.examples.map((example) => [example]) : void 0, reporter: params.reporter !== void 0 ? (runDetails) => params.reporter(adaptRunDetailsForRecord(runDetails, params)) : void 0, asyncReporter: params.asyncReporter !== void 0 ? (runDetails) => params.asyncReporter(adaptRunDetailsForRecord(runDetails, params)) : void 0 } : void 0; buildTestWithPropRunner(testFn, testName, [recordArb], (value) => prop(value), recordParams, timeout, jest, fc); }; }; } /** * Build the enriched version of {it,test}, the one with added `.prop` */ function buildTest(testFn, jest, fc) { let atLeastOneExtra = false; const extraKeys = {}; for (const key in testFn) if (typeof testFn[key] === "function") { atLeastOneExtra = true; extraKeys[key] = key !== "each" ? buildTest(testFn[key], jest, fc) : testFn[key]; } if (!atLeastOneExtra) return testFn; const enrichedTestFn = (...args) => testFn(...args); if ("each" in testFn) extraKeys["prop"] = buildTestProp(testFn, jest, fc); return Object.assign(enrichedTestFn, extraKeys); } //#endregion export { buildTest as t };