Diff
Modified: trunk/LayoutTests/ChangeLog (210366 => 210367)
--- trunk/LayoutTests/ChangeLog 2017-01-05 19:51:38 UTC (rev 210366)
+++ trunk/LayoutTests/ChangeLog 2017-01-05 20:07:44 UTC (rev 210367)
@@ -1,3 +1,40 @@
+2017-01-04 Brian Burg <[email protected]>
+
+ Web Inspector: Test.html should support globals reportInternalError, reportUnhandledRejection, reportUncaughtException
+ https://bugs.webkit.org/show_bug.cgi?id=161358
+ <rdar://problem/28066446>
+
+ Reviewed by Joseph Pecoraro.
+
+ Improve uncaught exception reporting and add some tests to document
+ new and existing behavior.
+
+ * http/tests/inspector/resources/inspector-test.js:
+ (runTest.runTestMethodInFrontend):
+ (runTest): Outsource reporting of an uncaught exception while injecting
+ a method into the frontend. By doing this, we can make the report using
+ the actual exception object since it doesn't go through window.onerror.
+
+ * inspector/unit-tests/async-test-suite-expected.txt:
+ * inspector/unit-tests/async-test-suite.html:
+ * inspector/unit-tests/sync-test-suite-expected.txt:
+ * inspector/unit-tests/sync-test-suite.html:
+ Rebaseline and force suppression of stack traces, which are not deterministic
+ across commits due to logging specific lines and columns in TestCombined.js.
+
+ * inspector/unit-tests/globals-uncaught-exception-from-timer-callback-expected.txt: Added.
+ * inspector/unit-tests/globals-uncaught-exception-from-timer-callback.html: Added.
+ * inspector/unit-tests/globals-uncaught-exception-in-test-function-expected.txt: Added.
+ * inspector/unit-tests/globals-uncaught-exception-in-test-function.html: Added.
+ * inspector/unit-tests/globals-uncaught-exception-in-test-suite-expected.txt: Added.
+ * inspector/unit-tests/globals-uncaught-exception-in-test-suite.html: Added.
+ * inspector/unit-tests/globals-unhandled-rejection-in-test-function-expected.txt: Added.
+ * inspector/unit-tests/globals-unhandled-rejection-in-test-function.html: Added.
+ * inspector/unit-tests/globals-unhandled-rejection-in-test-suite-expected.txt: Added.
+ * inspector/unit-tests/globals-unhandled-rejection-in-test-suite.html: Added.
+ * inspector/unit-tests/globals-unhandled-rejection-in-timer-callback-expected.txt: Added.
+ * inspector/unit-tests/globals-unhandled-rejection-in-timer-callback.html: Added.
+
2017-01-05 Andreas Kling <[email protected]>
Skip fast/scrolling/page-cache-back-overflow-scroll-restore.html on iOS simulator.
Modified: trunk/LayoutTests/http/tests/inspector/resources/inspector-test.js (210366 => 210367)
--- trunk/LayoutTests/http/tests/inspector/resources/inspector-test.js 2017-01-05 19:51:38 UTC (rev 210366)
+++ trunk/LayoutTests/http/tests/inspector/resources/inspector-test.js 2017-01-05 20:07:44 UTC (rev 210367)
@@ -88,9 +88,9 @@
try {
testFunction();
} catch (e) {
- // FIXME: the redirected console methods do not forward additional arguments.
- console.error("Exception during test execution: " + e, e.stack || "(no stack trace)");
- InspectorTest.completeTest();
+ // Using this instead of window.onerror will preserve the stack trace.
+ e.code = testFunction.toString();
+ InspectorTest.reportUncaughtException(e);
}
}
Modified: trunk/LayoutTests/inspector/unit-tests/async-test-suite-expected.txt (210366 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/async-test-suite-expected.txt 2017-01-05 19:51:38 UTC (rev 210366)
+++ trunk/LayoutTests/inspector/unit-tests/async-test-suite-expected.txt 2017-01-05 20:07:44 UTC (rev 210367)
@@ -26,6 +26,7 @@
-- Running test case: DummyTest3
-- Running test case: FailingTest4
!! EXCEPTION: [object Object]
+Stack Trace: (suppressed)
PASS: Promise from sequentialExecutionSuite.runTestCases() should reject when a test case fails.
PASS: Promise from sequentialExecutionSuite.runTestCases() should reject without altering its result value.
PASS: sequentialExecutionSuite should have executed four tests.
@@ -37,6 +38,7 @@
-- Running test case: PassingTest5
-- Running test case: FailingTest6
!! EXCEPTION: {"token":666}
+Stack Trace: (suppressed)
PASS: Promise from abortOnFailureSuite.runTestCases() should reject when a test case fails.
PASS: Promise from abortOnFailureSuite.runTestCases() should reject without altering its result value.
PASS: abortOnFailureSuite should have executed two tests.
@@ -58,11 +60,13 @@
== Running test suite: AsyncTestSuite.SetupException
-- Running test setup.
!! EXCEPTION:
+Stack Trace: (suppressed)
PASS: Promise from setupExceptionTestSuite.runTestCases() should reject.
== Running test suite: AsyncTestSuite.SetupFailure
-- Running test setup.
!! EXCEPTION: undefined
+Stack Trace: (suppressed)
PASS: Promise from setupFailureTestSuite.runTestCases() should reject.
== Running test suite: AsyncTestSuite.TeardownException
@@ -69,6 +73,7 @@
-- Running test case: TestWithExceptionDuringTeardown
-- Running test teardown.
!! EXCEPTION:
+Stack Trace: (suppressed)
PASS: Promise from teardownExceptionTestSuite.runTestCases() should reject.
== Running test suite: AsyncTestSuite.TeardownFailure
@@ -75,5 +80,6 @@
-- Running test case: TestWithExceptionDuringTeardown
-- Running test teardown.
!! EXCEPTION: undefined
+Stack Trace: (suppressed)
PASS: Promise from teardownFailureTestSuite.runTestCases() should reject.
Modified: trunk/LayoutTests/inspector/unit-tests/async-test-suite.html (210366 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/async-test-suite.html 2017-01-05 19:51:38 UTC (rev 210366)
+++ trunk/LayoutTests/inspector/unit-tests/async-test-suite.html 2017-01-05 20:07:44 UTC (rev 210367)
@@ -5,6 +5,8 @@
<script>
function test()
{
+ ProtocolTest.suppressStackTraces = true;
+
try {
let result = new AsyncTestSuite(this);
ProtocolTest.log("FAIL: instantiating AsyncTestSuite requires name argument.");
Added: trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-from-timer-callback-expected.txt (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-from-timer-callback-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-from-timer-callback-expected.txt 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,5 @@
+Test that the uncaught exception hook will immediately terminate the test and print the associated exception and stack trace.
+
+Uncaught exception in Inspector page: Error: This is an exception thrown in the inspector page. [global:20:24]
+
+
Added: trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-from-timer-callback.html (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-from-timer-callback.html (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-from-timer-callback.html 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script>
+function test()
+{
+ InspectorTest.suppressStackTraces = true;
+
+ setTimeout(() => {
+ throw new Error("This is an exception thrown in the inspector page.");
+ });
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<p>Test that the uncaught exception hook will immediately terminate the test and print the associated exception and stack trace.</p>
+</body>
+</html>
Added: trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-function-expected.txt (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-function-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-function-expected.txt 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,15 @@
+Test that the uncaught exception hook will immediately terminate the test and print the associated exception and stack trace.
+
+Uncaught exception in Inspector page: This is an exception thrown in the inspector page.
+
+Stack Trace:
+(suppressed)
+
+Evaluated Code:
+function test()
+{
+ InspectorTest.suppressStackTraces = true;
+
+ throw new Error("This is an exception thrown in the inspector page.");
+}
+
Added: trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-function.html (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-function.html (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-function.html 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,17 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script>
+function test()
+{
+ InspectorTest.suppressStackTraces = true;
+
+ throw new Error("This is an exception thrown in the inspector page.");
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<p>Test that the uncaught exception hook will immediately terminate the test and print the associated exception and stack trace.</p>
+</body>
+</html>
Added: trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-suite-expected.txt (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-suite-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-suite-expected.txt 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,8 @@
+Test that the unhandled promise rejection hook will immediately terminate the test and print the associated exception and stack trace.
+
+
+== Running test suite: UncaughtExceptionInsideTestCase
+-- Running test case: CatchRejectedPromise
+!! EXCEPTION: This promise is rejected with an Error object.
+Stack Trace: (suppressed)
+
Added: trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-suite.html (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-suite.html (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-uncaught-exception-in-test-suite.html 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,26 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script>
+function test()
+{
+ InspectorTest.suppressStackTraces = true;
+
+ let suite = InspectorTest.createAsyncSuite("UncaughtExceptionInsideTestCase");
+ suite.addTestCase({
+ name: "CatchRejectedPromise",
+ description: "window.reportUnhandledRejection should dump the unhandled exception and quit testing.",
+ test(resolve, reject) {
+ throw new Error("This promise is rejected with an Error object.");
+ }
+ })
+
+ suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<p>Test that the unhandled promise rejection hook will immediately terminate the test and print the associated exception and stack trace.</p>
+</body>
+</html>
Added: trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-function-expected.txt (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-function-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-function-expected.txt 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,7 @@
+Test that the unhandled hook will immediately terminate the test and print the associated exception and stack trace.
+
+Unhandled promise rejection in inspector page: This is an exception thrown in the inspector page.
+
+Stack Trace: (suppressed)
+
+
Added: trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-function.html (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-function.html (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-function.html 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,17 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script>
+function test()
+{
+ InspectorTest.suppressStackTraces = true;
+
+ reportUnhandledRejection(new Error("This is an exception thrown in the inspector page."));
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<p>Test that the unhandled hook will immediately terminate the test and print the associated exception and stack trace.</p>
+</body>
+</html>
Added: trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-suite-expected.txt (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-suite-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-suite-expected.txt 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,10 @@
+Test that the unhandled promise rejection hook will immediately terminate the test and print the associated exception and stack trace.
+
+
+== Running test suite: ReportUnhandledRejection
+-- Running test case: CatchRejectedPromise
+Unhandled promise rejection in inspector page: This promise is rejected with an Error object.
+
+Stack Trace: (suppressed)
+
+
Added: trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-suite.html (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-suite.html (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-test-suite.html 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script>
+function test()
+{
+ InspectorTest.suppressStackTraces = true;
+
+ let suite = InspectorTest.createAsyncSuite("ReportUnhandledRejection");
+ suite.addTestCase({
+ name: "CatchRejectedPromise",
+ description: "window.reportUnhandledRejection should dump the unhandled exception and quit testing.",
+ test(resolve, reject) {
+ let rejectedPromise = Promise.reject(new Error("This promise is rejected with an Error object."));
+ rejectedPromise.catch(reportUnhandledRejection);
+ }
+ })
+
+ suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<p>Test that the unhandled promise rejection hook will immediately terminate the test and print the associated exception and stack trace.</p>
+</body>
+</html>
Added: trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-timer-callback-expected.txt (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-timer-callback-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-timer-callback-expected.txt 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,5 @@
+Test that the uncaught exception hook will immediately terminate the test and print the associated exception and stack trace.
+
+Unhandled promise rejection in inspector page: This is an exception thrown in the inspector page.
+
+
Added: trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-timer-callback.html (0 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-timer-callback.html (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/globals-unhandled-rejection-in-timer-callback.html 2017-01-05 20:07:44 UTC (rev 210367)
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script>
+function test()
+{
+ InspectorTest.suppressStackTraces = true;
+
+ setTimeout(() => {
+ reportUnhandledRejection(new Error("This is an exception thrown in the inspector page."));
+ });
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<p>Test that the uncaught exception hook will immediately terminate the test and print the associated exception and stack trace.</p>
+</body>
+</html>
Modified: trunk/LayoutTests/inspector/unit-tests/sync-test-suite-expected.txt (210366 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/sync-test-suite-expected.txt 2017-01-05 19:51:38 UTC (rev 210366)
+++ trunk/LayoutTests/inspector/unit-tests/sync-test-suite-expected.txt 2017-01-05 20:07:44 UTC (rev 210367)
@@ -26,6 +26,7 @@
-- Running test case: DummyTest3
-- Running test case: FailingTest4
!! EXCEPTION: [object Object]
+Stack Trace: (suppressed)
PASS: Return value of sequentialExecutionSuite.runTestCases() should be false when a test case fails.
PASS: sequentialExecutionSuite should have executed four tests.
PASS: sequentialExecutionSuite should have passed three tests.
@@ -54,18 +55,20 @@
== Running test suite: SyncTestSuite.SetupException
-- Running test setup.
!! EXCEPTION:
+Stack Trace: (suppressed)
== Running test suite: SyncTestSuite.SetupFailure
-- Running test setup.
-!! EXCEPTION
+!! SETUP FAILED
== Running test suite: SyncTestSuite.TeardownException
-- Running test case: TestWithExceptionDuringTeardown
-- Running test teardown.
!! EXCEPTION:
+Stack Trace: (suppressed)
== Running test suite: SyncTestSuite.TeardownFailure
-- Running test case: TestWithExceptionDuringTeardown
-- Running test teardown.
-!! EXCEPTION:
+!! TEARDOWN FAILED
Modified: trunk/LayoutTests/inspector/unit-tests/sync-test-suite.html (210366 => 210367)
--- trunk/LayoutTests/inspector/unit-tests/sync-test-suite.html 2017-01-05 19:51:38 UTC (rev 210366)
+++ trunk/LayoutTests/inspector/unit-tests/sync-test-suite.html 2017-01-05 20:07:44 UTC (rev 210367)
@@ -5,6 +5,8 @@
<script>
function test()
{
+ ProtocolTest.suppressStackTraces = true;
+
try {
let result = new SyncTestSuite(this);
ProtocolTest.log("FAIL: instantiating SyncTestSuite requires name argument.");
Modified: trunk/Source/WebInspectorUI/ChangeLog (210366 => 210367)
--- trunk/Source/WebInspectorUI/ChangeLog 2017-01-05 19:51:38 UTC (rev 210366)
+++ trunk/Source/WebInspectorUI/ChangeLog 2017-01-05 20:07:44 UTC (rev 210367)
@@ -1,3 +1,62 @@
+2017-01-04 Brian Burg <[email protected]>
+
+ Web Inspector: Test.html should support globals reportInternalError, reportUnhandledRejection, reportUncaughtException
+ https://bugs.webkit.org/show_bug.cgi?id=161358
+ <rdar://problem/28066446>
+
+ Reviewed by Joseph Pecoraro.
+
+ We have a hodgepodge of redundant code that reports uncaught exceptions in the inspector page.
+ There is better handling of uncaught exceptions in the inspected page, such as including stack traces.
+
+ This patch consolidates a lot of this code and makes it possible to report
+ unhandled promise rejections, top-level uncaught exceptions, and exceptions
+ caught in a try-catch block. The formatting and sanitization code for all of
+ these things is shared and consistent. Finally, some tests have been added to
+ catch regressions in unhandled rejection/uncaught exception reporting.
+
+ * UserInterface/Test/FrontendTestHarness.js:
+ (FrontendTestHarness): Explicitly set initial flag state here so it's easy to find all flags.
+
+ (FrontendTestHarness.prototype.redirectConsoleToTestOutput):
+ Extract this code to sanitize stack frames and put it in TestHarness. It is used
+ by other methods that need to print stack frames.
+
+ (FrontendTestHarness.prototype.reportUnhandledRejection):
+ (FrontendTestHarness.prototype.reportUncaughtException):
+ Added. Sanitize stack trace data so it is deterministic. Log the message to the
+ original window.console but don't exit early. Sometimes the test page is not
+ fully loaded if we throw an exception quite early in the test() method, and there's
+ no harm in not early returning. If we do early return in this case, then a test that
+ uses reportUncaughtException on purpose may not complete because the call to completeTest()
+ would be skipped by returning early.
+
+ (FrontendTestHarness.prototype.reportUncaughtExceptionFromEvent):
+ Renamed from reportUncaughtException since the signature of that method suggests
+ it should have a single exception argument rather than lots of data arguments.
+
+ * UserInterface/Test/Test.js: Add globals.
+
+ * UserInterface/Test/TestHarness.js:
+ (TestHarness): Document class flags.
+ (TestHarness.sanitizeURL):
+ (TestHarness.sanitizeStackFrame):
+ (TestHarness.prototype.sanitizeStack):
+ Extract this code from other parts of the test harness. Make sanitizeStack
+ an instance method so that there is only one place that needs to check the
+ 'suppressStackTraces' flag.
+
+ * UserInterface/Test/TestSuite.js:
+ (TestSuite.prototype.logThrownObject):
+ (TestSuite):
+ (AsyncTestSuite.prototype.runTestCases):
+ (AsyncTestSuite):
+ (SyncTestSuite.prototype.runTestCases):
+ (SyncTestSuite):
+ (TestSuite.messageFromThrownObject): Deleted.
+ Inline some helpers with only one use-site and consolidate redundant code
+ for adding an exception and message to the test results.
+
2017-01-04 Nikita Vasilyev <[email protected]>
Web Inspector: application cache details not shown in Storage Tab
Modified: trunk/Source/WebInspectorUI/UserInterface/Test/FrontendTestHarness.js (210366 => 210367)
--- trunk/Source/WebInspectorUI/UserInterface/Test/FrontendTestHarness.js 2017-01-05 19:51:38 UTC (rev 210366)
+++ trunk/Source/WebInspectorUI/UserInterface/Test/FrontendTestHarness.js 2017-01-05 20:07:44 UTC (rev 210367)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,6 +31,9 @@
this._results = [];
this._shouldResendResults = true;
+
+ // Options that are set per-test for debugging purposes.
+ this.dumpActivityToSystemConsole = false;
}
// TestHarness Overrides
@@ -151,25 +154,7 @@
} catch (e) {
// Skip the first frame which is added by this function.
let frames = e.stack.split("\n").slice(1);
- let sanitizedFrames = frames.map((frame, i) => {
- // Most frames are of the form "functionName@file:///foo/bar/File.js:345".
- // But, some frames do not have a functionName. Get rid of the file path.
- let nameAndURLSeparator = frame.indexOf("@");
- let frameName = (nameAndURLSeparator > 0) ? frame.substr(0, nameAndURLSeparator) : "(anonymous)";
-
- let lastPathSeparator = Math.max(frame.lastIndexOf("/"), frame.lastIndexOf("\\"));
- let frameLocation = (lastPathSeparator > 0) ? frame.substr(lastPathSeparator + 1) : frame;
- if (!frameLocation.length)
- frameLocation = "unknown";
-
- // Clean up the location so it is bracketed or in parenthesis.
- if (frame.indexOf("[native code]") !== -1)
- frameLocation = "[native code]";
- else
- frameLocation = "(" + frameLocation + ")";
-
- return `#${i}: ${frameName} ${frameLocation}`;
- });
+ let sanitizedFrames = frames.map(TestHarness.sanitizeStackFrame);
self.addResult("TRACE: " + Array.from(arguments).join(" "));
self.addResult(sanitizedFrames.join("\n"));
}
@@ -189,23 +174,63 @@
window.console = redirectedMethods;
}
- reportUncaughtException(message, url, lineNumber, columnNumber)
+ reportUnhandledRejection(error)
{
- let result = `Uncaught exception in inspector page: ${message} [${url}:${lineNumber}:${columnNumber}]`;
+ let message = error.message;
+ let stack = error.stack;
+ let result = `Unhandled promise rejection in inspector page: ${message}\n`;
+ if (stack) {
+ let sanitizedStack = this.sanitizeStack(stack);
+ result += `\nStack Trace: ${sanitizedStack}\n`;
+ }
// If the connection to the test page is not set up, then just dump to console and give up.
// Errors encountered this early can be debugged by loading Test.html in a normal browser page.
- if (this._originalConsole && !this._testPageHasLoaded()) {
+ if (this._originalConsole && !this._testPageHasLoaded())
this._originalConsole["error"](result);
- return false;
- }
this.addResult(result);
this.completeTest();
+
// Stop default handler so we can empty InspectorBackend's message queue.
return true;
}
+ reportUncaughtExceptionFromEvent(message, url, lineNumber, columnNumber)
+ {
+ // An exception thrown from a timer callback does not report a URL.
+ if (url ="" "undefined")
+ url = ""
+
+ return this.reportUncaughtException({message, url, lineNumber, columnNumber});
+ }
+
+ reportUncaughtException({message, url, lineNumber, columnNumber, stack, code})
+ {
+ let result;
+ let sanitizedURL = TestHarness.sanitizeURL(url);
+ let sanitizedStack = this.sanitizeStack(stack);
+ if (url || lineNumber || columnNumber)
+ result = `Uncaught exception in Inspector page: ${message} [${sanitizedURL}:${lineNumber}:${columnNumber}]\n`;
+ else
+ result = `Uncaught exception in Inspector page: ${message}\n`;
+
+ if (stack)
+ result += `\nStack Trace:\n${sanitizedStack}\n`;
+ if (code)
+ result += `\nEvaluated Code:\n${code}`;
+
+ // If the connection to the test page is not set up, then just dump to console and give up.
+ // Errors encountered this early can be debugged by loading Test.html in a normal browser page.
+ if (this._originalConsole && !this._testPageHasLoaded())
+ this._originalConsole["error"](result);
+
+ this.addResult(result);
+ this.completeTest();
+ // Stop default handler so we can empty InspectorBackend's message queue.
+ return true;
+ }
+
// Private
_testPageHasLoaded()
Modified: trunk/Source/WebInspectorUI/UserInterface/Test/Test.js (210366 => 210367)
--- trunk/Source/WebInspectorUI/UserInterface/Test/Test.js 2017-01-05 19:51:38 UTC (rev 210366)
+++ trunk/Source/WebInspectorUI/UserInterface/Test/Test.js 2017-01-05 20:07:44 UTC (rev 210367)
@@ -115,3 +115,6 @@
InspectorTest.redirectConsoleToTestOutput();
WebInspector.reportInternalError = (e) => { console.error(e); }
+
+window.reportUnhandledRejection = InspectorTest.reportUnhandledRejection.bind(InspectorTest);
+window._onerror_ = InspectorTest.reportUncaughtExceptionFromEvent.bind(InspectorTest);
Modified: trunk/Source/WebInspectorUI/UserInterface/Test/TestHarness.js (210366 => 210367)
--- trunk/Source/WebInspectorUI/UserInterface/Test/TestHarness.js 2017-01-05 19:51:38 UTC (rev 210366)
+++ trunk/Source/WebInspectorUI/UserInterface/Test/TestHarness.js 2017-01-05 20:07:44 UTC (rev 210367)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,6 +32,12 @@
this._logCount = 0;
this._failureObjects = new Map;
this._failureObjectIdentifier = 1;
+
+ // Options that are set per-test for debugging purposes.
+ this.forceDebugLogging = false;
+
+ // Options that are set per-test to ensure deterministic output.
+ this.suppressStackTraces = false;
}
completeTest()
@@ -183,6 +189,55 @@
return (typeof message !== "string") ? JSON.stringify(message) : message;
}
+ static sanitizeURL(url)
+ {
+ if (!url)
+ return "(unknown)";
+
+ let lastPathSeparator = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));
+ let location = (lastPathSeparator > 0) ? url.substr(lastPathSeparator + 1) : url;
+ if (!location.length)
+ location = "(unknown)";
+
+ // Clean up the location so it is bracketed or in parenthesis.
+ if (url.indexOf("[native code]") !== -1)
+ location = "[native code]";
+
+ return location;
+ }
+
+ static sanitizeStackFrame(frame, i)
+ {
+ // Most frames are of the form "functionName@file:///foo/bar/File.js:345".
+ // But, some frames do not have a functionName. Get rid of the file path.
+ let nameAndURLSeparator = frame.indexOf("@");
+ let frameName = (nameAndURLSeparator > 0) ? frame.substr(0, nameAndURLSeparator) : "(anonymous)";
+
+ let lastPathSeparator = Math.max(frame.lastIndexOf("/"), frame.lastIndexOf("\\"));
+ let frameLocation = (lastPathSeparator > 0) ? frame.substr(lastPathSeparator + 1) : frame;
+ if (!frameLocation.length)
+ frameLocation = "unknown";
+
+ // Clean up the location so it is bracketed or in parenthesis.
+ if (frame.indexOf("[native code]") !== -1)
+ frameLocation = "[native code]";
+ else
+ frameLocation = "(" + frameLocation + ")";
+
+ return `#${i}: ${frameName} ${frameLocation}`;
+ }
+
+ sanitizeStack(stack)
+ {
+ if (this.suppressStackTraces)
+ return "(suppressed)";
+
+ if (!stack || typeof stack !== "string")
+ return "(unknown)";
+
+ return stack.split("\n").map(TestHarness.sanitizeStackFrame).join("\n");
+ }
+
// Private
_expect(type, condition, message, ...values)
Modified: trunk/Source/WebInspectorUI/UserInterface/Test/TestSuite.js (210366 => 210367)
--- trunk/Source/WebInspectorUI/UserInterface/Test/TestSuite.js 2017-01-05 19:51:38 UTC (rev 210366)
+++ trunk/Source/WebInspectorUI/UserInterface/Test/TestSuite.js 2017-01-05 20:07:44 UTC (rev 210367)
@@ -87,16 +87,28 @@
this.testcases.push(testcase);
}
- static messageFromThrownObject(e)
+ // Protected
+
+ logThrownObject(e)
{
let message = e;
- if (e instanceof Error)
+ let stack = "(unknown)";
+ if (e instanceof Error) {
message = e.message;
+ if (e.stack)
+ stack = e.stack;
+ }
if (typeof message !== "string")
message = JSON.stringify(message);
- return message;
+ let sanitizedStack = this._harness.sanitizeStack(stack);
+
+ let result = `!! EXCEPTION: ${message}`;
+ if (stack)
+ result += `\nStack Trace: ${sanitizedStack}`;
+
+ this._harness.log(result);
}
};
@@ -154,8 +166,7 @@
return result.catch((e) => {
this.failCount++;
- let message = TestSuite.messageFromThrownObject(e);
- this._harness.log(`!! EXCEPTION: ${message}`);
+ this.logThrownObject(e);
throw e; // Reject this promise by re-throwing the error.
});
@@ -196,12 +207,11 @@
try {
let result = testcase.setup.call(null);
if (result === false) {
- this._harness.log("!! EXCEPTION");
+ this._harness.log("!! SETUP FAILED");
return false;
}
} catch (e) {
- let message = TestSuite.messageFromThrownObject(e);
- this._harness.log(`!! EXCEPTION: ${message}`);
+ this.logThrownObject(e);
return false;
}
}
@@ -216,8 +226,7 @@
}
} catch (e) {
this.failCount++;
- let message = TestSuite.messageFromThrownObject(e);
- this._harness.log(`!! EXCEPTION: ${message}`);
+ this.logThrownObject(e);
return false;
}
@@ -227,12 +236,11 @@
try {
let result = testcase.teardown.call(null);
if (result === false) {
- this._harness.log("!! EXCEPTION:");
+ this._harness.log("!! TEARDOWN FAILED");
return false;
}
} catch (e) {
- let message = TestSuite.messageFromThrownObject(e);
- this._harness.log(`!! EXCEPTION: ${message}`);
+ this.logThrownObject(e);
return false;
}
}