| // Copyright 2009 The Closure Library Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS-IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| goog.provide('goog.debug.ErrorReporterTest'); |
| goog.setTestOnly('goog.debug.ErrorReporterTest'); |
| |
| goog.require('goog.debug.ErrorReporter'); |
| goog.require('goog.events'); |
| goog.require('goog.functions'); |
| goog.require('goog.testing.PropertyReplacer'); |
| goog.require('goog.testing.jsunit'); |
| goog.require('goog.userAgent'); |
| |
| MockXhrIo = function() {}; |
| |
| MockXhrIo.prototype.onReadyStateChangeEntryPoint_ = function() {}; |
| |
| MockXhrIo.protectEntryPoints = function() {}; |
| |
| MockXhrIo.lastUrl = null; |
| |
| MockXhrIo.send = function(url, opt_callback, opt_method, opt_content, |
| opt_headers, opt_timeInterval) { |
| MockXhrIo.lastUrl = url; |
| MockXhrIo.lastContent = opt_content; |
| MockXhrIo.lastHeaders = opt_headers; |
| }; |
| |
| var errorReporter; |
| var originalSetTimeout = window.setTimeout; |
| var stubs = new goog.testing.PropertyReplacer(); |
| var url = 'http://www.your.tst/more/bogus.js'; |
| var encodedUrl = 'http%3A%2F%2Fwww.your.tst%2Fmore%2Fbogus.js'; |
| |
| function setUp() { |
| stubs.set(goog.net, 'XhrIo', MockXhrIo); |
| goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT = true; |
| } |
| |
| function tearDown() { |
| goog.dispose(errorReporter); |
| stubs.reset(); |
| MockXhrIo.lastUrl = null; |
| } |
| |
| function throwAnErrorWith(script, line, message, opt_stack) { |
| var error = { |
| message: message, |
| fileName: script, |
| lineNumber: line}; |
| if (opt_stack) { |
| error['stack'] = opt_stack; |
| } |
| |
| throw error; |
| } |
| |
| function testsendErrorReport() { |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| errorReporter.sendErrorReport( |
| 'message', 'filename.js', 123, 'trace'); |
| |
| assertEquals('/log?script=filename.js&error=message&line=123', |
| MockXhrIo.lastUrl); |
| assertEquals('trace=trace', MockXhrIo.lastContent); |
| } |
| |
| function testsendErrorReportWithCustomSender() { |
| var uri = null; |
| var method = null; |
| var content = null; |
| var headers = null; |
| function mockXhrSender(uriIn, methodIn, contentIn, headersIn) { |
| uri = uriIn; |
| method = methodIn; |
| content = contentIn; |
| headers = headersIn; |
| } |
| |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| errorReporter.setXhrSender(mockXhrSender); |
| errorReporter.sendErrorReport('message', 'filename.js', 123, 'trace'); |
| |
| assertEquals('/log?script=filename.js&error=message&line=123', uri); |
| assertEquals('POST', method); |
| assertEquals('trace=trace', content); |
| assertUndefined(headers); |
| } |
| |
| function testsendErrorReport_noTrace() { |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| errorReporter.sendErrorReport( |
| 'message', 'filename.js', 123); |
| |
| assertEquals('/log?script=filename.js&error=message&line=123', |
| MockXhrIo.lastUrl); |
| assertEquals('', MockXhrIo.lastContent); |
| } |
| |
| function test_nonInternetExplorerSendErrorReport() { |
| stubs.set(goog.userAgent, 'IE', false); |
| stubs.set(goog.global, 'setTimeout', |
| function(fcn, time) { |
| fcn.call(); |
| }); |
| |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter'); |
| |
| var errorFunction = goog.partial(throwAnErrorWith, url, 5, 'Hello :)'); |
| |
| try { |
| goog.global.setTimeout(errorFunction, 0); |
| } catch (e) { |
| // Expected. The error is rethrown after sending. |
| } |
| |
| assertEquals( |
| '/errorreporter?script=' + encodedUrl + '&error=Hello%20%3A)&line=5', |
| MockXhrIo.lastUrl); |
| assertEquals('trace=Not%20available', MockXhrIo.lastContent); |
| } |
| |
| function test_internetExplorerSendErrorReport() { |
| stubs.set(goog.userAgent, 'IE', true); |
| stubs.set(goog.userAgent, 'isVersionOrHigher', goog.functions.FALSE); |
| |
| // Remove test runner's onerror handler so the test doesn't fail. |
| stubs.set(goog.global, 'onerror', null); |
| |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter'); |
| goog.global.onerror('Goodbye :(', url, 22); |
| assertEquals( |
| '/errorreporter?script=' + encodedUrl + '&error=Goodbye%20%3A(&line=22', |
| MockXhrIo.lastUrl); |
| assertEquals('trace=Not%20available', MockXhrIo.lastContent); |
| } |
| |
| function test_setLoggingHeaders() { |
| stubs.set(goog.userAgent, 'IE', true); |
| stubs.set(goog.userAgent, 'isVersionOrHigher', goog.functions.FALSE); |
| // Remove test runner's onerror handler so the test doesn't fail. |
| stubs.set(goog.global, 'onerror', null); |
| |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter'); |
| errorReporter.setLoggingHeaders('header!'); |
| goog.global.onerror('Goodbye :(', 'http://www.your.tst/more/bogus.js', 22); |
| assertEquals('header!', MockXhrIo.lastHeaders); |
| } |
| |
| function test_nonInternetExplorerSendErrorReportWithTrace() { |
| stubs.set(goog.userAgent, 'IE', false); |
| stubs.set(goog.global, 'setTimeout', |
| function(fcn, time) { |
| fcn.call(); |
| }); |
| |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter'); |
| |
| var trace = |
| 'Error(\"Something Wrong\")@:0\n' + |
| '$MF$E$Nx$([object Object])@http://a.b.c:83/a/f.js:901\n' + |
| '([object Object])@http://a.b.c:813/a/f.js:37'; |
| |
| |
| var errorFunction = goog.partial(throwAnErrorWith, url, 5, 'Hello :)', |
| trace); |
| |
| try { |
| goog.global.setTimeout(errorFunction, 0); |
| } catch (e) { |
| // Expected. The error is rethrown after sending. |
| } |
| |
| assertEquals( |
| '/errorreporter?script=' + encodedUrl + '&error=Hello%20%3A)&line=5', |
| MockXhrIo.lastUrl); |
| assertEquals('trace=' + |
| 'Error(%22Something%20Wrong%22)%40%3A0%0A' + |
| '%24MF%24E%24Nx%24(%5Bobject%20Object%5D)%40' + |
| 'http%3A%2F%2Fa.b.c%3A83%2Fa%2Ff.js%3A901%0A' + |
| '(%5Bobject%20Object%5D)%40http%3A%2F%2Fa.b.c%3A813%2Fa%2Ff.js%3A37', |
| MockXhrIo.lastContent); |
| } |
| |
| function testProtectAdditionalEntryPoint_nonIE() { |
| stubs.set(goog.userAgent, 'IE', false); |
| |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter'); |
| var fn = function() {}; |
| var protectedFn = errorReporter.protectAdditionalEntryPoint(fn); |
| assertNotNull(protectedFn); |
| assertNotEquals(fn, protectedFn); |
| } |
| |
| function testProtectAdditionalEntryPoint_IE() { |
| stubs.set(goog.userAgent, 'IE', true); |
| stubs.set(goog.userAgent, 'isVersionOrHigher', goog.functions.FALSE); |
| |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter'); |
| var fn = function() {}; |
| var protectedFn = errorReporter.protectAdditionalEntryPoint(fn); |
| assertNull(protectedFn); |
| } |
| |
| function testHandleException_dispatchesEvent() { |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter'); |
| var loggedErrors = 0; |
| goog.events.listen(errorReporter, |
| goog.debug.ErrorReporter.ExceptionEvent.TYPE, |
| function(event) { |
| assertNotNullNorUndefined(event.error); |
| loggedErrors++; |
| }); |
| errorReporter.handleException(new Error()); |
| errorReporter.handleException(new Error()); |
| assertEquals('Expected 2 errors. ' + |
| '(Ensure an exception was not swallowed.)', 2, loggedErrors); |
| } |
| |
| function testHandleException_includesContext() { |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter'); |
| var loggedErrors = 0; |
| var testError = new Error('test error'); |
| var testContext = { 'contextParam' : 'contextValue' }; |
| goog.events.listen(errorReporter, |
| goog.debug.ErrorReporter.ExceptionEvent.TYPE, |
| function(event) { |
| assertNotNullNorUndefined(event.error); |
| assertObjectEquals({ contextParam: 'contextValue' }, event.context); |
| loggedErrors++; |
| }); |
| errorReporter.handleException(testError, testContext); |
| assertEquals('Expected 1 error. ' + |
| '(Ensure an exception was not swallowed.)', 1, loggedErrors); |
| } |
| |
| function testContextProvider() { |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter', |
| function(error, context) { |
| context.providedContext = 'value'; |
| }); |
| var loggedErrors = 0; |
| var testError = new Error('test error'); |
| goog.events.listen(errorReporter, |
| goog.debug.ErrorReporter.ExceptionEvent.TYPE, |
| function(event) { |
| assertNotNullNorUndefined(event.error); |
| assertObjectEquals({ providedContext: 'value' } , event.context); |
| loggedErrors++; |
| }); |
| errorReporter.handleException(testError); |
| assertEquals('Expected 1 error. ' + |
| '(Ensure an exception was not swallowed.)', 1, loggedErrors); |
| } |
| |
| function testContextProvider_withOtherContext() { |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter', |
| function(error, context) { |
| context.providedContext = 'value'; |
| }); |
| var loggedErrors = 0; |
| var testError = new Error('test error'); |
| goog.events.listen(errorReporter, |
| goog.debug.ErrorReporter.ExceptionEvent.TYPE, |
| function(event) { |
| assertNotNullNorUndefined(event.error); |
| assertObjectEquals( |
| { providedContext: 'value', otherContext: 'value' }, |
| event.context); |
| loggedErrors++; |
| }); |
| errorReporter.handleException(testError, { 'otherContext' : 'value' }); |
| assertEquals('Expected 1 error. ' + |
| '(Ensure an exception was not swallowed.)', 1, loggedErrors); |
| } |
| |
| function testHandleException_ignoresExceptionsDuringEventDispatch() { |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter'); |
| goog.events.listen(errorReporter, |
| goog.debug.ErrorReporter.ExceptionEvent.TYPE, |
| function(event) { |
| fail('This exception should be swallowed.'); |
| }); |
| errorReporter.handleException(new Error()); |
| } |
| |
| function testDisposal() { |
| errorReporter = goog.debug.ErrorReporter.install('/errorreporter'); |
| if (!goog.userAgent.IE) { |
| assertNotEquals(originalSetTimeout, window.setTimeout); |
| } |
| goog.dispose(errorReporter); |
| assertEquals(originalSetTimeout, window.setTimeout); |
| } |
| |
| function testSetContextPrefix() { |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| errorReporter.setContextPrefix('baz.'); |
| errorReporter.sendErrorReport( |
| 'message', 'filename.js', 123, 'trace', {'foo': 'bar'}); |
| assertEquals('trace=trace&baz.foo=bar', MockXhrIo.lastContent); |
| } |
| |
| function testTruncationLimit() { |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| errorReporter.setTruncationLimit(6); |
| errorReporter.sendErrorReport( |
| 'message', 'filename.js', 123, 'trace', {'foo': 'bar'}); |
| assertEquals('trace=', MockXhrIo.lastContent); |
| } |
| |
| function testZeroTruncationLimit() { |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| errorReporter.setTruncationLimit(0); |
| errorReporter.sendErrorReport( |
| 'message', 'filename.js', 123, 'trace', {'foo': 'bar'}); |
| assertEquals('', MockXhrIo.lastContent); |
| } |
| |
| function testTruncationLimitLargerThanBody() { |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| errorReporter.setTruncationLimit(9999); |
| errorReporter.sendErrorReport( |
| 'message', 'filename.js', 123, 'trace', {'foo': 'bar'}); |
| assertEquals('trace=trace&context.foo=bar', MockXhrIo.lastContent); |
| } |
| |
| function testSetNegativeTruncationLimit() { |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| assertThrows(function() { |
| errorReporter.setTruncationLimit(-10); |
| }); |
| } |
| |
| function testSetTruncationLimitNull() { |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| errorReporter.setTruncationLimit(null); |
| errorReporter.sendErrorReport( |
| 'message', 'filename.js', 123, 'trace', {'foo': 'bar'}); |
| assertEquals('trace=trace&context.foo=bar', MockXhrIo.lastContent); |
| } |
| |
| function testAttemptAutoProtectWithAllowAutoProtectOff() { |
| goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT = false; |
| assertThrows(function() { |
| errorReporter = new goog.debug.ErrorReporter( |
| '/log', function(e, context) {}, false); |
| }); |
| } |
| |
| function testSetAdditionalArgumentsArgsEmptyObject() { |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| errorReporter.setAdditionalArguments({}); |
| errorReporter.sendErrorReport( |
| 'message', 'filename.js', 123, 'trace', {'foo': 'bar'}); |
| assertEquals('/log?script=filename.js&error=message&line=123', |
| MockXhrIo.lastUrl); |
| } |
| |
| function testSetAdditionalArgumentsSingleArgument() { |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| errorReporter.setAdditionalArguments({'extra': 'arg'}); |
| errorReporter.sendErrorReport( |
| 'message', 'filename.js', 123, 'trace', {'foo': 'bar'}); |
| assertEquals('/log?script=filename.js&error=message&line=123&extra=arg', |
| MockXhrIo.lastUrl); |
| } |
| |
| function testSetAdditionalArgumentsMultipleArguments() { |
| errorReporter = new goog.debug.ErrorReporter('/log'); |
| errorReporter.setAdditionalArguments({'extra': 'arg', 'cat': 'dog'}); |
| errorReporter.sendErrorReport( |
| 'message', 'filename.js', 123, 'trace', {'foo': 'bar'}); |
| assertEquals( |
| '/log?script=filename.js&error=message&line=123&extra=arg&cat=dog', |
| MockXhrIo.lastUrl); |
| } |