UNPKG

@testduet/given-when-then

Version:

Write behavior-driven development (BDD) tests using "given-when-then" pattern and execute them in any traditional "describe-before-it-after" test framework.

212 lines (208 loc) 6.88 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { mergeInto: () => mergeInto, scenario: () => scenario }); module.exports = __toCommonJS(src_exports); // src/private/isPromiseLike.ts function isPromiseLike(promise) { return !!promise && typeof promise === "object" && "then" in promise && typeof promise.then === "function"; } // src/givenWhenThen.ts function createChain(mutableStacks, stack) { const given = (isConjunction) => { const given2 = (message, setup, teardown) => { const nextChain = createChain( mutableStacks, Object.freeze([ ...stack, { isConjunction, operation: "given", permutations: [[message, setup, teardown]] } ]) ); return { and: nextChain.given(true), when: nextChain.when() }; }; given2.oneOf = (permutations) => { const nextChain = createChain( mutableStacks, Object.freeze([ ...stack, { isConjunction, operation: "given", permutations } ]) ); return { and: nextChain.given(true), when: nextChain.when() }; }; return given2; }; const when = () => { const when2 = (message, setup, teardown) => { const nextChain = createChain( mutableStacks, Object.freeze([...stack, { operation: "when", permutations: [[message, setup, teardown]] }]) ); return { then: nextChain.then(false) }; }; when2.oneOf = (permutations) => { const nextChain = createChain( mutableStacks, Object.freeze([ ...stack, { operation: "when", permutations } ]) ); return { then: nextChain.then(false) }; }; return when2; }; const then = (isConjunction) => { return (message, fn) => { mutableStacks.push( Object.freeze([ ...stack, { isConjunction, fn, message, operation: "then" } ]) ); const currentChain = createChain(mutableStacks, stack); return { and: currentChain.then(true), when: currentChain.when() }; }; }; return { given, then, when }; } function scenario(message, fn, options) { const stacks = []; const fnResult = fn({ given: createChain(stacks, Object.freeze([])).given(false) }); if (isPromiseLike(fnResult)) { throw new Error("The function passed to scenario() cannot asynchronous"); } else if (!stacks.some((frames) => frames.some((frame) => frame.operation === "then"))) { throw new Error("Scenario should contains at least one then clause"); } const facility = { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore afterEach: (options == null ? void 0 : options.afterEach) || globalThis.afterEach, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore beforeEach: (options == null ? void 0 : options.beforeEach) || globalThis.beforeEach, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore describe: (options == null ? void 0 : options.describe) || globalThis.describe, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore it: (options == null ? void 0 : options.it) || globalThis.it }; facility.describe(message, () => { for (const stack of stacks) { runStack(stack, { value: void 0 }, { value: void 0 }, facility); } }); } function runStack(stack, preconditionRef, outcomeRef, facility) { const frame = stack.at(0); if (!frame) { return; } if (frame.operation === "given") { for (const [message, setup, teardown] of frame.permutations) { facility.describe(`${frame.isConjunction ? "and" : "given"} ${message}`, () => { let currentPreconditionRef; facility.beforeEach(() => { const save = (value2) => { currentPreconditionRef = { value: value2 }; preconditionRef.value = value2; }; const value = setup(preconditionRef.value); return isPromiseLike(value) ? Promise.resolve(value.then(save)) : save(value); }); facility.afterEach(() => { const value = teardown == null ? void 0 : teardown(currentPreconditionRef.value); return isPromiseLike(value) ? Promise.resolve(value) : value; }); return runStack(stack.slice(1), preconditionRef, outcomeRef, facility); }); } } else if (frame.operation === "when") { for (const [message, setup, teardown] of frame.permutations) { facility.describe(`when ${message}`, () => { let currentOutcomeRef; facility.beforeEach(() => { const save = (value2) => { currentOutcomeRef = { value: value2 }; outcomeRef.value = value2; }; const value = setup(preconditionRef.value, outcomeRef.value); return isPromiseLike(value) ? Promise.resolve(value.then(save)) : save(value); }); facility.afterEach(() => { const value = teardown == null ? void 0 : teardown(preconditionRef.value, currentOutcomeRef.value); return isPromiseLike(value) ? Promise.resolve(value) : value; }); return runStack(stack.slice(1), preconditionRef, outcomeRef, facility); }); } } else if (frame.operation === "then") { facility.it( `${frame.isConjunction ? "and" : "then"} ${frame.message}`, () => frame.fn(preconditionRef.value, outcomeRef.value) ); return runStack(stack.slice(1), preconditionRef, outcomeRef, facility); } } // src/mergeInto.ts function mergeInto(objectToMerge) { return (scope) => ({ ...scope, ...objectToMerge }); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { mergeInto, scenario }); //# sourceMappingURL=given-when-then.js.map