UNPKG

testdouble

Version:

A minimal test double library for TDD with JavaScript

91 lines (88 loc) 4.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const lodash_1 = require("./wrap/lodash"); const args_match_1 = require("./args-match"); const calls_1 = require("./store/calls"); const log_1 = require("./log"); const store_1 = require("./store"); const arguments_1 = require("./stringify/arguments"); const stubbings_1 = require("./store/stubbings"); const notify_after_satisfaction_1 = require("./matchers/notify-after-satisfaction"); const clone_deep_if_possible_1 = require("./clone-deep-if-possible"); const symbols_1 = require("./symbols"); exports.default = (__userDoesRehearsalInvocationHere__, config = {}) => { const last = calls_1.default.pop(); ensureRehearsalOccurred(last); ensureCloneableIfCloneArgs(last, config); if (calls_1.default.wasInvoked(last.testDouble, last.args, config)) { notifyMatchers(last.testDouble, last.args, config); warnIfStubbed(last.testDouble, last.args); } else { log_1.default.fail(unsatisfiedErrorMessage(last.testDouble, last.args, config)); } }; const ensureRehearsalOccurred = (last) => { if (!last) { log_1.default.error('td.verify', `\ No test double invocation detected for \`verify()\`. Usage: verify(myTestDouble('foo'))\ `); } }; function ensureCloneableIfCloneArgs(last, config) { if (config.cloneArgs && (0, clone_deep_if_possible_1.default)(last.args) === symbols_1.default.uncloneable) { return log_1.default.error('td.verify', `\ Failed to deep-clone arguments. Ensure lodash _.cloneDeep works on them `); } } const notifyMatchers = (testDouble, expectedArgs, config) => { lodash_1.default.each(calls_1.default.where(testDouble, expectedArgs, config), (invocation) => { (0, notify_after_satisfaction_1.default)(expectedArgs, invocation.args); }); }; const warnIfStubbed = (testDouble, actualArgs) => { if (lodash_1.default.some(stubbings_1.default.for(testDouble), (stubbing) => (0, args_match_1.default)(stubbing.args, actualArgs, stubbing.config))) { log_1.default.warn('td.verify', `test double${stringifyName(testDouble)} was both stubbed and verified with arguments (${(0, arguments_1.default)(actualArgs)}), which is redundant and probably unnecessary.`, 'https://github.com/testdouble/testdouble.js/blob/main/docs/B-frequently-asked-questions.md#why-shouldnt-i-call-both-tdwhen-and-tdverify-for-a-single-interaction-with-a-test-double'); } }; const unsatisfiedErrorMessage = (testDouble, args, config) => baseSummary(testDouble, args, config) + matchedInvocationSummary(testDouble, args, config) + invocationSummary(testDouble, args, config); const stringifyName = (testDouble) => { const name = store_1.default.for(testDouble).name; return name ? ` \`${name}\`` : ''; }; const baseSummary = (testDouble, args, config) => `\ Unsatisfied verification on test double${stringifyName(testDouble)}. Wanted: - called with \`(${(0, arguments_1.default)(args)})\`${timesMessage(config)}${ignoreMessage(config)}.\ `; const invocationSummary = (testDouble, args, config) => { const calls = calls_1.default.for(testDouble); if (calls.length === 0) { return '\n\n But there were no invocations of the test double.'; } else { return lodash_1.default.reduce(calls, (desc, call) => desc + `\n - called with \`(${(0, arguments_1.default)(call.args)})\`.`, '\n\n All calls of the test double, in order were:'); } }; const matchedInvocationSummary = (testDouble, args, config) => { const calls = calls_1.default.where(testDouble, args, config); const expectedCalls = config.times || 0; if (calls.length === 0 || calls.length > expectedCalls) { return ''; } else { return lodash_1.default.reduce(lodash_1.default.groupBy(calls, 'args'), (desc, callsMatchingArgs, args) => desc + `\n - called ${pluralize(callsMatchingArgs.length, 'time')} with \`(${(0, arguments_1.default)(callsMatchingArgs[0].args)})\`.`, `\n\n ${pluralize(calls.length, 'call')} that satisfied this verification:`); } }; const pluralize = (x, msg) => `${x} ${msg}${x === 1 ? '' : 's'}`; const timesMessage = (config) => config.times != null ? ` ${pluralize(config.times, 'time')}` : ''; const ignoreMessage = (config) => config.ignoreExtraArgs != null ? ', ignoring any additional arguments' : '';