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.
222 lines
5.6 KiB
222 lines
5.6 KiB
'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;
|
|
|