UNPKG

testdouble

Version:

A minimal test double library for TDD with JavaScript

118 lines (117 loc) 4.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const lodash_1 = require("./wrap/lodash"); const proxy_safe_clone_deep_with_1 = require("./wrap/proxy-safe-clone-deep-with"); const calls_1 = require("./store/calls"); const store_1 = require("./store"); const arguments_1 = require("./stringify/arguments"); const stubbings_1 = require("./store/stubbings"); const symbols_1 = require("./symbols"); function explain(testDouble) { if (lodash_1.default.isFunction(testDouble)) { return explainFunction(testDouble); } else if (lodash_1.default.isObject(testDouble)) { return explainObject(testDouble); } else { return explainNonTestDouble(testDouble); } } exports.default = explain; function explainObject(obj) { const { explanations, children } = explainChildren(obj); return { name: null, callCount: 0, calls: [], description: describeObject(explanations), children, isTestDouble: explanations.length > 0 }; } function explainChildren(thing) { const explanations = []; const children = (0, proxy_safe_clone_deep_with_1.default)(thing, (val, key, obj, stack) => { if (lodash_1.default.isFunction(val) && stack) { return lodash_1.default.tap(explainFunction(val), (explanation) => { if (explanation.isTestDouble) explanations.push(explanation); }); } }); return { explanations, children }; } function describeObject(explanations) { const count = explanations.length; if (count === 0) return 'This object contains no test doubles'; return `This object contains ${count} test double function${count > 1 ? 's' : ''}: [${lodash_1.default.map(explanations, e => `"${e.name}"`).join(', ')}]`; } function explainFunction(testDouble) { if (store_1.default.for(testDouble, false) == null) { return explainNonTestDouble(testDouble); } const calls = calls_1.default.for(testDouble); const stubs = stubbings_1.default.for(testDouble); const { children } = explainChildren(testDouble); return { name: store_1.default.for(testDouble).name, callCount: calls.length, calls, description: testdoubleDescription(testDouble, stubs, calls) + stubbingDescription(stubs) + callDescription(calls), children, isTestDouble: true }; } function explainNonTestDouble(thing) { return ({ name: undefined, callCount: 0, calls: [], description: `This is not a test double${lodash_1.default.isFunction(thing) ? ' function' : ''}.`, isTestDouble: false }); } function testdoubleDescription(testDouble, stubs, calls) { return `This test double ${stringifyName(testDouble)}has ${stubs.length} stubbings and ${calls.length} invocations.`; } function stubbingDescription(stubs) { return stubs.length > 0 ? lodash_1.default.reduce(stubs, (desc, stub) => desc + `\n - when called with \`(${(0, arguments_1.default)(stub.args)})\`, then ${planFor(stub)} ${argsFor(stub)}.`, '\n\nStubbings:') : ''; } function planFor(stub) { switch (stub.config.plan) { case 'thenCallback': return 'callback'; case 'thenResolve': return 'resolve'; case 'thenReject': return 'reject'; default: return 'return'; } } function argsFor(stub) { switch (stub.config.plan) { case 'thenCallback': return `\`(${(0, arguments_1.default)(stub.stubbedValues, ', ')})\``; default: return (0, arguments_1.default)(stub.stubbedValues, ', then ', '`'); } } function callDescription(calls) { return calls.length > 0 ? lodash_1.default.reduce(calls, (desc, call) => { let argDescription; if (call.cloneArgs !== symbols_1.default.uncloneable) { argDescription = `\`(${(0, arguments_1.default)(call.cloneArgs)})\`.`; } else { argDescription = `\`(${(0, arguments_1.default)(call.args)})\` [Cloning argument values failed; displaying current references]`; } return desc + `\n - called with ${argDescription}`; }, '\n\nInvocations:') : ''; } function stringifyName(testDouble) { const name = store_1.default.for(testDouble).name; return name ? `\`${name}\` ` : ''; }