testdouble
Version:
A minimal test double library for TDD with JavaScript
103 lines (101 loc) • 4.01 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_1 = require("../wrap/lodash");
const args_match_1 = require("../args-match");
const is_callback_1 = require("../matchers/is-callback");
const notify_after_satisfaction_1 = require("../matchers/notify-after-satisfaction");
const config_1 = require("../config");
const log_1 = require("../log");
const index_1 = require("./index");
exports.default = {
add(testDouble, args, stubbedValues, config) {
return index_1.default.for(testDouble).stubbings.push({
callCount: 0,
stubbedValues,
args: config.cloneArgs ? lodash_1.default.cloneDeep(args) : args,
config
});
},
invoke(testDouble, actualArgs, actualContext) {
const stubbing = stubbingFor(testDouble, actualArgs);
if (stubbing) {
(0, notify_after_satisfaction_1.default)(stubbing.args, actualArgs);
return executePlan(stubbing, actualArgs, actualContext);
}
},
for(testDouble) {
return index_1.default.for(testDouble).stubbings;
}
};
const stubbingFor = (testDouble, actualArgs) => lodash_1.default.findLast(index_1.default.for(testDouble).stubbings, stubbing => isSatisfied(stubbing, actualArgs));
const executePlan = (stubbing, actualArgs, actualContext) => {
const value = stubbedValueFor(stubbing);
stubbing.callCount += 1;
invokeCallbackFor(stubbing, actualArgs);
switch (stubbing.config.plan) {
case 'thenReturn': return value;
case 'thenDo': return value.apply(actualContext, actualArgs);
case 'thenThrow': throw value;
case 'thenResolve': return createPromise(stubbing, value, true);
case 'thenReject': return createPromise(stubbing, value, false);
}
};
const invokeCallbackFor = (stubbing, actualArgs) => {
if (lodash_1.default.some(stubbing.args, is_callback_1.default)) {
lodash_1.default.each(stubbing.args, (expectedArg, i) => {
if ((0, is_callback_1.default)(expectedArg)) {
callCallback(stubbing, actualArgs[i], callbackArgs(stubbing, expectedArg));
}
});
}
};
const callbackArgs = (stubbing, expectedArg) => {
if (expectedArg.args != null) {
return expectedArg.args;
}
else if (stubbing.config.plan === 'thenCallback') {
return stubbing.stubbedValues;
}
else {
return [];
}
};
const callCallback = (stubbing, callback, args) => {
if (stubbing.config.delay) {
lodash_1.default.delay(callback, stubbing.config.delay, ...args);
}
else if (stubbing.config.defer) {
lodash_1.default.defer(callback, ...args);
}
else {
callback(...args); // eslint-disable-line
}
};
const createPromise = (stubbing, value, willResolve) => {
const Promise = (0, config_1.default)().promiseConstructor;
ensurePromise(Promise);
return new Promise((resolve, reject) => {
callCallback(stubbing, () => willResolve ? resolve(value) : reject(value), [value]);
});
};
const stubbedValueFor = (stubbing) => stubbing.callCount < stubbing.stubbedValues.length
? stubbing.stubbedValues[stubbing.callCount]
: lodash_1.default.last(stubbing.stubbedValues);
const isSatisfied = (stubbing, actualArgs) => (0, args_match_1.default)(stubbing.args, actualArgs, stubbing.config) &&
hasTimesRemaining(stubbing);
const hasTimesRemaining = (stubbing) => stubbing.config.times == null
? true
: stubbing.callCount < stubbing.config.times;
const ensurePromise = (Promise) => {
if (Promise == null) {
return log_1.default.error('td.when', `\
no promise constructor is set (perhaps this runtime lacks a native Promise
function?), which means this stubbing can't return a promise to your
subject under test, resulting in this error. To resolve the issue, set
a promise constructor with \`td.config\`, like this:
td.config({
promiseConstructor: require('bluebird')
})\
`);
}
};
;