Changeset 245914 in webkit
- Timestamp:
- May 30, 2019, 5:12:03 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 22 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/inspector/audit/manager-start-setup-expected.txt (modified) (1 diff)
-
LayoutTests/inspector/audit/manager-start-setup.html (modified) (8 diffs)
-
LayoutTests/inspector/model/auditTestCase-expected.txt (modified) (2 diffs)
-
LayoutTests/inspector/model/auditTestCaseResult-expected.txt (modified) (1 diff)
-
LayoutTests/inspector/model/auditTestGroup-expected.txt (modified) (7 diffs)
-
LayoutTests/inspector/unit-tests/object-utilities-expected.txt (modified) (1 diff)
-
LayoutTests/inspector/unit-tests/object-utilities.html (modified) (1 diff)
-
Source/JavaScriptCore/ChangeLog (modified) (1 diff)
-
Source/JavaScriptCore/inspector/protocol/Audit.json (modified) (1 diff)
-
Source/WebInspectorUI/ChangeLog (modified) (1 diff)
-
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (modified) (2 diffs)
-
Source/WebInspectorUI/UserInterface/Base/Utilities.js (modified) (1 diff)
-
Source/WebInspectorUI/UserInterface/Controllers/AuditManager.js (modified) (1 diff)
-
Source/WebInspectorUI/UserInterface/Models/AuditTestBase.js (modified) (4 diffs)
-
Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js (modified) (3 diffs)
-
Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js (modified) (3 diffs)
-
Source/WebInspectorUI/UserInterface/Models/AuditTestGroup.js (modified) (2 diffs)
-
Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css (modified) (1 diff)
-
Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js (modified) (4 diffs)
-
Source/WebInspectorUI/UserInterface/Views/AuditTestContentView.js (modified) (2 diffs)
-
Source/WebInspectorUI/UserInterface/Views/AuditTreeElement.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r245912 r245914 1 2019-05-30 Devin Rousso <drousso@apple.com> 2 3 Web Inspector: Audit: there should be a default test for WebInspectorAudit.Resources functionality 4 https://bugs.webkit.org/show_bug.cgi?id=196710 5 <rdar://problem/49712348> 6 7 Reviewed by Joseph Pecoraro. 8 9 * inspector/audit/manager-start-setup.html: 10 * inspector/audit/manager-start-setup-expected.txt: 11 * inspector/model/auditTestCase-expected.txt: 12 * inspector/model/auditTestCaseResult-expected.txt: 13 * inspector/model/auditTestGroup-expected.txt: 14 * inspector/unit-tests/object-utilities.html: 15 * inspector/unit-tests/object-utilities-expected.txt: 16 1 17 2019-05-30 Andres Gonzalez <andresg_22@apple.com> 2 18 -
trunk/LayoutTests/inspector/audit/manager-start-setup-expected.txt
r242808 r245914 4 4 == Running test suite: AuditManager.prototype.start 5 5 -- Running test case: AuditManager.prototype.start.SyncSetup 6 PASS: The setup function should have set __test to 42.6 PASS: The setup function should have set test to 42. 7 7 8 8 -- Running test case: AuditManager.prototype.start.AsyncSetup 9 PASS: The setup function should have set __test to 42.9 PASS: The setup function should have set test to 42. 10 10 11 11 -- Running test case: AuditManager.prototype.start.SubLevelSetup 12 PASS: The setup function should have set __test to undefined.12 PASS: The setup function should have set test to undefined. 13 13 14 14 -- Running test case: AuditManager.prototype.start.OverriddenSetup 15 PASS: The setup function should have set __test to B.15 PASS: The setup function should have set test to B. 16 16 17 17 -- Running test case: AuditManager.prototype.start.MultipleTopLevel 18 PASS: The setup function should have set __test to A.19 PASS: The setup function should have set __test to B.18 PASS: The setup function should have set test to A. 19 PASS: The setup function should have set test to B. 20 20 -
trunk/LayoutTests/inspector/audit/manager-start-setup.html
r242808 r245914 8 8 { 9 9 const auditTestString = (function() { 10 return {11 level: "pass",12 __test: WebInspectorAudit.__test,13 };14 }).toString();10 return { 11 level: "pass", 12 test: WebInspectorAudit.test, 13 }; 14 }).toString(); 15 15 16 16 async function wrapTest(audit, expected, {getResultCallback} = {}) { … … 23 23 InspectorTest.assert(result.didPass, "The test should pass."); 24 24 InspectorTest.assert(!result.data.errors, "There should be no errors."); 25 InspectorTest.expectEqual(result.data.__test.value, expected, `The setup function should have set __test to ${expected}.`); 25 if (result.data.errors) 26 InspectorTest.json(result.data.errors); 27 28 InspectorTest.expectEqual(result.data.test, expected, `The setup function should have set test to ${expected}.`); 26 29 27 30 WI.auditManager.removeTest(audit); … … 35 38 async test() { 36 39 const setup = (function() { 37 WebInspectorAudit. __test = 42;40 WebInspectorAudit.test = 42; 38 41 }).toString(); 39 42 … … 53 56 }); 54 57 55 WebInspectorAudit. __test = 42;58 WebInspectorAudit.test = 42; 56 59 }).toString(); 57 60 … … 67 70 async test() { 68 71 const setup = (function() { 69 WebInspectorAudit. __test = 42;72 WebInspectorAudit.test = 42; 70 73 }).toString(); 71 74 … … 87 90 async test() { 88 91 const setupA = (function() { 89 if (!WebInspectorAudit. __test)90 WebInspectorAudit. __test = "";91 WebInspectorAudit. __test += "A";92 if (!WebInspectorAudit.test) 93 WebInspectorAudit.test = ""; 94 WebInspectorAudit.test += "A"; 92 95 }).toString(); 93 96 94 97 const setupB = (function() { 95 if (!WebInspectorAudit. __test)96 WebInspectorAudit. __test = "";97 WebInspectorAudit. __test += "B";98 if (!WebInspectorAudit.test) 99 WebInspectorAudit.test = ""; 100 WebInspectorAudit.test += "B"; 98 101 }).toString(); 99 102 … … 115 118 async test() { 116 119 const setupA = (function() { 117 if (!WebInspectorAudit. __test)118 WebInspectorAudit. __test = "";119 WebInspectorAudit. __test += "A";120 if (!WebInspectorAudit.test) 121 WebInspectorAudit.test = ""; 122 WebInspectorAudit.test += "A"; 120 123 }).toString(); 121 124 … … 125 128 126 129 const setupB = (function() { 127 if (!WebInspectorAudit. __test)128 WebInspectorAudit. __test = "";129 WebInspectorAudit. __test += "B";130 if (!WebInspectorAudit.test) 131 WebInspectorAudit.test = ""; 132 WebInspectorAudit.test += "B"; 130 133 }).toString(); 131 134 -
trunk/LayoutTests/inspector/model/auditTestCase-expected.txt
r242808 r245914 29 29 "type": "test-case", 30 30 "name": "validWithInvalidOptionals test name", 31 "supports": 3,31 "supports": 4, 32 32 "test": "validWithInvalidOptionals test function" 33 33 } … … 38 38 "name": "validWithValidOptionals test name", 39 39 "description": "validWithValidOptionals test description", 40 "supports": 1,40 "supports": 2, 41 41 "setup": "validWithValidOptionals test setup", 42 42 "test": "validWithValidOptionals test function" -
trunk/LayoutTests/inspector/model/auditTestCaseResult-expected.txt
r240471 r245914 33 33 34 34 -- Running test case: AuditTestCaseResult.fromPayload.validWithInvalidSubOptionals 35 WARN: Audit Warning: "validWithInvalidSubOptionals test result name" has a non-array "data.domNodes" value 36 WARN: Audit Warning: "validWithInvalidSubOptionals test result name" has a non-array "data.domAttributes" value 37 WARN: Audit Warning: "validWithInvalidSubOptionals test result name" has a non-array "data.errors" value 35 38 WARN: Audit Warning: "validWithInvalidSubOptionals test result name" has a non-object "metadata.startTimestamp" value 36 39 WARN: Audit Warning: "validWithInvalidSubOptionals test result name" has a non-object "metadata.asyncTimestamp" value -
trunk/LayoutTests/inspector/model/auditTestGroup-expected.txt
r242808 r245914 44 44 "type": "test-group", 45 45 "name": "validWithInvalidOptionals group name", 46 "supports": 3,46 "supports": 4, 47 47 "tests": [ 48 48 { 49 49 "type": "test-case", 50 50 "name": "validWithInvalidOptionals test name", 51 "supports": 4,51 "supports": 5, 52 52 "test": "validWithInvalidOptionals test function" 53 53 } … … 60 60 "name": "validWithValidOptionals group name", 61 61 "description": "validWithValidOptionals group description", 62 "supports": 1,62 "supports": 2, 63 63 "setup": "validWithValidOptionals group setup", 64 64 "tests": [ … … 67 67 "name": "validWithValidOptionals test name", 68 68 "description": "validWithValidOptionals test description", 69 "supports": 0,69 "supports": 1, 70 70 "setup": "validWithValidOptionals test setup", 71 71 "test": "validWithValidOptionals test function" … … 79 79 "name": "validNested group name", 80 80 "description": "validNested group description", 81 "supports": 1,81 "supports": 2, 82 82 "setup": "validNested group setup", 83 83 "tests": [ … … 86 86 "name": "validNested nested group name", 87 87 "description": "validNested nested group description", 88 "supports": 0,88 "supports": 1, 89 89 "setup": "validNested nested group setup", 90 90 "tests": [ … … 93 93 "name": "validNested nested test name", 94 94 "description": "validNested nested test description", 95 "supports": -1,95 "supports": 0, 96 96 "setup": "validNested nested test setup", 97 97 "test": "validNested nested test function" … … 103 103 "name": "validNested test name", 104 104 "description": "validNested test description", 105 "supports": - 2,105 "supports": -1, 106 106 "setup": "validNested test setup", 107 107 "test": "validNested test function" -
trunk/LayoutTests/inspector/unit-tests/object-utilities-expected.txt
r228336 r245914 23 23 PASS: shallowEqual of objects with different constructors should be false. 24 24 25 -- Running test case: Object.filter 26 PASS: filter should remove all entries where the key isn't in ["a","b","c"]. 27 PASS: filter should remove all entries where the key isn't in ["a"]. 28 PASS: filter should remove all entries where the key isn't in ["b"]. 29 PASS: filter should remove all entries where the key isn't in ["c"]. 30 PASS: filter should remove all entries where the value isn't in [1,2,3]. 31 PASS: filter should remove all entries where the value isn't in [1]. 32 PASS: filter should remove all entries where the value isn't in [2]. 33 PASS: filter should remove all entries where the value isn't in [3]. 34 -
trunk/LayoutTests/inspector/unit-tests/object-utilities.html
r243355 r245914 52 52 }); 53 53 54 suite.addTestCase({ 55 name: "Object.filter", 56 test() { 57 const object = {a: 1, b: 2}; 58 59 function checkKey(keys, expected) { 60 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)}.`); 61 } 62 checkKey(["a", "b", "c"], {a: 1, b: 2}); 63 checkKey(["a"], {a: 1}); 64 checkKey(["b"], {b: 2}); 65 checkKey(["c"], {}); 66 67 function checkValue(values, expected) { 68 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)}.`); 69 } 70 checkValue([1, 2, 3], {a: 1, b: 2}); 71 checkValue([1], {a: 1}); 72 checkValue([2], {b: 2}); 73 checkValue([3], {}); 74 } 75 }); 76 54 77 suite.runTestCasesAndFinish(); 55 78 } -
trunk/Source/JavaScriptCore/ChangeLog
r245909 r245914 1 2019-05-30 Devin Rousso <drousso@apple.com> 2 3 Web Inspector: Audit: there should be a default test for WebInspectorAudit.Resources functionality 4 https://bugs.webkit.org/show_bug.cgi?id=196710 5 <rdar://problem/49712348> 6 7 Reviewed by Joseph Pecoraro. 8 9 * inspector/protocol/Audit.json: 10 Increment Audit version. 11 1 12 2019-05-30 Devin Rousso <drousso@apple.com> 2 13 -
trunk/Source/JavaScriptCore/inspector/protocol/Audit.json
r242808 r245914 2 2 "domain": "Audit", 3 3 "description": "", 4 "version": 2,4 "version": 3, 5 5 "commands": [ 6 6 { -
trunk/Source/WebInspectorUI/ChangeLog
r245833 r245914 1 2019-05-30 Devin Rousso <drousso@apple.com> 2 3 Web Inspector: Audit: there should be a default test for WebInspectorAudit.Resources functionality 4 https://bugs.webkit.org/show_bug.cgi?id=196710 5 <rdar://problem/49712348> 6 7 Reviewed by Joseph Pecoraro. 8 9 Previously, there was no way to return data from Audit that wasn't a DOM node, a DOM 10 attribute (which wasn't "shown" anywhere, as it would highlight that attribute on any 11 returned DOM nodes), or an error string. 12 13 In order for Audits to be more flexible with the types of things they test, there needs to 14 be a way for other types of data to be sent back and displayed in the Audit tab. 15 16 This patch makes it so that an Audit result can now contain other keys/values that are all 17 expected to be JSON serializable. It will take all of the non-"special" (e.g. "domNodes" or 18 "errors") keys/values and display them as object trees. This way, any JSON serializable data 19 can be sent with the result and be displayed in the Audit tab. 20 21 * UserInterface/Models/AuditTestBase.js: 22 (WI.AuditTestBase.prototype.async setup): 23 (WI.AuditTestBase.prototype.clearResult): 24 * UserInterface/Models/AuditTestGroup.js: 25 (WI.AuditTestCase.prototype.clearResult): 26 (WI.AuditTestCase.prototype._updateResult): 27 * UserInterface/Models/AuditTestCase.js: 28 (WI.AuditTestCase.prototype.async run): 29 (WI.AuditTestCase.prototype.async run.async parseResponse): 30 (WI.AuditTestCase.prototype.async run.async parseResponse.checkResultProperty): 31 (WI.AuditTestCase.prototype.async run.async parseResponse.checkResultProperty.addErrorForValueType): 32 (WI.AuditTestCase.prototype.async run.async parseResponse.async resultArrayForEach): 33 (WI.AuditTestCase.prototype.async run.async parseResponse.inspectedPage_stringify): Added. 34 Rename `ResultCleared` to `ResultChanged` so that it can (semantically) be used whenever a 35 new result is set in addition to when an existing one is cleared. This is needed so that 36 `AuditTestCaseContentView` will refresh each time the result changes, instead of only in the 37 first `layout()` after the last result was cleared. 38 39 * UserInterface/Models/AuditTestCaseResult.js: 40 (WI.AuditTestCaseResult.async fromPayload): 41 (WI.AuditTestCaseResult.prototype.toJSON): 42 Drive-by: fix the check for optional `data` values to still warn if the value is `null`. 43 44 * UserInterface/Controllers/AuditManager.js: 45 (WI.AuditManager.prototype._addDefaultTests): 46 Add a default test "Demo Audit > Result Data > data-custom" as an example how to write an 47 Audit that returns custom data, as well as how that custom data is shown in the Audit tab. 48 49 * UserInterface/Views/AuditTestContentView.js: 50 (WI.AuditTestContentView.prototype.shown): 51 (WI.AuditTestContentView.prototype.handleResultChanged): Added. 52 * UserInterface/Views/AuditTestCaseContentView.js: 53 (WI.AuditTestCaseContentView): 54 (WI.AuditTestCaseContentView.prototype.layout): 55 (WI.AuditTestCaseContentView.prototype.handleResultChanged): Added. 56 Preserve the UI for each section across `layout()`s, so that expand/collapse states aren't 57 reset each time the user changes the selected Audit. 58 59 * UserInterface/Views/AuditTestCaseContentView.css: 60 (.content-view.audit-test-case > section table > tr > td + td): Added. 61 Drive-by: ensure that the "index" table column is never larger than it needs to be. 62 63 * UserInterface/Views/AuditTreeElement.js: 64 (WI.AuditTreeElement.prototype.onattach): 65 (WI.AuditTreeElement.prototype._handleTestResultChanged): Added. 66 (WI.AuditTreeElement.prototype._handleTestResultCleared): Deleted. 67 68 * Localizations/en.lproj/localizedStrings.js: 69 1 70 2019-05-28 Devin Rousso <drousso@apple.com> 2 71 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r245833 r245914 1082 1082 localizedStrings["This action moves the path outside the visible area"] = "This action moves the path outside the visible area"; 1083 1083 localizedStrings["This audit is not supported"] = "This audit is not supported"; 1084 localizedStrings["This is an example of how custom result data is shown."] = "This is an example of how custom result data is shown."; 1084 1085 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."; 1085 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.";1086 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."; 1086 1087 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."; 1087 1088 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."; … … 1205 1206 localizedStrings["\u0022%s\u0022 has a non-string \u0022%s\u0022 value"] = "\u0022%s\u0022 has a non-string \u0022%s\u0022 value"; 1206 1207 localizedStrings["\u0022%s\u0022 has an invalid \u0022%s\u0022 value"] = "\u0022%s\u0022 has an invalid \u0022%s\u0022 value"; 1208 localizedStrings["\u0022%s\u0022 is not JSON serializable"] = "\u0022%s\u0022 is not JSON serializable"; 1207 1209 localizedStrings["\u0022%s\u0022 is not valid for %s"] = "\u0022%s\u0022 is not valid for %s"; 1208 1210 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"; -
trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js
r244154 r245914 81 81 }); 82 82 83 Object.defineProperty(Object, "filter", 84 { 85 value(object, callback) 86 { 87 let filtered = {}; 88 for (let key in object) { 89 if (callback(key, object[key])) 90 filtered[key] = object[key]; 91 } 92 return filtered; 93 } 94 }); 95 83 96 Object.defineProperty(Object.prototype, "valueForCaseInsensitiveKey", 84 97 { -
trunk/Source/WebInspectorUI/UserInterface/Controllers/AuditManager.js
r244039 r245914 892 892 new WI.AuditTestGroup(WI.UIString("Result Data"), [ 893 893 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.")}), 894 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.")}),894 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.")}), 895 895 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.")}), 896 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.")}), 896 897 ], {description: WI.UIString("These are all of the different types of data that can be returned with the test result.")}), 897 898 ], {description: WI.UIString("These tests serve as a demonstration of the functionality and structure of audits.")}), -
trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestBase.js
r242808 r245914 117 117 agentCommandFunction = RuntimeAgent.evaluate; 118 118 agentCommandArguments.expression = `(function() { "use strict"; return eval(\`(${this._setup.replace(/`/g, "\\`")})\`)(); })()`; 119 agentCommandArguments.objectGroup = "audit";119 agentCommandArguments.objectGroup = AuditTestBase.ObjectGroup; 120 120 agentCommandArguments.doNotPauseOnExceptionsAndMuteConsole = true; 121 121 } … … 192 192 this._result = null; 193 193 194 if (!options.suppressResultC learedEvent)195 this.dispatchEventToListeners(WI.AuditTestBase.Event.ResultC leared);194 if (!options.suppressResultChangedEvent) 195 this.dispatchEventToListeners(WI.AuditTestBase.Event.ResultChanged); 196 196 197 197 return true; … … 229 229 230 230 // Keep this in sync with Inspector::Protocol::Audit::VERSION. 231 WI.AuditTestBase.Version = 2; 231 WI.AuditTestBase.Version = 3; 232 233 WI.AuditTestBase.ObjectGroup = "audit"; 232 234 233 235 WI.AuditTestBase.Event = { … … 235 237 DisabledChanged: "audit-test-base-disabled-changed", 236 238 Progress: "audit-test-base-progress", 237 ResultC leared: "audit-test-base-result-cleared",239 ResultChanged: "audit-test-base-result-changed", 238 240 Scheduled: "audit-test-base-scheduled", 239 241 Stopping: "audit-test-base-stopping", -
trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js
r242808 r245914 127 127 async function parseResponse(response) { 128 128 let remoteObject = WI.RemoteObject.fromPayload(response.result, WI.mainTarget); 129 if (response.wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error")) 129 if (response.wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error")) { 130 130 addError(remoteObject.description); 131 else if (remoteObject.type === "boolean") 131 return; 132 } 133 134 if (remoteObject.type === "boolean") { 132 135 setLevel(remoteObject.value ? WI.AuditTestCaseResult.Level.Pass : WI.AuditTestCaseResult.Level.Fail); 133 else if (remoteObject.type === "string") 136 return; 137 } 138 139 if (remoteObject.type === "string") { 134 140 setLevel(remoteObject.value.trim().toLowerCase()); 135 else if (remoteObject.type === "object" && !remoteObject.subtype) { 136 const options = { 137 ownProperties: true, 138 }; 139 140 let properties = await new Promise((resolve, reject) => remoteObject.getPropertyDescriptorsAsObject(resolve, options)); 141 142 function checkResultProperty(key, type, subtype) { 143 if (!(key in properties)) 144 return null; 145 146 let property = properties[key].value; 147 if (!property) 148 return null; 149 150 function addErrorForValueType(valueType) { 151 let value = null; 152 if (valueType === "object" || valueType === "array") 153 value = WI.UIString("\u0022%s\u0022 must be an %s"); 154 else 155 value = WI.UIString("\u0022%s\u0022 must be a %s"); 156 addError(value.format(key, valueType)); 157 } 158 159 if (property.subtype !== subtype) { 160 addErrorForValueType(subtype); 161 return null; 162 } 163 164 if (property.type !== type) { 165 addErrorForValueType(type); 166 return null; 167 } 168 169 if (type === "boolean" || type === "string") 170 return property.value; 171 172 return property; 173 } 174 175 async function resultArrayForEach(key, callback) { 176 let array = checkResultProperty(key, "object", "array"); 177 if (!array) 178 return; 179 180 // `getPropertyDescriptorsAsObject` returns an object, meaning that if we 181 // want to iterate over `array` by index, we have to count. 182 let asObject = await new Promise((resolve, reject) => array.getPropertyDescriptorsAsObject(resolve, options)); 183 for (let i = 0; i < array.size; ++i) { 184 if (i in asObject) 185 await callback(asObject[i]); 186 } 187 } 188 189 let levelString = checkResultProperty("level", "string"); 190 if (levelString) 191 setLevel(levelString.trim().toLowerCase()); 192 193 if (checkResultProperty("pass", "boolean")) 194 setLevel(WI.AuditTestCaseResult.Level.Pass); 195 if (checkResultProperty("warn", "boolean")) 196 setLevel(WI.AuditTestCaseResult.Level.Warn); 197 if (checkResultProperty("fail", "boolean")) 198 setLevel(WI.AuditTestCaseResult.Level.Fail); 199 if (checkResultProperty("error", "boolean")) 200 setLevel(WI.AuditTestCaseResult.Level.Error); 201 if (checkResultProperty("unsupported", "boolean")) 202 setLevel(WI.AuditTestCaseResult.Level.Unsupported); 203 204 await resultArrayForEach("domNodes", async (item) => { 205 if (!item || !item.value || item.value.type !== "object" || item.value.subtype !== "node") { 206 addError(WI.UIString("All items in \u0022%s\u0022 must be valid DOM nodes").format(WI.unlocalizedString("domNodes"))); 207 return; 208 } 209 210 let domNodeId = await new Promise((resolve, reject) => item.value.pushNodeToFrontend(resolve)); 211 let domNode = WI.domManager.nodeForId(domNodeId); 212 if (!domNode) 213 return; 214 215 if (!data.domNodes) 216 data.domNodes = []; 217 data.domNodes.push(WI.cssPath(domNode, {full: true})); 218 219 if (!resolvedDOMNodes) 220 resolvedDOMNodes = []; 221 resolvedDOMNodes.push(domNode); 222 }); 223 224 await resultArrayForEach("domAttributes", (item) => { 225 if (!item || !item.value || item.value.type !== "string" || !item.value.value.length) { 226 addError(WI.UIString("All items in \u0022%s\u0022 must be non-empty strings").format(WI.unlocalizedString("domAttributes"))); 227 return; 228 } 229 230 if (!data.domAttributes) 231 data.domAttributes = []; 232 data.domAttributes.push(item.value.value); 233 }); 234 235 await resultArrayForEach("errors", (item) => { 236 if (!item || !item.value || item.value.type !== "object" || item.value.subtype !== "error") { 237 addError(WI.UIString("All items in \u0022%s\u0022 must be error objects").format(WI.unlocalizedString("errors"))); 238 return; 239 } 240 241 addError(item.value.description); 242 }); 243 244 if (window.InspectorTest && properties.__test) 245 data.__test = properties.__test.value; 246 } else 141 return; 142 } 143 144 if (remoteObject.type !== "object" || remoteObject.subtype) { 247 145 addError(WI.UIString("Return value is not an object, string, or boolean")); 146 return; 147 } 148 149 const options = { 150 ownProperties: true, 151 }; 152 153 function checkResultProperty(key, value, type, subtype) { 154 function addErrorForValueType(valueType) { 155 let errorString = null; 156 if (valueType === "object" || valueType === "array") 157 errorString = WI.UIString("\u0022%s\u0022 must be an %s"); 158 else 159 errorString = WI.UIString("\u0022%s\u0022 must be a %s"); 160 addError(errorString.format(key, valueType)); 161 } 162 163 if (value.subtype !== subtype) { 164 addErrorForValueType(subtype); 165 return null; 166 } 167 168 if (value.type !== type) { 169 addErrorForValueType(type); 170 return null; 171 } 172 173 if (type === "boolean" || type === "string") 174 return value.value; 175 176 return value; 177 } 178 179 async function resultArrayForEach(key, value, callback) { 180 let array = checkResultProperty(key, value, "object", "array"); 181 if (!array) 182 return; 183 184 // `getPropertyDescriptorsAsObject` returns an object, meaning that if we 185 // want to iterate over `array` by index, we have to count. 186 let asObject = await new Promise((resolve, reject) => array.getPropertyDescriptorsAsObject(resolve, options)); 187 for (let i = 0; i < array.size; ++i) { 188 if (i in asObject) 189 await callback(asObject[i]); 190 } 191 } 192 193 let properties = await new Promise((resolve, reject) => remoteObject.getPropertyDescriptors(resolve, options)); 194 for (let property of properties) { 195 let key = property.name; 196 if (key === "__proto__") 197 continue; 198 199 let value = property.value; 200 201 switch (key) { 202 case "level": { 203 let levelString = checkResultProperty(key, value, "string"); 204 if (levelString) 205 setLevel(levelString.trim().toLowerCase()); 206 break; 207 } 208 209 case "pass": 210 if (checkResultProperty(key, value, "boolean")) 211 setLevel(WI.AuditTestCaseResult.Level.Pass); 212 break; 213 214 case "warn": 215 if (checkResultProperty(key, value, "boolean")) 216 setLevel(WI.AuditTestCaseResult.Level.Warn); 217 break; 218 219 case "fail": 220 if (checkResultProperty(key, value, "boolean")) 221 setLevel(WI.AuditTestCaseResult.Level.Fail); 222 break; 223 224 case "error": 225 if (checkResultProperty(key, value, "boolean")) 226 setLevel(WI.AuditTestCaseResult.Level.Error); 227 break; 228 229 case "unsupported": 230 if (checkResultProperty(key, value, "boolean")) 231 setLevel(WI.AuditTestCaseResult.Level.Unsupported); 232 break; 233 234 case "domNodes": 235 await resultArrayForEach(key, value, async (item) => { 236 if (!item || !item.value || item.value.type !== "object" || item.value.subtype !== "node") { 237 addError(WI.UIString("All items in \u0022%s\u0022 must be valid DOM nodes").format(WI.unlocalizedString("domNodes"))); 238 return; 239 } 240 241 let domNodeId = await new Promise((resolve, reject) => item.value.pushNodeToFrontend(resolve)); 242 let domNode = WI.domManager.nodeForId(domNodeId); 243 if (!domNode) 244 return; 245 246 if (!data.domNodes) 247 data.domNodes = []; 248 data.domNodes.push(WI.cssPath(domNode, {full: true})); 249 250 if (!resolvedDOMNodes) 251 resolvedDOMNodes = []; 252 resolvedDOMNodes.push(domNode); 253 }); 254 break; 255 256 case "domAttributes": 257 await resultArrayForEach(key, value, (item) => { 258 if (!item || !item.value || item.value.type !== "string" || !item.value.value.length) { 259 addError(WI.UIString("All items in \u0022%s\u0022 must be non-empty strings").format(WI.unlocalizedString("domAttributes"))); 260 return; 261 } 262 263 if (!data.domAttributes) 264 data.domAttributes = []; 265 data.domAttributes.push(item.value.value); 266 }); 267 break; 268 269 case "errors": 270 await resultArrayForEach(key, value, (item) => { 271 if (!item || !item.value || item.value.type !== "object" || item.value.subtype !== "error") { 272 addError(WI.UIString("All items in \u0022%s\u0022 must be error objects").format(WI.unlocalizedString("errors"))); 273 return; 274 } 275 276 addError(item.value.description); 277 }); 278 break; 279 280 default: 281 if (value.objectId) { 282 try { 283 function inspectedPage_stringify() { 284 return JSON.stringify(this); 285 } 286 let stringifiedValue = await value.callFunction(inspectedPage_stringify); 287 data[key] = JSON.parse(stringifiedValue.value); 288 } catch { 289 addError(WI.UIString("\u0022%s\u0022 is not JSON serializable").format(key)); 290 } 291 } else 292 data[key] = value.value; 293 break; 294 } 295 } 248 296 } 249 297 … … 256 304 agentCommandFunction = RuntimeAgent.evaluate; 257 305 agentCommandArguments.expression = `(function() { "use strict"; return eval(\`(${this._test.replace(/`/g, "\\`")})\`)(); })()`; 258 agentCommandArguments.objectGroup = "audit";306 agentCommandArguments.objectGroup = WI.AuditTestCase.ObjectGroup; 259 307 agentCommandArguments.doNotPauseOnExceptionsAndMuteConsole = true; 260 308 } … … 296 344 options.resolvedDOMNodes = resolvedDOMNodes; 297 345 this._result = new WI.AuditTestCaseResult(this.name, level, options); 346 347 this.dispatchEventToListeners(WI.AuditTestBase.Event.ResultChanged); 298 348 } 299 349 }; -
trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js
r240471 r245914 68 68 } else { 69 69 function checkArray(key) { 70 if (! payload.data[key])70 if (!(key in payload.data)) 71 71 return; 72 72 … … 133 133 if (!isEmptyObject(payload.data)) { 134 134 options.data = {}; 135 if (payload.data.domNodes && payload.data.domNodes.length) { 136 if (window.DOMAgent && (!payload.metadata.url || payload.metadata.url === WI.networkManager.mainFrame.url)) { 137 let documentNode = await new Promise((resolve) => WI.domManager.requestDocument(resolve)); 138 options.resolvedDOMNodes = await Promise.all(payload.data.domNodes.map(async (domNodeString) => { 139 let nodeId = 0; 140 try { 141 nodeId = await WI.domManager.querySelector(documentNode, domNodeString); 142 } catch { } 143 return WI.domManager.nodeForId(nodeId) || null; 144 })); 135 for (let key in payload.data) { 136 if (key === "domNodes" || key === "domAttributes" || key === "errors") { 137 if (!payload.data[key].length) 138 continue; 145 139 } 146 140 147 options.data.domNodes = payload.data.domNodes; 148 } 149 if (payload.data.domAttributes && payload.data.domAttributes.length) 150 options.data.domAttributes = payload.data.domAttributes; 151 if (payload.data.errors && payload.data.errors.length) 152 options.data.errors = payload.data.errors; 141 if (key === "domNodes") { 142 if (window.DOMAgent && (!payload.metadata.url || payload.metadata.url === WI.networkManager.mainFrame.url)) { 143 let documentNode = await new Promise((resolve) => WI.domManager.requestDocument(resolve)); 144 options.resolvedDOMNodes = await Promise.all(payload.data.domNodes.map(async (domNodeString) => { 145 let nodeId = 0; 146 try { 147 nodeId = await WI.domManager.querySelector(documentNode, domNodeString); 148 } catch { } 149 return WI.domManager.nodeForId(nodeId) || null; 150 })); 151 } 152 } 153 154 options.data[key] = payload.data[key]; 155 } 153 156 } 154 157 … … 211 214 212 215 let data = {}; 213 if (this._data.domNodes && this._data.domNodes.length) { 214 data.domNodes = this._data.domNodes; 215 if (this._data.domAttributes && this._data.domAttributes.length) 216 data.domAttributes = this._data.domAttributes; 217 } 218 if (this._data.errors && this._data.errors.length) 219 data.errors = this._data.errors; 216 for (let key in this._data) { 217 if (key === "domNodes" || key === "domAttributes" || key === "errors") { 218 if (!this._data[key].length) 219 continue; 220 } 221 222 data[key] = this._data[key]; 223 } 220 224 if (!isEmptyObject(data)) 221 225 json.data = data; -
trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestGroup.js
r242808 r245914 170 170 return super.clearResult({ 171 171 ...options, 172 suppressResultC learedEvent: !cleared,172 suppressResultChangedEvent: !cleared, 173 173 }); 174 174 } … … 211 211 description: this.description, 212 212 }); 213 214 this.dispatchEventToListeners(WI.AuditTestBase.Event.ResultChanged); 213 215 } 214 216 -
trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css
r245497 r245914 128 128 } 129 129 130 .content-view.audit-test-case > section table > tr > td + td { 131 width: 100%; 132 } 133 130 134 .content-view.audit-test-case > section .CodeMirror { 131 135 width: 100%; -
trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js
r245497 r245914 33 33 34 34 this.element.classList.add("audit-test-case"); 35 36 this._resultDataGeneralContainer = null; 37 this._resultDataDOMNodesContainer = null; 38 this._resultDataErrorsContainer = null; 35 39 } 36 40 … … 134 138 let resultData = result.data; 135 139 136 if (resultData.domNodes && resultData.domNodes.length) { 137 let domNodesContainer = this.contentView.element.appendChild(document.createElement("div")); 138 domNodesContainer.classList.add("dom-nodes"); 139 140 let domNodeText = domNodesContainer.appendChild(document.createElement("h1")); 140 if (!this._resultDataGeneralContainer) { 141 let nonSpecialData = Object.filter(resultData, (key) => key !== "domNodes" && key !== "errors"); 142 if (!isEmptyObject(nonSpecialData)) { 143 this._resultDataGeneralContainer = document.createElement("div"); 144 145 let expression = "(" + JSON.stringify(nonSpecialData) + ")"; 146 const options = { 147 objectGroup: WI.AuditTestBase.ObjectGroup, 148 doNotPauseOnExceptionsAndMuteConsole: true, 149 }; 150 WI.runtimeManager.evaluateInInspectedWindow(expression, options, (nonSpecialDataRemoteObject, wasThrown) => { 151 console.assert(!wasThrown); 152 if (!nonSpecialDataRemoteObject) 153 return; 154 155 if (!this.representedObject.result || this.representedObject.result.data !== resultData) 156 return; 157 158 const propertyPath = null; 159 const forceExpanding = true; 160 let element = WI.FormattedValue.createObjectTreeOrFormattedValueForRemoteObject(nonSpecialDataRemoteObject, propertyPath, forceExpanding); 161 162 let objectTree = element.__objectTree; 163 if (objectTree) { 164 objectTree.showOnlyProperties(); 165 objectTree.expand(); 166 } 167 168 this._resultDataGeneralContainer.appendChild(element); 169 170 this.hidePlaceholder(); 171 }); 172 } 173 } 174 175 if (this._resultDataGeneralContainer) 176 this.contentView.element.appendChild(this._resultDataGeneralContainer); 177 178 if (!this._resultDataDOMNodesContainer && resultData.domNodes && resultData.domNodes.length) { 179 this._resultDataDOMNodesContainer = document.createElement("div"); 180 this._resultDataDOMNodesContainer.classList.add("dom-nodes"); 181 182 let domNodeText = this._resultDataDOMNodesContainer.appendChild(document.createElement("h1")); 141 183 domNodeText.textContent = WI.UIString("DOM Nodes:"); 142 184 143 let tableContainer = domNodesContainer.appendChild(document.createElement("table"));185 let tableContainer = this._resultDataDOMNodesContainer.appendChild(document.createElement("table")); 144 186 145 187 resultData.domNodes.forEach((domNode, index) => { … … 205 247 } 206 248 207 if (resultData.errors && resultData.errors.length) { 208 let errorContainer = this.contentView.element.appendChild(document.createElement("div")); 209 errorContainer.classList.add("errors"); 210 211 let errorText = errorContainer.appendChild(document.createElement("h1")); 249 if (this._resultDataDOMNodesContainer) 250 this.contentView.element.appendChild(this._resultDataDOMNodesContainer); 251 252 if (!this._resultDataErrorsContainer && resultData.errors && resultData.errors.length) { 253 this._resultDataErrorsContainer = document.createElement("div"); 254 this._resultDataErrorsContainer.classList.add("errors"); 255 256 let errorText = this._resultDataErrorsContainer.appendChild(document.createElement("h1")); 212 257 errorText.textContent = WI.UIString("Errors:"); 213 258 214 let tableContainer = errorContainer.appendChild(document.createElement("table"));259 let tableContainer = this._resultDataErrorsContainer.appendChild(document.createElement("table")); 215 260 216 261 resultData.errors.forEach((error, index) => { … … 228 273 } 229 274 275 if (this._resultDataErrorsContainer) 276 this.contentView.element.appendChild(this._resultDataErrorsContainer); 277 230 278 if (!this.contentView.element.children.length) 231 279 this.showNoResultDataPlaceholder(); 280 } 281 282 handleResultChanged(event) 283 { 284 super.handleResultChanged(event); 285 286 this._resultDataGeneralContainer = null; 287 this._resultDataDOMNodesContainer = null; 288 this._resultDataErrorsContainer = null; 232 289 } 233 290 -
trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestContentView.js
r244157 r245914 103 103 this.representedObject.addEventListener(WI.AuditTestBase.Event.Completed, this._handleTestChanged, this); 104 104 this.representedObject.addEventListener(WI.AuditTestBase.Event.Progress, this._handleTestChanged, this); 105 this.representedObject.addEventListener(WI.AuditTestBase.Event.ResultC leared, this._handleTestChanged, this);105 this.representedObject.addEventListener(WI.AuditTestBase.Event.ResultChanged, this.handleResultChanged, this); 106 106 this.representedObject.addEventListener(WI.AuditTestBase.Event.Scheduled, this._handleTestChanged, this); 107 107 this.representedObject.addEventListener(WI.AuditTestBase.Event.Stopping, this._handleTestChanged, this); … … 115 115 116 116 super.hidden(); 117 } 118 119 handleResultChanged(event) 120 { 121 // Overridden by sub-classes. 122 123 this.needsLayout(); 117 124 } 118 125 -
trunk/Source/WebInspectorUI/UserInterface/Views/AuditTreeElement.js
r240469 r245914 63 63 if (this.representedObject instanceof WI.AuditTestBase) { 64 64 this.representedObject.addEventListener(WI.AuditTestBase.Event.DisabledChanged, this._handleTestDisabledChanged, this); 65 this.representedObject.addEventListener(WI.AuditTestBase.Event.ResultC leared, this._handleTestResultCleared, this);65 this.representedObject.addEventListener(WI.AuditTestBase.Event.ResultChanged, this._handleTestResultChanged, this); 66 66 67 67 if (this.representedObject instanceof WI.AuditTestCase) … … 282 282 } 283 283 284 _handleTestResultC leared(event)284 _handleTestResultChanged(event) 285 285 { 286 286 this._updateStatus();
Note:
See TracChangeset
for help on using the changeset viewer.