From d6f1f8dec5165a6e1a9b98e8cc3cb44937758c5c Mon Sep 17 00:00:00 2001 From: Ben Christel Date: Mon, 1 Feb 2016 17:45:47 -0800 Subject: [PATCH] Correctly teardown spies on inherited methods - If the spied method is not an own property of the object being spied upon, the method is deleted from the object on teardown instead of being set to the original implementation. - #737 --- spec/core/SpyRegistrySpec.js | 17 +++++++++++++++++ src/core/SpyRegistry.js | 25 +++++++++++++++++-------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/spec/core/SpyRegistrySpec.js b/spec/core/SpyRegistrySpec.js index 0511e2a8..4ce31ddd 100644 --- a/spec/core/SpyRegistrySpec.js +++ b/spec/core/SpyRegistrySpec.js @@ -89,5 +89,22 @@ describe("SpyRegistry", function() { expect(subject.spiedFunc).toBe(originalFunction); }); + + it("does not add a property that the spied-upon object didn't originally have", function() { + var spies = [], + spyRegistry = new jasmineUnderTest.SpyRegistry({currentSpies: function() { return spies; }}), + originalFunction = function() {}, + subjectParent = {spiedFunc: originalFunction}; + + var subject = Object.create(subjectParent); + + expect(subject.hasOwnProperty('spiedFunc')).toBe(false); + + spyRegistry.spyOn(subject, 'spiedFunc'); + spyRegistry.clearSpies(); + + expect(subject.hasOwnProperty('spiedFunc')).toBe(false); + expect(subject.spiedFunc).toBe(originalFunction); + }) }); }); diff --git a/src/core/SpyRegistry.js b/src/core/SpyRegistry.js index 25c9b343..7215ca67 100644 --- a/src/core/SpyRegistry.js +++ b/src/core/SpyRegistry.js @@ -33,25 +33,34 @@ getJasmineRequireObj().SpyRegistry = function(j$) { throw new Error(methodName + ' is not declared writable or has no setter'); } - var spy = j$.createSpy(methodName, obj[methodName]); + var originalMethod = obj[methodName], + spiedMethod = j$.createSpy(methodName, originalMethod), + restoreStrategy; + + if (Object.prototype.hasOwnProperty.call(obj, methodName)) { + restoreStrategy = function() { + obj[methodName] = originalMethod; + }; + } else { + restoreStrategy = function() { + delete obj[methodName]; + }; + } currentSpies().push({ - spy: spy, - baseObj: obj, - methodName: methodName, - originalValue: obj[methodName] + restoreObjectToOriginalState: restoreStrategy }); - obj[methodName] = spy; + obj[methodName] = spiedMethod; - return spy; + return spiedMethod; }; this.clearSpies = function() { var spies = currentSpies(); for (var i = 0; i < spies.length; i++) { var spyEntry = spies[i]; - spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue; + spyEntry.restoreObjectToOriginalState(); } }; }