sinon
Version:
JavaScript test spies, stubs and mocks.
112 lines (91 loc) • 3.29 kB
JavaScript
;
var commons = require('@sinonjs/commons');
var proxyCallUtil = require('./proxy-call-util.js');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var commons__default = /*#__PURE__*/_interopDefault(commons);
const { prototypes } = commons__default.default;
const { push, forEach, concat } = prototypes.array;
const ErrorConstructor = Error.prototype.constructor;
const { bind } = Function.prototype;
let callId = 0;
/**
* @callback SinonFunction
* @param {...unknown} args
* @returns {unknown}
*/
/**
* Invokes a proxy function.
*
* @param {SinonFunction} func The original function
* @param {unknown} thisValue The `this` context for the call
* @param {Array} args The arguments for the call
* @returns {unknown} The return value of the function call
*/
function invoke(func, thisValue, args) {
const matchings = this.matchingFakes(args);
const currentCallId = callId++;
let exception, returnValue;
proxyCallUtil.incrementCallCount(this);
push(this.thisValues, thisValue);
push(this.args, args);
push(this.callIds, currentCallId);
forEach(matchings, function (matching) {
proxyCallUtil.incrementCallCount(matching);
push(matching.thisValues, thisValue);
push(matching.args, args);
push(matching.callIds, currentCallId);
});
// Make call properties available from within the spied function:
proxyCallUtil.createCallProperties(this);
forEach(matchings, proxyCallUtil.createCallProperties);
try {
this.invoking = true;
const thisCall = this.getCall(this.callCount - 1);
if (thisCall.calledWithNew()) {
// Call through with `new`
returnValue = new (bind.apply(
this.func || func,
concat([thisValue], args),
))();
if (
typeof returnValue !== "object" &&
typeof returnValue !== "function"
) {
returnValue = thisValue;
}
} else {
returnValue = (this.func || func).apply(thisValue, args);
}
} catch (e) {
exception = e;
} finally {
delete this.invoking;
}
push(this.exceptions, exception);
push(this.returnValues, returnValue);
forEach(matchings, function (matching) {
push(matching.exceptions, exception);
push(matching.returnValues, returnValue);
});
const err = new ErrorConstructor();
// 1. Please do not get stack at this point. It may be so very slow, and not actually used
// 2. PhantomJS does not serialize the stack trace until the error has been thrown:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Stack
try {
throw err;
} catch (e) {
/* empty */
}
push(this.errorsWithCallStack, err);
forEach(matchings, function (matching) {
push(matching.errorsWithCallStack, err);
});
// Make return value and exception available in the calls:
proxyCallUtil.createCallProperties(this);
forEach(matchings, proxyCallUtil.createCallProperties);
if (exception !== undefined) {
throw exception;
}
return returnValue;
}
module.exports = invoke;