diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 6b06fd18..e0778d74 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -4809,6 +4809,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) { function SpyRegistry(options) { options = options || {}; + var global = options.global || j$.getGlobal(); var currentSpies = options.currentSpies || function() { return []; }; this.allowRespy = function(allow){ @@ -4852,7 +4853,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) { spiedMethod = j$.createSpy(methodName, originalMethod), restoreStrategy; - if (Object.prototype.hasOwnProperty.call(obj, methodName)) { + if (Object.prototype.hasOwnProperty.call(obj, methodName) || (obj === global && methodName === 'onerror')) { restoreStrategy = function() { obj[methodName] = originalMethod; }; diff --git a/spec/core/SpyRegistrySpec.js b/spec/core/SpyRegistrySpec.js index 4f09c932..1d01a3c4 100644 --- a/spec/core/SpyRegistrySpec.js +++ b/spec/core/SpyRegistrySpec.js @@ -287,6 +287,24 @@ describe("SpyRegistry", function() { expect(jasmineUnderTest.isSpy(subject.spiedFunc)).toBe(false); }); + + it("restores window.onerror by overwriting, not deleting", function() { + function FakeWindow() { + } + FakeWindow.prototype.onerror = function() {}; + + var spies = [], + global = new FakeWindow(), + spyRegistry = new jasmineUnderTest.SpyRegistry({ + currentSpies: function() { return spies; }, + global: global + }); + + spyRegistry.spyOn(global, 'onerror'); + spyRegistry.clearSpies(); + expect(global.onerror).toBe(FakeWindow.prototype.onerror); + expect(global.hasOwnProperty('onerror')).toBe(true); + }); }); describe('spying on properties', function() { diff --git a/spec/html/SpyRegistryHtmlSpec.js b/spec/html/SpyRegistryHtmlSpec.js new file mode 100644 index 00000000..fd9a81fb --- /dev/null +++ b/spec/html/SpyRegistryHtmlSpec.js @@ -0,0 +1,34 @@ +describe('Spy Registry browser-specific behavior', function() { + it('can spy on and unspy window.onerror', function() { + requireWriteableOnerror(); + + var spies = [], + spyRegistry = new jasmineUnderTest.SpyRegistry({ + currentSpies: function() { return spies; }, + global: window + }), + originalHandler = window.onerror; + + try { + spyRegistry.spyOn(window, 'onerror'); + spyRegistry.clearSpies(); + expect(window.onerror).toBe(originalHandler); + } finally { + window.onerror = originalHandler; + } + }); + + function requireWriteableOnerror() { + var descriptor; + + try { + descriptor = Object.getOwnPropertyDescriptor(window, 'onerror'); + } catch(e) { + // IE 8 doesn't support `definePropery` on non-DOM nodes + } + + if (descriptor && !(descriptor.writable || descriptor.set)) { + pending('Browser declares window.onerror to be readonly'); + } + } +}); diff --git a/src/core/SpyRegistry.js b/src/core/SpyRegistry.js index d8d4cf7f..74a1db6d 100644 --- a/src/core/SpyRegistry.js +++ b/src/core/SpyRegistry.js @@ -4,6 +4,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) { function SpyRegistry(options) { options = options || {}; + var global = options.global || j$.getGlobal(); var currentSpies = options.currentSpies || function() { return []; }; this.allowRespy = function(allow){ @@ -47,7 +48,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) { spiedMethod = j$.createSpy(methodName, originalMethod), restoreStrategy; - if (Object.prototype.hasOwnProperty.call(obj, methodName)) { + if (Object.prototype.hasOwnProperty.call(obj, methodName) || (obj === global && methodName === 'onerror')) { restoreStrategy = function() { obj[methodName] = originalMethod; };