Merge branch 'custom-spy-strategy' into 3.0-features
This commit is contained in:
@@ -108,6 +108,13 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
return true;
|
||||
};
|
||||
|
||||
this.addSpyStrategy = function(name, fn) {
|
||||
if(!currentRunnable()) {
|
||||
throw new Error('Custom spy strategies must be added in a before function or a spec');
|
||||
}
|
||||
runnableResources[currentRunnable().id].customSpyStrategies[name] = fn;
|
||||
};
|
||||
|
||||
this.addCustomEqualityTester = function(tester) {
|
||||
if(!currentRunnable()) {
|
||||
throw new Error('Custom Equalities must be added in a before function or a spec');
|
||||
@@ -152,7 +159,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
var defaultResourcesForRunnable = function(id, parentRunnableId) {
|
||||
var resources = {spies: [], customEqualityTesters: [], customMatchers: {}};
|
||||
var resources = {spies: [], customEqualityTesters: [], customMatchers: {}, customSpyStrategies: {}};
|
||||
|
||||
if(runnableResources[parentRunnableId]){
|
||||
resources.customEqualityTesters = j$.util.clone(runnableResources[parentRunnableId].customEqualityTesters);
|
||||
@@ -393,12 +400,27 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
reporter.clearReporters();
|
||||
};
|
||||
|
||||
var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
|
||||
if(!currentRunnable()) {
|
||||
throw new Error('Spies must be created in a before function or a spec');
|
||||
var spyFactory = new j$.SpyFactory(function() {
|
||||
var runnable = currentRunnable();
|
||||
|
||||
if (runnable) {
|
||||
return runnableResources[runnable.id].customSpyStrategies;
|
||||
}
|
||||
return runnableResources[currentRunnable().id].spies;
|
||||
}});
|
||||
|
||||
return {};
|
||||
});
|
||||
|
||||
var spyRegistry = new j$.SpyRegistry({
|
||||
currentSpies: function() {
|
||||
if(!currentRunnable()) {
|
||||
throw new Error('Spies must be created in a before function or a spec');
|
||||
}
|
||||
return runnableResources[currentRunnable().id].spies;
|
||||
},
|
||||
createSpy: function(name, originalFn) {
|
||||
return self.createSpy(name, originalFn);
|
||||
}
|
||||
});
|
||||
|
||||
this.allowRespy = function(allow){
|
||||
spyRegistry.allowRespy(allow);
|
||||
@@ -412,6 +434,14 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
return spyRegistry.spyOnProperty.apply(spyRegistry, arguments);
|
||||
};
|
||||
|
||||
this.createSpy = function(name, originalFn) {
|
||||
return spyFactory.createSpy(name, originalFn);
|
||||
};
|
||||
|
||||
this.createSpyObj = function(baseName, methodNames) {
|
||||
return spyFactory.createSpyObj(baseName, methodNames);
|
||||
};
|
||||
|
||||
var ensureIsFunction = function(fn, caller) {
|
||||
if (!j$.isFunction_(fn)) {
|
||||
throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn));
|
||||
|
||||
@@ -13,7 +13,7 @@ getJasmineRequireObj().Spy = function (j$) {
|
||||
* @constructor
|
||||
* @name Spy
|
||||
*/
|
||||
function Spy(name, originalFn) {
|
||||
function Spy(name, originalFn, customStrategies) {
|
||||
var numArgs = (typeof originalFn === 'function' ? originalFn.length : 0),
|
||||
wrapper = makeFunc(numArgs, function () {
|
||||
return spy.apply(this, Array.prototype.slice.call(arguments));
|
||||
@@ -23,7 +23,8 @@ getJasmineRequireObj().Spy = function (j$) {
|
||||
fn: originalFn,
|
||||
getSpy: function () {
|
||||
return wrapper;
|
||||
}
|
||||
},
|
||||
customStrategies: customStrategies
|
||||
}),
|
||||
callTracker = new j$.CallTracker(),
|
||||
spy = function () {
|
||||
|
||||
45
src/core/SpyFactory.js
Normal file
45
src/core/SpyFactory.js
Normal file
@@ -0,0 +1,45 @@
|
||||
getJasmineRequireObj().SpyFactory = function(j$) {
|
||||
|
||||
function SpyFactory(getCustomStrategies) {
|
||||
var self = this;
|
||||
|
||||
this.createSpy = function(name, originalFn) {
|
||||
return j$.Spy(name, originalFn, getCustomStrategies());
|
||||
};
|
||||
|
||||
this.createSpyObj = function(baseName, methodNames) {
|
||||
var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName);
|
||||
|
||||
if (baseNameIsCollection && j$.util.isUndefined(methodNames)) {
|
||||
methodNames = baseName;
|
||||
baseName = 'unknown';
|
||||
}
|
||||
|
||||
var obj = {};
|
||||
var spiesWereSet = false;
|
||||
|
||||
if (j$.isArray_(methodNames)) {
|
||||
for (var i = 0; i < methodNames.length; i++) {
|
||||
obj[methodNames[i]] = self.createSpy(baseName + '.' + methodNames[i]);
|
||||
spiesWereSet = true;
|
||||
}
|
||||
} else if (j$.isObject_(methodNames)) {
|
||||
for (var key in methodNames) {
|
||||
if (methodNames.hasOwnProperty(key)) {
|
||||
obj[key] = self.createSpy(baseName + '.' + key);
|
||||
obj[key].and.returnValue(methodNames[key]);
|
||||
spiesWereSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!spiesWereSet) {
|
||||
throw 'createSpyObj requires a non-empty array or object of method names to create spies for';
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
return SpyFactory;
|
||||
};
|
||||
@@ -5,6 +5,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
|
||||
function SpyRegistry(options) {
|
||||
options = options || {};
|
||||
var global = options.global || j$.getGlobal();
|
||||
var createSpy = options.createSpy;
|
||||
var currentSpies = options.currentSpies || function() { return []; };
|
||||
|
||||
this.allowRespy = function(allow){
|
||||
@@ -40,7 +41,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
|
||||
}
|
||||
|
||||
var originalMethod = obj[methodName],
|
||||
spiedMethod = j$.createSpy(methodName, originalMethod),
|
||||
spiedMethod = createSpy(methodName, originalMethod),
|
||||
restoreStrategy;
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(obj, methodName) || (obj === global && methodName === 'onerror')) {
|
||||
@@ -95,7 +96,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
|
||||
}
|
||||
|
||||
var originalDescriptor = j$.util.clone(descriptor),
|
||||
spy = j$.createSpy(propertyName, descriptor[accessType]),
|
||||
spy = createSpy(propertyName, descriptor[accessType]),
|
||||
restoreStrategy;
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(obj, propertyName)) {
|
||||
|
||||
@@ -16,6 +16,26 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
|
||||
this.originalFn = options.fn || function() {};
|
||||
this.getSpy = options.getSpy || function() {};
|
||||
this.plan = this._defaultPlan = function() {};
|
||||
|
||||
var k, cs = options.customStrategies || {};
|
||||
for (k in cs) {
|
||||
if (j$.util.has(cs, k) && !this[k]) {
|
||||
this[k] = createCustomPlan(cs[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createCustomPlan(factory) {
|
||||
return function() {
|
||||
var plan = factory.apply(null, arguments);
|
||||
|
||||
if (!j$.isFunction_(plan)) {
|
||||
throw new Error('Spy strategy must return a function');
|
||||
}
|
||||
|
||||
this.plan = plan;
|
||||
return this.getSpy();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -173,18 +173,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
return new j$.ArrayWithExactContents(sample);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
|
||||
* @name jasmine.createSpy
|
||||
* @function
|
||||
* @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
|
||||
* @param {Function} [originalFn] - Function to act as the real implementation.
|
||||
* @return {Spy}
|
||||
*/
|
||||
j$.createSpy = function(name, originalFn) {
|
||||
return j$.Spy(name, originalFn);
|
||||
};
|
||||
|
||||
j$.isSpy = function(putativeSpy) {
|
||||
if (!putativeSpy) {
|
||||
return false;
|
||||
@@ -192,45 +180,4 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
return putativeSpy.and instanceof j$.SpyStrategy &&
|
||||
putativeSpy.calls instanceof j$.CallTracker;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an object with multiple {@link Spy}s as its members.
|
||||
* @name jasmine.createSpyObj
|
||||
* @function
|
||||
* @param {String} [baseName] - Base name for the spies in the object.
|
||||
* @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}.
|
||||
* @return {Object}
|
||||
*/
|
||||
j$.createSpyObj = function(baseName, methodNames) {
|
||||
var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName);
|
||||
|
||||
if (baseNameIsCollection && j$.util.isUndefined(methodNames)) {
|
||||
methodNames = baseName;
|
||||
baseName = 'unknown';
|
||||
}
|
||||
|
||||
var obj = {};
|
||||
var spiesWereSet = false;
|
||||
|
||||
if (j$.isArray_(methodNames)) {
|
||||
for (var i = 0; i < methodNames.length; i++) {
|
||||
obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
|
||||
spiesWereSet = true;
|
||||
}
|
||||
} else if (j$.isObject_(methodNames)) {
|
||||
for (var key in methodNames) {
|
||||
if (methodNames.hasOwnProperty(key)) {
|
||||
obj[key] = j$.createSpy(baseName + '.' + key);
|
||||
obj[key].and.returnValue(methodNames[key]);
|
||||
spiesWereSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!spiesWereSet) {
|
||||
throw 'createSpyObj requires a non-empty array or object of method names to create spies for';
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -48,6 +48,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
|
||||
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
||||
j$.Spec = jRequire.Spec(j$);
|
||||
j$.Spy = jRequire.Spy(j$);
|
||||
j$.SpyFactory = jRequire.SpyFactory(j$);
|
||||
j$.SpyRegistry = jRequire.SpyRegistry(j$);
|
||||
j$.SpyStrategy = jRequire.SpyStrategy(j$);
|
||||
j$.StringMatching = jRequire.StringMatching(j$);
|
||||
|
||||
@@ -256,5 +256,42 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
return env.clock;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
|
||||
* @name jasmine.createSpy
|
||||
* @function
|
||||
* @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
|
||||
* @param {Function} [originalFn] - Function to act as the real implementation.
|
||||
* @return {Spy}
|
||||
*/
|
||||
jasmine.createSpy = function(name, originalFn) {
|
||||
return env.createSpy(name, originalFn);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an object with multiple {@link Spy}s as its members.
|
||||
* @name jasmine.createSpyObj
|
||||
* @function
|
||||
* @param {String} [baseName] - Base name for the spies in the object.
|
||||
* @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}.
|
||||
* @return {Object}
|
||||
*/
|
||||
jasmine.createSpyObj = function(baseName, methodNames) {
|
||||
return env.createSpyObj(baseName, methodNames);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a custom spy strategy for the current scope of specs.
|
||||
*
|
||||
* _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
|
||||
* @name jasmine.addSpyStrategy
|
||||
* @function
|
||||
* @param {String} name - The name of the strategy (i.e. what you call from `and`)
|
||||
* @param {Function} factory - Factory function that returns the plan to be executed.
|
||||
*/
|
||||
jasmine.addSpyStrategy = function(name, factory) {
|
||||
return env.addSpyStrategy(identifier, factory);
|
||||
};
|
||||
|
||||
return jasmineInterface;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user