Skip to content

Commit

Permalink
Core: Report full stack trace for uncaught errors if possible (#1324)
Browse files Browse the repository at this point in the history
Currently, when QUnit catches an uncaught error in its window.onerror
handler, it reports it with a source of `fileName + ":" + lineNumber`.

While it's not standard, most modern browsers include an errorObj
argument to window.onerror, which can be used to get a more complete
stacktrace
([source](https://blog.sentry.io/2016/01/04/client-javascript-reporting-window-onerror)).
This change modifies the HTML reporter and the `QUnit.onError` method to
do that.
  • Loading branch information
anandthakker authored and trentmwillis committed Nov 1, 2018
1 parent 112d782 commit ed88074
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 4 deletions.
21 changes: 19 additions & 2 deletions reporter/html.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import QUnit from "../src/core";
import { extractStacktrace } from "../src/core/stacktrace";
import { window, navigator } from "../src/globals";
import "./urlparams";

Expand Down Expand Up @@ -970,10 +971,18 @@ export function escapeText( s ) {
// Cover uncaught exceptions
// Returning true will suppress the default browser handler,
// returning false will let it run.
window.onerror = function( message, fileName, lineNumber, ...args ) {
window.onerror = function( message, fileName, lineNumber, columnNumber, errorObj, ...args ) {
var ret = false;
if ( originalWindowOnError ) {
ret = originalWindowOnError.call( this, message, fileName, lineNumber, ...args );
ret = originalWindowOnError.call(
this,
message,
fileName,
lineNumber,
columnNumber,
errorObj,
...args
);
}

// Treat return value as window.onerror itself does,
Expand All @@ -985,6 +994,14 @@ export function escapeText( s ) {
lineNumber
};

// According to
// https://blog.sentry.io/2016/01/04/client-javascript-reporting-window-onerror,
// most modern browsers support an errorObj argument; use that to
// get a full stack trace if it's available.
if ( errorObj && errorObj.stack ) {
error.stacktrace = extractStacktrace( errorObj, 0 );
}

ret = QUnit.onError( error );
}

Expand Down
12 changes: 10 additions & 2 deletions src/core/onerror.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@ export default function onError( error, ...args ) {
if ( config.current.ignoreGlobalErrors ) {
return true;
}
pushFailure( error.message, error.fileName + ":" + error.lineNumber, ...args );
pushFailure(
error.message,
error.stacktrace || error.fileName + ":" + error.lineNumber,
...args
);
} else {
test( "global failure", extend( function() {
pushFailure( error.message, error.fileName + ":" + error.lineNumber, ...args );
pushFailure(
error.message,
error.stacktrace || error.fileName + ":" + error.lineNumber,
...args
);
}, { validTest: true } ) );
}

Expand Down
23 changes: 23 additions & 0 deletions test/onerror/inside-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,29 @@ QUnit.module( "QUnit.onError", function() {
assert.strictEqual( result, false, "onError should allow other error handlers to run" );
} );

QUnit.test( "Should use stacktrace argument when it is present", function( assert ) {
assert.expect( 3 );

QUnit.config.current.pushFailure = function( message, source ) {
assert.strictEqual( message, "Error message", "Message is correct" );
assert.strictEqual(
source,
"DummyError\nfilePath.js:1 foo()\nfilePath.js:2 bar()",
"Source is correct"
);
};

var result = QUnit.onError( {
message: "Error message",
fileName: "filePath.js",
lineNumber: 1,
stacktrace: "DummyError\nfilePath.js:1 foo()\nfilePath.js:2 bar()"
} );

assert.strictEqual( result, false, "onError should allow other error handlers to run" );
} );


QUnit.test( "Shouldn't push failure if ignoreGlobalErrors is enabled", function( assert ) {
assert.expect( 1 );

Expand Down
15 changes: 15 additions & 0 deletions test/reporter-html/window-onerror.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ QUnit.module( "window.onerror (no preexisting handler)", function( hooks ) {
window.onerror( "An error message", "filename.js", 1 );
} );

QUnit.test( "Should extract stacktrace if it is available", function( assert ) {
assert.expect( 1 );

const errorObj = {
stack: "dummy.js:1 top()\ndummy.js:2 middle()\ndummy.js:3 bottom()"
};

QUnit.onError = function( error ) {
assert.equal( error.stacktrace, errorObj.stack, "QUnit.onError was called" );
};

window.onerror( "An error message", "filename.js", 1, 1, errorObj );
} );


QUnit.test( "Should return QUnit.error return value if it is called", function( assert ) {
assert.expect( 1 );

Expand Down

0 comments on commit ed88074

Please sign in to comment.