spy4js
Advanced tools
Comparing version 1.9.1 to 2.0.0
@@ -1,134 +0,73 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
exports.SpyRegistry = undefined; | ||
exports.SpyRegistry = SpyRegistry; | ||
var _utils = require('./utils'); | ||
var _utils = require("./utils"); | ||
var restoreAttributeForEntry = function restoreAttributeForEntry(value) { | ||
var obj = value.obj, | ||
method = value.method, | ||
methodName = value.methodName; | ||
var obj = value.obj, | ||
method = value.method, | ||
methodName = value.methodName; | ||
if (obj) { | ||
obj[methodName] = method; | ||
} | ||
if (obj) { | ||
obj[methodName] = method; | ||
} | ||
}; | ||
/** | ||
* The SpyRegistry is a class to handle the | ||
* correct restoration of spied objects. | ||
* | ||
* You may push an objects information about | ||
* a spied method to store it and be able to | ||
* restore it at any time. | ||
* Consider the SpyRegistry as information storage | ||
* for spied objects. | ||
* | ||
* @constructor | ||
*/ | ||
/** | ||
* This file is part of spy4js which is released under MIT license. | ||
* | ||
* The LICENSE file can be found in the root directory of this project. | ||
* | ||
* | ||
*/ | ||
function SpyRegistry() { | ||
if (!(this instanceof SpyRegistry)) { | ||
throw new Error('\n\nPlease make sure to use this constructor only with "new" keyword.\n\n'); | ||
} | ||
function SpyRegistry() { | ||
if (!(this instanceof SpyRegistry)) { | ||
throw new Error('\n\nPlease make sure to use this constructor only with "new" keyword.\n\n'); | ||
} | ||
this.register = {}; | ||
this.persReg = {}; | ||
this.registerCount = 0; | ||
this.register = {}; | ||
this.persReg = {}; | ||
this.registerCount = 0; | ||
} | ||
/** | ||
* If called, the SypRegistry will be resetting to its initial state. | ||
* Exception: the unique register count will not be touched. | ||
* Meaning that all stored object information will be restored | ||
* to their individual previous state. | ||
*/ | ||
SpyRegistry.prototype.restoreAll = function () { | ||
(0, _utils.forEach)(this.register, function (ignored, entry) { | ||
restoreAttributeForEntry(entry); | ||
}); | ||
this.register = {}; | ||
(0, _utils.forEach)(this.register, function (ignored, entry) { | ||
restoreAttributeForEntry(entry); | ||
}); | ||
this.register = {}; | ||
}; | ||
/** | ||
* If called, the SpyRegistry will restore the object, | ||
* which was registered at given index and is getting lose | ||
* of the stored information. | ||
* | ||
* If the registry entry for the given index does not exist, | ||
* nothing will happen. | ||
* | ||
* @param {number} index -> the unique identifier of stored information. | ||
*/ | ||
SpyRegistry.prototype.restore = function (index) { | ||
var entry = this.register[index]; | ||
if (entry) { | ||
restoreAttributeForEntry(entry); | ||
delete this.register[index]; | ||
} | ||
var entry = this.register[index]; | ||
if (entry) { | ||
restoreAttributeForEntry(entry); | ||
delete this.register[index]; | ||
} | ||
}; | ||
/** | ||
* If called, the SpyRegistry will store the given information. | ||
* The unique identifier index will be returned. | ||
* | ||
* @param {Object} obj -> The related object, which will be spied. | ||
* @param {string} methodName -> The name of the mocked method. | ||
* @return {number} -> The unique store index. | ||
*/ | ||
SpyRegistry.prototype.push = function (obj, methodName) { | ||
this.registerCount += 1; | ||
this.register[this.registerCount] = { | ||
obj: obj, | ||
method: obj[methodName], | ||
methodName: methodName | ||
}; | ||
return this.registerCount; | ||
this.registerCount += 1; | ||
this.register[this.registerCount] = { | ||
obj: obj, | ||
method: obj[methodName], | ||
methodName: methodName | ||
}; | ||
return this.registerCount; | ||
}; | ||
/** | ||
* If called, the stored method for the corresponding index | ||
* will be returned. If the registry entry does not exist, | ||
* undefined will be returned. | ||
* | ||
* @param {number} index -> the unique identifier of stored information. | ||
* @return {any} -> Any stored information can be returned. | ||
* BUT: Usually this method returns a function or | ||
* undefined. | ||
*/ | ||
SpyRegistry.prototype.getOriginalMethod = function (index) { | ||
var entry = this.register[index]; | ||
if (entry) { | ||
return entry.method; | ||
} | ||
var entry = this.register[index]; | ||
if (entry) { | ||
return entry.method; | ||
} | ||
}; | ||
/** | ||
* If called, the stored method will be moved from the standard | ||
* registry into the persistent registry or vice versa. | ||
* This can make restore and restoreAll having no effect anymore. | ||
* | ||
* @param {number} index -> the unique identifier of stored information. | ||
* @param {boolean} intoPersReg -> boolean to determine the moving | ||
* direction. | ||
*/ | ||
SpyRegistry.prototype.persist = function (index, intoPersReg) { | ||
var fromReg = intoPersReg ? this.register : this.persReg; | ||
var toReg = intoPersReg ? this.persReg : this.register; | ||
var entry = fromReg[index]; | ||
if (entry) { | ||
toReg[index] = entry; | ||
delete fromReg[index]; | ||
} | ||
}; | ||
var fromReg = intoPersReg ? this.register : this.persReg; | ||
var toReg = intoPersReg ? this.persReg : this.register; | ||
var entry = fromReg[index]; | ||
exports.SpyRegistry = SpyRegistry; | ||
if (entry) { | ||
toReg[index] = entry; | ||
delete fromReg[index]; | ||
} | ||
}; |
@@ -1,2 +0,2 @@ | ||
'use strict'; | ||
"use strict"; | ||
@@ -6,18 +6,12 @@ Object.defineProperty(exports, "__esModule", { | ||
}); | ||
exports.serialize = undefined; | ||
exports.serialize = void 0; | ||
var _utils = require('./utils'); | ||
var _utils = require("./utils"); | ||
var _serializeAsCode = require('serialize-as-code'); | ||
var _serializeAsCode = require("serialize-as-code"); | ||
/** | ||
* This file is part of spy4js which is released under MIT license. | ||
* | ||
* The LICENSE file can be found in the root directory of this project. | ||
* | ||
* | ||
*/ | ||
var serialize = _serializeAsCode.Serializer.create(function (o) { | ||
return o === _utils.IGNORE && '>IGNORED<' || undefined; | ||
}); | ||
var serialize = exports.serialize = _serializeAsCode.Serializer.create(function (o) { | ||
return o === _utils.IGNORE && '>IGNORED<' || undefined; | ||
}); | ||
exports.serialize = serialize; |
1014
dist/spy.js
@@ -1,788 +0,400 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
exports.Spy = undefined; | ||
exports.Spy = void 0; | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
var _utils = require("./utils"); | ||
var _utils = require('./utils'); | ||
var _registry = require("./registry"); | ||
var _registry = require('./registry'); | ||
var _serializer = require("./serializer"); | ||
var _serializer = require('./serializer'); | ||
var _mock = require("./mock"); | ||
var _testSuite = require("./test-suite"); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } /** | ||
* This file is part of spy4js which is released under MIT license. | ||
* | ||
* The LICENSE file can be found in the root directory of this project. | ||
* | ||
* | ||
*/ | ||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } | ||
/** | ||
* | ||
* Instantiating the SpyRegistry to handle all | ||
* mocked object relative information and | ||
* restore their functionality if requested. | ||
* | ||
*/ | ||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } | ||
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; } | ||
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } | ||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } | ||
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } | ||
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } | ||
var registry = new _registry.SpyRegistry(); | ||
var __LOCK__ = true; | ||
/** | ||
* Those symbols are used to protect the private spy properties from outer manipulation by mistake. | ||
*/ | ||
var Symbols = { | ||
name: Symbol.for('__Spy_name__'), | ||
isSpy: Symbol.for('__Spy_isSpy__'), | ||
func: Symbol.for('__Spy_func__'), | ||
calls: Symbol.for('__Spy_calls__'), | ||
config: Symbol.for('__Spy_config__'), | ||
index: Symbol.for('__Spy_index__') | ||
name: Symbol.for('__Spy_name__'), | ||
isSpy: Symbol.for('__Spy_isSpy__'), | ||
func: Symbol.for('__Spy_func__'), | ||
calls: Symbol.for('__Spy_calls__'), | ||
config: Symbol.for('__Spy_config__'), | ||
index: Symbol.for('__Spy_index__') | ||
}; | ||
/** | ||
* Initial default settings for every | ||
* spy instance. Can be modified only | ||
* implicitly by "Spy.configure". | ||
* | ||
* @type {{useOwnEquals: boolean}} | ||
*/ | ||
var DefaultSettings = { | ||
useOwnEquals: true | ||
useOwnEquals: true | ||
}; | ||
var SpyFunctions = { | ||
/** | ||
* Configures this spy behaviour in a special | ||
* way. Passing in an object that contains | ||
* meaningful attributes can configure: | ||
* | ||
* - useOwnEquals:boolean -> toggles the usage of own | ||
* implementation of "equals" | ||
* matcher, e.g. for comparing | ||
* call params with "wasCalledWith". | ||
* | ||
* - persistent:boolean -> toggles the persistence of the spy. | ||
* I.e. making it restorable or not. | ||
* Throws for not mocking spies. | ||
* | ||
* @param {Object} config <- An object containing attributes | ||
* for special configuration | ||
* @return {SpyInstance} <- BuilderPattern. | ||
*/ | ||
configure: function configure(config) { | ||
if (config.useOwnEquals !== undefined) { | ||
this[Symbols.config].useOwnEquals = config.useOwnEquals; | ||
} | ||
if (config.persistent !== undefined) { | ||
if (!this[Symbols.index]) { | ||
throw new Error('\n\n' + this[Symbols.name] + ' can not' + ' be configured to be persistent!' + ' It does not mock any object.'); | ||
} | ||
this[Symbols.config].persistent = config.persistent; | ||
registry.persist(this[Symbols.index], this[Symbols.config].persistent); | ||
} | ||
return this; | ||
}, | ||
configure: function configure(config) { | ||
if (config.useOwnEquals !== undefined) { | ||
this[Symbols.config].useOwnEquals = config.useOwnEquals; | ||
} | ||
if (config.persistent !== undefined) { | ||
if (!this[Symbols.index]) { | ||
throw new Error("\n\n".concat(this[Symbols.name], " can not") + ' be configured to be persistent!' + ' It does not mock any object.'); | ||
} | ||
/** | ||
* Accepts multiple functions. If called more often, | ||
* calling always the last supplied function. | ||
* | ||
* @param {Array<Function>} funcs | ||
* -> The iterative provided functions | ||
* can be accessed as array. | ||
* And will be called one by one | ||
* for each made call on the spy. | ||
* | ||
* @return {SpyInstance} <- BuilderPattern. | ||
*/ | ||
calls: function calls() { | ||
for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) { | ||
funcs[_key] = arguments[_key]; | ||
} | ||
this[Symbols.config].persistent = config.persistent; | ||
registry.persist(this[Symbols.index], this[Symbols.config].persistent); | ||
} | ||
if (funcs.length === 0) { | ||
// no arguments provided | ||
this[Symbols.func] = function () {}; | ||
return this; | ||
} | ||
return this; | ||
}, | ||
calls: function calls() { | ||
for (var _len = arguments.length, funcs = new Array(_len), _key = 0; _key < _len; _key++) { | ||
funcs[_key] = arguments[_key]; | ||
} | ||
var max = funcs.length - 1; | ||
var counter = -1; | ||
if (funcs.length === 0) { | ||
this[Symbols.func] = function () {}; | ||
this[Symbols.func] = function () { | ||
counter++; | ||
return funcs[max < counter ? max : counter].apply(funcs, arguments); | ||
}; | ||
return this; | ||
} | ||
return this; | ||
}, | ||
var max = funcs.length - 1; | ||
var counter = -1; | ||
this[Symbols.func] = function () { | ||
counter++; | ||
return funcs[max < counter ? max : counter].apply(funcs, arguments); | ||
}; | ||
/** | ||
* Accepts multiple return values. If called more often, | ||
* returns always the last supplied return value. | ||
* | ||
* @param {Array<any>} args -> The iterative provided arguments | ||
* can be accessed as array. | ||
* And will be returned one by one | ||
* for each made call. | ||
* | ||
* @return {SpyInstance} <- BuilderPattern. | ||
*/ | ||
returns: function returns() { | ||
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
args[_key2] = arguments[_key2]; | ||
} | ||
return this; | ||
}, | ||
returns: function returns() { | ||
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
args[_key2] = arguments[_key2]; | ||
} | ||
return this.calls.apply(this, _toConsumableArray(args.map(function (arg) { | ||
return function () { | ||
return arg; | ||
}; | ||
}))); | ||
}, | ||
return this.calls.apply(this, _toConsumableArray(args.map(function (arg) { | ||
return function () { | ||
return arg; | ||
}; | ||
}))); | ||
}, | ||
resolves: function resolves() { | ||
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | ||
args[_key3] = arguments[_key3]; | ||
} | ||
return this.returns.apply(this, _toConsumableArray(args.map(function (arg) { | ||
return Promise.resolve(arg); | ||
}))); | ||
}, | ||
rejects: function rejects() { | ||
var _this = this; | ||
/** | ||
* Accepts multiple values, which will be resolved sequentially. | ||
* If called more often, resolves always the last supplied value. | ||
* | ||
* @param {Array<any>} args -> The iterative provided arguments | ||
* can be accessed as array. | ||
* And will be resolved one by one | ||
* for each made call. | ||
* | ||
* @return {SpyInstance} <- BuilderPattern. | ||
*/ | ||
resolves: function resolves() { | ||
for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | ||
args[_key3] = arguments[_key3]; | ||
} | ||
for (var _len4 = arguments.length, msgOrErrors = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { | ||
msgOrErrors[_key4] = arguments[_key4]; | ||
} | ||
return this.returns.apply(this, _toConsumableArray(args.map(function (arg) { | ||
return Promise.resolve(arg); | ||
}))); | ||
}, | ||
return this.calls.apply(this, _toConsumableArray(msgOrErrors.map(function (msgOrError) { | ||
return function () { | ||
return Promise.reject((0, _utils.toError)(msgOrError, _this[Symbols.name])); | ||
}; | ||
}))); | ||
}, | ||
throws: function throws(msgOrError) { | ||
var _this2 = this; | ||
this[Symbols.func] = function () { | ||
throw (0, _utils.toError)(msgOrError, _this2[Symbols.name]); | ||
}; | ||
/** | ||
* Accepts multiple values, which will be rejected sequentially. | ||
* If called more often, rejects always the last supplied value. | ||
* | ||
* @param {Array<OptionalMessageOrError>} msgOrErrors | ||
* -> The iterative provided arguments | ||
* can be accessed as array. | ||
* And will be rejected one by one | ||
* for each made call. | ||
* | ||
* @return {SpyInstance} <- BuilderPattern. | ||
*/ | ||
rejects: function rejects() { | ||
var _this = this; | ||
return this; | ||
}, | ||
reset: function reset() { | ||
this[Symbols.calls] = []; | ||
return this; | ||
}, | ||
restore: function restore() { | ||
if (this[Symbols.config].persistent) { | ||
throw new Error("\n\n".concat(this[Symbols.name], " can not be restored!") + ' It was configured to be persistent.'); | ||
} | ||
for (var _len4 = arguments.length, msgOrErrors = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { | ||
msgOrErrors[_key4] = arguments[_key4]; | ||
} | ||
registry.restore(this[Symbols.index]); | ||
return this; | ||
}, | ||
transparent: function transparent() { | ||
return this.transparentAfter(0); | ||
}, | ||
transparentAfter: function transparentAfter(callCount) { | ||
var _this3 = this; | ||
return this.calls.apply(this, _toConsumableArray(msgOrErrors.map(function (msgOrError) { | ||
return function () { | ||
return Promise.reject((0, _utils.toError)(msgOrError, _this[Symbols.name])); | ||
}; | ||
}))); | ||
}, | ||
var oldFunc = this[Symbols.func]; | ||
this[Symbols.func] = function () { | ||
if (_this3[Symbols.calls].length > callCount) { | ||
var originalMethod = registry.getOriginalMethod(_this3[Symbols.index]); | ||
/** | ||
* Will make the spy throw an Error, if called next time. | ||
* The error message can be provided as parameter. | ||
* | ||
* @param {OptionalMessageOrError} msgOrError -> Will be the error message. | ||
* | ||
* @return {SpyInstance} <- BuilderPattern | ||
*/ | ||
throws: function throws(msgOrError) { | ||
var _this2 = this; | ||
this[Symbols.func] = function () { | ||
throw (0, _utils.toError)(msgOrError, _this2[Symbols.name]); | ||
}; | ||
return this; | ||
}, | ||
/** | ||
* Deletes all notices of made calls with this spy. | ||
* | ||
* @return {SpyInstance} <- BuilderPattern | ||
*/ | ||
reset: function reset() { | ||
this[Symbols.calls] = []; | ||
return this; | ||
}, | ||
/** | ||
* Restores the last by this spy manipulated object | ||
* and removes this special mock. | ||
* | ||
* Restoring objects does not disable any | ||
* other behaviours/features of the spies. | ||
* | ||
* If the spy was configured persistent, than this | ||
* method will throw an exception. | ||
* | ||
* Other than "Spy.restoreAll" this method only removes | ||
* a maximum of one mock. | ||
* | ||
* @return {SpyInstance} <- BuilderPattern | ||
*/ | ||
restore: function restore() { | ||
if (this[Symbols.config].persistent) { | ||
throw new Error('\n\n' + this[Symbols.name] + ' can not be restored!' + ' It was configured to be persistent.'); | ||
if (originalMethod) { | ||
return originalMethod.apply(void 0, arguments); | ||
} | ||
registry.restore(this[Symbols.index]); | ||
return this; | ||
}, | ||
return; | ||
} | ||
/** | ||
* Makes the spy behave like the mocked | ||
* function. If no function was mocked by | ||
* this spy, it will do nothing if called. | ||
* | ||
* This function works exactly like | ||
* spy.transparentAfter(0). | ||
* | ||
* For example: | ||
* const spy = Spy.on(someObject, 'someFunc'); | ||
* someObject.someFunc(); // calls only the spy | ||
* spy.transparent(); | ||
* someObject.someFunc(); // behaves like calling the original method | ||
* | ||
* @return {SpyInstance} <- BuilderPattern | ||
*/ | ||
transparent: function transparent() { | ||
return this.transparentAfter(0); | ||
}, | ||
return oldFunc.apply(void 0, arguments); | ||
}; | ||
return this; | ||
}, | ||
wasCalled: function wasCalled(callCount) { | ||
var madeCalls = this[Symbols.calls].length; | ||
/** | ||
* If called with n as callCount this will make | ||
* the spy call the mocked function after called | ||
* the n'th time. For any spy that does not mock | ||
* any objects attribute, this will make the spy | ||
* do nothing if called after the n'th time. | ||
* | ||
* If the mocked function will get called again, | ||
* the made calls will still be registered. | ||
* | ||
* For example: | ||
* Spy.on(someObject, 'someFunc').transparentAfter(2); | ||
* someObject.someFunc(); // calls only the spy | ||
* someObject.someFunc(); // calls only the spy | ||
* someObject.someFunc(); // behaves like calling the original method | ||
* | ||
* @param {number} callCount <- The number after which the mocked function | ||
* should be called again. | ||
* | ||
* @return {SpyInstance} <- BuilderPattern | ||
*/ | ||
transparentAfter: function transparentAfter(callCount) { | ||
var _this3 = this; | ||
if (typeof callCount === 'number') { | ||
if (madeCalls !== callCount) { | ||
throw new Error("\n\n".concat(this[Symbols.name], " was called ").concat(madeCalls, " times,") + " but there were expected ".concat(callCount, " calls.\n\n") + 'Actually there were:\n\n' + this.showCallArguments()); | ||
} | ||
} else if (madeCalls === 0) { | ||
throw new Error("\n\n".concat(this[Symbols.name], " was never called!\n\n")); | ||
} | ||
}, | ||
hasCallHistory: function hasCallHistory() { | ||
var _this4 = this; | ||
var oldFunc = this[Symbols.func]; | ||
this[Symbols.func] = function () { | ||
// before the function call is executed, | ||
// the call arguments were already saved | ||
// -> so we are interested if the made calls | ||
// are more than the call count were we | ||
// need to modify the behavior | ||
if (_this3[Symbols.calls].length > callCount) { | ||
var originalMethod = registry.getOriginalMethod(_this3[Symbols.index]); | ||
if (originalMethod) { | ||
return originalMethod.apply(undefined, arguments); | ||
} | ||
return; | ||
} | ||
return oldFunc.apply(undefined, arguments); | ||
}; | ||
return this; | ||
}, | ||
var madeCalls = this[Symbols.calls]; | ||
for (var _len5 = arguments.length, callHistory = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { | ||
callHistory[_key5] = arguments[_key5]; | ||
} | ||
/** | ||
* Checks if the spy was called callCount times often. | ||
* | ||
* If callCount is not provided then it only | ||
* checks if the spy was called at least once. | ||
* | ||
* Throws an error if the expectation is wrong. | ||
* | ||
* @param {?number} callCount -> Is the number of expected calls made. | ||
*/ | ||
wasCalled: function wasCalled(callCount) { | ||
var madeCalls = this[Symbols.calls].length; | ||
if (typeof callCount === 'number') { | ||
if (madeCalls !== callCount) { | ||
throw new Error('\n\n' + this[Symbols.name] + ' was called ' + madeCalls + ' times,' + (' but there were expected ' + callCount + ' calls.\n\n') + 'Actually there were:\n\n' + this.showCallArguments()); | ||
} | ||
} else if (madeCalls === 0) { | ||
throw new Error('\n\n' + this[Symbols.name] + ' was never called!\n\n'); | ||
} | ||
}, | ||
var callCount = callHistory.length; | ||
if (madeCalls.length !== callCount) { | ||
throw new Error("\n\n".concat(this[Symbols.name], " was called ").concat(madeCalls.length, " times,") + " but the expected call history includes exactly ".concat(callHistory.length, " calls.\n\n") + 'Actually there were:\n\n' + this.showCallArguments()); | ||
} | ||
/** | ||
* Checks if the spy was call history matches the expectation. | ||
* | ||
* The call history has to match the call count and order. | ||
* Single arguments will be automatically wrapped as array, e.g.: | ||
* 1, 2, 3 -> [1], [2], [3] | ||
* ** Inspired by jest test.each ** | ||
* | ||
* Throws an error if the expectation is wrong. | ||
* | ||
* @param {Array<Array<any> | any>} callHistory | ||
* -> Are the expected made call arguments in correct order. | ||
*/ | ||
hasCallHistory: function hasCallHistory() { | ||
var _this4 = this; | ||
var modifiedCallHistory = callHistory.map(function (arg) { | ||
return Array.isArray(arg) ? arg : [arg]; | ||
}); | ||
var hasErrors = false; | ||
var diffInfo = madeCalls.map(function (call, index) { | ||
var diff = (0, _utils.differenceOf)(call.args, modifiedCallHistory[index], _this4[Symbols.config]); | ||
if (diff) hasErrors = true; | ||
return diff; | ||
}); | ||
if (hasErrors) throw new Error("\n\n".concat(this[Symbols.name], " was considered") + ' to be called with the following arguments in the given order:\n\n' + "".concat(modifiedCallHistory.map(function (entry, index) { | ||
return "call ".concat(index, ": ").concat((0, _serializer.serialize)(entry)); | ||
}).join('\n'), "\n\n") + 'Actually there were:\n\n' + this.showCallArguments(diffInfo)); | ||
}, | ||
wasNotCalled: function wasNotCalled() { | ||
var madeCalls = this[Symbols.calls]; | ||
var madeCalls = this[Symbols.calls]; | ||
if (madeCalls.length !== 0) { | ||
throw new Error("\n\n".concat(this[Symbols.name], " was not") + ' considered to be called.\n\n' + 'Actually there were:\n\n' + this.showCallArguments()); | ||
} | ||
}, | ||
wasCalledWith: function wasCalledWith() { | ||
var madeCalls = this[Symbols.calls]; | ||
for (var _len5 = arguments.length, callHistory = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { | ||
callHistory[_key5] = arguments[_key5]; | ||
} | ||
if (madeCalls.length === 0) { | ||
throw new Error("\n\n".concat(this[Symbols.name], " was never called!\n\n")); | ||
} | ||
var callCount = callHistory.length; | ||
if (madeCalls.length !== callCount) { | ||
throw new Error('\n\n' + this[Symbols.name] + ' was called ' + madeCalls.length + ' times,' + (' but the expected call history includes exactly ' + callHistory.length + ' calls.\n\n') + 'Actually there were:\n\n' + this.showCallArguments()); | ||
} | ||
var modifiedCallHistory = callHistory.map(function (arg) { | ||
return Array.isArray(arg) ? arg : [arg]; | ||
}); | ||
var hasErrors = false; | ||
var diffInfo = madeCalls.map(function (call, index) { | ||
var diff = (0, _utils.differenceOf)(call.args, modifiedCallHistory[index], _this4[Symbols.config]); | ||
if (diff) hasErrors = true; | ||
return diff; | ||
}); | ||
if (hasErrors) throw new Error('\n\n' + this[Symbols.name] + ' was considered' + ' to be called with the following arguments in the given order:\n\n' + (modifiedCallHistory.map(function (entry, index) { | ||
return 'call ' + index + ': ' + (0, _serializer.serialize)(entry); | ||
}).join('\n') + '\n\n') + 'Actually there were:\n\n' + this.showCallArguments(diffInfo)); | ||
}, | ||
var diffInfo = []; | ||
for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { | ||
args[_key6] = arguments[_key6]; | ||
} | ||
/** | ||
* Checks that the spy was never called. | ||
* Throws an error if the spy was called at least once. | ||
*/ | ||
wasNotCalled: function wasNotCalled() { | ||
var madeCalls = this[Symbols.calls]; | ||
if (madeCalls.length !== 0) { | ||
throw new Error('\n\n' + this[Symbols.name] + ' was not' + ' considered to be called.\n\n' + 'Actually there were:\n\n' + this.showCallArguments()); | ||
} | ||
}, | ||
for (var i = 0; i < madeCalls.length; i++) { | ||
var diff = (0, _utils.differenceOf)(madeCalls[i].args, args, this[Symbols.config]); | ||
if (!diff) { | ||
return; | ||
} | ||
/** | ||
* Checks if the spy was called with the provided arguments. | ||
* | ||
* Throws an error if the expectation is wrong. | ||
* | ||
* For example: | ||
* const spy = new Spy(); | ||
* spy(arg1, arg2, arg3); | ||
* spy(arg4, arg5); | ||
* spy.wasCalledWith(arg1, arg2, arg3); // no error | ||
* spy.wasCalledWith(arg4, arg5); // no error | ||
* spy.wasCalledWith(arg1); // error!!! | ||
* | ||
* @param {Array<any>} args -> The expected arguments | ||
* for any made call. | ||
*/ | ||
wasCalledWith: function wasCalledWith() { | ||
var madeCalls = this[Symbols.calls]; | ||
if (madeCalls.length === 0) { | ||
throw new Error('\n\n' + this[Symbols.name] + ' was never called!\n\n'); | ||
} | ||
var diffInfo = []; | ||
diffInfo.push(diff); | ||
} | ||
for (var _len6 = arguments.length, args = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { | ||
args[_key6] = arguments[_key6]; | ||
} | ||
throw new Error("\n\n".concat(this[Symbols.name], " was considered") + ' to be called with the following arguments:\n\n' + " --> ".concat((0, _serializer.serialize)(args), "\n\n") + 'Actually there were:\n\n' + this.showCallArguments(diffInfo)); | ||
}, | ||
wasNotCalledWith: function wasNotCalledWith() { | ||
var errorOccurred = false; | ||
for (var i = 0; i < madeCalls.length; i++) { | ||
var diff = (0, _utils.differenceOf)(madeCalls[i].args, args, this[Symbols.config]); | ||
if (!diff) { | ||
return; | ||
} | ||
diffInfo.push(diff); | ||
} | ||
throw new Error('\n\n' + this[Symbols.name] + ' was considered' + ' to be called with the following arguments:\n\n' + (' --> ' + (0, _serializer.serialize)(args) + '\n\n') + 'Actually there were:\n\n' + this.showCallArguments(diffInfo)); | ||
}, | ||
for (var _len7 = arguments.length, args = new Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { | ||
args[_key7] = arguments[_key7]; | ||
} | ||
try { | ||
this.wasCalledWith.apply(this, args); | ||
} catch (e) { | ||
errorOccurred = true; | ||
} | ||
/** | ||
* Checks if the spy was NOT called with the provided arguments. | ||
* This method checks the direct opposite of the method | ||
* spy.wasCalledWith. | ||
* | ||
* It throws an error if the upper method would not. | ||
* | ||
* For example: | ||
* const spy = new Spy(); | ||
* spy(arg1, arg2, arg3); | ||
* spy(arg4, arg5); | ||
* spy.wasCalledWith(arg1); // no error | ||
* spy.wasCalledWith(arg4, arg3); // no error | ||
* spy.wasCalledWith(arg4, arg5); // error!!! | ||
* | ||
* @param {Array<any>} args -> The not expected arguments | ||
* for any made call. | ||
*/ | ||
wasNotCalledWith: function wasNotCalledWith() { | ||
var errorOccurred = false; | ||
if (!errorOccurred) { | ||
throw new Error("\n\n".concat(this[Symbols.name], " was called") + ' unexpectedly with the following arguments:\n\n' + " --> ".concat((0, _serializer.serialize)(args), "\n\n")); | ||
} | ||
}, | ||
getCallArguments: function getCallArguments() { | ||
var callNr = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; | ||
var madeCalls = this[Symbols.calls]; | ||
for (var _len7 = arguments.length, args = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { | ||
args[_key7] = arguments[_key7]; | ||
} | ||
if (callNr % 1 !== 0 || callNr >= madeCalls.length) { | ||
throw new Error("\n\nThe provided callNr \"".concat(callNr, "\" was not valid.\n\n") + "Made calls for ".concat(this[Symbols.name], ":\n\n") + this.showCallArguments()); | ||
} | ||
try { | ||
this.wasCalledWith.apply(this, _toConsumableArray(args)); | ||
} catch (e) { | ||
errorOccurred = true; | ||
} | ||
if (!errorOccurred) { | ||
throw new Error('\n\n' + this[Symbols.name] + ' was called' + ' unexpectedly with the following arguments:\n\n' + (' --> ' + (0, _serializer.serialize)(args) + '\n\n')); | ||
} | ||
}, | ||
return madeCalls[callNr].args; | ||
}, | ||
getCallArgument: function getCallArgument() { | ||
var callNr = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; | ||
var argNr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; | ||
return this.getCallArguments(callNr)[argNr]; | ||
}, | ||
getCallCount: function getCallCount() { | ||
return this[Symbols.calls].length; | ||
}, | ||
showCallArguments: function showCallArguments() { | ||
var additionalInformation = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; | ||
var madeCalls = this[Symbols.calls]; | ||
if (madeCalls.length === 0) { | ||
return "".concat(this[Symbols.name], " was never called!\n"); | ||
} | ||
/** | ||
* This method returns the call arguments of the | ||
* n'th made call as array. If less than n calls were made, | ||
* it will throw an error. | ||
* | ||
* By default n = 1. This corresponds to callNr = 0. | ||
* | ||
* For example: | ||
* const spy = new Spy(); | ||
* spy(arg1, arg2, arg3); | ||
* spy.getCallArguments(); // returns [arg1, arg2, arg3] | ||
* | ||
* @param {number} callNr -> represents the callNr for which | ||
* the call argument should be returned. | ||
* | ||
* @return {Array<any>} -> the call arguments of the (callNr + 1)'th call. | ||
*/ | ||
getCallArguments: function getCallArguments() { | ||
var callNr = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; | ||
var response = ''; | ||
var madeCalls = this[Symbols.calls]; | ||
if (callNr % 1 !== 0 || callNr >= madeCalls.length) { | ||
throw new Error('\n\nThe provided callNr "' + callNr + '" was not valid.\n\n' + ('Made calls for ' + this[Symbols.name] + ':\n\n') + this.showCallArguments()); | ||
} | ||
return madeCalls[callNr].args; | ||
}, | ||
for (var i = 0; i < madeCalls.length; i++) { | ||
var _args = (0, _serializer.serialize)(madeCalls[i].args); | ||
response += "call ".concat(i, ": ").concat(_args, "\n"); | ||
/** | ||
* This method returns the m'th call argument of the | ||
* n'th made call. If less than n calls were made, it will throw | ||
* an error. | ||
* | ||
* By default n = 1. This corresponds to callNr = 0. | ||
* By default m = 1. This corresponds to argNr = 0. | ||
* | ||
* For example: | ||
* const spy = new Spy(); | ||
* spy(arg1, arg2, arg3); | ||
* spy(arg4, arg5, arg6); | ||
* spy.getCallArgument() === arg1; // true | ||
* spy.getCallArgument(1) === arg4; // true | ||
* spy.getCallArgument(0, 2) === arg3; // true | ||
* spy.getCallArgument(1, 1) === arg5; // true | ||
* | ||
* spy.getCallArgument(1, 5) === undefined; // true | ||
* spy.getCallArgument(2); // throws an exception | ||
* | ||
* @param {number} callNr -> represents the callNr for which | ||
* a call argument should be returned. | ||
* @param {number} argNr -> represents position of the argument | ||
* when the corresponding call was made. | ||
* | ||
* @return {any} -> the (argNr + 1)'th call argument | ||
* of the (callNr + 1)'th call. | ||
*/ | ||
getCallArgument: function getCallArgument() { | ||
var callNr = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; | ||
var argNr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; | ||
if (additionalInformation[i]) { | ||
response += " ".concat(additionalInformation[i], "\n"); | ||
} | ||
} | ||
return this.getCallArguments(callNr)[argNr]; | ||
}, | ||
/** | ||
* This method returns the number of made calls on the spy. | ||
* | ||
* @return {number} -> the number of made calls. | ||
*/ | ||
getCallCount: function getCallCount() { | ||
return this[Symbols.calls].length; | ||
}, | ||
/** | ||
* This method returns a formatted text string for debugging | ||
* made calls with the given Spy. It is used also internally | ||
* if some wrong assertions were made on the Spy. | ||
* Some sample: | ||
* | ||
* call 0: [{"_key":"test1"}] | ||
* call 1: [{"_key":"test1"},{"_key":"test2"}] | ||
* call 2: [{"_key":"test3"},{"_key":"test2"},{"_key":"test1"}] | ||
* call 3: [{"_key":"test2"}] | ||
* | ||
* If an array of strings is provided, the given strings will | ||
* be printed just below params of each call. | ||
* | ||
* Some sample: additionalInformation = [ | ||
* '-> 0 / _key / different string', | ||
* '-> 1 / _key / different object types' | ||
* ] | ||
* | ||
* call 0: [{"_key":"test1"}] | ||
* -> 0 / _key / different string | ||
* call 1: [{"_key":"test1"},{"_key":"test2"}] | ||
* -> 1 / _key / different object types | ||
* call 2: [{"_key":"test3"},{"_key":"test2"},{"_key":"test1"}] | ||
* call 3: [{"_key":"test2"}] | ||
* | ||
* @param {Array<string>} additionalInformation | ||
* -> will be displayed below each call information | ||
* as additional information. | ||
* | ||
* @return {string} -> The information about made calls. | ||
*/ | ||
showCallArguments: function showCallArguments() { | ||
var additionalInformation = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; | ||
var madeCalls = this[Symbols.calls]; | ||
if (madeCalls.length === 0) { | ||
return this[Symbols.name] + ' was never called!\n'; | ||
} | ||
var response = ''; | ||
for (var i = 0; i < madeCalls.length; i++) { | ||
var _args = (0, _serializer.serialize)(madeCalls[i].args); | ||
response += 'call ' + i + ': ' + _args + '\n'; | ||
if (additionalInformation[i]) { | ||
response += ' ' + additionalInformation[i] + '\n'; | ||
} | ||
} | ||
return response; | ||
} | ||
return response; | ||
} | ||
}; | ||
var Spy = function () { | ||
/** | ||
* This constructor does instantiate a new spy | ||
* object. | ||
* | ||
* This spy is callable. | ||
* It does inherit all Spy specific methods below. | ||
* It holds additional (private) fields: | ||
* _name:string -> Will be displayed in all displayed | ||
* error messages. | ||
* _isSpy:boolean -> Always true for spies. | ||
* _func:Function -> The internal function, that will | ||
* actually we called, when calling | ||
* the spy. | ||
* _calls:Array<{arguments:Array<any>}> | ||
* -> Stores the arguments with whom the spy was called. | ||
* Each call adds another entry in the calls array. | ||
* _config = {useOwnEquals: boolean} -> internal spy config. | ||
* | ||
* | ||
* @param {string} name -> the identifier of the spy. | ||
* Useful for debugging issues. | ||
* @param {string} __mock -> DO NOT USE. | ||
* | ||
* @constructor | ||
*/ | ||
function Spy() { | ||
var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'the spy'; | ||
var __mock = arguments[1]; | ||
function Spy() { | ||
var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'the spy'; | ||
_classCallCheck(this, Spy); | ||
var __mock = arguments.length > 1 ? arguments[1] : undefined; | ||
var spy = function spy() { | ||
for (var _len8 = arguments.length, args = Array(_len8), _key8 = 0; _key8 < _len8; _key8++) { | ||
args[_key8] = arguments[_key8]; | ||
} | ||
_classCallCheck(this, Spy); | ||
spy[Symbols.calls].push({ args: args }); | ||
return spy[Symbols.func].apply(spy, args); | ||
}; | ||
if (__mock && !__LOCK__) { | ||
spy[Symbols.index] = registry.push(__mock.obj, __mock.methodName); | ||
} else { | ||
spy[Symbols.index] = null; | ||
} | ||
spy[Symbols.name] = name; | ||
spy[Symbols.isSpy] = true; | ||
spy[Symbols.func] = function () {}; | ||
spy[Symbols.calls] = []; | ||
spy[Symbols.config] = { useOwnEquals: DefaultSettings.useOwnEquals }; | ||
(0, _utils.forEach)(SpyFunctions, function (key, value) { | ||
spy[key] = value; | ||
}); | ||
return spy; | ||
} | ||
var spy = function spy() { | ||
for (var _len8 = arguments.length, args = new Array(_len8), _key8 = 0; _key8 < _len8; _key8++) { | ||
args[_key8] = arguments[_key8]; | ||
} | ||
/** | ||
* This static method can be used to configure | ||
* the default behaviour of created spy instances. | ||
* | ||
* For example, | ||
* | ||
* Spy.configure({useOwnEquals: false}); | ||
* | ||
* would initially configure every spy to not | ||
* favor own "equals" implementation while | ||
* comparing any objects. | ||
* | ||
* @param {Object} config <- Holds the configuration params. | ||
*/ | ||
spy[Symbols.calls].push({ | ||
args: args | ||
}); | ||
return spy[Symbols.func].apply(spy, args); | ||
}; | ||
if (__mock && !__LOCK__) { | ||
spy[Symbols.index] = registry.push(__mock.obj, __mock.methodName); | ||
} else { | ||
spy[Symbols.index] = null; | ||
} | ||
_createClass(Spy, null, [{ | ||
key: 'configure', | ||
value: function configure(config) { | ||
if (config.useOwnEquals !== undefined) { | ||
DefaultSettings.useOwnEquals = config.useOwnEquals; | ||
} | ||
} | ||
spy[Symbols.name] = name; | ||
spy[Symbols.isSpy] = true; | ||
/** | ||
* This static attribute can be used to ignore the match | ||
* of a specific argument when using "wasCalledWith". | ||
*/ | ||
spy[Symbols.func] = function () {}; | ||
spy[Symbols.calls] = []; | ||
spy[Symbols.config] = { | ||
useOwnEquals: DefaultSettings.useOwnEquals | ||
}; | ||
(0, _utils.forEach)(SpyFunctions, function (key, value) { | ||
spy[key] = value; | ||
}); | ||
return spy; | ||
} | ||
/** | ||
* This static attribute can be called with a custom | ||
* comparator that returns a boolean indicating if the | ||
* comparison holds. Can be used when calling e.g. "wasCalledWith". | ||
*/ | ||
_createClass(Spy, null, [{ | ||
key: "configure", | ||
value: function configure(config) { | ||
if (config.useOwnEquals !== undefined) { | ||
DefaultSettings.useOwnEquals = config.useOwnEquals; | ||
} | ||
}, { | ||
key: 'on', | ||
(0, _testSuite.configureTestSuite)({ | ||
afterEach: config.afterEach, | ||
beforeEach: config.beforeEach | ||
}); | ||
} | ||
}, { | ||
key: "on", | ||
value: function on(obj, methodName) { | ||
var method = obj[methodName]; | ||
if (!(method instanceof Function)) { | ||
throw new Error("The object attribute '".concat(methodName, "' ") + "was: ".concat((0, _serializer.serialize)(method), "\n\n") + 'You should only spy on functions!'); | ||
} | ||
/** | ||
* This static method is an alternative way to | ||
* create a Spy which mocks the an objects attribute. | ||
* | ||
* The attribute of the object "obj[methodName]" will | ||
* be replaced by the spy and the previous attribute | ||
* will be stored in the spy registry. | ||
* Therefore this information is always restorable. | ||
* The most common use case, will be to mock | ||
* another function as attribute of the object. | ||
* | ||
* The method has to met the following conditions: | ||
* | ||
* - The attribute to spy has to be function itself. | ||
* - The attribute to spy should not be spied already. | ||
* | ||
* If the upper conditions are not fulfilled, this | ||
* method will throw to avoid unexpected behaviour. | ||
* | ||
* @param {Object} obj -> The manipulated object. | ||
* @param {string} methodName -> The mocked attributes name. | ||
* | ||
* @return {SpyInstance} | ||
*/ | ||
value: function on(obj, methodName) { | ||
var method = obj[methodName]; | ||
if (!(method instanceof Function)) { | ||
throw new Error('The object attribute \'' + methodName + '\' ' + ('was: ' + (0, _serializer.serialize)(method) + '\n\n') + 'You should only spy on functions!'); | ||
} | ||
if (method[Symbols.isSpy]) { | ||
throw new Error('The objects attribute \'' + methodName + '\'' + ' was already spied. Please make sure to spy' + ' only once at a time at any attribute.'); | ||
} | ||
__LOCK__ = false; | ||
var spy = new Spy('the spy on \'' + methodName + '\'', { obj: obj, methodName: methodName }); | ||
__LOCK__ = true; | ||
obj[methodName] = spy; | ||
return spy; | ||
} | ||
if (method[Symbols.isSpy]) { | ||
throw new Error("The objects attribute '".concat(methodName, "'") + ' was already spied. Please make sure to spy' + ' only once at a time at any attribute.'); | ||
} | ||
/** | ||
* This static method is shortcut for applying multiple | ||
* spies on one object at (different) attributes. | ||
* | ||
* For example: | ||
* | ||
* const spy1 = Spy.on(obj, 'methodName1'); | ||
* const spy2 = Spy.on(obj, 'methodName2'); | ||
* const spy3 = Spy.on(obj, 'methodName3'); | ||
* | ||
* Is equivalent to: | ||
* | ||
* const [spy1, spy2, spy3] = | ||
* Spy.onMany(obj, 'methodName1', 'methodName2', 'methodName3') | ||
* | ||
* @param {Object} obj -> The manipulated object. | ||
* @param {Array<string>} methodNames -> Iterative provided attribute | ||
* names that will be mocked. | ||
* | ||
* @return {Array<SpyInstance>} | ||
*/ | ||
__LOCK__ = false; | ||
var spy = new Spy("the spy on '".concat(methodName, "'"), { | ||
obj: obj, | ||
methodName: methodName | ||
}); | ||
__LOCK__ = true; | ||
obj[methodName] = spy; | ||
return spy; | ||
} | ||
}, { | ||
key: "mock", | ||
value: function mock(obj) { | ||
for (var _len9 = arguments.length, methodNames = new Array(_len9 > 1 ? _len9 - 1 : 0), _key9 = 1; _key9 < _len9; _key9++) { | ||
methodNames[_key9 - 1] = arguments[_key9]; | ||
} | ||
}, { | ||
key: 'onMany', | ||
value: function onMany(obj) { | ||
var spies = []; | ||
return (0, _mock.createMock)(obj, methodNames); | ||
} | ||
}, { | ||
key: "initMocks", | ||
value: function initMocks() { | ||
(0, _mock.initMocks)(Spy.on); | ||
} | ||
}, { | ||
key: "restoreAll", | ||
value: function restoreAll() { | ||
registry.restoreAll(); | ||
} | ||
}]); | ||
for (var _len9 = arguments.length, methodNames = Array(_len9 > 1 ? _len9 - 1 : 0), _key9 = 1; _key9 < _len9; _key9++) { | ||
methodNames[_key9 - 1] = arguments[_key9]; | ||
} | ||
return Spy; | ||
}(); | ||
for (var i = 0; i < methodNames.length; i++) { | ||
var spy = Spy.on(obj, methodNames[i]); | ||
spies.push(spy); | ||
} | ||
return spies; | ||
} | ||
exports.Spy = Spy; | ||
/** | ||
* This static method does restore all | ||
* manipulated objects and remove therefore | ||
* all mocks. | ||
* | ||
* Restoring objects does not disable any | ||
* other behaviours/features of the spies. | ||
*/ | ||
_defineProperty(Spy, "IGNORE", _utils.IGNORE); | ||
}, { | ||
key: 'restoreAll', | ||
value: function restoreAll() { | ||
registry.restoreAll(); | ||
} | ||
}]); | ||
_defineProperty(Spy, "COMPARE", _utils.COMPARE); | ||
return Spy; | ||
}(); | ||
Spy.IGNORE = _utils.IGNORE; | ||
Spy.COMPARE = _utils.COMPARE; | ||
exports.Spy = Spy; | ||
(0, _testSuite.configureTestSuite)({ | ||
beforeEach: Spy.initMocks, | ||
afterEach: Spy.restoreAll | ||
}); |
@@ -1,252 +0,183 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
exports.toError = exports.COMPARE = exports.IGNORE = exports.objectKeys = exports.forEach = exports.differenceOf = void 0; | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } | ||
/** | ||
* This file is part of spy4js which is released under MIT license. | ||
* | ||
* The LICENSE file can be found in the root directory of this project. | ||
* | ||
* | ||
*/ | ||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } | ||
/** | ||
* This function takes a handler as second argument to process | ||
* all key-value-pairs of the given object through this handler. | ||
* | ||
* For example: | ||
* | ||
* forEach({attr1: 'str1', attr2: 123}, (k, v) => { | ||
* console.log(k + 'has value: ' + v); | ||
* }); | ||
* | ||
* @param {Array<any>|Object} arrOrObj <- Array or Object to iterate. | ||
* (Flow does not want to iterate | ||
* over arrays with for-in, so we | ||
* have to write here any.) | ||
* @param {Function} handler <- Handler function to process all values. | ||
* | ||
*/ | ||
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; } | ||
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } | ||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } | ||
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } | ||
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } | ||
var forEach = function forEach(arrOrObj, handler) { | ||
for (var _key in arrOrObj) { | ||
if (arrOrObj.hasOwnProperty(_key)) { | ||
handler(_key, arrOrObj[_key]); | ||
} | ||
for (var _key in arrOrObj) { | ||
if (arrOrObj.hasOwnProperty(_key)) { | ||
handler(_key, arrOrObj[_key]); | ||
} | ||
} | ||
}; | ||
/** | ||
* This function returns all own keys for the given | ||
* object or array as array. | ||
* | ||
* For example: | ||
* | ||
* objectKeys({attr1: 'something', attr2: 123, attr3: {deepAttr: 42}}) | ||
* === ['attr1', 'attr2', 'attr3'] | ||
* | ||
* objectKeys(['something', 123, {attr: 42}]) === ['0', '1', '2'] | ||
* | ||
* @param {Array<any>|Object} arrOrObj <- Array or Object to iterate. | ||
* (Flow does not want to iterate | ||
* over arrays with for-in, so we | ||
* have to write here any. | ||
* @return {Array} <- containing all keys for the input object. | ||
*/ | ||
exports.forEach = forEach; | ||
var objectKeys = function objectKeys(arrOrObj) { | ||
var keys = []; | ||
forEach(arrOrObj, function (key) { | ||
return keys.push(key); | ||
}); | ||
return keys; | ||
var keys = []; | ||
forEach(arrOrObj, function (key) { | ||
return keys.push(key); | ||
}); | ||
return keys; | ||
}; | ||
exports.objectKeys = objectKeys; | ||
var mergeArrays = function mergeArrays(arr1, arr2) { | ||
var result = [].concat(_toConsumableArray(arr1)); | ||
forEach(arr2, function (key, val) { | ||
if (arr1.indexOf(val) === -1) { | ||
result.push(val); | ||
} | ||
}); | ||
return result; | ||
var result = _toConsumableArray(arr1); | ||
forEach(arr2, function (key, val) { | ||
if (arr1.indexOf(val) === -1) { | ||
result.push(val); | ||
} | ||
}); | ||
return result; | ||
}; | ||
/** | ||
* This symbol serves as replacement to ignore any | ||
* inequality and skip further comparisons. | ||
*/ | ||
var IGNORE = Symbol.for('__Spy_IGNORE__'); | ||
exports.IGNORE = IGNORE; | ||
/** | ||
* Uniquely identifiable container for spy relevant comparators. | ||
*/ | ||
var SpyComparator = function () { | ||
function SpyComparator(comparator) { | ||
_classCallCheck(this, SpyComparator); | ||
function SpyComparator(comparator) { | ||
_classCallCheck(this, SpyComparator); | ||
this._func = comparator; | ||
_defineProperty(this, "_func", void 0); | ||
this._func = comparator; | ||
} | ||
_createClass(SpyComparator, [{ | ||
key: "compare", | ||
value: function compare(arg) { | ||
if (!this._func(arg)) return 'custom comparison failed'; | ||
} | ||
}]); | ||
_createClass(SpyComparator, [{ | ||
key: 'compare', | ||
value: function compare(arg) { | ||
if (!this._func(arg)) return 'custom comparison failed'; | ||
} | ||
}]); | ||
return SpyComparator; | ||
return SpyComparator; | ||
}(); | ||
/** | ||
* This function may create individual comparators | ||
* to define argument based comparison for arbitrary | ||
* nested objects. | ||
*/ | ||
var COMPARE = function COMPARE(comparator) { | ||
return new SpyComparator(comparator); | ||
return new SpyComparator(comparator); | ||
}; | ||
/** | ||
* This function is the internal representation of | ||
* "differenceOf". It does recursively call itself. | ||
* Read more below. | ||
* | ||
* @param {any} a <- any param. | ||
* @param {any} b <- any param to compare with the first param. | ||
* @param {boolean} initial <- is responsible for result | ||
* string building for deep equal checks. | ||
* @param {boolean} useOwnEquals <- enables/disables the usage | ||
* of own "equals" implementations. | ||
* @param {Array<any>} alreadyComparedArray | ||
* <- All flatly compared objects | ||
* will be temporarily stored | ||
* in this array to resolve | ||
* circular structures. | ||
* | ||
* @return {string|void} <- information about the difference | ||
* of the provided arguments. | ||
*/ | ||
exports.COMPARE = COMPARE; | ||
var __diff = function __diff(a, b, initial, useOwnEquals) { | ||
var alreadyComparedArray = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : []; | ||
var alreadyComparedArray = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : []; | ||
if (a === IGNORE || b === IGNORE) return; | ||
if (a instanceof SpyComparator) return a.compare(b); | ||
if (b instanceof SpyComparator) return b.compare(a); | ||
if (a === b) return; | ||
if (a === undefined || b === undefined) return 'one was undefined'; | ||
if (a === null || b === null) return 'one was null'; | ||
var aClass = Object.prototype.toString.call(a); | ||
var bClass = Object.prototype.toString.call(b); | ||
if (aClass !== bClass) return "different object types: ".concat(aClass, " <-> ").concat(bClass); | ||
if (a === IGNORE || b === IGNORE) return; | ||
if (a instanceof SpyComparator) return a.compare(b); | ||
if (b instanceof SpyComparator) return b.compare(a); | ||
if (a === b) return; | ||
if (a === undefined || b === undefined) return 'one was undefined'; | ||
if (a === null || b === null) return 'one was null'; | ||
var aClass = Object.prototype.toString.call(a); | ||
var bClass = Object.prototype.toString.call(b); | ||
if (aClass !== bClass) return 'different object types: ' + aClass + ' <-> ' + bClass; | ||
switch (aClass) { | ||
case '[object RegExp]': | ||
if (String(a) === String(b)) { | ||
return; | ||
} | ||
return 'different regexp'; | ||
case '[object String]': | ||
return 'different string'; | ||
case '[object Function]': | ||
return 'different function'; | ||
case '[object Number]': | ||
if (isNaN(a) && isNaN(b)) { | ||
return; | ||
} | ||
return 'different number'; | ||
case '[object Date]': | ||
if (Number(a) === Number(b)) { | ||
return; | ||
} | ||
return 'different date'; | ||
case '[object Boolean]': | ||
return 'different bool'; | ||
case '[object Symbol]': | ||
return 'different symbols'; | ||
case '[object Error]': | ||
if (String(a) === String(b)) { | ||
return; | ||
} | ||
return 'different error'; | ||
default: | ||
if (a.constructor !== b.constructor) { | ||
return 'different constructor'; | ||
} | ||
} | ||
if (useOwnEquals && a.equals instanceof Function) { | ||
if (a.equals(b)) { | ||
return; | ||
} | ||
return 'own equals method failed <- ' + 'Maybe you want to disable the usage ' + 'of own equals implementation? ' + '[ Use: spy.configure({useOwnEquals: false}) ]'; | ||
} | ||
if (alreadyComparedArray.indexOf(a) !== -1) { | ||
switch (aClass) { | ||
case '[object RegExp]': | ||
if (String(a) === String(b)) { | ||
return; | ||
} | ||
return 'different regexp'; | ||
case '[object String]': | ||
return 'different string'; | ||
case '[object Function]': | ||
return 'different function'; | ||
case '[object Number]': | ||
if (isNaN(a) && isNaN(b)) { | ||
return; | ||
} | ||
return 'different number'; | ||
case '[object Date]': | ||
if (Number(a) === Number(b)) { | ||
return; | ||
} | ||
return 'different date'; | ||
case '[object Boolean]': | ||
return 'different bool'; | ||
case '[object Symbol]': | ||
return 'different symbols'; | ||
case '[object Error]': | ||
if (String(a) === String(b)) { | ||
return; | ||
} | ||
return 'different error'; | ||
default: | ||
if (a.constructor !== b.constructor) { | ||
return 'different constructor'; | ||
} | ||
} | ||
if (useOwnEquals && a.equals instanceof Function) { | ||
if (a.equals(b)) { | ||
return; | ||
} | ||
var compared = [].concat(_toConsumableArray(alreadyComparedArray), [a]); | ||
var keys = mergeArrays(objectKeys(a), objectKeys(b)); | ||
for (var i = 0; i < keys.length; i++) { | ||
var _key2 = keys[i]; | ||
var diffStr = __diff(a[_key2], b[_key2], false, useOwnEquals, compared); | ||
if (diffStr !== undefined) { | ||
return (initial ? '--> ' + _key2 : '' + _key2) + ' / ' + diffStr; | ||
} | ||
return 'own equals method failed <- ' + 'Maybe you want to disable the usage ' + 'of own equals implementation? ' + '[ Use: spy.configure({useOwnEquals: false}) ]'; | ||
} | ||
if (alreadyComparedArray.indexOf(a) !== -1) { | ||
return; | ||
} | ||
var compared = _toConsumableArray(alreadyComparedArray).concat([a]); | ||
var keys = mergeArrays(objectKeys(a), objectKeys(b)); | ||
for (var i = 0; i < keys.length; i++) { | ||
var _key2 = keys[i]; | ||
var diffStr = __diff(a[_key2], b[_key2], false, useOwnEquals, compared); | ||
if (diffStr !== undefined) { | ||
return "".concat(initial ? "--> ".concat(_key2) : "".concat(_key2), " / ").concat(diffStr); | ||
} | ||
} | ||
}; | ||
/** | ||
* This function does make a comparison of two provided params. | ||
* | ||
* If found any difference it will return a string containing | ||
* information about the first detected difference. | ||
* | ||
* If the given params were proven "identical" this function | ||
* returns undefined. | ||
* | ||
* In first place the params are flatly checked. The checks are | ||
* in the following order: | ||
* | ||
* - identical objects | ||
* - one param is null or undefined | ||
* - object type | ||
* - regexp/string/number/date/boolean | ||
* - constructor | ||
* - keys length | ||
* - own "equals" implementation | ||
* | ||
* In second place all keys of the params are deeply checked. | ||
* Using the above flat checks for all attributes. | ||
* | ||
* Also all circular structures will be resolved and repeating | ||
* attributes will be assumed to be equal. | ||
* | ||
* @param {any} a <- any param. | ||
* @param {any} b <- any param to compare with the first param. | ||
* @param {{useOwnEquals:boolean}} config <- controls the usage of own | ||
* "equals" implementations. | ||
* | ||
* @return {string|void} <- information about the difference | ||
* of the provided arguments. | ||
*/ | ||
var differenceOf = function differenceOf(a, b) { | ||
var config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { useOwnEquals: true }; | ||
return __diff(a, b, true, config.useOwnEquals); | ||
var config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { | ||
useOwnEquals: true | ||
}; | ||
return __diff(a, b, true, config.useOwnEquals); | ||
}; | ||
exports.differenceOf = differenceOf; | ||
var toError = function toError(msgOrError, spyName) { | ||
return msgOrError instanceof Error ? msgOrError : new Error(msgOrError || spyName + ' was requested to throw'); | ||
return msgOrError instanceof Error ? msgOrError : new Error(msgOrError || "".concat(spyName, " was requested to throw")); | ||
}; | ||
exports.differenceOf = differenceOf; | ||
exports.forEach = forEach; | ||
exports.objectKeys = objectKeys; | ||
exports.IGNORE = IGNORE; | ||
exports.COMPARE = COMPARE; | ||
exports.toError = toError; |
{ | ||
"name": "spy4js", | ||
"version": "1.9.1", | ||
"version": "2.0.0", | ||
"description": "Smart, compact and powerful spy test framework", | ||
@@ -52,32 +52,34 @@ "jest": { | ||
"devDependencies": { | ||
"babel-cli": "^6.26.0", | ||
"babel-core": "^6.26.3", | ||
"babel-eslint": "^9.0.0", | ||
"@babel/cli": "^7.1.5", | ||
"@babel/core": "^7.1.5", | ||
"@babel/plugin-proposal-class-properties": "^7.1.0", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0", | ||
"@babel/plugin-transform-runtime": "^7.1.0", | ||
"@babel/preset-env": "^7.1.5", | ||
"@babel/preset-flow": "^7.0.0", | ||
"@babel/runtime": "^7.1.5", | ||
"babel-core": "7.0.0-bridge.0", | ||
"babel-eslint": "^10.0.1", | ||
"babel-jest": "^23.6.0", | ||
"babel-plugin-transform-class-properties": "^6.24.1", | ||
"babel-plugin-transform-object-rest-spread": "^6.26.0", | ||
"babel-plugin-transform-runtime": "^6.23.0", | ||
"babel-preset-env": "^1.7.0", | ||
"babel-preset-flow": "^6.23.0", | ||
"coveralls": "^3.0.2", | ||
"eslint": "^5.5.0", | ||
"eslint-config-prettier": "^3.0.1", | ||
"eslint-plugin-flowtype": "^2.50.0", | ||
"eslint": "^5.9.0", | ||
"eslint-config-prettier": "^3.2.0", | ||
"eslint-plugin-flowtype": "^3.2.0", | ||
"eslint-plugin-import": "^2.14.0", | ||
"eslint-plugin-prettier": "^2.6.2", | ||
"flow-bin": "^0.85.0", | ||
"eslint-plugin-prettier": "^3.0.0", | ||
"flow-bin": "^0.86.0", | ||
"jest": "^23.6.0", | ||
"prettier": "^1.14.2" | ||
"prettier": "^1.15.2" | ||
}, | ||
"babel": { | ||
"comments": false, | ||
"presets": [ | ||
"env", | ||
"flow" | ||
"@babel/preset-env", | ||
"@babel/preset-flow" | ||
], | ||
"plugins": [ | ||
"transform-class-properties", | ||
"@babel/plugin-proposal-class-properties", | ||
[ | ||
"transform-runtime", | ||
"@babel/plugin-transform-runtime", | ||
{ | ||
"polyfill": false, | ||
"helpers": false, | ||
@@ -88,3 +90,3 @@ "regenerator": true | ||
[ | ||
"transform-object-rest-spread", | ||
"@babel/plugin-proposal-object-rest-spread", | ||
{ | ||
@@ -91,0 +93,0 @@ "useBuiltIns": true |
@@ -27,2 +27,7 @@ [![GitHub license][license-image]][license-url] | ||
**Hint**: | ||
My favorite test framework is [Jest](https://jestjs.io/). If you are using other | ||
frameworks you might get issues related to automatically applied test suite hooks. | ||
To overcome this default behaviour see [here](#configure-static). | ||
### Installation | ||
@@ -54,7 +59,7 @@ ##### With yarn | ||
const spy3 = Spy.on(someObject1, 'toJSON'); | ||
// (spy name will be accordingly: 'the spy on \'toJSON\'') | ||
// (spy name will be accordingly: "the spy on 'toJSON'") | ||
// initialize many by mocking another objects attributes | ||
const someObject2 = new Date(2017, 1, 15); | ||
const [spy4, spy5, spy6] = Spy.onMany(someObject2, 'toJSON', 'toString', 'getDate'); | ||
const someObject2$Mock = Spy.mock(someObject2, 'toJSON', 'toString', 'getDate'); | ||
``` | ||
@@ -162,3 +167,3 @@ | ||
This is extremely useful to clean up all still existing mocks and also | ||
a very comfortable to this automatically after every test (like in an "afterEach"). | ||
a very comfortable to this automatically after every test (this is done by default). | ||
@@ -171,23 +176,2 @@ - `restoreAll` (does restore every existing spy) | ||
**Hint**: | ||
To integrate as default that all spies get restored after each test run, | ||
you can integrate the following snippet to replace the default describe. | ||
For those of you working with | ||
[create-react-app](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#srcsetuptestsjs) | ||
may include the snippet in the `src/setupTests.js`. | ||
```js | ||
import { Spy } from 'spy4js'; | ||
const oldDescribe = describe; | ||
window.describe = (string, func) => { | ||
oldDescribe(string, () => { | ||
afterEach(() => { | ||
Spy.restoreAll(); | ||
}); | ||
return func(); | ||
}); | ||
}; | ||
``` | ||
And also sometimes it is necessary to have access to some of the call arguments with | ||
@@ -239,7 +223,13 @@ which the spy was called. | ||
``` | ||
Spy.configure(config:{useOwnEquals?:boolean}) => void | ||
Spy.configure(config: { | ||
useOwnEquals?:boolean, | ||
beforeEach?: void => void, | ||
afterEach?: void => void, | ||
}) => void | ||
``` | ||
Using this function you may edit the default behaviour of every spy instance. The only | ||
configuration possibility for now is "useOwnEquals". See [configure](#configure) for more | ||
details. | ||
Using this function you may edit the default behaviour spy4js itself. | ||
The configuration possibility are: | ||
- **useOwnEquals**: Applies for all spy instances. See [configure](#configure) for more details. | ||
- **beforeEach**: Let's you override the default beforeEach test suite hook. | ||
- **afterEach**: Let's you override the default afterEach test suite hook. | ||
@@ -257,15 +247,25 @@ ### on (static) | ||
### onMany (static) | ||
### mock (static) | ||
``` | ||
Spy.onMany(object:Object, ...methodNames:Array<string>) => Array<SpyInstance> | ||
Spy.mock(object:Object, ...methodNames:Array<string>) => Object (Mock) | ||
``` | ||
Initializing as many spies as required for one and the same object. Same as calling | ||
`Spy.on` for each method name. | ||
Creating an object that references spies for all given methodNames. | ||
Initialize as many spies as required for one and the same object. Only | ||
after `Spy.initMocks` gets called, the created mock does affect the given object. | ||
### initMocks (static) | ||
``` | ||
Spy.initMocks() => void | ||
``` | ||
Does initialize all mocks by applying spies. Mocks can be created with | ||
[mock](#mock). This function has not be called manually, if you rely on | ||
the default test suite hooks. | ||
### restoreAll (static) | ||
``` | ||
Spy.restoreAll() => Array<SpyInstance> | ||
Spy.restoreAll() => void | ||
``` | ||
Does restore all mocked objects to their original state. See [restore](#restore) for | ||
further information. | ||
further information. This function has not be called manually, if you rely on | ||
the default test suite hooks. | ||
@@ -272,0 +272,0 @@ ### IGNORE (static) |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
15
87219
20
583
1