diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 740ab3f9..417c90d3 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -773,6 +773,10 @@ getJasmineRequireObj().Env = function(j$) { return runnableResources[currentRunnable().id].spies; }}); + this.allowRespy = function(allow){ + spyRegistry.allowRespy(allow); + }; + this.spyOn = function() { return spyRegistry.spyOn.apply(spyRegistry, arguments); }; @@ -2006,6 +2010,10 @@ getJasmineRequireObj().SpyRegistry = function(j$) { options = options || {}; var currentSpies = options.currentSpies || function() { return []; }; + this.allowRespy = function(allow){ + this.respy = allow; + }; + this.spyOn = function(obj, methodName) { if (j$.util.isUndefined(obj)) { throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()'); @@ -2019,9 +2027,12 @@ getJasmineRequireObj().SpyRegistry = function(j$) { throw new Error(methodName + '() method does not exist'); } - if (obj[methodName] && j$.isSpy(obj[methodName])) { - //TODO?: should this return the current spy? Downside: may cause user confusion about spy state - throw new Error(methodName + ' has already been spied upon'); + if (obj[methodName] && j$.isSpy(obj[methodName]) ) { + if ( !!this.respy ){ + return obj[methodName]; + }else { + throw new Error(methodName + ' has already been spied upon'); + } } var descriptor; diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 4ea60413..cb4e3779 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -677,6 +677,31 @@ describe("Env integration", function() { env.execute(); }); + it('can be configured to allow respying on functions', function () { + var env = new jasmineUnderTest.Env(), + foo = { + bar: function () { + return 1; + } + }; + + env.allowRespy(true); + + env.describe('test suite', function(){ + env.it('spec 0', function(){ + env.spyOn(foo,'bar'); + + var error = null; + + expect(function() { + env.spyOn(foo, 'bar'); + }).not.toThrow(); + }); + }); + + env.execute(); + }); + it('removes all spies added in a spec after the spec is complete', function(done) { var env = new jasmineUnderTest.Env(), originalFoo = function() {}, diff --git a/src/core/Env.js b/src/core/Env.js index 95c93d63..0cdea404 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -269,6 +269,10 @@ getJasmineRequireObj().Env = function(j$) { return runnableResources[currentRunnable().id].spies; }}); + this.allowRespy = function(allow){ + spyRegistry.allowRespy(allow); + }; + this.spyOn = function() { return spyRegistry.spyOn.apply(spyRegistry, arguments); }; diff --git a/src/core/SpyRegistry.js b/src/core/SpyRegistry.js index 9e168c88..aa7ee21a 100644 --- a/src/core/SpyRegistry.js +++ b/src/core/SpyRegistry.js @@ -4,6 +4,10 @@ getJasmineRequireObj().SpyRegistry = function(j$) { options = options || {}; var currentSpies = options.currentSpies || function() { return []; }; + this.allowRespy = function(allow){ + this.respy = allow; + }; + this.spyOn = function(obj, methodName) { if (j$.util.isUndefined(obj)) { throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()'); @@ -17,9 +21,12 @@ getJasmineRequireObj().SpyRegistry = function(j$) { throw new Error(methodName + '() method does not exist'); } - if (obj[methodName] && j$.isSpy(obj[methodName])) { - //TODO?: should this return the current spy? Downside: may cause user confusion about spy state - throw new Error(methodName + ' has already been spied upon'); + if (obj[methodName] && j$.isSpy(obj[methodName]) ) { + if ( !!this.respy ){ + return obj[methodName]; + }else { + throw new Error(methodName + ' has already been spied upon'); + } } var descriptor;