From 45475f6d1ecc489025e9f1f756847a33bc5bc98d Mon Sep 17 00:00:00 2001 From: Elliot Nelson Date: Thu, 20 Jun 2019 07:33:10 -0400 Subject: [PATCH] Allow users to pass property names to createSpyObj --- spec/core/SpySpec.js | 39 +++++++++++++++++++++++++ src/core/Env.js | 4 +-- src/core/SpyFactory.js | 55 +++++++++++++++++++++++++----------- src/core/requireInterface.js | 5 ++-- 4 files changed, 83 insertions(+), 20 deletions(-) diff --git a/spec/core/SpySpec.js b/spec/core/SpySpec.js index f2eea200..2295d8a6 100644 --- a/spec/core/SpySpec.js +++ b/spec/core/SpySpec.js @@ -174,6 +174,45 @@ describe('Spies', function() { 'createSpyObj requires a non-empty array or object of method names to create spies for' ); }); + + it('creates an object with spy properties if a second list is passed', function() { + var spyObj = env.createSpyObj('base', ['method1'], ['prop1']); + + expect(spyObj).toEqual({ + method1: jasmine.any(Function) + }); + + var descriptor = Object.getOwnPropertyDescriptor(spyObj, 'prop1'); + expect(descriptor.get.and.identity).toEqual('base.prop1.get'); + expect(descriptor.set.and.identity).toEqual('base.prop1.set'); + + expect(spyObj.prop1).toBeUndefined(); + }); + + it('creates an object with property names and return values if second object is passed', function() { + var spyObj = env.createSpyObj('base', ['method1'], { + prop1: 'foo', + prop2: 37 + }); + + expect(spyObj).toEqual({ + method1: jasmine.any(Function) + }); + + expect(spyObj.prop1).toEqual('foo'); + expect(spyObj.prop2).toEqual(37); + spyObj.prop2 = 4; + expect(spyObj.prop2).toEqual(37); + expect(Object.getOwnPropertyDescriptor(spyObj, 'prop2').set.calls.count()).toBe(1); + }); + + it('allows base name to be ommitted when assigning methods and properties', function() { + var spyObj = env.createSpyObj({ m: 3 }, { p: 4 }); + + expect(spyObj.m()).toEqual(3); + expect(spyObj.p).toEqual(4); + expect(Object.getOwnPropertyDescriptor(spyObj, 'p').get.and.identity).toEqual('unknown.p.get'); + }); }); it('can use different strategies for different arguments', function() { diff --git a/src/core/Env.js b/src/core/Env.js index 18924dcd..0bed0229 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -764,8 +764,8 @@ getJasmineRequireObj().Env = function(j$) { return spyFactory.createSpy(name, originalFn); }; - this.createSpyObj = function(baseName, methodNames) { - return spyFactory.createSpyObj(baseName, methodNames); + this.createSpyObj = function(baseName, methodNames, propertyNames) { + return spyFactory.createSpyObj(baseName, methodNames, propertyNames); }; var ensureIsFunction = function(fn, caller) { diff --git a/src/core/SpyFactory.js b/src/core/SpyFactory.js index a622a8a3..d7446cb7 100644 --- a/src/core/SpyFactory.js +++ b/src/core/SpyFactory.js @@ -6,34 +6,41 @@ getJasmineRequireObj().SpyFactory = function(j$) { return j$.Spy(name, originalFn, getCustomStrategies(), getPromise); }; - this.createSpyObj = function(baseName, methodNames) { + this.createSpyObj = function(baseName, methodNames, propertyNames) { var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName); - if (baseNameIsCollection && j$.util.isUndefined(methodNames)) { + if (baseNameIsCollection) { + propertyNames = methodNames; methodNames = baseName; baseName = 'unknown'; } var obj = {}; - var spiesWereSet = false; + var spy, descriptor; - 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; - } + var methods = normalizeKeyValues(methodNames); + for (var i = 0; i < methods.length; i++) { + spy = obj[methods[i][0]] = self.createSpy(baseName + '.' + methods[i][0]); + if (methods[i].length > 1) { + spy.and.returnValue(methods[i][1]); } } - if (!spiesWereSet) { + var properties = normalizeKeyValues(propertyNames); + for (var i = 0; i < properties.length; i++) { + descriptor = { + get: self.createSpy(baseName + '.' + properties[i][0] + '.get'), + set: self.createSpy(baseName + '.' + properties[i][0] + '.set') + }; + if (properties[i].length > 1) { + descriptor.get.and.returnValue(properties[i][1]); + descriptor.set.and.returnValue(properties[i][1]); + } + Object.defineProperty(obj, properties[i][0], descriptor); + } + + if (methods.length === 0 && properties.length === 0) { throw 'createSpyObj requires a non-empty array or object of method names to create spies for'; } @@ -41,5 +48,21 @@ getJasmineRequireObj().SpyFactory = function(j$) { }; } + function normalizeKeyValues(object) { + var result = []; + if (j$.isArray_(object)) { + for (var i = 0; i < object.length; i++) { + result.push([object[i]]); + } + } else if (j$.isObject_(object)) { + for (var key in object) { + if (object.hasOwnProperty(key)) { + result.push([key, object[key]]); + } + } + } + return result; + } + return SpyFactory; }; diff --git a/src/core/requireInterface.js b/src/core/requireInterface.js index cff7403b..494c2823 100644 --- a/src/core/requireInterface.js +++ b/src/core/requireInterface.js @@ -311,10 +311,11 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @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}. + * @param {String[]|Object} [propertyNames] - Array of property names to create spies for, or Object whose keys will be propertynames and values the {@link Spy#and#returnValue|returnValue}. * @return {Object} */ - jasmine.createSpyObj = function(baseName, methodNames) { - return env.createSpyObj(baseName, methodNames); + jasmine.createSpyObj = function(baseName, methodNames, propertyNames) { + return env.createSpyObj(baseName, methodNames, propertyNames); }; /**