Report uncaught errors via mw.track
Adds a global error handler that sends errors to mw.track as an errorLogging.windowOnerror event. Bug: T88874 Change-Id: Ic091c9f93c59bda47bda2cfd609c64cd1d014b39
This commit is contained in:
parent
7ab9e6ed0c
commit
23c1cebca0
7 changed files with 98 additions and 2 deletions
|
|
@ -22,6 +22,7 @@
|
|||
"mediaWiki": true,
|
||||
"JSON": true,
|
||||
"jQuery": false,
|
||||
"QUnit": false
|
||||
"QUnit": false,
|
||||
"sinon": false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
"mw.html.Cdata",
|
||||
"mw.html.Raw",
|
||||
"mw.hook",
|
||||
"mw.template"
|
||||
"mw.template",
|
||||
"mw.errorLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
</script>
|
||||
<script src="modules/lib/jquery/jquery.js"></script>
|
||||
<script src="modules/src/mediawiki/mediawiki.js"></script>
|
||||
<script src="modules/src/mediawiki/mediawiki.errorLogger.js"></script>
|
||||
<script src="modules/src/mediawiki/mediawiki.startUp.js"></script>
|
||||
<style>
|
||||
.mw-jsduck-log {
|
||||
|
|
|
|||
|
|
@ -775,6 +775,7 @@ return array(
|
|||
// Keep maintenance/jsduck/eg-iframe.html in sync
|
||||
'scripts' => array(
|
||||
'resources/src/mediawiki/mediawiki.js',
|
||||
'resources/src/mediawiki/mediawiki.errorLogger.js',
|
||||
'resources/src/mediawiki/mediawiki.startUp.js',
|
||||
),
|
||||
'debugScripts' => 'resources/src/mediawiki/mediawiki.log.js',
|
||||
|
|
|
|||
49
resources/src/mediawiki/mediawiki.errorLogger.js
Normal file
49
resources/src/mediawiki/mediawiki.errorLogger.js
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* Try to catch errors in modules which don't do their own error handling.
|
||||
* @class mw.errorLogger
|
||||
* @singleton
|
||||
*/
|
||||
( function ( mw ) {
|
||||
'use strict';
|
||||
|
||||
mw.errorLogger = {
|
||||
/**
|
||||
* Fired via mw.track when an error is not handled by local code and is caught by the
|
||||
* window.onerror handler.
|
||||
*
|
||||
* @event global_error
|
||||
* @param {string} errorMessage Error errorMessage.
|
||||
* @param {string} url URL where error was raised.
|
||||
* @param {number} lineNumber Line number where error was raised.
|
||||
* @param {number} [columnNumber] Line number where error was raised. Not all browsers
|
||||
* support this.
|
||||
* @param {Error|Mixed} [errorObject] The error object. Typically an instance of Error, but anything
|
||||
* (even a primitive value) passed to a throw clause will end up here.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Install a window.onerror handler that will report via mw.track, while preserving
|
||||
* any previous handler.
|
||||
* @param {Object} window
|
||||
*/
|
||||
installGlobalHandler: function ( window ) {
|
||||
// We will preserve the return value of the previous handler. window.onerror works the
|
||||
// opposite way than normal event handlers (returning true will prevent the default
|
||||
// action, returning false will let the browser handle the error normally, by e.g.
|
||||
// logging to the console), so our fallback old handler needs to return false.
|
||||
var oldHandler = window.onerror || function () { return false; };
|
||||
|
||||
/**
|
||||
* Dumb window.onerror handler which forwards the errors via mw.track.
|
||||
* @fires global_error
|
||||
*/
|
||||
window.onerror = function ( errorMessage, url, lineNumber, columnNumber, errorObject ) {
|
||||
mw.track( 'global.error', { errorMessage: errorMessage, url: url,
|
||||
lineNumber: lineNumber, columnNumber: columnNumber, errorObject: errorObject } );
|
||||
return oldHandler.apply( this, arguments );
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
mw.errorLogger.installGlobalHandler( window );
|
||||
}( mediaWiki ) );
|
||||
|
|
@ -62,6 +62,7 @@ return array(
|
|||
'tests/qunit/suites/resources/jquery/jquery.tablesorter.parsers.test.js',
|
||||
'tests/qunit/suites/resources/jquery/jquery.textSelection.test.js',
|
||||
'tests/qunit/data/mediawiki.jqueryMsg.data.js',
|
||||
'tests/qunit/suites/resources/mediawiki/mediawiki.errorLogger.test.js',
|
||||
'tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js',
|
||||
'tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js',
|
||||
'tests/qunit/suites/resources/mediawiki/mediawiki.test.js',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
( function ( $, mw ) {
|
||||
QUnit.module( 'mediawiki.errorLogger', QUnit.newMwEnvironment() );
|
||||
|
||||
QUnit.test( 'installGlobalHandler', 7, function ( assert ) {
|
||||
var w = {},
|
||||
errorMessage = 'Foo',
|
||||
errorUrl = 'http://example.com',
|
||||
errorLine = '123',
|
||||
errorColumn = '45',
|
||||
errorObject = new Error( 'Foo'),
|
||||
oldHandler = this.sandbox.stub();
|
||||
|
||||
this.sandbox.stub( mw, 'track' );
|
||||
|
||||
mw.errorLogger.installGlobalHandler( w );
|
||||
|
||||
assert.ok( w.onerror, 'Global handler has been installed' );
|
||||
assert.strictEqual( w.onerror( errorMessage, errorUrl, errorLine ), false,
|
||||
'Global handler returns false when there is no previous handler' );
|
||||
sinon.assert.calledWithExactly( mw.track, 'global.error',
|
||||
sinon.match( { errorMessage: errorMessage, url: errorUrl, lineNumber: errorLine } ) );
|
||||
|
||||
mw.track.reset();
|
||||
w.onerror( errorMessage, errorUrl, errorLine, errorColumn, errorObject );
|
||||
sinon.assert.calledWithExactly( mw.track, 'global.error',
|
||||
sinon.match( { errorMessage: errorMessage, url: errorUrl, lineNumber: errorLine,
|
||||
columnNumber: errorColumn, errorObject: errorObject } ) );
|
||||
|
||||
w = { onerror: oldHandler };
|
||||
|
||||
mw.errorLogger.installGlobalHandler( w );
|
||||
w.onerror( errorMessage, errorUrl, errorLine );
|
||||
sinon.assert.calledWithExactly( oldHandler, errorMessage, errorUrl, errorLine );
|
||||
|
||||
oldHandler.returns( false );
|
||||
assert.strictEqual( w.onerror( errorMessage, errorUrl, errorLine ), false,
|
||||
'Global handler preserves false return from previous handler' );
|
||||
oldHandler.returns( true );
|
||||
assert.strictEqual( w.onerror( errorMessage, errorUrl, errorLine ), true,
|
||||
'Global handler preserves true return from previous handler' );
|
||||
} );
|
||||
}( jQuery, mediaWiki ) );
|
||||
Loading…
Reference in a new issue