You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
5.6 KiB

2 years ago
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = void 0;
var _CallTracker = _interopRequireDefault(require('./CallTracker'));
var _SpyStrategy = _interopRequireDefault(require('./SpyStrategy'));
var _createSpy = _interopRequireDefault(require('./createSpy'));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
const formatErrorMsg = (domain, usage) => {
const usageDefinition = usage ? '\nUsage: ' + usage : '';
return msg => domain + ' : ' + msg + usageDefinition;
};
function isSpy(putativeSpy) {
if (!putativeSpy) {
return false;
}
return (
putativeSpy.and instanceof _SpyStrategy.default &&
putativeSpy.calls instanceof _CallTracker.default
);
}
const getErrorMsg = formatErrorMsg('<spyOn>', 'spyOn(<object>, <methodName>)');
class SpyRegistry {
constructor({currentSpies = () => []} = {}) {
_defineProperty(this, 'allowRespy', void 0);
_defineProperty(this, 'spyOn', void 0);
_defineProperty(this, 'clearSpies', void 0);
_defineProperty(this, 'respy', void 0);
_defineProperty(this, '_spyOnProperty', void 0);
this.allowRespy = function (allow) {
this.respy = allow;
};
this.spyOn = (obj, methodName, accessType) => {
if (accessType) {
return this._spyOnProperty(obj, methodName, accessType);
}
if (obj === void 0) {
throw new Error(
getErrorMsg(
'could not find an object to spy upon for ' + methodName + '()'
)
);
}
if (methodName === void 0) {
throw new Error(getErrorMsg('No method name supplied'));
}
if (obj[methodName] === void 0) {
throw new Error(getErrorMsg(methodName + '() method does not exist'));
}
if (obj[methodName] && isSpy(obj[methodName])) {
if (this.respy) {
return obj[methodName];
} else {
throw new Error(
getErrorMsg(methodName + ' has already been spied upon')
);
}
}
let descriptor;
try {
descriptor = Object.getOwnPropertyDescriptor(obj, methodName);
} catch {
// IE 8 doesn't support `definePropery` on non-DOM nodes
}
if (descriptor && !(descriptor.writable || descriptor.set)) {
throw new Error(
getErrorMsg(methodName + ' is not declared writable or has no setter')
);
}
const originalMethod = obj[methodName];
const spiedMethod = (0, _createSpy.default)(methodName, originalMethod);
let restoreStrategy;
if (Object.prototype.hasOwnProperty.call(obj, methodName)) {
restoreStrategy = function () {
obj[methodName] = originalMethod;
};
} else {
restoreStrategy = function () {
if (!delete obj[methodName]) {
obj[methodName] = originalMethod;
}
};
}
currentSpies().push({
restoreObjectToOriginalState: restoreStrategy
});
obj[methodName] = spiedMethod;
return spiedMethod;
};
this._spyOnProperty = function (obj, propertyName, accessType = 'get') {
if (!obj) {
throw new Error(
getErrorMsg(
'could not find an object to spy upon for ' + propertyName
)
);
}
if (!propertyName) {
throw new Error(getErrorMsg('No property name supplied'));
}
let descriptor;
try {
descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
} catch {
// IE 8 doesn't support `definePropery` on non-DOM nodes
}
if (!descriptor) {
throw new Error(getErrorMsg(propertyName + ' property does not exist'));
}
if (!descriptor.configurable) {
throw new Error(
getErrorMsg(propertyName + ' is not declared configurable')
);
}
if (!descriptor[accessType]) {
throw new Error(
getErrorMsg(
'Property ' +
propertyName +
' does not have access type ' +
accessType
)
);
}
if (obj[propertyName] && isSpy(obj[propertyName])) {
if (this.respy) {
return obj[propertyName];
} else {
throw new Error(
getErrorMsg(propertyName + ' has already been spied upon')
);
}
}
const originalDescriptor = descriptor;
const spiedProperty = (0, _createSpy.default)(
propertyName,
descriptor[accessType]
);
let restoreStrategy;
if (Object.prototype.hasOwnProperty.call(obj, propertyName)) {
restoreStrategy = function () {
Object.defineProperty(obj, propertyName, originalDescriptor);
};
} else {
restoreStrategy = function () {
delete obj[propertyName];
};
}
currentSpies().push({
restoreObjectToOriginalState: restoreStrategy
});
const spiedDescriptor = {...descriptor, [accessType]: spiedProperty};
Object.defineProperty(obj, propertyName, spiedDescriptor);
return spiedProperty;
};
this.clearSpies = function () {
const spies = currentSpies();
for (let i = spies.length - 1; i >= 0; i--) {
const spyEntry = spies[i];
spyEntry.restoreObjectToOriginalState();
}
};
}
}
exports.default = SpyRegistry;