Diff
Modified: trunk/LayoutTests/ChangeLog (238849 => 238850)
--- trunk/LayoutTests/ChangeLog 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/LayoutTests/ChangeLog 2018-12-04 09:08:42 UTC (rev 238850)
@@ -1,3 +1,27 @@
+2018-12-04 Devin Rousso <drou...@apple.com>
+
+ Web Inspector: Audit: tests should support async operations
+ https://bugs.webkit.org/show_bug.cgi?id=192171
+ <rdar://problem/46423562>
+
+ Reviewed by Joseph Pecoraro.
+
+ * inspector/audit/resources/audit-utilities.js:
+ (TestPage.registerInitializer.InspectorTest.Audit.addFunctionlessTest):
+ (TestPage.registerInitializer.InspectorTest.Audit.addStringTest):
+ (TestPage.registerInitializer.InspectorTest.Audit.addObjectTest):
+ (TestPage.registerInitializer.InspectorTest.Audit.addPromiseTest): Added.
+ * inspector/audit/basic-expected.txt:
+ * inspector/audit/basic.html:
+
+ * inspector/model/auditTestCaseResult-expected.txt:
+ * inspector/model/auditTestCaseResult.html:
+ * inspector/model/auditTestGroupResult-expected.txt:
+ * inspector/model/auditTestGroupResult.html:
+
+ * inspector/runtime/awaitPromise-expected.txt: Added.
+ * inspector/runtime/awaitPromise.html: Added.
+
2018-12-03 Carlos Garcia Campos <cgar...@igalia.com>
[GTK] Bump freetype, fontconfig, harfbuzz, cairo and icu in jhbuild
Modified: trunk/LayoutTests/inspector/audit/basic-expected.txt (238849 => 238850)
--- trunk/LayoutTests/inspector/audit/basic-expected.txt 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/LayoutTests/inspector/audit/basic-expected.txt 2018-12-04 09:08:42 UTC (rev 238850)
@@ -50,23 +50,51 @@
Testing value `{"level":"unsupported"}`...
PASS: Result should be "unsupported".
+-- Running test case: Audit.Basic.Promise.Boolean.True
+Testing value `new Promise((resolve, reject) => resolve(true))`...
+PASS: Result should be "pass".
+
+-- Running test case: Audit.Basic.Promise.String.Pass
+Testing value `new Promise((resolve, reject) => resolve("pass"))`...
+PASS: Result should be "pass".
+
+-- Running test case: Audit.Basic.Promise.Object.Pass
+Testing value `new Promise((resolve, reject) => resolve({level: "pass"}))`...
+PASS: Result should be "pass".
+
+-- Running test case: Audit.Basic.Async.Boolean.True
+Testing value `true`...
+PASS: Result should be "pass".
+
+-- Running test case: Audit.Basic.Async.String.Pass
+Testing value `"pass"`...
+PASS: Result should be "pass".
+
+-- Running test case: Audit.Basic.Async.Object.Pass
+Testing value `{"level":"pass"}`...
+PASS: Result should be "pass".
+
+-- Running test case: Audit.Basic.Timeout.Pass
+Testing value `new Promise((resolve, reject) => setTimeout(resolve, 0, "pass"))`...
+PASS: Result should be "pass".
+
-- Running test case: Audit.Basic.Error.Undefined
-Testing...
+Testing value `undefined`...
PASS: Result should be "error".
errors:
- - TypeError: eval(undefined) is not a function. (In 'eval(undefined)()', 'eval(undefined)' is undefined)
+ - Return value is not an object, string, or boolean
-- Running test case: Audit.Basic.Error.Null
-Testing...
+Testing value `null`...
PASS: Result should be "error".
errors:
- - TypeError: eval(null) is not a function. (In 'eval(null)()', 'eval(null)' is null)
+ - Return value is not an object, string, or boolean
-- Running test case: Audit.Basic.Error.Number
-Testing...
+Testing value `42`...
PASS: Result should be "error".
errors:
- - TypeError: eval(42) is not a function. (In 'eval(42)()', 'eval(42)' is 42)
+ - Return value is not an object, string, or boolean
-- Running test case: Audit.Basic.Error.String
Testing value `"foo"`...
@@ -81,8 +109,20 @@
- Missing result level
-- Running test case: Audit.Basic.Error.Variable
-Testing...
+Testing value `INVALID`...
PASS: Result should be "error".
errors:
- ReferenceError: Can't find variable: INVALID
+-- Running test case: Audit.Basic.Error.Promise.Resolved
+Testing value `new Promise((resolve, reject) => setTimeout(resolve, 0))`...
+PASS: Result should be "error".
+ errors:
+ - Return value is not an object, string, or boolean
+
+-- Running test case: Audit.Basic.Error.Promise.Rejected
+Testing value `new Promise((resolve, reject) => setTimeout(reject, 0, "rejected"))`...
+PASS: Result should be "error".
+ errors:
+ - rejected
+
Modified: trunk/LayoutTests/inspector/audit/basic.html (238849 => 238850)
--- trunk/LayoutTests/inspector/audit/basic.html 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/LayoutTests/inspector/audit/basic.html 2018-12-04 09:08:42 UTC (rev 238850)
@@ -4,6 +4,9 @@
<script src=""
<script src=""
<script>
+if (window.internals)
+ window.internals.settings.setUnhandledPromiseRejectionToConsoleEnabled(false);
+
function test()
{
let suite = InspectorTest.Audit.createSuite("Audit.Basic");
@@ -23,12 +26,24 @@
InspectorTest.Audit.addObjectTest("Audit.Basic.Object.Error", {level: WI.AuditTestCaseResult.Level.Error}, WI.AuditTestCaseResult.Level.Error);
InspectorTest.Audit.addObjectTest("Audit.Basic.Object.Unsupported", {level: WI.AuditTestCaseResult.Level.Unsupported}, WI.AuditTestCaseResult.Level.Unsupported);
- InspectorTest.Audit.addTest("Audit.Basic.Error.Undefined", undefined, WI.AuditTestCaseResult.Level.Error);
- InspectorTest.Audit.addTest("Audit.Basic.Error.Null", null, WI.AuditTestCaseResult.Level.Error);
- InspectorTest.Audit.addTest("Audit.Basic.Error.Number", 42, WI.AuditTestCaseResult.Level.Error);
+ InspectorTest.Audit.addPromiseTest("Audit.Basic.Promise.Boolean.True", `resolve(true)`, WI.AuditTestCaseResult.Level.Pass);
+ InspectorTest.Audit.addPromiseTest("Audit.Basic.Promise.String.Pass", `resolve("${WI.AuditTestCaseResult.Level.Pass}")`, WI.AuditTestCaseResult.Level.Pass);
+ InspectorTest.Audit.addPromiseTest("Audit.Basic.Promise.Object.Pass", `resolve({level: "${WI.AuditTestCaseResult.Level.Pass}"})`, WI.AuditTestCaseResult.Level.Pass);
+
+ InspectorTest.Audit.addFunctionlessTest("Audit.Basic.Async.Boolean.True", true, WI.AuditTestCaseResult.Level.Pass, {async: true});
+ InspectorTest.Audit.addStringTest("Audit.Basic.Async.String.Pass", WI.AuditTestCaseResult.Level.Pass, WI.AuditTestCaseResult.Level.Pass, {async: true});
+ InspectorTest.Audit.addObjectTest("Audit.Basic.Async.Object.Pass", {level: WI.AuditTestCaseResult.Level.Pass}, WI.AuditTestCaseResult.Level.Pass, {async: true});
+
+ InspectorTest.Audit.addPromiseTest("Audit.Basic.Timeout.Pass", `setTimeout(resolve, 0, "${WI.AuditTestCaseResult.Level.Pass}")`, WI.AuditTestCaseResult.Level.Pass);
+
+ InspectorTest.Audit.addFunctionlessTest("Audit.Basic.Error.Undefined", undefined, WI.AuditTestCaseResult.Level.Error);
+ InspectorTest.Audit.addFunctionlessTest("Audit.Basic.Error.Null", null, WI.AuditTestCaseResult.Level.Error);
+ InspectorTest.Audit.addFunctionlessTest("Audit.Basic.Error.Number", 42, WI.AuditTestCaseResult.Level.Error);
InspectorTest.Audit.addStringTest("Audit.Basic.Error.String", "foo", WI.AuditTestCaseResult.Level.Error);
InspectorTest.Audit.addObjectTest("Audit.Basic.Error.Object", {}, WI.AuditTestCaseResult.Level.Error);
- InspectorTest.Audit.addTest("Audit.Basic.Error.Variable", "INVALID", WI.AuditTestCaseResult.Level.Error);
+ InspectorTest.Audit.addFunctionlessTest("Audit.Basic.Error.Variable", "INVALID", WI.AuditTestCaseResult.Level.Error);
+ InspectorTest.Audit.addPromiseTest("Audit.Basic.Error.Promise.Resolved", `setTimeout(resolve, 0)`, WI.AuditTestCaseResult.Level.Error);
+ InspectorTest.Audit.addPromiseTest("Audit.Basic.Error.Promise.Rejected", `setTimeout(reject, 0, "rejected")`, WI.AuditTestCaseResult.Level.Error);
suite.runTestCasesAndFinish();
}
Modified: trunk/LayoutTests/inspector/audit/resources/audit-utilities.js (238849 => 238850)
--- trunk/LayoutTests/inspector/audit/resources/audit-utilities.js 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/LayoutTests/inspector/audit/resources/audit-utilities.js 2018-12-04 09:08:42 UTC (rev 238850)
@@ -69,20 +69,24 @@
});
};
- InspectorTest.Audit.addFunctionlessTest = function(name, test, level) {
- InspectorTest.Audit.addTest(name, `function() { return ${test} }`, level, {
+ InspectorTest.Audit.addFunctionlessTest = function(name, test, level, options = {}) {
+ InspectorTest.Audit.addTest(name, (options.async ? "async " : "") + `function() { return ${test} }`, level, {
beforeStart: ` value \`${test}\``,
});
};
- InspectorTest.Audit.addStringTest = function(name, test, level) {
- InspectorTest.Audit.addFunctionlessTest(name, `"${test}"`, level);
+ InspectorTest.Audit.addStringTest = function(name, test, level, options = {}) {
+ InspectorTest.Audit.addFunctionlessTest(name, `"${test}"`, level, options);
};
- InspectorTest.Audit.addObjectTest = function(name, test, level) {
- InspectorTest.Audit.addFunctionlessTest(name, JSON.stringify(test), level);
+ InspectorTest.Audit.addObjectTest = function(name, test, level, options = {}) {
+ InspectorTest.Audit.addFunctionlessTest(name, JSON.stringify(test), level, options);
};
+ InspectorTest.Audit.addPromiseTest = function(name, test, level, options = {}) {
+ InspectorTest.Audit.addFunctionlessTest(name, `new Promise((resolve, reject) => ${test})`, level, options);
+ };
+
InspectorTest.Audit.addDOMSelectorTest = function(name, test, level) {
InspectorTest.Audit.addTest(name, querySelectorTest.format(test), level, {
beforeStart: ` selector \`${test}\``,
Modified: trunk/LayoutTests/inspector/model/auditTestCaseResult-expected.txt (238849 => 238850)
--- trunk/LayoutTests/inspector/model/auditTestCaseResult-expected.txt 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/LayoutTests/inspector/model/auditTestCaseResult-expected.txt 2018-12-04 09:08:42 UTC (rev 238850)
@@ -55,7 +55,8 @@
},
"metadata": {
"startTimestamp": "0001-01-01T00:00:00.000Z",
- "endTimestamp": "0002-01-01T00:00:00.000Z",
+ "asyncTimestamp": "0002-01-01T00:00:00.000Z",
+ "endTimestamp": "0003-01-01T00:00:00.000Z",
"url": "validWithValidSubOptionals test result url"
}
}
Modified: trunk/LayoutTests/inspector/model/auditTestCaseResult.html (238849 => 238850)
--- trunk/LayoutTests/inspector/model/auditTestCaseResult.html 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/LayoutTests/inspector/model/auditTestCaseResult.html 2018-12-04 09:08:42 UTC (rev 238850)
@@ -71,6 +71,7 @@
},
metadata: {
startTimestamp: null,
+ asyncTimestamp: null,
endTimestamp: null,
url: null,
},
@@ -90,7 +91,8 @@
},
metadata: {
startTimestamp: "1",
- endTimestamp: "2",
+ asyncTimestamp: "2",
+ endTimestamp: "3",
url: "validWithValidSubOptionals test result url",
},
},
Modified: trunk/LayoutTests/inspector/model/auditTestGroupResult-expected.txt (238849 => 238850)
--- trunk/LayoutTests/inspector/model/auditTestGroupResult-expected.txt 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/LayoutTests/inspector/model/auditTestGroupResult-expected.txt 2018-12-04 09:08:42 UTC (rev 238850)
@@ -70,7 +70,8 @@
},
"metadata": {
"startTimestamp": "0001-01-01T00:00:00.000Z",
- "endTimestamp": "0002-01-01T00:00:00.000Z",
+ "asyncTimestamp": "0002-01-01T00:00:00.000Z",
+ "endTimestamp": "0003-01-01T00:00:00.000Z",
"url": "validWithValidOptionals test result url"
}
}
@@ -106,7 +107,8 @@
},
"metadata": {
"startTimestamp": "0001-01-01T00:00:00.000Z",
- "endTimestamp": "0002-01-01T00:00:00.000Z",
+ "asyncTimestamp": "0002-01-01T00:00:00.000Z",
+ "endTimestamp": "0003-01-01T00:00:00.000Z",
"url": "validNested nested test result url"
}
}
@@ -129,8 +131,9 @@
]
},
"metadata": {
- "startTimestamp": "0003-01-01T00:00:00.000Z",
- "endTimestamp": "0004-01-01T00:00:00.000Z",
+ "startTimestamp": "0004-01-01T00:00:00.000Z",
+ "asyncTimestamp": "0005-01-01T00:00:00.000Z",
+ "endTimestamp": "0006-01-01T00:00:00.000Z",
"url": "validNested test result url"
}
}
Modified: trunk/LayoutTests/inspector/model/auditTestGroupResult.html (238849 => 238850)
--- trunk/LayoutTests/inspector/model/auditTestGroupResult.html 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/LayoutTests/inspector/model/auditTestGroupResult.html 2018-12-04 09:08:42 UTC (rev 238850)
@@ -107,7 +107,8 @@
},
metadata: {
startTimestamp: "1",
- endTimestamp: "2",
+ asyncTimestamp: "2",
+ endTimestamp: "3",
url: "validWithValidOptionals test result url",
},
},
@@ -138,7 +139,8 @@
},
metadata: {
startTimestamp: "1",
- endTimestamp: "2",
+ asyncTimestamp: "2",
+ endTimestamp: "3",
url: "validNested nested test result url",
},
},
@@ -155,8 +157,9 @@
errors: ["validNested test result error"],
},
metadata: {
- startTimestamp: "3",
- endTimestamp: "4",
+ startTimestamp: "4",
+ asyncTimestamp: "5",
+ endTimestamp: "6",
url: "validNested test result url",
},
},
Added: trunk/LayoutTests/inspector/runtime/awaitPromise-expected.txt (0 => 238850)
--- trunk/LayoutTests/inspector/runtime/awaitPromise-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/runtime/awaitPromise-expected.txt 2018-12-04 09:08:42 UTC (rev 238850)
@@ -0,0 +1,60 @@
+Tests functionality of Runtime.awaitPromise.
+
+
+== Running test suite: Runtime.awaitPromise
+-- Running test case: Runtime.awaitPromise.Resolve.Undefined
+PASS: The resolved value should be undefined
+
+-- Running test case: Runtime.awaitPromise.Resolve.Null
+PASS: The resolved value should be null
+
+-- Running test case: Runtime.awaitPromise.Resolve.Boolean
+PASS: The resolved value should be true
+
+-- Running test case: Runtime.awaitPromise.Resolve.Number
+PASS: The resolved value should be 42
+
+-- Running test case: Runtime.awaitPromise.Resolve.String
+PASS: The resolved value should be "foo"
+
+-- Running test case: Runtime.awaitPromise.Resolve.Array
+PASS: The resolved value should be [0,1]
+
+-- Running test case: Runtime.awaitPromise.Resolve.Object
+PASS: The resolved value should be {"a":1,"b":2}
+
+-- Running test case: Runtime.awaitPromise.Resolve.Chain
+PASS: The resolved value should be 3.
+
+-- Running test case: Runtime.awaitPromise.Reject.Undefined
+PASS: The rejected value should be undefined
+
+-- Running test case: Runtime.awaitPromise.Reject.Null
+PASS: The rejected value should be null
+
+-- Running test case: Runtime.awaitPromise.Reject.Boolean
+PASS: The rejected value should be true
+
+-- Running test case: Runtime.awaitPromise.Reject.Number
+PASS: The rejected value should be 42
+
+-- Running test case: Runtime.awaitPromise.Reject.String
+PASS: The rejected value should be "foo"
+
+-- Running test case: Runtime.awaitPromise.Reject.Array
+PASS: The rejected value should be [0,1]
+
+-- Running test case: Runtime.awaitPromise.Reject.Object
+PASS: The rejected value should be {"a":1,"b":2}
+
+-- Running test case: Runtime.awaitPromise.Reject.Chain
+PASS: The rejected value should be 3.
+
+-- Running test case: Runtime.awaitPromise.Error.NonPromiseObjectId
+PASS: Should produce an error.
+Error: Error: Object with given id is not a Promise
+
+-- Running test case: Runtime.awaitPromise.Error.InvalidPromiseObjectId
+PASS: Should produce an error.
+Error: Could not find InjectedScript for promiseObjectId
+
Added: trunk/LayoutTests/inspector/runtime/awaitPromise.html (0 => 238850)
--- trunk/LayoutTests/inspector/runtime/awaitPromise.html (rev 0)
+++ trunk/LayoutTests/inspector/runtime/awaitPromise.html 2018-12-04 09:08:42 UTC (rev 238850)
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+<script>
+if (window.internals)
+ window.internals.settings.setUnhandledPromiseRejectionToConsoleEnabled(false);
+
+function test()
+{
+ let savedResultCount = 0;
+
+ let suite = InspectorTest.createAsyncSuite("Runtime.awaitPromise");
+
+ function addTest(name, _expression_, options = {}, callback) {
+ suite.addTestCase({
+ name,
+ async test() {
+ let evaluateResponse = await RuntimeAgent.evaluate(_expression_);
+ InspectorTest.assert(evaluateResponse.result.type === "object");
+ InspectorTest.assert(evaluateResponse.result.className === "Promise");
+
+ let awaitPromiseResponse = await RuntimeAgent.awaitPromise(evaluateResponse.result.objectId, options.returnByValue, options.generatePreview, options.saveResult);
+
+ if (!awaitPromiseResponse.wasThrown && options.saveResult)
+ InspectorTest.assert(++savedResultCount === awaitPromiseResponse.savedResultIndex, "savedResultIndex should match.");
+
+ await callback(WI.RemoteObject.fromPayload(awaitPromiseResponse.result), awaitPromiseResponse.wasThrown, awaitPromiseResponse.savedResultIndex);
+ },
+ });
+ }
+
+ function addResolveTest(name, value, options = {}) {
+ let _expression_ = `new Promise((resolve, reject) => setTimeout(resolve, 0, ${JSON.stringify(value)}))`;
+ addTest(name, _expression_, options, async (remoteObject, wasThrown) => {
+ InspectorTest.assert(!wasThrown, "There should be no error.");
+ if (options.returnByValue) {
+ if (value && typeof value === "object")
+ InspectorTest.expectShallowEqual(remoteObject.value, value, "The resolved value should be " + JSON.stringify(value));
+ else
+ InspectorTest.expectEqual(remoteObject.value, value, "The resolved value should be " + JSON.stringify(value));
+ } else {
+ InspectorTest.expectEqual(remoteObject.type, value.type, "The type should be " + value.type);
+ InspectorTest.expectEqual(remoteObject.subtype, value.subtype, "The subtype should be " + value.subtype);
+ InspectorTest.expectEqual(remoteObject.description, value.description, "The description should be " + value.description);
+ }
+ });
+ }
+
+ function addRejectTest(name, value, options = {}) {
+ let _expression_ = `new Promise((resolve, reject) => setTimeout(reject, 0, ${JSON.stringify(value)}))`;
+ addTest(name, _expression_, options, async (remoteObject, wasThrown) => {
+ InspectorTest.assert(wasThrown, "There should be an error.");
+ if (value && typeof value === "object") {
+ let propertyDescriptors = await new Promise((resolve) => remoteObject.getPropertyDescriptorsAsObject(resolve));
+ let properties = Array.isArray(value) ? [] : {};
+ for (let key in value)
+ properties[key] = propertyDescriptors[key].value.value;
+ InspectorTest.expectShallowEqual(properties, value, "The rejected value should be " + JSON.stringify(value));
+ } else
+ InspectorTest.expectEqual(remoteObject.value, value, "The rejected value should be " + JSON.stringify(value));
+ });
+ }
+
+ addResolveTest("Runtime.awaitPromise.Resolve.Undefined", undefined, {returnByValue: true, saveResult: true});
+ addResolveTest("Runtime.awaitPromise.Resolve.Null", null, {returnByValue: true, saveResult: true});
+ addResolveTest("Runtime.awaitPromise.Resolve.Boolean", true, {returnByValue: true, saveResult: true});
+ addResolveTest("Runtime.awaitPromise.Resolve.Number", 42, {returnByValue: true, saveResult: true});
+ addResolveTest("Runtime.awaitPromise.Resolve.String", "foo", {returnByValue: true, saveResult: true});
+ addResolveTest("Runtime.awaitPromise.Resolve.Array", [0, 1], {returnByValue: true, saveResult: true});
+ addResolveTest("Runtime.awaitPromise.Resolve.Object", {a: 1, b: 2}, {returnByValue: true, saveResult: true});
+
+ addTest("Runtime.awaitPromise.Resolve.Chain", `Promise.resolve(1).then(() => 2).then(() => 3)`, {returnByValue: true, saveResult: true}, async (remoteObject, wasThrown) => {
+ InspectorTest.assert(!wasThrown, "There should be no error.");
+ InspectorTest.expectEqual(remoteObject.value, 3, "The resolved value should be 3.");
+ });
+
+ addRejectTest("Runtime.awaitPromise.Reject.Undefined", undefined);
+ addRejectTest("Runtime.awaitPromise.Reject.Null", null);
+ addRejectTest("Runtime.awaitPromise.Reject.Boolean", true);
+ addRejectTest("Runtime.awaitPromise.Reject.Number", 42);
+ addRejectTest("Runtime.awaitPromise.Reject.String", "foo");
+ addRejectTest("Runtime.awaitPromise.Reject.Array", [0, 1]);
+ addRejectTest("Runtime.awaitPromise.Reject.Object", {a: 1, b: 2});
+
+ addTest("Runtime.awaitPromise.Reject.Chain", `Promise.reject(1).catch(() => Promise.reject(2)).catch(() => Promise.reject(3))`, {}, async (remoteObject, wasThrown) => {
+ InspectorTest.assert(wasThrown, "There should be an error.");
+ InspectorTest.expectEqual(remoteObject.value, 3, "The rejected value should be 3.");
+ });
+
+ suite.addTestCase({
+ name: "Runtime.awaitPromise.Error.NonPromiseObjectId",
+ test(resolve, reject) {
+ RuntimeAgent.evaluate("window")
+ .then((response) => RuntimeAgent.awaitPromise(response.result.objectId))
+ .then((response) => {
+ InspectorTest.fail("Should not be able to call awaitPromise for a non-Promise object.");
+ resolve();
+ })
+ .catch((error) => {
+ InspectorTest.expectThat(error, "Should produce an error.");
+ InspectorTest.log("Error: " + error);
+ resolve();
+ });
+ },
+ });
+
+ suite.addTestCase({
+ name: "Runtime.awaitPromise.Error.InvalidPromiseObjectId",
+ test(resolve, reject) {
+ const promiseObjectId = "DOES_NOT_EXIST";
+ RuntimeAgent.awaitPromise(promiseObjectId, (error) => {
+ InspectorTest.expectThat(error, "Should produce an error.");
+ InspectorTest.log("Error: " + error);
+ resolve();
+ });
+ },
+ });
+
+ suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+ <p>Tests functionality of Runtime.awaitPromise.</p>
+</body>
+</html>
Modified: trunk/Source/_javascript_Core/ChangeLog (238849 => 238850)
--- trunk/Source/_javascript_Core/ChangeLog 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/_javascript_Core/ChangeLog 2018-12-04 09:08:42 UTC (rev 238850)
@@ -1,3 +1,43 @@
+2018-12-04 Devin Rousso <drou...@apple.com>
+
+ Web Inspector: Audit: tests should support async operations
+ https://bugs.webkit.org/show_bug.cgi?id=192171
+ <rdar://problem/46423562>
+
+ Reviewed by Joseph Pecoraro.
+
+ Add `awaitPromise` command for executing a callback when a Promise gets settled.
+
+ Drive-by: allow `wasThrown` to be optional, instead of expecting it to always have a value.
+
+ * inspector/protocol/Runtime.json:
+
+ * inspector/InjectedScriptSource.js:
+ (InjectedScript.prototype.awaitPromise): Added.
+
+ * inspector/InjectedScript.h:
+ * inspector/InjectedScript.cpp:
+ (Inspector::InjectedScript::evaluate):
+ (Inspector::InjectedScript::awaitPromise): Added.
+ (Inspector::InjectedScript::callFunctionOn):
+ (Inspector::InjectedScript::evaluateOnCallFrame):
+
+ * inspector/InjectedScriptBase.h:
+ * inspector/InjectedScriptBase.cpp:
+ (Inspector::InjectedScriptBase::makeEvalCall):
+ (Inspector::InjectedScriptBase::makeAsyncCall): Added.
+ (Inspector::InjcetedScriptBase::checkCallResult): Added.
+ (Inspector::InjcetedScriptBase::checkAsyncCallResult): Added.
+
+ * inspector/agents/InspectorRuntimeAgent.h:
+ * inspector/agents/InspectorRuntimeAgent.cpp:
+ (Inspector::InspectorRuntimeAgent::evaluate):
+ (Inspector::InspectorRuntimeAgent::awaitPromise):
+ (Inspector::InspectorRuntimeAgent::callFunctionOn):
+
+ * inspector/agents/InspectorDebuggerAgent.cpp:
+ (Inspector::InspectorDebuggerAgent::evaluateOnCallFrame):
+
2018-12-03 Ryan Haddad <ryanhad...@apple.com>
Unreviewed, rolling out r238833.
Modified: trunk/Source/_javascript_Core/inspector/InjectedScript.cpp (238849 => 238850)
--- trunk/Source/_javascript_Core/inspector/InjectedScript.cpp 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/_javascript_Core/inspector/InjectedScript.cpp 2018-12-04 09:08:42 UTC (rev 238850)
@@ -54,7 +54,7 @@
{
}
-void InjectedScript::evaluate(ErrorString& errorString, const String& _expression_, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, bool& wasThrown, std::optional<int>& savedResultIndex)
+void InjectedScript::evaluate(ErrorString& errorString, const String& _expression_, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& wasThrown, std::optional<int>& savedResultIndex)
{
Deprecated::ScriptFunctionCall function(injectedScriptObject(), "evaluate"_s, inspectorEnvironment()->functionCallHandler());
function.appendArgument(_expression_);
@@ -66,8 +66,18 @@
makeEvalCall(errorString, function, result, wasThrown, savedResultIndex);
}
-void InjectedScript::callFunctionOn(ErrorString& errorString, const String& objectId, const String& _expression_, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<Protocol::Runtime::RemoteObject>& result, bool& wasThrown)
+void InjectedScript::awaitPromise(const String& promiseObjectId, bool returnByValue, bool generatePreview, bool saveResult, AsyncCallCallback&& callback)
{
+ Deprecated::ScriptFunctionCall function(injectedScriptObject(), "awaitPromise"_s, inspectorEnvironment()->functionCallHandler());
+ function.appendArgument(promiseObjectId);
+ function.appendArgument(returnByValue);
+ function.appendArgument(generatePreview);
+ function.appendArgument(saveResult);
+ makeAsyncCall(function, WTFMove(callback));
+}
+
+void InjectedScript::callFunctionOn(ErrorString& errorString, const String& objectId, const String& _expression_, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& wasThrown)
+{
Deprecated::ScriptFunctionCall function(injectedScriptObject(), "callFunctionOn"_s, inspectorEnvironment()->functionCallHandler());
function.appendArgument(objectId);
function.appendArgument(_expression_);
@@ -74,12 +84,13 @@
function.appendArgument(arguments);
function.appendArgument(returnByValue);
function.appendArgument(generatePreview);
-
- std::optional<int> unused;
- makeEvalCall(errorString, function, result, wasThrown, unused);
+
+ std::optional<int> savedResultIndex;
+ makeEvalCall(errorString, function, result, wasThrown, savedResultIndex);
+ ASSERT(!savedResultIndex);
}
-void InjectedScript::evaluateOnCallFrame(ErrorString& errorString, JSC::JSValue callFrames, const String& callFrameId, const String& _expression_, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, bool& wasThrown, std::optional<int>& savedResultIndex)
+void InjectedScript::evaluateOnCallFrame(ErrorString& errorString, JSC::JSValue callFrames, const String& callFrameId, const String& _expression_, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& wasThrown, std::optional<int>& savedResultIndex)
{
Deprecated::ScriptFunctionCall function(injectedScriptObject(), "evaluateOnCallFrame"_s, inspectorEnvironment()->functionCallHandler());
function.appendArgument(callFrames);
Modified: trunk/Source/_javascript_Core/inspector/InjectedScript.h (238849 => 238850)
--- trunk/Source/_javascript_Core/inspector/InjectedScript.h 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/_javascript_Core/inspector/InjectedScript.h 2018-12-04 09:08:42 UTC (rev 238850)
@@ -33,6 +33,7 @@
#include "InjectedScriptBase.h"
#include <wtf/Forward.h>
+#include <wtf/Function.h>
#include <wtf/RefPtr.h>
namespace Deprecated {
@@ -50,9 +51,10 @@
InjectedScript(Deprecated::ScriptObject, InspectorEnvironment*);
virtual ~InjectedScript();
- void evaluate(ErrorString&, const String& _expression_, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, bool& wasThrown, std::optional<int>& savedResultIndex);
- void evaluateOnCallFrame(ErrorString&, JSC::JSValue callFrames, const String& callFrameId, const String& _expression_, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, bool& wasThrown, std::optional<int>& savedResultIndex);
- void callFunctionOn(ErrorString&, const String& objectId, const String& _expression_, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<Protocol::Runtime::RemoteObject>& result, bool& wasThrown);
+ void evaluate(ErrorString&, const String& _expression_, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& wasThrown, std::optional<int>& savedResultIndex);
+ void awaitPromise(const String& promiseObjectId, bool returnByValue, bool generatePreview, bool saveResult, AsyncCallCallback&&);
+ void evaluateOnCallFrame(ErrorString&, JSC::JSValue callFrames, const String& callFrameId, const String& _expression_, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& wasThrown, std::optional<int>& savedResultIndex);
+ void callFunctionOn(ErrorString&, const String& objectId, const String& _expression_, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& wasThrown);
void getFunctionDetails(ErrorString&, const String& functionId, RefPtr<Protocol::Debugger::FunctionDetails>& result);
void functionDetails(ErrorString&, JSC::JSValue, RefPtr<Protocol::Debugger::FunctionDetails>& result);
void getPreview(ErrorString&, const String& objectId, RefPtr<Protocol::Runtime::ObjectPreview>& result);
Modified: trunk/Source/_javascript_Core/inspector/InjectedScriptBase.cpp (238849 => 238850)
--- trunk/Source/_javascript_Core/inspector/InjectedScriptBase.cpp 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/_javascript_Core/inspector/InjectedScriptBase.cpp 2018-12-04 09:08:42 UTC (rev 238850)
@@ -35,6 +35,9 @@
#include "DebuggerEvalEnabler.h"
#include "JSCInlines.h"
#include "JSGlobalObject.h"
+#include "JSLock.h"
+#include "JSNativeStdFunction.h"
+#include "NativeStdFunctionCell.h"
#include "ScriptFunctionCall.h"
#include <wtf/JSONValues.h>
#include <wtf/text/WTFString.h>
@@ -93,9 +96,53 @@
return resultJSONValue.releaseNonNull();
}
-void InjectedScriptBase::makeEvalCall(ErrorString& errorString, Deprecated::ScriptFunctionCall& function, RefPtr<Protocol::Runtime::RemoteObject>& out_resultObject, bool& out_wasThrown, std::optional<int>& out_savedResultIndex)
+void InjectedScriptBase::makeEvalCall(ErrorString& errorString, Deprecated::ScriptFunctionCall& function, RefPtr<Protocol::Runtime::RemoteObject>& out_resultObject, std::optional<bool>& out_wasThrown, std::optional<int>& out_savedResultIndex)
{
- RefPtr<JSON::Value> result = makeCall(function);
+ checkCallResult(errorString, makeCall(function), out_resultObject, out_wasThrown, out_savedResultIndex);
+}
+
+void InjectedScriptBase::makeAsyncCall(Deprecated::ScriptFunctionCall& function, AsyncCallCallback&& callback)
+{
+ if (hasNoValue() || !hasAccessToInspectedScriptState()) {
+ checkAsyncCallResult(JSON::Value::null(), callback);
+ return;
+ }
+
+ auto* scriptState = m_injectedScriptObject.scriptState();
+ JSC::VM& vm = scriptState->vm();
+
+ JSC::JSNativeStdFunction* jsFunction;
+
+ {
+ JSC::JSLockHolder locker(vm);
+
+ jsFunction = JSC::JSNativeStdFunction::create(vm, scriptState->lexicalGlobalObject(), 1, String(), [&, callback = WTFMove(callback)] (JSC::ExecState* exec) {
+ if (!exec)
+ checkAsyncCallResult(JSON::Value::create("Exception while making a call."), callback);
+ if (auto resultJSONValue = toInspectorValue(*exec, exec->argument(0)))
+ checkAsyncCallResult(resultJSONValue, callback);
+ else
+ checkAsyncCallResult(JSON::Value::create(String::format("Object has too long reference chain (must not be longer than %d)", JSON::Value::maxDepth)), callback);
+ return JSC::JSValue::encode(JSC::jsUndefined());
+ });
+ }
+
+ function.appendArgument(JSC::JSValue(jsFunction));
+
+ bool hadException = false;
+ auto resultJSValue = callFunctionWithEvalEnabled(function, hadException);
+ ASSERT_UNUSED(resultJSValue, resultJSValue.isUndefined());
+
+ ASSERT(!hadException);
+ if (hadException) {
+ // Since `callback` is moved above, we can't call it if there's an exception while trying to
+ // execute the `JSNativeStdFunction` inside InjectedScriptSource.js.
+ jsFunction->nativeStdFunctionCell()->function()(nullptr);
+ }
+}
+
+void InjectedScriptBase::checkCallResult(ErrorString& errorString, RefPtr<JSON::Value> result, RefPtr<Protocol::Runtime::RemoteObject>& out_resultObject, std::optional<bool>& out_wasThrown, std::optional<int>& out_savedResultIndex)
+{
if (!result) {
errorString = "Internal error: result value is empty"_s;
return;
@@ -126,12 +173,26 @@
}
out_resultObject = BindingTraits<Protocol::Runtime::RemoteObject>::runtimeCast(resultObject);
- out_wasThrown = wasThrown;
+ if (wasThrown)
+ out_wasThrown = wasThrown;
+
int savedResultIndex;
if (resultTuple->getInteger("savedResultIndex"_s, savedResultIndex))
out_savedResultIndex = savedResultIndex;
}
+void InjectedScriptBase::checkAsyncCallResult(RefPtr<JSON::Value> result, const AsyncCallCallback& callback)
+{
+ ErrorString errorString;
+ RefPtr<Protocol::Runtime::RemoteObject> resultObject;
+ std::optional<bool> wasThrown;
+ std::optional<int> savedResultIndex;
+
+ checkCallResult(errorString, result, resultObject, wasThrown, savedResultIndex);
+
+ callback(errorString, WTFMove(resultObject), wasThrown, savedResultIndex);
+}
+
} // namespace Inspector
Modified: trunk/Source/_javascript_Core/inspector/InjectedScriptBase.h (238849 => 238850)
--- trunk/Source/_javascript_Core/inspector/InjectedScriptBase.h 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/_javascript_Core/inspector/InjectedScriptBase.h 2018-12-04 09:08:42 UTC (rev 238850)
@@ -35,6 +35,7 @@
#include "InspectorProtocolObjects.h"
#include "ScriptObject.h"
#include <wtf/Forward.h>
+#include <wtf/Function.h>
#include <wtf/RefPtr.h>
namespace Deprecated {
@@ -44,6 +45,7 @@
namespace Inspector {
typedef String ErrorString;
+typedef WTF::Function<void(ErrorString&, RefPtr<Protocol::Runtime::RemoteObject>&&, std::optional<bool>&, std::optional<int>&)> AsyncCallCallback;
class JS_EXPORT_PRIVATE InjectedScriptBase {
public:
@@ -64,9 +66,13 @@
const Deprecated::ScriptObject& injectedScriptObject() const;
JSC::JSValue callFunctionWithEvalEnabled(Deprecated::ScriptFunctionCall&, bool& hadException) const;
Ref<JSON::Value> makeCall(Deprecated::ScriptFunctionCall&);
- void makeEvalCall(ErrorString&, Deprecated::ScriptFunctionCall&, RefPtr<Protocol::Runtime::RemoteObject>& resultObject, bool& wasThrown, std::optional<int>& savedResultIndex);
+ void makeEvalCall(ErrorString&, Deprecated::ScriptFunctionCall&, RefPtr<Protocol::Runtime::RemoteObject>& resultObject, std::optional<bool>& wasThrown, std::optional<int>& savedResultIndex);
+ void makeAsyncCall(Deprecated::ScriptFunctionCall&, AsyncCallCallback&&);
private:
+ void checkCallResult(ErrorString&, RefPtr<JSON::Value> result, RefPtr<Protocol::Runtime::RemoteObject>& resultObject, std::optional<bool>& wasThrown, std::optional<int>& savedResultIndex);
+ void checkAsyncCallResult(RefPtr<JSON::Value> result, const AsyncCallCallback&);
+
String m_name;
Deprecated::ScriptObject m_injectedScriptObject;
InspectorEnvironment* m_environment { nullptr };
Modified: trunk/Source/_javascript_Core/inspector/InjectedScriptSource.js (238849 => 238850)
--- trunk/Source/_javascript_Core/inspector/InjectedScriptSource.js 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/_javascript_Core/inspector/InjectedScriptSource.js 2018-12-04 09:08:42 UTC (rev 238850)
@@ -108,6 +108,43 @@
return this._evaluateAndWrap(InjectedScriptHost.evaluateWithScopeExtension, InjectedScriptHost, _expression_, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview, saveResult);
}
+ awaitPromise(promiseObjectId, returnByValue, generatePreview, saveResult, callback)
+ {
+ let parsedPromiseObjectId = this._parseObjectId(promiseObjectId);
+ let promiseObject = this._objectForId(parsedPromiseObjectId);
+ let promiseObjectGroupName = this._idToObjectGroupName[parsedPromiseObjectId.id];
+
+ if (!isDefined(promiseObject)) {
+ callback("Could not find object with given id");
+ return;
+ }
+
+ if (!(promiseObject instanceof Promise)) {
+ callback("Object with given id is not a Promise");
+ return;
+ }
+
+ let resolve = (value) => {
+ let returnObject = {
+ wasThrown: false,
+ result: RemoteObject.create(value, promiseObjectGroupName, returnByValue, generatePreview),
+ };
+
+ if (saveResult) {
+ this._savedResultIndex = 0;
+ this._saveResult(returnObject.result);
+ if (this._savedResultIndex)
+ returnObject.savedResultIndex = this._savedResultIndex;
+ }
+
+ callback(returnObject);
+ };
+ let reject = (reason) => {
+ callback(this._createThrownValue(reason, promiseObjectGroupName));
+ };
+ promiseObject.then(resolve, reject);
+ }
+
evaluateOnCallFrame(topCallFrame, callFrameId, _expression_, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, saveResult)
{
let callFrame = this._callFrameForId(topCallFrame, callFrameId);
Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.cpp (238849 => 238850)
--- trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.cpp 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.cpp 2018-12-04 09:08:42 UTC (rev 238850)
@@ -827,7 +827,7 @@
m_pauseOnAssertionFailures = enabled;
}
-void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString& errorString, const String& callFrameId, const String& _expression_, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& outWasThrown, std::optional<int>& savedResultIndex)
+void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString& errorString, const String& callFrameId, const String& _expression_, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& wasThrown, std::optional<int>& savedResultIndex)
{
if (!m_currentCallStack) {
errorString = "Not paused"_s;
@@ -848,11 +848,9 @@
muteConsole();
}
- bool wasThrown;
injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack.get(), callFrameId, _expression_,
objectGroup ? *objectGroup : emptyString(), includeCommandLineAPI && *includeCommandLineAPI, returnByValue && *returnByValue, generatePreview && *generatePreview, saveResult && *saveResult,
result, wasThrown, savedResultIndex);
- outWasThrown = wasThrown;
if (pauseAndMute) {
unmuteConsole();
Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp (238849 => 238850)
--- trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp 2018-12-04 09:08:42 UTC (rev 238850)
@@ -111,7 +111,7 @@
}
}
-void InspectorRuntimeAgent::evaluate(ErrorString& errorString, const String& _expression_, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& outWasThrown, std::optional<int>& savedResultIndex)
+void InspectorRuntimeAgent::evaluate(ErrorString& errorString, const String& _expression_, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& wasThrown, std::optional<int>& savedResultIndex)
{
InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId);
if (injectedScript.hasNoValue())
@@ -123,9 +123,7 @@
if (asBool(doNotPauseOnExceptionsAndMuteConsole))
muteConsole();
- bool wasThrown;
injectedScript.evaluate(errorString, _expression_, objectGroup ? *objectGroup : String(), asBool(includeCommandLineAPI), asBool(returnByValue), asBool(generatePreview), asBool(saveResult), result, wasThrown, savedResultIndex);
- outWasThrown = wasThrown;
if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
unmuteConsole();
@@ -133,8 +131,24 @@
}
}
-void InspectorRuntimeAgent::callFunctionOn(ErrorString& errorString, const String& objectId, const String& _expression_, const JSON::Array* optionalArguments, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& outWasThrown)
+void InspectorRuntimeAgent::awaitPromise(const String& promiseObjectId, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, Ref<AwaitPromiseCallback>&& callback)
{
+ InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(promiseObjectId);
+ if (injectedScript.hasNoValue()) {
+ callback->sendFailure("Could not find InjectedScript for promiseObjectId"_s);
+ return;
+ }
+
+ injectedScript.awaitPromise(promiseObjectId, asBool(returnByValue), asBool(generatePreview), asBool(saveResult), [callback = WTFMove(callback)] (ErrorString& errorString, RefPtr<Protocol::Runtime::RemoteObject>&& result, std::optional<bool>& wasThrown, std::optional<int>& savedResultIndex) {
+ if (!errorString.isEmpty())
+ callback->sendFailure(errorString);
+ else
+ callback->sendSuccess(WTFMove(result), wasThrown, savedResultIndex);
+ });
+}
+
+void InspectorRuntimeAgent::callFunctionOn(ErrorString& errorString, const String& objectId, const String& _expression_, const JSON::Array* optionalArguments, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& wasThrown)
+{
InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(objectId);
if (injectedScript.hasNoValue()) {
errorString = "Could not find InjectedScript for objectId"_s;
@@ -151,12 +165,8 @@
if (asBool(doNotPauseOnExceptionsAndMuteConsole))
muteConsole();
- bool wasThrown;
-
injectedScript.callFunctionOn(errorString, objectId, _expression_, arguments, asBool(returnByValue), asBool(generatePreview), result, wasThrown);
- outWasThrown = wasThrown;
-
if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
unmuteConsole();
setPauseOnExceptionsState(m_scriptDebugServer, previousPauseOnExceptionsState);
Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.h (238849 => 238850)
--- trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.h 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.h 2018-12-04 09:08:42 UTC (rev 238850)
@@ -59,6 +59,7 @@
void disable(ErrorString&) override { m_enabled = false; }
void parse(ErrorString&, const String& _expression_, Protocol::Runtime::SyntaxErrorType* result, std::optional<String>& message, RefPtr<Protocol::Runtime::ErrorRange>&) final;
void evaluate(ErrorString&, const String& _expression_, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& wasThrown, std::optional<int>& savedResultIndex) final;
+ void awaitPromise(const String& promiseObjectId, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, Ref<AwaitPromiseCallback>&&) final;
void callFunctionOn(ErrorString&, const String& objectId, const String& _expression_, const JSON::Array* optionalArguments, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, RefPtr<Protocol::Runtime::RemoteObject>& result, std::optional<bool>& wasThrown) final;
void releaseObject(ErrorString&, const ErrorString& objectId) final;
void getPreview(ErrorString&, const String& objectId, RefPtr<Protocol::Runtime::ObjectPreview>&) final;
Modified: trunk/Source/_javascript_Core/inspector/protocol/Runtime.json (238849 => 238850)
--- trunk/Source/_javascript_Core/inspector/protocol/Runtime.json 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/_javascript_Core/inspector/protocol/Runtime.json 2018-12-04 09:08:42 UTC (rev 238850)
@@ -226,6 +226,22 @@
]
},
{
+ "name": "awaitPromise",
+ "description": "Calls the async callback when the promise with the given ID gets settled.",
+ "parameters": [
+ { "name": "promiseObjectId", "$ref": "RemoteObjectId", "description": "Identifier of the promise." },
+ { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." },
+ { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." },
+ { "name": "saveResult", "type": "boolean", "optional": true, "description": "Whether the resulting value should be considered for saving in the $n history." }
+ ],
+ "returns": [
+ { "name": "result", "$ref": "RemoteObject", "description": "Evaluation result." },
+ { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." },
+ { "name": "savedResultIndex", "type": "integer", "optional": true, "description": "If the result was saved, this is the $n index that can be used to access the value." }
+ ],
+ "async": true
+ },
+ {
"name": "callFunctionOn",
"description": "Calls function with given declaration on the given object. Object group of the result is inherited from the target object.",
"parameters": [
Modified: trunk/Source/WebCore/ChangeLog (238849 => 238850)
--- trunk/Source/WebCore/ChangeLog 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/WebCore/ChangeLog 2018-12-04 09:08:42 UTC (rev 238850)
@@ -1,3 +1,16 @@
+2018-12-04 Devin Rousso <drou...@apple.com>
+
+ Web Inspector: Audit: tests should support async operations
+ https://bugs.webkit.org/show_bug.cgi?id=192171
+ <rdar://problem/46423562>
+
+ Reviewed by Joseph Pecoraro.
+
+ * page/Settings.yaml:
+ * dom/ScriptExecutionContext.cpp:
+ (ScriptExecutionContext::reportUnhandledPromiseRejection):
+ Add setting for muting the "Unhandled Promise Rejection" console message.
+
2018-12-03 Tim Horton <timothy_hor...@apple.com>
Fix the build
Modified: trunk/Source/WebCore/dom/ScriptExecutionContext.cpp (238849 => 238850)
--- trunk/Source/WebCore/dom/ScriptExecutionContext.cpp 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/WebCore/dom/ScriptExecutionContext.cpp 2018-12-04 09:08:42 UTC (rev 238850)
@@ -39,6 +39,7 @@
#include "JSDOMWindow.h"
#include "MessagePort.h"
#include "Navigator.h"
+#include "Page.h"
#include "PublicURLManager.h"
#include "RejectedPromiseTracker.h"
#include "ResourceRequest.h"
@@ -392,6 +393,14 @@
void ScriptExecutionContext::reportUnhandledPromiseRejection(JSC::ExecState& state, JSC::JSPromise& promise, RefPtr<Inspector::ScriptCallStack>&& callStack)
{
+ Page* page = nullptr;
+ if (is<Document>(this))
+ page = downcast<Document>(this)->page();
+ // FIXME: allow Workers to mute unhandled promise rejection messages.
+
+ if (page && !page->settings().unhandledPromiseRejectionToConsoleEnabled())
+ return;
+
JSC::VM& vm = state.vm();
auto scope = DECLARE_CATCH_SCOPE(vm);
Modified: trunk/Source/WebCore/page/Settings.yaml (238849 => 238850)
--- trunk/Source/WebCore/page/Settings.yaml 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/WebCore/page/Settings.yaml 2018-12-04 09:08:42 UTC (rev 238850)
@@ -224,6 +224,8 @@
initial: false
webGLErrorsToConsoleEnabled:
initial: true
+unhandledPromiseRejectionToConsoleEnabled:
+ initial: true
forceSoftwareWebGLRendering:
initial: false
forceWebGLUsesLowPower:
Modified: trunk/Source/WebInspectorUI/ChangeLog (238849 => 238850)
--- trunk/Source/WebInspectorUI/ChangeLog 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/WebInspectorUI/ChangeLog 2018-12-04 09:08:42 UTC (rev 238850)
@@ -1,3 +1,31 @@
+2018-12-04 Devin Rousso <drou...@apple.com>
+
+ Web Inspector: Audit: tests should support async operations
+ https://bugs.webkit.org/show_bug.cgi?id=192171
+ <rdar://problem/46423562>
+
+ Reviewed by Joseph Pecoraro.
+
+ * UserInterface/Controllers/RuntimeManager.js:
+ (WI.RuntimeManager.supportsAwaitPromise): Added.
+
+ * UserInterface/Models/AuditTestCase.js:
+ (WI.AuditTestCase.prototype.async run.async parseResponse.checkResultProperty.addErrorForValueType): Deleted.
+ (WI.AuditTestCase.prototype.async run.async parseResponse.checkResultProperty): Deleted.
+ (WI.AuditTestCase.prototype.async run.async parseResponse.async resultArrayForEach): Deleted.
+ (WI.AuditTestCase.prototype.async run.async parseResponse): Added.
+ (WI.AuditTestCase.prototype.async run):
+ (WI.AuditTestCase.prototype.async run.checkResultProperty.addErrorForValueType): Deleted.
+ (WI.AuditTestCase.prototype.async run.checkResultProperty): Deleted.
+ (WI.AuditTestCase.prototype.async run.async resultArrayForEach): Deleted.
+
+ * UserInterface/Models/AuditTestCaseResult.js:
+ (WI.AuditTestCaseResult.async fromPayload):
+ (WI.AuditTestCaseResult.prototype.toJSON):
+
+ * UserInterface/Views/AuditTestCaseContentView.js:
+ (WI.AuditTestCaseContentView.prototype.layout):
+
2018-12-03 Devin Rousso <drou...@apple.com>
Web Inspector: Audit: save the expanded state of test groups
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js (238849 => 238850)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js 2018-12-04 09:08:42 UTC (rev 238850)
@@ -34,6 +34,14 @@
WI.Frame.addEventListener(WI.Frame.Event.ExecutionContextsCleared, this._frameExecutionContextsCleared, this);
}
+ // Static
+
+ static supportsAwaitPromise()
+ {
+ // COMPATIBILITY (iOS 12): Runtime.awaitPromise did not exist
+ return !!InspectorBackend.domains.Runtime.awaitPromise;
+ }
+
// Target
initializeTarget(target)
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js (238849 => 238850)
--- trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js 2018-12-04 09:08:42 UTC (rev 238850)
@@ -112,13 +112,9 @@
doNotPauseOnExceptionsAndMuteConsole: true,
};
- try {
- metadata.startTimestamp = new Date;
- let evaluateResponse = await RuntimeAgent.evaluate.invoke(evaluateArguments);
- metadata.endTimestamp = new Date;
-
- let remoteObject = WI.RemoteObject.fromPayload(evaluateResponse.result, WI.mainTarget);
- if (evaluateResponse.wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error"))
+ async function parseResponse(response) {
+ let remoteObject = WI.RemoteObject.fromPayload(response.result, WI.mainTarget);
+ if (response.wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error"))
addError(remoteObject.description);
else if (remoteObject.type === "boolean")
setLevel(remoteObject.value ? WI.AuditTestCaseResult.Level.Pass : WI.AuditTestCaseResult.Level.Fail);
@@ -234,6 +230,27 @@
});
} else
addError(WI.UIString("Return value is not an object, string, or boolean"));
+ }
+
+ try {
+ metadata.startTimestamp = new Date;
+ let response = await RuntimeAgent.evaluate.invoke(evaluateArguments);
+ metadata.endTimestamp = new Date;
+
+ if (response.result.type === "object" && response.result.className === "Promise") {
+ if (WI.RuntimeManager.supportsAwaitPromise()) {
+ metadata.asyncTimestamp = metadata.endTimestamp;
+ response = await RuntimeAgent.awaitPromise(response.result.objectId);
+ metadata.endTimestamp = new Date;
+ } else {
+ response = null;
+ addError(WI.UIString("Async audits are not supported."));
+ setLevel(WI.AuditTestCaseResult.Level.Unsupported);
+ }
+ }
+
+ if (response)
+ await parseResponse(response);
} catch (error) {
metadata.endTimestamp = new Date;
addError(error.message);
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js (238849 => 238850)
--- trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js 2018-12-04 09:08:42 UTC (rev 238850)
@@ -80,6 +80,7 @@
metadata = {};
else {
metadata.startTimestamp = typeof metadata.startTimestamp === "string" ? new Date(metadata.startTimestamp) : null;
+ metadata.asyncTimestamp = typeof metadata.asyncTimestamp === "string" ? new Date(metadata.asyncTimestamp) : null;
metadata.endTimestamp = typeof metadata.endTimestamp === "string" ? new Date(metadata.endTimestamp) : null;
metadata.url = "" metadata.url ="" "string" ? metadata.url : null;
}
@@ -112,6 +113,8 @@
options.metadata = {};
if (metadata.startTimestamp && !isNaN(metadata.startTimestamp))
options.metadata.startTimestamp = metadata.startTimestamp;
+ if (metadata.asyncTimestamp && !isNaN(metadata.asyncTimestamp))
+ options.metadata.asyncTimestamp = metadata.asyncTimestamp;
if (metadata.endTimestamp && !isNaN(metadata.endTimestamp))
options.metadata.endTimestamp = metadata.endTimestamp;
if (metadata.url)
@@ -177,6 +180,8 @@
let metadata = {};
if (this._metadata.startTimestamp && !isNaN(this._metadata.startTimestamp))
metadata.startTimestamp = this._metadata.startTimestamp;
+ if (this._metadata.asyncTimestamp && !isNaN(this._metadata.asyncTimestamp))
+ metadata.asyncTimestamp = this._metadata.asyncTimestamp;
if (this._metadata.endTimestamp && !isNaN(this._metadata.endTimestamp))
metadata.endTimestamp = this._metadata.endTimestamp;
if (this._metadata.url)
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js (238849 => 238850)
--- trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js 2018-12-04 09:00:54 UTC (rev 238849)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js 2018-12-04 09:08:42 UTC (rev 238850)
@@ -104,9 +104,19 @@
timeElement.textContent = metadata.startTimestamp.toLocaleString();
if (metadata.endTimestamp) {
+ let totalDuration = Number.secondsToString((metadata.endTimestamp - metadata.startTimestamp) / 1000);
+
let durationElement = this._metadataElement.appendChild(document.createElement("span"));
durationElement.classList.add("duration");
- durationElement.textContent = Number.secondsToString((metadata.endTimestamp - metadata.startTimestamp) / 1000);
+ durationElement.textContent = totalDuration;
+
+ if (metadata.asyncTimestamp) {
+ let evalDuration = Number.secondsToString((metadata.asyncTimestamp - metadata.startTimestamp) / 1000);
+ let asyncDuration = Number.secondsToString((metadata.endTimestamp - metadata.asyncTimestamp) / 1000);
+
+ durationElement.classList.add("async");
+ durationElement.title = WI.UIString("%s eval\n%s async").format(evalDuration, asyncDuration);
+ }
}
}