Diff
Modified: trunk/LayoutTests/ChangeLog (245913 => 245914)
--- trunk/LayoutTests/ChangeLog 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/LayoutTests/ChangeLog 2019-05-31 00:12:03 UTC (rev 245914)
@@ -1,3 +1,19 @@
+2019-05-30 Devin Rousso <[email protected]>
+
+ Web Inspector: Audit: there should be a default test for WebInspectorAudit.Resources functionality
+ https://bugs.webkit.org/show_bug.cgi?id=196710
+ <rdar://problem/49712348>
+
+ Reviewed by Joseph Pecoraro.
+
+ * inspector/audit/manager-start-setup.html:
+ * inspector/audit/manager-start-setup-expected.txt:
+ * inspector/model/auditTestCase-expected.txt:
+ * inspector/model/auditTestCaseResult-expected.txt:
+ * inspector/model/auditTestGroup-expected.txt:
+ * inspector/unit-tests/object-utilities.html:
+ * inspector/unit-tests/object-utilities-expected.txt:
+
2019-05-30 Andres Gonzalez <[email protected]>
Inserting a newline in contenteditable causes two characters to be added instead of one
Modified: trunk/LayoutTests/inspector/audit/manager-start-setup-expected.txt (245913 => 245914)
--- trunk/LayoutTests/inspector/audit/manager-start-setup-expected.txt 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/LayoutTests/inspector/audit/manager-start-setup-expected.txt 2019-05-31 00:12:03 UTC (rev 245914)
@@ -3,18 +3,18 @@
== Running test suite: AuditManager.prototype.start
-- Running test case: AuditManager.prototype.start.SyncSetup
-PASS: The setup function should have set __test to 42.
+PASS: The setup function should have set test to 42.
-- Running test case: AuditManager.prototype.start.AsyncSetup
-PASS: The setup function should have set __test to 42.
+PASS: The setup function should have set test to 42.
-- Running test case: AuditManager.prototype.start.SubLevelSetup
-PASS: The setup function should have set __test to undefined.
+PASS: The setup function should have set test to undefined.
-- Running test case: AuditManager.prototype.start.OverriddenSetup
-PASS: The setup function should have set __test to B.
+PASS: The setup function should have set test to B.
-- Running test case: AuditManager.prototype.start.MultipleTopLevel
-PASS: The setup function should have set __test to A.
-PASS: The setup function should have set __test to B.
+PASS: The setup function should have set test to A.
+PASS: The setup function should have set test to B.
Modified: trunk/LayoutTests/inspector/audit/manager-start-setup.html (245913 => 245914)
--- trunk/LayoutTests/inspector/audit/manager-start-setup.html 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/LayoutTests/inspector/audit/manager-start-setup.html 2019-05-31 00:12:03 UTC (rev 245914)
@@ -7,11 +7,11 @@
function test()
{
const auditTestString = (function() {
- return {
- level: "pass",
- __test: WebInspectorAudit.__test,
- };
- }).toString();
+ return {
+ level: "pass",
+ test: WebInspectorAudit.test,
+ };
+}).toString();
async function wrapTest(audit, expected, {getResultCallback} = {}) {
WI.auditManager._addTest(audit);
@@ -22,8 +22,11 @@
InspectorTest.assert(result.didPass, "The test should pass.");
InspectorTest.assert(!result.data.errors, "There should be no errors.");
- InspectorTest.expectEqual(result.data.__test.value, expected, `The setup function should have set __test to ${expected}.`);
+ if (result.data.errors)
+ InspectorTest.json(result.data.errors);
+ InspectorTest.expectEqual(result.data.test, expected, `The setup function should have set test to ${expected}.`);
+
WI.auditManager.removeTest(audit);
}
@@ -34,7 +37,7 @@
description: "Check that the setup of an audit is actually run.",
async test() {
const setup = (function() {
- WebInspectorAudit.__test = 42;
+ WebInspectorAudit.test = 42;
}).toString();
let audit = new WI.AuditTestCase("AuditManager.prototype.start.SyncSetup", auditTestString, {setup});
@@ -52,7 +55,7 @@
setTimeout(resolve, 10);
});
- WebInspectorAudit.__test = 42;
+ WebInspectorAudit.test = 42;
}).toString();
let audit = new WI.AuditTestCase("AuditManager.prototype.start.AsyncSetup", auditTestString, {setup});
@@ -66,7 +69,7 @@
description: "Check that the setup of a non-top-level audit is not run.",
async test() {
const setup = (function() {
- WebInspectorAudit.__test = 42;
+ WebInspectorAudit.test = 42;
}).toString();
let audit = new WI.AuditTestGroup("AuditManager.prototype.start.SubLevelSetup.Group", [
@@ -86,15 +89,15 @@
description: "Check that only the setup of top-level audits is run.",
async test() {
const setupA = (function() {
- if (!WebInspectorAudit.__test)
- WebInspectorAudit.__test = "";
- WebInspectorAudit.__test += "A";
+ if (!WebInspectorAudit.test)
+ WebInspectorAudit.test = "";
+ WebInspectorAudit.test += "A";
}).toString();
const setupB = (function() {
- if (!WebInspectorAudit.__test)
- WebInspectorAudit.__test = "";
- WebInspectorAudit.__test += "B";
+ if (!WebInspectorAudit.test)
+ WebInspectorAudit.test = "";
+ WebInspectorAudit.test += "B";
}).toString();
let audit = new WI.AuditTestGroup("AuditManager.prototype.start.OverriddenLevelSetup.Group", [
@@ -114,9 +117,9 @@
description: "Test that a new WebInspectorAudit object is created for each setup call.",
async test() {
const setupA = (function() {
- if (!WebInspectorAudit.__test)
- WebInspectorAudit.__test = "";
- WebInspectorAudit.__test += "A";
+ if (!WebInspectorAudit.test)
+ WebInspectorAudit.test = "";
+ WebInspectorAudit.test += "A";
}).toString();
let auditA = new WI.AuditTestCase("AuditManager.prototype.start.MultipleTopLevel.A", auditTestString, {setup: setupA});
@@ -124,9 +127,9 @@
await wrapTest(auditA, "A");
const setupB = (function() {
- if (!WebInspectorAudit.__test)
- WebInspectorAudit.__test = "";
- WebInspectorAudit.__test += "B";
+ if (!WebInspectorAudit.test)
+ WebInspectorAudit.test = "";
+ WebInspectorAudit.test += "B";
}).toString();
let auditB = new WI.AuditTestCase("AuditManager.prototype.start.MultipleTopLevel.B", auditTestString, {setup: setupB});
Modified: trunk/LayoutTests/inspector/model/auditTestCase-expected.txt (245913 => 245914)
--- trunk/LayoutTests/inspector/model/auditTestCase-expected.txt 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/LayoutTests/inspector/model/auditTestCase-expected.txt 2019-05-31 00:12:03 UTC (rev 245914)
@@ -28,7 +28,7 @@
{
"type": "test-case",
"name": "validWithInvalidOptionals test name",
- "supports": 3,
+ "supports": 4,
"test": "validWithInvalidOptionals test function"
}
@@ -37,7 +37,7 @@
"type": "test-case",
"name": "validWithValidOptionals test name",
"description": "validWithValidOptionals test description",
- "supports": 1,
+ "supports": 2,
"setup": "validWithValidOptionals test setup",
"test": "validWithValidOptionals test function"
}
Modified: trunk/LayoutTests/inspector/model/auditTestCaseResult-expected.txt (245913 => 245914)
--- trunk/LayoutTests/inspector/model/auditTestCaseResult-expected.txt 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/LayoutTests/inspector/model/auditTestCaseResult-expected.txt 2019-05-31 00:12:03 UTC (rev 245914)
@@ -32,6 +32,9 @@
}
-- Running test case: AuditTestCaseResult.fromPayload.validWithInvalidSubOptionals
+WARN: Audit Warning: "validWithInvalidSubOptionals test result name" has a non-array "data.domNodes" value
+WARN: Audit Warning: "validWithInvalidSubOptionals test result name" has a non-array "data.domAttributes" value
+WARN: Audit Warning: "validWithInvalidSubOptionals test result name" has a non-array "data.errors" value
WARN: Audit Warning: "validWithInvalidSubOptionals test result name" has a non-object "metadata.startTimestamp" value
WARN: Audit Warning: "validWithInvalidSubOptionals test result name" has a non-object "metadata.asyncTimestamp" value
WARN: Audit Warning: "validWithInvalidSubOptionals test result name" has a non-object "metadata.endTimestamp" value
Modified: trunk/LayoutTests/inspector/model/auditTestGroup-expected.txt (245913 => 245914)
--- trunk/LayoutTests/inspector/model/auditTestGroup-expected.txt 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/LayoutTests/inspector/model/auditTestGroup-expected.txt 2019-05-31 00:12:03 UTC (rev 245914)
@@ -43,12 +43,12 @@
{
"type": "test-group",
"name": "validWithInvalidOptionals group name",
- "supports": 3,
+ "supports": 4,
"tests": [
{
"type": "test-case",
"name": "validWithInvalidOptionals test name",
- "supports": 4,
+ "supports": 5,
"test": "validWithInvalidOptionals test function"
}
]
@@ -59,7 +59,7 @@
"type": "test-group",
"name": "validWithValidOptionals group name",
"description": "validWithValidOptionals group description",
- "supports": 1,
+ "supports": 2,
"setup": "validWithValidOptionals group setup",
"tests": [
{
@@ -66,7 +66,7 @@
"type": "test-case",
"name": "validWithValidOptionals test name",
"description": "validWithValidOptionals test description",
- "supports": 0,
+ "supports": 1,
"setup": "validWithValidOptionals test setup",
"test": "validWithValidOptionals test function"
}
@@ -78,7 +78,7 @@
"type": "test-group",
"name": "validNested group name",
"description": "validNested group description",
- "supports": 1,
+ "supports": 2,
"setup": "validNested group setup",
"tests": [
{
@@ -85,7 +85,7 @@
"type": "test-group",
"name": "validNested nested group name",
"description": "validNested nested group description",
- "supports": 0,
+ "supports": 1,
"setup": "validNested nested group setup",
"tests": [
{
@@ -92,7 +92,7 @@
"type": "test-case",
"name": "validNested nested test name",
"description": "validNested nested test description",
- "supports": -1,
+ "supports": 0,
"setup": "validNested nested test setup",
"test": "validNested nested test function"
}
@@ -102,7 +102,7 @@
"type": "test-case",
"name": "validNested test name",
"description": "validNested test description",
- "supports": -2,
+ "supports": -1,
"setup": "validNested test setup",
"test": "validNested test function"
}
Modified: trunk/LayoutTests/inspector/unit-tests/object-utilities-expected.txt (245913 => 245914)
--- trunk/LayoutTests/inspector/unit-tests/object-utilities-expected.txt 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/LayoutTests/inspector/unit-tests/object-utilities-expected.txt 2019-05-31 00:12:03 UTC (rev 245914)
@@ -22,3 +22,13 @@
PASS: shallowEqual of objects with different constructors should be false.
PASS: shallowEqual of objects with different constructors should be false.
+-- Running test case: Object.filter
+PASS: filter should remove all entries where the key isn't in ["a","b","c"].
+PASS: filter should remove all entries where the key isn't in ["a"].
+PASS: filter should remove all entries where the key isn't in ["b"].
+PASS: filter should remove all entries where the key isn't in ["c"].
+PASS: filter should remove all entries where the value isn't in [1,2,3].
+PASS: filter should remove all entries where the value isn't in [1].
+PASS: filter should remove all entries where the value isn't in [2].
+PASS: filter should remove all entries where the value isn't in [3].
+
Modified: trunk/LayoutTests/inspector/unit-tests/object-utilities.html (245913 => 245914)
--- trunk/LayoutTests/inspector/unit-tests/object-utilities.html 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/LayoutTests/inspector/unit-tests/object-utilities.html 2019-05-31 00:12:03 UTC (rev 245914)
@@ -51,6 +51,29 @@
}
});
+ suite.addTestCase({
+ name: "Object.filter",
+ test() {
+ const object = {a: 1, b: 2};
+
+ function checkKey(keys, expected) {
+ InspectorTest.expectShallowEqual(Object.filter(object, (key, value) => keys.includes(key)), expected, `filter should remove all entries where the key isn't in ${JSON.stringify(keys)}.`);
+ }
+ checkKey(["a", "b", "c"], {a: 1, b: 2});
+ checkKey(["a"], {a: 1});
+ checkKey(["b"], {b: 2});
+ checkKey(["c"], {});
+
+ function checkValue(values, expected) {
+ InspectorTest.expectShallowEqual(Object.filter(object, (key, value) => values.includes(value)), expected, `filter should remove all entries where the value isn't in ${JSON.stringify(values)}.`);
+ }
+ checkValue([1, 2, 3], {a: 1, b: 2});
+ checkValue([1], {a: 1});
+ checkValue([2], {b: 2});
+ checkValue([3], {});
+ }
+ });
+
suite.runTestCasesAndFinish();
}
</script>
Modified: trunk/Source/_javascript_Core/ChangeLog (245913 => 245914)
--- trunk/Source/_javascript_Core/ChangeLog 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/_javascript_Core/ChangeLog 2019-05-31 00:12:03 UTC (rev 245914)
@@ -1,5 +1,16 @@
2019-05-30 Devin Rousso <[email protected]>
+ Web Inspector: Audit: there should be a default test for WebInspectorAudit.Resources functionality
+ https://bugs.webkit.org/show_bug.cgi?id=196710
+ <rdar://problem/49712348>
+
+ Reviewed by Joseph Pecoraro.
+
+ * inspector/protocol/Audit.json:
+ Increment Audit version.
+
+2019-05-30 Devin Rousso <[email protected]>
+
Web Inspector: Audit: tests are unable to get the current Audit version
https://bugs.webkit.org/show_bug.cgi?id=198270
Modified: trunk/Source/_javascript_Core/inspector/protocol/Audit.json (245913 => 245914)
--- trunk/Source/_javascript_Core/inspector/protocol/Audit.json 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/_javascript_Core/inspector/protocol/Audit.json 2019-05-31 00:12:03 UTC (rev 245914)
@@ -1,7 +1,7 @@
{
"domain": "Audit",
"description": "",
- "version": 2,
+ "version": 3,
"commands": [
{
"name": "setup",
Modified: trunk/Source/WebInspectorUI/ChangeLog (245913 => 245914)
--- trunk/Source/WebInspectorUI/ChangeLog 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/ChangeLog 2019-05-31 00:12:03 UTC (rev 245914)
@@ -1,3 +1,72 @@
+2019-05-30 Devin Rousso <[email protected]>
+
+ Web Inspector: Audit: there should be a default test for WebInspectorAudit.Resources functionality
+ https://bugs.webkit.org/show_bug.cgi?id=196710
+ <rdar://problem/49712348>
+
+ Reviewed by Joseph Pecoraro.
+
+ Previously, there was no way to return data from Audit that wasn't a DOM node, a DOM
+ attribute (which wasn't "shown" anywhere, as it would highlight that attribute on any
+ returned DOM nodes), or an error string.
+
+ In order for Audits to be more flexible with the types of things they test, there needs to
+ be a way for other types of data to be sent back and displayed in the Audit tab.
+
+ This patch makes it so that an Audit result can now contain other keys/values that are all
+ expected to be JSON serializable. It will take all of the non-"special" (e.g. "domNodes" or
+ "errors") keys/values and display them as object trees. This way, any JSON serializable data
+ can be sent with the result and be displayed in the Audit tab.
+
+ * UserInterface/Models/AuditTestBase.js:
+ (WI.AuditTestBase.prototype.async setup):
+ (WI.AuditTestBase.prototype.clearResult):
+ * UserInterface/Models/AuditTestGroup.js:
+ (WI.AuditTestCase.prototype.clearResult):
+ (WI.AuditTestCase.prototype._updateResult):
+ * UserInterface/Models/AuditTestCase.js:
+ (WI.AuditTestCase.prototype.async run):
+ (WI.AuditTestCase.prototype.async run.async parseResponse):
+ (WI.AuditTestCase.prototype.async run.async parseResponse.checkResultProperty):
+ (WI.AuditTestCase.prototype.async run.async parseResponse.checkResultProperty.addErrorForValueType):
+ (WI.AuditTestCase.prototype.async run.async parseResponse.async resultArrayForEach):
+ (WI.AuditTestCase.prototype.async run.async parseResponse.inspectedPage_stringify): Added.
+ Rename `ResultCleared` to `ResultChanged` so that it can (semantically) be used whenever a
+ new result is set in addition to when an existing one is cleared. This is needed so that
+ `AuditTestCaseContentView` will refresh each time the result changes, instead of only in the
+ first `layout()` after the last result was cleared.
+
+ * UserInterface/Models/AuditTestCaseResult.js:
+ (WI.AuditTestCaseResult.async fromPayload):
+ (WI.AuditTestCaseResult.prototype.toJSON):
+ Drive-by: fix the check for optional `data` values to still warn if the value is `null`.
+
+ * UserInterface/Controllers/AuditManager.js:
+ (WI.AuditManager.prototype._addDefaultTests):
+ Add a default test "Demo Audit > Result Data > data-custom" as an example how to write an
+ Audit that returns custom data, as well as how that custom data is shown in the Audit tab.
+
+ * UserInterface/Views/AuditTestContentView.js:
+ (WI.AuditTestContentView.prototype.shown):
+ (WI.AuditTestContentView.prototype.handleResultChanged): Added.
+ * UserInterface/Views/AuditTestCaseContentView.js:
+ (WI.AuditTestCaseContentView):
+ (WI.AuditTestCaseContentView.prototype.layout):
+ (WI.AuditTestCaseContentView.prototype.handleResultChanged): Added.
+ Preserve the UI for each section across `layout()`s, so that expand/collapse states aren't
+ reset each time the user changes the selected Audit.
+
+ * UserInterface/Views/AuditTestCaseContentView.css:
+ (.content-view.audit-test-case > section table > tr > td + td): Added.
+ Drive-by: ensure that the "index" table column is never larger than it needs to be.
+
+ * UserInterface/Views/AuditTreeElement.js:
+ (WI.AuditTreeElement.prototype.onattach):
+ (WI.AuditTreeElement.prototype._handleTestResultChanged): Added.
+ (WI.AuditTreeElement.prototype._handleTestResultCleared): Deleted.
+
+ * Localizations/en.lproj/localizedStrings.js:
+
2019-05-28 Devin Rousso <[email protected]>
Web Inspector: Timelines: spacing around pie chart is different between CPU and Memory
Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (245913 => 245914)
--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2019-05-31 00:12:03 UTC (rev 245914)
@@ -1081,8 +1081,9 @@
localizedStrings["This action causes no visual change"] = "This action causes no visual change";
localizedStrings["This action moves the path outside the visible area"] = "This action moves the path outside the visible area";
localizedStrings["This audit is not supported"] = "This audit is not supported";
+localizedStrings["This is an example of how custom result data is shown."] = "This is an example of how custom result data is shown.";
localizedStrings["This is an example of how errors are shown. The error was thrown manually, but execution errors will appear in the same way."] = "This is an example of how errors are shown. The error was thrown manually, but execution errors will appear in the same way.";
-localizedStrings["This is an example of how result DOM nodes are shown. It will pass with all elements with an id attribute."] = "This is an example of how result DOM nodes are shown. It will pass with all elements with an id attribute.";
+localizedStrings["This is an example of how result DOM attributes are highlighted on any returned DOM nodes. It will pass with all elements with an id attribute."] = "This is an example of how result DOM attributes are highlighted on any returned DOM nodes. It will pass with all elements with an id attribute.";
localizedStrings["This is an example of how result DOM nodes are shown. It will pass with the <body> element."] = "This is an example of how result DOM nodes are shown. It will pass with the <body> element.";
localizedStrings["This is what the result of a failing test with no data looks like."] = "This is what the result of a failing test with no data looks like.";
localizedStrings["This is what the result of a passing test with no data looks like."] = "This is what the result of a passing test with no data looks like.";
@@ -1204,6 +1205,7 @@
localizedStrings["\u0022%s\u0022 has a non-object \u0022%s\u0022 value"] = "\u0022%s\u0022 has a non-object \u0022%s\u0022 value";
localizedStrings["\u0022%s\u0022 has a non-string \u0022%s\u0022 value"] = "\u0022%s\u0022 has a non-string \u0022%s\u0022 value";
localizedStrings["\u0022%s\u0022 has an invalid \u0022%s\u0022 value"] = "\u0022%s\u0022 has an invalid \u0022%s\u0022 value";
+localizedStrings["\u0022%s\u0022 is not JSON serializable"] = "\u0022%s\u0022 is not JSON serializable";
localizedStrings["\u0022%s\u0022 is not valid for %s"] = "\u0022%s\u0022 is not valid for %s";
localizedStrings["\u0022%s\u0022 is too new to run in this Web Inspector"] = "\u0022%s\u0022 is too new to run in this Web Inspector";
localizedStrings["\u0022%s\u0022 is too new to run on this inspected page"] = "\u0022%s\u0022 is too new to run on this inspected page";
Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js (245913 => 245914)
--- trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js 2019-05-31 00:12:03 UTC (rev 245914)
@@ -80,6 +80,19 @@
}
});
+Object.defineProperty(Object, "filter",
+{
+ value(object, callback)
+ {
+ let filtered = {};
+ for (let key in object) {
+ if (callback(key, object[key]))
+ filtered[key] = object[key];
+ }
+ return filtered;
+ }
+});
+
Object.defineProperty(Object.prototype, "valueForCaseInsensitiveKey",
{
value(key)
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/AuditManager.js (245913 => 245914)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/AuditManager.js 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/AuditManager.js 2019-05-31 00:12:03 UTC (rev 245914)
@@ -891,8 +891,9 @@
], {description: WI.UIString("These are all of the different test result levels.")}),
new WI.AuditTestGroup(WI.UIString("Result Data"), [
new WI.AuditTestCase(`data-domNodes`, `function() { return {domNodes: [document.body], level: "pass"}; }`, {description: WI.UIString("This is an example of how result DOM nodes are shown. It will pass with the <body> element.")}),
- new WI.AuditTestCase(`data-domAttributes`, `function() { return {domNodes: Array.from(document.querySelectorAll("[id]")), domAttributes: ["id"], level: "pass"}; }`, {description: WI.UIString("This is an example of how result DOM nodes are shown. It will pass with all elements with an id attribute.")}),
+ new WI.AuditTestCase(`data-domAttributes`, `function() { return {domNodes: Array.from(document.querySelectorAll("[id]")), domAttributes: ["id"], level: "pass"}; }`, {description: WI.UIString("This is an example of how result DOM attributes are highlighted on any returned DOM nodes. It will pass with all elements with an id attribute.")}),
new WI.AuditTestCase(`data-errors`, `function() { throw Error("this error was thrown from inside the audit test code."); }`, {description: WI.UIString("This is an example of how errors are shown. The error was thrown manually, but execution errors will appear in the same way.")}),
+ new WI.AuditTestCase(`data-custom`, `function() { return {level: "pass", a: 1, b: [2], c: {key: 3}}; }`, {description: WI.UIString("This is an example of how custom result data is shown.")}),
], {description: WI.UIString("These are all of the different types of data that can be returned with the test result.")}),
], {description: WI.UIString("These tests serve as a demonstration of the functionality and structure of audits.")}),
new WI.AuditTestGroup(WI.UIString("Accessibility"), [
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestBase.js (245913 => 245914)
--- trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestBase.js 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestBase.js 2019-05-31 00:12:03 UTC (rev 245914)
@@ -116,7 +116,7 @@
} else {
agentCommandFunction = RuntimeAgent.evaluate;
agentCommandArguments._expression_ = `(function() { "use strict"; return eval(\`(${this._setup.replace(/`/g, "\\`")})\`)(); })()`;
- agentCommandArguments.objectGroup = "audit";
+ agentCommandArguments.objectGroup = AuditTestBase.ObjectGroup;
agentCommandArguments.doNotPauseOnExceptionsAndMuteConsole = true;
}
@@ -191,8 +191,8 @@
this._result = null;
- if (!options.suppressResultClearedEvent)
- this.dispatchEventToListeners(WI.AuditTestBase.Event.ResultCleared);
+ if (!options.suppressResultChangedEvent)
+ this.dispatchEventToListeners(WI.AuditTestBase.Event.ResultChanged);
return true;
}
@@ -228,13 +228,15 @@
};
// Keep this in sync with Inspector::Protocol::Audit::VERSION.
-WI.AuditTestBase.Version = 2;
+WI.AuditTestBase.Version = 3;
+WI.AuditTestBase.ObjectGroup = "audit";
+
WI.AuditTestBase.Event = {
Completed: "audit-test-base-completed",
DisabledChanged: "audit-test-base-disabled-changed",
Progress: "audit-test-base-progress",
- ResultCleared: "audit-test-base-result-cleared",
+ ResultChanged: "audit-test-base-result-changed",
Scheduled: "audit-test-base-scheduled",
Stopping: "audit-test-base-stopping",
};
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js (245913 => 245914)
--- trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js 2019-05-31 00:12:03 UTC (rev 245914)
@@ -126,125 +126,173 @@
async function parseResponse(response) {
let remoteObject = WI.RemoteObject.fromPayload(response.result, WI.mainTarget);
- if (response.wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error"))
+ if (response.wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error")) {
addError(remoteObject.description);
- else if (remoteObject.type === "boolean")
+ return;
+ }
+
+ if (remoteObject.type === "boolean") {
setLevel(remoteObject.value ? WI.AuditTestCaseResult.Level.Pass : WI.AuditTestCaseResult.Level.Fail);
- else if (remoteObject.type === "string")
+ return;
+ }
+
+ if (remoteObject.type === "string") {
setLevel(remoteObject.value.trim().toLowerCase());
- else if (remoteObject.type === "object" && !remoteObject.subtype) {
- const options = {
- ownProperties: true,
- };
+ return;
+ }
- let properties = await new Promise((resolve, reject) => remoteObject.getPropertyDescriptorsAsObject(resolve, options));
+ if (remoteObject.type !== "object" || remoteObject.subtype) {
+ addError(WI.UIString("Return value is not an object, string, or boolean"));
+ return;
+ }
- function checkResultProperty(key, type, subtype) {
- if (!(key in properties))
- return null;
+ const options = {
+ ownProperties: true,
+ };
- let property = properties[key].value;
- if (!property)
- return null;
+ function checkResultProperty(key, value, type, subtype) {
+ function addErrorForValueType(valueType) {
+ let errorString = null;
+ if (valueType === "object" || valueType === "array")
+ errorString = WI.UIString("\u0022%s\u0022 must be an %s");
+ else
+ errorString = WI.UIString("\u0022%s\u0022 must be a %s");
+ addError(errorString.format(key, valueType));
+ }
- function addErrorForValueType(valueType) {
- let value = null;
- if (valueType === "object" || valueType === "array")
- value = WI.UIString("\u0022%s\u0022 must be an %s");
- else
- value = WI.UIString("\u0022%s\u0022 must be a %s");
- addError(value.format(key, valueType));
- }
+ if (value.subtype !== subtype) {
+ addErrorForValueType(subtype);
+ return null;
+ }
- if (property.subtype !== subtype) {
- addErrorForValueType(subtype);
- return null;
- }
+ if (value.type !== type) {
+ addErrorForValueType(type);
+ return null;
+ }
- if (property.type !== type) {
- addErrorForValueType(type);
- return null;
- }
+ if (type === "boolean" || type === "string")
+ return value.value;
- if (type === "boolean" || type === "string")
- return property.value;
+ return value;
+ }
- return property;
+ async function resultArrayForEach(key, value, callback) {
+ let array = checkResultProperty(key, value, "object", "array");
+ if (!array)
+ return;
+
+ // `getPropertyDescriptorsAsObject` returns an object, meaning that if we
+ // want to iterate over `array` by index, we have to count.
+ let asObject = await new Promise((resolve, reject) => array.getPropertyDescriptorsAsObject(resolve, options));
+ for (let i = 0; i < array.size; ++i) {
+ if (i in asObject)
+ await callback(asObject[i]);
}
+ }
- async function resultArrayForEach(key, callback) {
- let array = checkResultProperty(key, "object", "array");
- if (!array)
- return;
+ let properties = await new Promise((resolve, reject) => remoteObject.getPropertyDescriptors(resolve, options));
+ for (let property of properties) {
+ let key = property.name;
+ if (key === "__proto__")
+ continue;
- // `getPropertyDescriptorsAsObject` returns an object, meaning that if we
- // want to iterate over `array` by index, we have to count.
- let asObject = await new Promise((resolve, reject) => array.getPropertyDescriptorsAsObject(resolve, options));
- for (let i = 0; i < array.size; ++i) {
- if (i in asObject)
- await callback(asObject[i]);
- }
+ let value = property.value;
+
+ switch (key) {
+ case "level": {
+ let levelString = checkResultProperty(key, value, "string");
+ if (levelString)
+ setLevel(levelString.trim().toLowerCase());
+ break;
}
- let levelString = checkResultProperty("level", "string");
- if (levelString)
- setLevel(levelString.trim().toLowerCase());
+ case "pass":
+ if (checkResultProperty(key, value, "boolean"))
+ setLevel(WI.AuditTestCaseResult.Level.Pass);
+ break;
- if (checkResultProperty("pass", "boolean"))
- setLevel(WI.AuditTestCaseResult.Level.Pass);
- if (checkResultProperty("warn", "boolean"))
- setLevel(WI.AuditTestCaseResult.Level.Warn);
- if (checkResultProperty("fail", "boolean"))
- setLevel(WI.AuditTestCaseResult.Level.Fail);
- if (checkResultProperty("error", "boolean"))
- setLevel(WI.AuditTestCaseResult.Level.Error);
- if (checkResultProperty("unsupported", "boolean"))
- setLevel(WI.AuditTestCaseResult.Level.Unsupported);
+ case "warn":
+ if (checkResultProperty(key, value, "boolean"))
+ setLevel(WI.AuditTestCaseResult.Level.Warn);
+ break;
- await resultArrayForEach("domNodes", async (item) => {
- if (!item || !item.value || item.value.type !== "object" || item.value.subtype !== "node") {
- addError(WI.UIString("All items in \u0022%s\u0022 must be valid DOM nodes").format(WI.unlocalizedString("domNodes")));
- return;
- }
+ case "fail":
+ if (checkResultProperty(key, value, "boolean"))
+ setLevel(WI.AuditTestCaseResult.Level.Fail);
+ break;
- let domNodeId = await new Promise((resolve, reject) => item.value.pushNodeToFrontend(resolve));
- let domNode = WI.domManager.nodeForId(domNodeId);
- if (!domNode)
- return;
+ case "error":
+ if (checkResultProperty(key, value, "boolean"))
+ setLevel(WI.AuditTestCaseResult.Level.Error);
+ break;
- if (!data.domNodes)
- data.domNodes = [];
- data.domNodes.push(WI.cssPath(domNode, {full: true}));
+ case "unsupported":
+ if (checkResultProperty(key, value, "boolean"))
+ setLevel(WI.AuditTestCaseResult.Level.Unsupported);
+ break;
- if (!resolvedDOMNodes)
- resolvedDOMNodes = [];
- resolvedDOMNodes.push(domNode);
- });
+ case "domNodes":
+ await resultArrayForEach(key, value, async (item) => {
+ if (!item || !item.value || item.value.type !== "object" || item.value.subtype !== "node") {
+ addError(WI.UIString("All items in \u0022%s\u0022 must be valid DOM nodes").format(WI.unlocalizedString("domNodes")));
+ return;
+ }
- await resultArrayForEach("domAttributes", (item) => {
- if (!item || !item.value || item.value.type !== "string" || !item.value.value.length) {
- addError(WI.UIString("All items in \u0022%s\u0022 must be non-empty strings").format(WI.unlocalizedString("domAttributes")));
- return;
- }
+ let domNodeId = await new Promise((resolve, reject) => item.value.pushNodeToFrontend(resolve));
+ let domNode = WI.domManager.nodeForId(domNodeId);
+ if (!domNode)
+ return;
- if (!data.domAttributes)
- data.domAttributes = [];
- data.domAttributes.push(item.value.value);
- });
+ if (!data.domNodes)
+ data.domNodes = [];
+ data.domNodes.push(WI.cssPath(domNode, {full: true}));
- await resultArrayForEach("errors", (item) => {
- if (!item || !item.value || item.value.type !== "object" || item.value.subtype !== "error") {
- addError(WI.UIString("All items in \u0022%s\u0022 must be error objects").format(WI.unlocalizedString("errors")));
- return;
- }
+ if (!resolvedDOMNodes)
+ resolvedDOMNodes = [];
+ resolvedDOMNodes.push(domNode);
+ });
+ break;
- addError(item.value.description);
- });
+ case "domAttributes":
+ await resultArrayForEach(key, value, (item) => {
+ if (!item || !item.value || item.value.type !== "string" || !item.value.value.length) {
+ addError(WI.UIString("All items in \u0022%s\u0022 must be non-empty strings").format(WI.unlocalizedString("domAttributes")));
+ return;
+ }
- if (window.InspectorTest && properties.__test)
- data.__test = properties.__test.value;
- } else
- addError(WI.UIString("Return value is not an object, string, or boolean"));
+ if (!data.domAttributes)
+ data.domAttributes = [];
+ data.domAttributes.push(item.value.value);
+ });
+ break;
+
+ case "errors":
+ await resultArrayForEach(key, value, (item) => {
+ if (!item || !item.value || item.value.type !== "object" || item.value.subtype !== "error") {
+ addError(WI.UIString("All items in \u0022%s\u0022 must be error objects").format(WI.unlocalizedString("errors")));
+ return;
+ }
+
+ addError(item.value.description);
+ });
+ break;
+
+ default:
+ if (value.objectId) {
+ try {
+ function inspectedPage_stringify() {
+ return JSON.stringify(this);
+ }
+ let stringifiedValue = await value.callFunction(inspectedPage_stringify);
+ data[key] = JSON.parse(stringifiedValue.value);
+ } catch {
+ addError(WI.UIString("\u0022%s\u0022 is not JSON serializable").format(key));
+ }
+ } else
+ data[key] = value.value;
+ break;
+ }
+ }
}
let agentCommandFunction = null;
@@ -255,7 +303,7 @@
} else {
agentCommandFunction = RuntimeAgent.evaluate;
agentCommandArguments._expression_ = `(function() { "use strict"; return eval(\`(${this._test.replace(/`/g, "\\`")})\`)(); })()`;
- agentCommandArguments.objectGroup = "audit";
+ agentCommandArguments.objectGroup = WI.AuditTestCase.ObjectGroup;
agentCommandArguments.doNotPauseOnExceptionsAndMuteConsole = true;
}
@@ -295,6 +343,8 @@
if (resolvedDOMNodes)
options.resolvedDOMNodes = resolvedDOMNodes;
this._result = new WI.AuditTestCaseResult(this.name, level, options);
+
+ this.dispatchEventToListeners(WI.AuditTestBase.Event.ResultChanged);
}
};
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js (245913 => 245914)
--- trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js 2019-05-31 00:12:03 UTC (rev 245914)
@@ -67,7 +67,7 @@
payload.data = ""
} else {
function checkArray(key) {
- if (!payload.data[key])
+ if (!(key in payload.data))
return;
if (!Array.isArray(payload.data[key])) {
@@ -132,24 +132,27 @@
if (!isEmptyObject(payload.data)) {
options.data = ""
- if (payload.data.domNodes && payload.data.domNodes.length) {
- if (window.DOMAgent && (!payload.metadata.url || payload.metadata.url ="" WI.networkManager.mainFrame.url)) {
- let documentNode = await new Promise((resolve) => WI.domManager.requestDocument(resolve));
- options.resolvedDOMNodes = await Promise.all(payload.data.domNodes.map(async (domNodeString) => {
- let nodeId = 0;
- try {
- nodeId = await WI.domManager.querySelector(documentNode, domNodeString);
- } catch { }
- return WI.domManager.nodeForId(nodeId) || null;
- }));
+ for (let key in payload.data) {
+ if (key === "domNodes" || key === "domAttributes" || key === "errors") {
+ if (!payload.data[key].length)
+ continue;
}
- options.data.domNodes = payload.data.domNodes;
+ if (key === "domNodes") {
+ if (window.DOMAgent && (!payload.metadata.url || payload.metadata.url ="" WI.networkManager.mainFrame.url)) {
+ let documentNode = await new Promise((resolve) => WI.domManager.requestDocument(resolve));
+ options.resolvedDOMNodes = await Promise.all(payload.data.domNodes.map(async (domNodeString) => {
+ let nodeId = 0;
+ try {
+ nodeId = await WI.domManager.querySelector(documentNode, domNodeString);
+ } catch { }
+ return WI.domManager.nodeForId(nodeId) || null;
+ }));
+ }
+ }
+
+ options.data[key] = payload.data[key];
}
- if (payload.data.domAttributes && payload.data.domAttributes.length)
- options.data.domAttributes = payload.data.domAttributes;
- if (payload.data.errors && payload.data.errors.length)
- options.data.errors = payload.data.errors;
}
if (!isEmptyObject(payload.metadata)) {
@@ -210,13 +213,14 @@
json.level = this._level;
let data = ""
- if (this._data.domNodes && this._data.domNodes.length) {
- data.domNodes = this._data.domNodes;
- if (this._data.domAttributes && this._data.domAttributes.length)
- data.domAttributes = this._data.domAttributes;
+ for (let key in this._data) {
+ if (key === "domNodes" || key === "domAttributes" || key === "errors") {
+ if (!this._data[key].length)
+ continue;
+ }
+
+ data[key] = this._data[key];
}
- if (this._data.errors && this._data.errors.length)
- data.errors = this._data.errors;
if (!isEmptyObject(data))
json.data = ""
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestGroup.js (245913 => 245914)
--- trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestGroup.js 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestGroup.js 2019-05-31 00:12:03 UTC (rev 245914)
@@ -169,7 +169,7 @@
return super.clearResult({
...options,
- suppressResultClearedEvent: !cleared,
+ suppressResultChangedEvent: !cleared,
});
}
@@ -210,6 +210,8 @@
this._result = new WI.AuditTestGroupResult(this.name, results, {
description: this.description,
});
+
+ this.dispatchEventToListeners(WI.AuditTestBase.Event.ResultChanged);
}
_handleTestCompleted(event)
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css (245913 => 245914)
--- trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css 2019-05-31 00:12:03 UTC (rev 245914)
@@ -127,6 +127,10 @@
top: -1px;
}
+.content-view.audit-test-case > section table > tr > td + td {
+ width: 100%;
+}
+
.content-view.audit-test-case > section .CodeMirror {
width: 100%;
height: auto;
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js (245913 => 245914)
--- trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js 2019-05-31 00:12:03 UTC (rev 245914)
@@ -32,6 +32,10 @@
super(representedObject);
this.element.classList.add("audit-test-case");
+
+ this._resultDataGeneralContainer = null;
+ this._resultDataDOMNodesContainer = null;
+ this._resultDataErrorsContainer = null;
}
// Protected
@@ -133,14 +137,52 @@
let resultData = result.data;
- if (resultData.domNodes && resultData.domNodes.length) {
- let domNodesContainer = this.contentView.element.appendChild(document.createElement("div"));
- domNodesContainer.classList.add("dom-nodes");
+ if (!this._resultDataGeneralContainer) {
+ let nonSpecialData = Object.filter(resultData, (key) => key !== "domNodes" && key !== "errors");
+ if (!isEmptyObject(nonSpecialData)) {
+ this._resultDataGeneralContainer = document.createElement("div");
- let domNodeText = domNodesContainer.appendChild(document.createElement("h1"));
+ let _expression_ = "(" + JSON.stringify(nonSpecialData) + ")";
+ const options = {
+ objectGroup: WI.AuditTestBase.ObjectGroup,
+ doNotPauseOnExceptionsAndMuteConsole: true,
+ };
+ WI.runtimeManager.evaluateInInspectedWindow(_expression_, options, (nonSpecialDataRemoteObject, wasThrown) => {
+ console.assert(!wasThrown);
+ if (!nonSpecialDataRemoteObject)
+ return;
+
+ if (!this.representedObject.result || this.representedObject.result.data !== resultData)
+ return;
+
+ const propertyPath = null;
+ const forceExpanding = true;
+ let element = WI.FormattedValue.createObjectTreeOrFormattedValueForRemoteObject(nonSpecialDataRemoteObject, propertyPath, forceExpanding);
+
+ let objectTree = element.__objectTree;
+ if (objectTree) {
+ objectTree.showOnlyProperties();
+ objectTree.expand();
+ }
+
+ this._resultDataGeneralContainer.appendChild(element);
+
+ this.hidePlaceholder();
+ });
+ }
+ }
+
+ if (this._resultDataGeneralContainer)
+ this.contentView.element.appendChild(this._resultDataGeneralContainer);
+
+ if (!this._resultDataDOMNodesContainer && resultData.domNodes && resultData.domNodes.length) {
+ this._resultDataDOMNodesContainer = document.createElement("div");
+ this._resultDataDOMNodesContainer.classList.add("dom-nodes");
+
+ let domNodeText = this._resultDataDOMNodesContainer.appendChild(document.createElement("h1"));
domNodeText.textContent = WI.UIString("DOM Nodes:");
- let tableContainer = domNodesContainer.appendChild(document.createElement("table"));
+ let tableContainer = this._resultDataDOMNodesContainer.appendChild(document.createElement("table"));
resultData.domNodes.forEach((domNode, index) => {
domNode = result.resolvedDOMNodes[index] || domNode;
@@ -204,14 +246,17 @@
});
}
- if (resultData.errors && resultData.errors.length) {
- let errorContainer = this.contentView.element.appendChild(document.createElement("div"));
- errorContainer.classList.add("errors");
+ if (this._resultDataDOMNodesContainer)
+ this.contentView.element.appendChild(this._resultDataDOMNodesContainer);
- let errorText = errorContainer.appendChild(document.createElement("h1"));
+ if (!this._resultDataErrorsContainer && resultData.errors && resultData.errors.length) {
+ this._resultDataErrorsContainer = document.createElement("div");
+ this._resultDataErrorsContainer.classList.add("errors");
+
+ let errorText = this._resultDataErrorsContainer.appendChild(document.createElement("h1"));
errorText.textContent = WI.UIString("Errors:");
- let tableContainer = errorContainer.appendChild(document.createElement("table"));
+ let tableContainer = this._resultDataErrorsContainer.appendChild(document.createElement("table"));
resultData.errors.forEach((error, index) => {
let rowElement = tableContainer.appendChild(document.createElement("tr"));
@@ -227,10 +272,22 @@
});
}
+ if (this._resultDataErrorsContainer)
+ this.contentView.element.appendChild(this._resultDataErrorsContainer);
+
if (!this.contentView.element.children.length)
this.showNoResultDataPlaceholder();
}
+ handleResultChanged(event)
+ {
+ super.handleResultChanged(event);
+
+ this._resultDataGeneralContainer = null;
+ this._resultDataDOMNodesContainer = null;
+ this._resultDataErrorsContainer = null;
+ }
+
showRunningPlaceholder()
{
if (!this.placeholderElement || !this.placeholderElement.__placeholderRunning) {
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestContentView.js (245913 => 245914)
--- trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestContentView.js 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestContentView.js 2019-05-31 00:12:03 UTC (rev 245914)
@@ -102,7 +102,7 @@
if (this.representedObject instanceof WI.AuditTestBase) {
this.representedObject.addEventListener(WI.AuditTestBase.Event.Completed, this._handleTestChanged, this);
this.representedObject.addEventListener(WI.AuditTestBase.Event.Progress, this._handleTestChanged, this);
- this.representedObject.addEventListener(WI.AuditTestBase.Event.ResultCleared, this._handleTestChanged, this);
+ this.representedObject.addEventListener(WI.AuditTestBase.Event.ResultChanged, this.handleResultChanged, this);
this.representedObject.addEventListener(WI.AuditTestBase.Event.Scheduled, this._handleTestChanged, this);
this.representedObject.addEventListener(WI.AuditTestBase.Event.Stopping, this._handleTestChanged, this);
}
@@ -116,6 +116,13 @@
super.hidden();
}
+ handleResultChanged(event)
+ {
+ // Overridden by sub-classes.
+
+ this.needsLayout();
+ }
+
get placeholderElement()
{
return this._placeholderElement;
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/AuditTreeElement.js (245913 => 245914)
--- trunk/Source/WebInspectorUI/UserInterface/Views/AuditTreeElement.js 2019-05-31 00:08:04 UTC (rev 245913)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/AuditTreeElement.js 2019-05-31 00:12:03 UTC (rev 245914)
@@ -62,7 +62,7 @@
if (this.representedObject instanceof WI.AuditTestBase) {
this.representedObject.addEventListener(WI.AuditTestBase.Event.DisabledChanged, this._handleTestDisabledChanged, this);
- this.representedObject.addEventListener(WI.AuditTestBase.Event.ResultCleared, this._handleTestResultCleared, this);
+ this.representedObject.addEventListener(WI.AuditTestBase.Event.ResultChanged, this._handleTestResultChanged, this);
if (this.representedObject instanceof WI.AuditTestCase)
this.representedObject.addEventListener(WI.AuditTestBase.Event.Scheduled, this._handleTestCaseScheduled, this);
@@ -281,7 +281,7 @@
this._updateTestGroupDisabled();
}
- _handleTestResultCleared(event)
+ _handleTestResultChanged(event)
{
this._updateStatus();
}