Changeset 237613 in webkit
- Timestamp:
- Oct 30, 2018 6:11:36 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 46 added
- 10 deleted
- 19 edited
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r237609 r237613 1 2018-10-30 Devin Rousso <drousso@apple.com> 2 3 Web Inspector: Audit: create Audit Tab 4 https://bugs.webkit.org/show_bug.cgi?id=190754 5 6 Reviewed by Matt Baker. 7 8 * inspector/audit/resources/audit-utilities.js: Added. 9 * inspector/audit/basic-expected.txt: Added. 10 * inspector/audit/basic.html: Added. 11 * inspector/audit/data-domAttributes-expected.txt: Added. 12 * inspector/audit/data-domAttributes.html: Added. 13 * inspector/audit/data-domNodes-expected.txt: Added. 14 * inspector/audit/data-domNodes.html: Added. 15 * inspector/audit/data-errors-expected.txt: Added. 16 * inspector/audit/data-errors.html: Added. 17 * inspector/model/auditTestCase-expected.txt: Added. 18 * inspector/model/auditTestCase.html: Added. 19 * inspector/model/auditTestCaseResult-expected.txt: Added. 20 * inspector/model/auditTestCaseResult.html: Added. 21 * inspector/model/auditTestGroup-expected.txt: Added. 22 * inspector/model/auditTestGroup.html: Added. 23 * inspector/model/auditTestGroupResult-expected.txt: Added. 24 * inspector/model/auditTestGroupResult.html: Added. 25 * inspector/unit-tests/promise-utilities-expected.txt: Added. 26 * inspector/unit-tests/promise-utilities.html: Added. 27 28 * inspector/audit/audit-manager-expected.txt: Removed. 29 * inspector/audit/audit-manager.html: Removed. 30 * inspector/audit/audit-report-expected.txt: Removed. 31 * inspector/audit/audit-report.html: Removed. 32 * inspector/audit/audit-test-case-expected.txt: Removed. 33 * inspector/audit/audit-test-case.html: Removed. 34 * inspector/audit/audit-test-suite-expected.txt: Removed. 35 * inspector/audit/audit-test-suite.html: Removed. 36 * inspector/audit/resources/audit-test-fixtures.js: Removed. 37 1 38 2018-10-30 Dawei Fenton <realdawei@apple.com> 2 39 -
trunk/Source/WebInspectorUI/ChangeLog
r237608 r237613 1 2018-10-30 Devin Rousso <drousso@apple.com> 2 3 Web Inspector: Audit: create Audit Tab 4 https://bugs.webkit.org/show_bug.cgi?id=190754 5 6 Reviewed by Matt Baker. 7 8 Create an Audit tab for running audits on the inspected page. Leverage `Runtime.evaluate` 9 for running the audit tests (arbitrary JavaScript), and use the returned value to generate 10 a preview UI of the results. All tests/results can be exported/imported to formatted JSON: 11 12 `AuditTestCase` JSON: 13 { 14 "type": "test-case", 15 "name": <string>, 16 <optional> "description": <string>, 17 "test": <stringified JavaScript function>, 18 } 19 20 `AuditTestGroup` JSON: 21 { 22 "type": "test-group", 23 "name": <string>, 24 <optional> "description": <string>, 25 "tests": [...<AuditTestCase, AuditTestGroup>], 26 } 27 28 `AuditTestCaseResult` JSON: 29 { 30 "type": "test-case-result", 31 "name": <string>, 32 <optional> "description": <string>, 33 "level": <"pass", "warn", "fail", "error", "unsupported">, 34 "data": { 35 "domNodes": [...<stringified CSS path>], 36 "domAttributes": [...<string>], 37 "errors": [...<string>], 38 }, 39 } 40 41 `AuditTestGroupResult` JSON: 42 { 43 "type": "test-group-result", 44 "name": <string>, 45 <optional> "description": <string>, 46 "results": [...<AuditTestCaseResult, AuditTestGroupResult>], 47 } 48 49 More keys may be added in the future (especially for `AuditTestCaseResult.data`). 50 51 * UserInterface/Controllers/AuditManager.js: 52 (WI.AuditManager): 53 (WI.AuditManager.synthesizeError): Added. 54 (WI.AuditManager.prototype.get tests): Added. 55 (WI.AuditManager.prototype.get results): Added. 56 (WI.AuditManager.prototype.get runningState): Added. 57 (WI.AuditManager.prototype.start): Added. 58 (WI.AuditManager.prototype.stop): Added. 59 (WI.AuditManager.prototype.import): Added. 60 (WI.AuditManager.prototype.export): Added. 61 (WI.AuditManager.prototype._addTest): Added. 62 (WI.AuditManager.prototype._addResult): Added. 63 (WI.AuditManager.prototype.get testSuites): Deleted. 64 (WI.AuditManager.prototype.get reports): Deleted. 65 (WI.AuditManager.prototype.async runAuditTestByRepresentedObject): Deleted. 66 (WI.AuditManager.prototype.reportForId): Deleted. 67 (WI.AuditManager.prototype.removeAllReports): Deleted. 68 (WI.AuditManager.prototype.async _runTestCase): Deleted. 69 70 * UserInterface/Models/AuditTestBase.js: Added. 71 (WI.AuditTestBases): 72 (WI.AuditTestBases.prototype.get name): 73 (WI.AuditTestBases.prototype.get description): 74 (WI.AuditTestBases.prototype.get runningState): 75 (WI.AuditTestBases.prototype.get result): 76 (WI.AuditTestBases.prototype.async start): 77 (WI.AuditTestBases.prototype.stop): 78 (WI.AuditTestBases.prototype.clearResult): 79 (WI.AuditTestBases.prototype.saveIdentityToCookie): 80 (WI.AuditTestBases.prototype.toJSON): 81 (WI.AuditTestBases.prototype.async run): 82 83 * UserInterface/Models/AuditTestCase.js: 84 (WI.AuditTestCase): 85 (WI.AuditTestCase.fromPayload): Added. 86 (WI.AuditTestCase.prototype.toJSON): Added. 87 (WI.AuditTestCase.prototype.async run): Added. 88 (WI.AuditTestCase.prototype.async run.setLevel): Added. 89 (WI.AuditTestCase.prototype.async run.addError): Added. 90 (WI.AuditTestCase.prototype.async run.checkResultProperty.addErrorForValueType): Added. 91 (WI.AuditTestCase.prototype.async run.checkResultProperty): Added. 92 (WI.AuditTestCase.prototype.async run.async resultArrayForEach): Added. 93 (WI.AuditTestCase.prototype.get id): Deleted. 94 (WI.AuditTestCase.prototype.get name): Deleted. 95 (WI.AuditTestCase.prototype.get suite): Deleted. 96 (WI.AuditTestCase.prototype.get setup): Deleted. 97 (WI.AuditTestCase.prototype.get tearDown): Deleted. 98 (WI.AuditTestCase.prototype.get errorDetails): Deleted. 99 100 * UserInterface/Models/AuditTestGroup.js: Added. 101 (WI.AuditTestGroup): 102 (WI.AuditTestGroup.fromPayload): 103 (WI.AuditTestGroup.prototype.get tests): 104 (WI.AuditTestGroup.prototype.stop): 105 (WI.AuditTestGroup.prototype.clearResult): 106 (WI.AuditTestGroup.prototype.async run): 107 (WI.AuditTestGroup.prototype.toJSON): 108 (WI.AuditTestGroup.prototype._updateResult): 109 (WI.AuditTestGroup.prototype._handleTestCompleted): 110 (WI.AuditTestGroup.prototype._handleTestProgress): 111 112 * UserInterface/Models/AuditTestResultBase.js: Added. 113 (WI.AuditTestResultBase): 114 (WI.AuditTestResultBase.prototype.get name): 115 (WI.AuditTestResultBase.prototype.get description): 116 (WI.AuditTestResultBase.prototype.get result): 117 (WI.AuditTestResultBase.prototype.get didPass): 118 (WI.AuditTestResultBase.prototype.get didWarn): 119 (WI.AuditTestResultBase.prototype.get didFail): 120 (WI.AuditTestResultBase.prototype.get didError): 121 (WI.AuditTestResultBase.prototype.get unsupported): 122 (WI.AuditTestResultBase.prototype.saveIdentityToCookie): 123 (WI.AuditTestResultBase.prototype.toJSON): 124 125 * UserInterface/Models/AuditTestCaseResult.js: Added. 126 (WI.AuditTestCaseResult): 127 (WI.AuditTestCaseResult.fromPayload.checkArray): 128 (WI.AuditTestCaseResult.fromPayload): 129 (WI.AuditTestCaseResult.prototype.get level): 130 (WI.AuditTestCaseResult.prototype.get data): 131 (WI.AuditTestCaseResult.prototype.get didPass): 132 (WI.AuditTestCaseResult.prototype.get didWarn): 133 (WI.AuditTestCaseResult.prototype.get didFail): 134 (WI.AuditTestCaseResult.prototype.get didError): 135 (WI.AuditTestCaseResult.prototype.get unsupported): 136 (WI.AuditTestCaseResult.prototype.toJSON): 137 138 * UserInterface/Models/AuditTestGroupResult.js: Added. 139 (WI.AuditTestGroupResult): 140 (WI.AuditTestGroupResult.fromPayload): 141 (WI.AuditTestGroupResult.prototype.get results): 142 (WI.AuditTestGroupResult.prototype.get levelCounts): 143 (WI.AuditTestGroupResult.prototype.get didPass): 144 (WI.AuditTestGroupResult.prototype.get didWarn): 145 (WI.AuditTestGroupResult.prototype.get didFail): 146 (WI.AuditTestGroupResult.prototype.get didError): 147 (WI.AuditTestGroupResult.prototype.get unsupported): 148 (WI.AuditTestGroupResult.prototype.toJSON): 149 150 * UserInterface/Views/AuditTabContentView.js: Added. 151 (WI.AuditTabContentView): 152 (WI.AuditTabContentView.tabInfo): 153 (WI.AuditTabContentView.isTabAllowed): 154 (WI.AuditTabContentView.prototype.get type): 155 (WI.AuditTabContentView.prototype.get supportsSplitContentBrowser): 156 (WI.AuditTabContentView.prototype.canShowRepresentedObject): 157 (WI.AuditTabContentView.prototype.shown): 158 (WI.AuditTabContentView.prototype.hidden): 159 (WI.AuditTabContentView.prototype._handleSpace): 160 161 * UserInterface/Views/AuditNavigationSidebarPanel.js: Added. 162 (WI.AuditNavigationSidebarPanel): 163 (WI.AuditNavigationSidebarPanel.prototype.showDefaultContentView): 164 (WI.AuditNavigationSidebarPanel.prototype.initialLayout): 165 (WI.AuditNavigationSidebarPanel.prototype.closed): 166 (WI.AuditNavigationSidebarPanel.prototype._addTest): 167 (WI.AuditNavigationSidebarPanel.prototype._addResult): 168 (WI.AuditNavigationSidebarPanel.prototype._updateStartStopButtonNavigationItemState): 169 (WI.AuditNavigationSidebarPanel.prototype._handleAuditTestAdded): 170 (WI.AuditNavigationSidebarPanel.prototype._handleAuditTestCompleted): 171 (WI.AuditNavigationSidebarPanel.prototype._handleAuditTestScheduled): 172 (WI.AuditNavigationSidebarPanel.prototype._treeSelectionDidChange): 173 (WI.AuditNavigationSidebarPanel.prototype._handleStartStopButtonNavigationItemClicked): 174 (WI.AuditNavigationSidebarPanel.prototype._handleImportButtonNavigationItemClicked): 175 * UserInterface/Views/AuditNavigationSidebarPanel.css: Added. 176 (.sidebar > .panel.navigation.audit > .content): 177 178 * UserInterface/Views/AuditTreeElement.js: Added. 179 (WI.AuditTreeElement): 180 (WI.AuditTreeElement.prototype.get result): 181 (WI.AuditTreeElement.prototype.onattach): 182 (WI.AuditTreeElement.prototype.ondetach): 183 (WI.AuditTreeElement.prototype.onpopulate): 184 (WI.AuditTreeElement.prototype.populateContextMenu): 185 (WI.AuditTreeElement.prototype._start): 186 (WI.AuditTreeElement.prototype._updateLevel): 187 (WI.AuditTreeElement.prototype._showRunningSpinner): 188 (WI.AuditTreeElement.prototype._showRunningProgress): 189 (WI.AuditTreeElement.prototype._handleTestCaseCompleted): 190 (WI.AuditTreeElement.prototype._handleTestResultCleared): 191 (WI.AuditTreeElement.prototype._handleTestCaseScheduled): 192 (WI.AuditTreeElement.prototype._handleTestGroupCompleted): 193 (WI.AuditTreeElement.prototype._handleTestGroupProgress): 194 (WI.AuditTreeElement.prototype._handleTestGroupScheduled): 195 (WI.AuditTreeElement.prototype._handleStatusClick): 196 * UserInterface/Views/AuditTreeElement.css: Added. 197 (.tree-outline .item.audit > .status): 198 (.tree-outline .item.audit > .status > img): 199 (.tree-outline .item.audit:matches(.test-case, .test-group) > .status:hover > img): 200 (.tree-outline .item.audit > .status:not(:hover) > img.show-on-hover, .tree-outline .item.audit.test-group.expanded > .status:not(:hover)): 201 (.tree-outline .item.audit.test-group.expanded > .status:hover > :not(img), .tree-outline .item.audit.test-group-result.expanded > .status): 202 (.tree-outline .item.audit > .status > img.pass): 203 (.tree-outline .item.audit > .status > img.warn): 204 (.tree-outline .item.audit > .status > img.fail): 205 (.tree-outline .item.audit > .status > img.error): 206 (.tree-outline .item.audit > .status > img.unsupported): 207 (.audit.test-case .icon): 208 (.audit.test-group .icon): 209 (.audit.test-case-result .icon): 210 (.audit.test-group-result .icon): 211 212 * UserInterface/Views/AuditTestContentView.js: Added. 213 (WI.AuditTestContentView): 214 (WI.AuditTestContentView.prototype.get navigationItems): 215 (WI.AuditTestContentView.prototype.get headerView): 216 (WI.AuditTestContentView.prototype.get contentView): 217 (WI.AuditTestContentView.prototype.get supportsSave): 218 (WI.AuditTestContentView.prototype.get saveData): 219 (WI.AuditTestContentView.prototype.initialLayout): 220 (WI.AuditTestContentView.prototype.layout): 221 (WI.AuditTestContentView.prototype.shown): 222 (WI.AuditTestContentView.prototype.hidden): 223 (WI.AuditTestContentView.prototype.get placeholderElement): 224 (WI.AuditTestContentView.prototype.set placeholderElement): 225 (WI.AuditTestContentView.prototype.showRunningPlaceholder): 226 (WI.AuditTestContentView.prototype.showStoppingPlaceholder): 227 (WI.AuditTestContentView.prototype.showNoResultPlaceholder): 228 (WI.AuditTestContentView.prototype.showNoResultDataPlaceholder): 229 (WI.AuditTestContentView.prototype.showFilteredPlaceholder): 230 (WI.AuditTestContentView.prototype.hidePlaceholder): 231 (WI.AuditTestContentView.prototype.applyFilter): 232 (WI.AuditTestContentView.prototype.resetFilter): 233 (WI.AuditTestContentView.prototype._exportAudit): 234 (WI.AuditTestContentView.prototype._updateExportButtonNavigationItemState): 235 (WI.AuditTestContentView.prototype._showPlaceholder): 236 (WI.AuditTestContentView.prototype._handleExportButtonNavigationItemClicked): 237 (WI.AuditTestContentView.prototype._handleTestChanged): 238 * UserInterface/Views/AuditTestContentView.css: Added. 239 (.content-view-container > .content-view.audit-test): 240 (.content-view-container > .content-view.audit-test > header): 241 (.content-view-container > .content-view.audit-test > header h1): 242 (.content-view-container > .content-view.audit-test > header p): 243 (.content-view.audit-test): 244 (.content-view.audit-test h1): 245 (.content-view.audit-test > header): 246 (.content-view.audit-test > header p): 247 (.content-view.audit-test .audit-test.filtered, .content-view.audit-test .audit-test .message-text-view): 248 (.content-view.audit-test > section): 249 (.content-view.audit-test > section > .message-text-view): 250 (.content-view.audit-test.showing-placeholder): 251 (.content-view.audit-test.showing-placeholder > section): 252 (.content-view.audit-test.showing-placeholder > section > :not(.message-text-view)): 253 (@media (prefers-dark-interface) .content-view.audit-test): 254 255 * UserInterface/Views/AuditTestCaseContentView.js: Added. 256 (WI.AuditTestCaseContentView): 257 (WI.AuditTestCaseContentView.prototype.initialLayout): 258 (WI.AuditTestCaseContentView.prototype.layout): 259 (WI.AuditTestCaseContentView.prototype.showRunningPlaceholder): 260 * UserInterface/Views/AuditTestCaseContentView.css: Added. 261 (.content-view-container > .content-view.audit-test-case > header): 262 (.content-view-container > .content-view.audit-test-case > section > :not(.message-text-view):first-child): 263 (.content-view.audit-test-case > header > h1): 264 (.content-view.audit-test-case > header > h1 > img): 265 (.content-view.audit-test-case > section > :not(.message-text-view)): 266 (.content-view.audit-test-case > section > :not(.message-text-view):last-child): 267 (.content-view.audit-test-case > section > :not(.message-text-view) + :not(.message-text-view)): 268 (.content-view.audit-test-case > section h1): 269 (.content-view.audit-test-case > section table): 270 (.content-view.audit-test-case > section table > tr + tr > td): 271 (.content-view.audit-test-case > section table > tr > td > :not(.tree-outline)): 272 (.content-view.audit-test-case > section table > tr > td:first-child): 273 (.content-view.audit-test-case > section > .dom-nodes > table > tr > td:first-child): 274 (.content-view.audit-test-case > section code): 275 (.content-view.audit-test-case > section mark): 276 277 * UserInterface/Views/AuditTestGroupContentView.js: Added. 278 (WI.AuditTestGroupContentView): 279 (WI.AuditTestGroupContentView.prototype.initialLayout): 280 (WI.AuditTestGroupContentView.prototype.layout): 281 (WI.AuditTestGroupContentView.prototype.shown): 282 (WI.AuditTestGroupContentView.prototype.hidden): 283 (WI.AuditTestGroupContentView.prototype.applyFilter): 284 (WI.AuditTestGroupContentView.prototype.resetFilter): 285 (WI.AuditTestGroupContentView.prototype.showRunningPlaceholder): 286 (WI.AuditTestGroupContentView.prototype._subobjects): 287 (WI.AuditTestGroupContentView.prototype._updateLevelScopeBar): 288 (WI.AuditTestGroupContentView.prototype._handleTestGroupCompleted): 289 (WI.AuditTestGroupContentView.prototype._handleTestGroupProgress): 290 (WI.AuditTestGroupContentView.prototype._handleTestGroupScheduled): 291 (WI.AuditTestGroupContentView.prototype._handleLevelScopeBarSelectionChanged): 292 * UserInterface/Views/AuditTestGroupContentView.css: Added. 293 (.content-view-container > .content-view.audit-test-group > header): 294 (.content-view.audit-test-group > header): 295 (.content-view.audit-test-group.no-matches + .audit-test-group > header): 296 (.content-view.audit-test-group > header, .content-view.audit-test-group:not(.filtered):last-child > header): 297 (.content-view.audit-test-group.contains-test-case > header): 298 (.content-view.audit-test-group.contains-test-case + .audit-test-group.contains-test-case): 299 (.content-view.audit-test-group.contains-test-case:not(.contains-test-group) > section, .content-view.audit-test-group.contains-test-case.contains-test-group > section > .audit-test-case): 300 (.content-view.audit-test-group > header > .information): 301 (.content-view.audit-test-group > header > .information > p): 302 (.content-view.audit-test-group > header > nav): 303 (.content-view.audit-test-group > header > nav:empty): 304 (.content-view.audit-test-group > header > nav:not(:empty):before): 305 (.content-view.audit-test-group > header > nav > .scope-bar > li): 306 (.content-view.audit-test-group > header > nav > .scope-bar > li:not(:hover, .selected)): 307 (.content-view.audit-test-group > header > nav > .scope-bar > li:last-child): 308 (.content-view.audit-test-group > header > nav > .scope-bar > li::before): 309 (.content-view.audit-test-group > header > nav > .scope-bar > li.pass::before): 310 (.content-view.audit-test-group > header > nav > .scope-bar > li.warn::before): 311 (.content-view.audit-test-group > header > nav > .scope-bar > li.fail::before): 312 (.content-view.audit-test-group > header > nav > .scope-bar > li.error::before): 313 (.content-view.audit-test-group > header > nav > .scope-bar > li.unsupported::before): 314 (.content-view.audit-test-group > header > .percentage-pass): 315 (.content-view.audit-test-group > header > .percentage-pass:not(:empty)::after): 316 (.content-view.audit-test-group > section > .audit-test-case:first-child, .content-view.audit-test-group > section > .audit-test-group + .audit-test-case, .content-view.audit-test-group > section > .audit-test-case + .audit-test-group): 317 (.content-view.audit-test-group > section > .audit-test-case:last-child): 318 319 * UserInterface/Views/ScopeBarItem.js: 320 (WI.ScopeBarItem): 321 (WI.ScopeBarItem.prototype.set selected): 322 * UserInterface/Views/MultipleScopeBarItem.js: 323 (WI.MultipleScopeBarItem.prototype.set selectedScopeBarItem): 324 Add an `independent` option that prevents selection changes from deselecting other 325 `WI.ScopeBarItem`s in the same `WI.ScopeBar` (`exclusive` takes precedence). 326 327 * UserInterface/Views/DOMTreeElement.js: 328 (WI.DOMTreeElement): 329 (WI.DOMTreeElement.prototype.highlightAttribute): 330 (WI.DOMTreeElement.prototype._buildAttributeDOM): 331 * UserInterface/Views/DOMTreeOutline.css: 332 (.tree-outline.dom li .highlight): 333 334 * UserInterface/Views/ToggleButtonNavigationItem.js: 335 (WI.ToggleButtonNavigationItem.prototype.set toggled): 336 Also change the `label` if the `ButtonStyle` has text. 337 338 * UserInterface/Base/Setting.js: 339 * UserInterface/Views/SettingsTabContentView.js: 340 (WI.SettingsTabContentView.prototype._createExperimentalSettingsView): 341 342 * UserInterface/Views/DividerNavigationItem.css: 343 (.navigation-bar .item.divider): 344 345 * UserInterface/Base/Utilities.js: 346 (Promise.chain): Added. 347 348 * UserInterface/Views/ContentView.js: 349 (WI.ContentView.createFromRepresentedObject): 350 (WI.ContentView.isViewable): 351 352 * UserInterface/Main.html: 353 * UserInterface/Base/Main.js: 354 (WI.loaded): 355 (WI.contentLoaded): 356 357 * UserInterface/Test.html: 358 * UserInterface/Base/Test.js: 359 (WI.loaded): 360 361 * UserInterface/Images/Audit.svg: Added. 362 * UserInterface/Images/AuditStart.svg: Added. 363 * UserInterface/Images/AuditStop.svg: Added. 364 * UserInterface/Images/AuditTestCase.svg: Added. 365 * UserInterface/Images/AuditTestCaseResult.svg: Added. 366 * UserInterface/Images/AuditTestError.svg: Added. 367 * UserInterface/Images/AuditTestFail.svg: Added. 368 * UserInterface/Images/AuditTestGroup.svg: Added. 369 * UserInterface/Images/AuditTestGroupResult.svg: Added. 370 * UserInterface/Images/AuditTestNoResult.svg: Added. 371 * UserInterface/Images/AuditTestPass.svg: Added. 372 * UserInterface/Images/AuditTestUnsupported.svg: Added. 373 * UserInterface/Images/AuditTestWarn.svg: Added. 374 375 * Localizations/en.lproj/localizedStrings.js: 376 1 377 2018-10-30 Devin Rousso <drousso@apple.com> 2 378 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r237574 r237613 23 23 localizedStrings["%.2fs"] = "%.2fs"; 24 24 localizedStrings["%.3fms"] = "%.3fms"; 25 localizedStrings["%d Error"] = "%d Error"; 25 26 localizedStrings["%d Errors"] = "%d Errors"; 26 27 localizedStrings["%d Errors, %d Warnings"] = "%d Errors, %d Warnings"; 28 localizedStrings["%d Fail"] = "%d Fail"; 27 29 localizedStrings["%d Frame"] = "%d Frame"; 28 30 localizedStrings["%d Frames"] = "%d Frames"; 29 31 localizedStrings["%d More\u2026"] = "%d More\u2026"; 32 localizedStrings["%d Pass"] = "%d Pass"; 30 33 localizedStrings["%d Threads"] = "%d Threads"; 34 localizedStrings["%d Unsupported"] = "%d Unsupported"; 35 localizedStrings["%d Warn"] = "%d Warn"; 31 36 localizedStrings["%d Warnings"] = "%d Warnings"; 32 37 localizedStrings["%d \xd7 %d pixels"] = "%d \xd7 %d pixels"; … … 44 49 localizedStrings["%s Fired"] = "%s Fired"; 45 50 localizedStrings["%s Prototype"] = "%s Prototype"; 51 localizedStrings["%s Result"] = "%s Result"; 46 52 localizedStrings["%s \u2013 %s"] = "%s \u2013 %s"; 47 53 localizedStrings["%s \u2014 %s"] = "%s \u2014 %s"; … … 89 95 localizedStrings["All Resources"] = "All Resources"; 90 96 localizedStrings["All Storage"] = "All Storage"; 97 localizedStrings["All items in “%s“ must be error objects"] = "All items in “%s“ must be error objects"; 98 localizedStrings["All items in “%s“ must be non-empty strings"] = "All items in “%s“ must be non-empty strings"; 99 localizedStrings["All items in “%s“ must be valid DOM nodes"] = "All items in “%s“ must be valid DOM nodes"; 91 100 localizedStrings["An error occurred trying to load the resource."] = "An error occurred trying to load the resource."; 92 101 localizedStrings["An error occurred trying to read the “%s” table."] = "An error occurred trying to read the “%s” table."; … … 114 123 localizedStrings["Attribute Modified"] = "Attribute Modified"; 115 124 localizedStrings["Attributes"] = "Attributes"; 125 localizedStrings["Audit"] = "Audit"; 126 localizedStrings["Audit test error: %s"] = "Audit test error: %s"; 127 localizedStrings["Audit:"] = "Audit:"; 128 localizedStrings["Audits"] = "Audits"; 116 129 localizedStrings["Author Stylesheet"] = "Author Stylesheet"; 117 130 localizedStrings["Auto Increment"] = "Auto Increment"; … … 245 258 localizedStrings["DOM Event"] = "DOM Event"; 246 259 localizedStrings["DOM Events"] = "DOM Events"; 260 localizedStrings["DOM Nodes:"] = "DOM Nodes:"; 247 261 localizedStrings["Damping"] = "Damping"; 248 262 localizedStrings["Data"] = "Data"; … … 330 344 localizedStrings["Element overlaps other compositing element"] = "Element overlaps other compositing element"; 331 345 localizedStrings["Elements"] = "Elements"; 346 localizedStrings["Enable Audit Tab"] = "Enable Audit Tab"; 332 347 localizedStrings["Enable Breakpoint"] = "Enable Breakpoint"; 333 348 localizedStrings["Enable Breakpoints"] = "Enable Breakpoints"; … … 347 362 localizedStrings["Error: "] = "Error: "; 348 363 localizedStrings["Errors"] = "Errors"; 364 localizedStrings["Errors:"] = "Errors:"; 349 365 localizedStrings["Eval Code"] = "Eval Code"; 350 366 localizedStrings["Evaluate JavaScript"] = "Evaluate JavaScript"; … … 363 379 localizedStrings["Export"] = "Export"; 364 380 localizedStrings["Export HAR"] = "Export HAR"; 381 localizedStrings["Export Result"] = "Export Result"; 382 localizedStrings["Export Test"] = "Export Test"; 365 383 localizedStrings["Export recording (%s)"] = "Export recording (%s)"; 366 384 localizedStrings["Expression"] = "Expression"; … … 454 472 localizedStrings["Import"] = "Import"; 455 473 localizedStrings["Import recording from file"] = "Import recording from file"; 474 localizedStrings["Imported"] = "Imported"; 456 475 localizedStrings["Imported Recordings"] = "Imported Recordings"; 457 476 localizedStrings["Incomplete"] = "Incomplete"; … … 538 557 localizedStrings["Method"] = "Method"; 539 558 localizedStrings["Microtask Dispatched"] = "Microtask Dispatched"; 559 localizedStrings["Missing result level"] = "Missing result level"; 540 560 localizedStrings["Mixed"] = "Mixed"; 541 561 localizedStrings["Module Code"] = "Module Code"; … … 566 586 localizedStrings["No Request Headers"] = "No Request Headers"; 567 587 localizedStrings["No Response Headers"] = "No Response Headers"; 588 localizedStrings["No Result"] = "No Result"; 568 589 localizedStrings["No Results Found"] = "No Results Found"; 569 590 localizedStrings["No Search Results"] = "No Search Results"; 570 591 localizedStrings["No Watch Expressions"] = "No Watch Expressions"; 592 localizedStrings["No audit selected"] = "No audit selected"; 571 593 localizedStrings["No matching ARIA role"] = "No matching ARIA role"; 572 594 localizedStrings["No preview available"] = "No preview available"; … … 627 649 localizedStrings["Prefer indent using:"] = "Prefer indent using:"; 628 650 localizedStrings["Preserve Log"] = "Preserve Log"; 651 localizedStrings["Press %s to import a test or result file"] = "Press %s to import a test or result file"; 629 652 localizedStrings["Press %s to load a recording from file."] = "Press %s to load a recording from file."; 653 localizedStrings["Press %s to start running the audit"] = "Press %s to start running the audit"; 630 654 localizedStrings["Pressed"] = "Pressed"; 631 655 localizedStrings["Pretty print"] = "Pretty print"; … … 700 724 localizedStrings["Restart (%s)"] = "Restart (%s)"; 701 725 localizedStrings["Restart animation"] = "Restart animation"; 726 localizedStrings["Results"] = "Results"; 702 727 localizedStrings["Resume Processing"] = "Resume Processing"; 703 728 localizedStrings["Resume Thread"] = "Resume Thread"; 704 729 localizedStrings["Retained Size"] = "Retained Size"; 730 localizedStrings["Return string must be one of %s"] = "Return string must be one of %s"; 705 731 localizedStrings["Return type for anonymous function"] = "Return type for anonymous function"; 706 732 localizedStrings["Return type for function: %s"] = "Return type for function: %s"; 733 localizedStrings["Return value is not an object, string, or boolean"] = "Return value is not an object, string, or boolean"; 707 734 localizedStrings["Reveal Breakpoint"] = "Reveal Breakpoint"; 708 735 localizedStrings["Reveal in DOM Tree"] = "Reveal in DOM Tree"; … … 714 741 localizedStrings["Reveal in Resources Tab"] = "Reveal in Resources Tab"; 715 742 localizedStrings["Role"] = "Role"; 743 localizedStrings["Run %d"] = "Run %d"; 744 localizedStrings["Running the “%s“ audit"] = "Running the “%s“ audit"; 716 745 localizedStrings["Same-Site"] = "Same-Site"; 717 746 localizedStrings["Samples"] = "Samples"; … … 791 820 localizedStrings["Show warnings logged to the Console"] = "Show warnings logged to the Console"; 792 821 localizedStrings["Show:"] = "Show:"; 822 localizedStrings["Showing:"] = "Showing:"; 793 823 localizedStrings["Size"] = "Size"; 794 824 localizedStrings["Size of current object plus all objects it keeps alive"] = "Size of current object plus all objects it keeps alive"; … … 810 840 localizedStrings["Spelling"] = "Spelling"; 811 841 localizedStrings["Stalled"] = "Stalled"; 842 localizedStrings["Start"] = "Start"; 812 843 localizedStrings["Start Time"] = "Start Time"; 813 844 localizedStrings["Start element selection (%s)"] = "Start element selection (%s)"; … … 822 853 localizedStrings["Step over (%s or %s)"] = "Step over (%s or %s)"; 823 854 localizedStrings["Stiffness"] = "Stiffness"; 855 localizedStrings["Stop"] = "Stop"; 824 856 localizedStrings["Stop Recording"] = "Stop Recording"; 825 857 localizedStrings["Stop element selection (%s)"] = "Stop element selection (%s)"; … … 827 859 localizedStrings["Stop recording (%s)"] = "Stop recording (%s)"; 828 860 localizedStrings["Stop recording canvas actions"] = "Stop recording canvas actions"; 861 localizedStrings["Stopping the “%s“ audit"] = "Stopping the “%s“ audit"; 829 862 localizedStrings["Storage"] = "Storage"; 830 863 localizedStrings["Style Attribute"] = "Style Attribute"; … … 850 883 localizedStrings["Text Node"] = "Text Node"; 851 884 localizedStrings["The page's content has changed"] = "The page's content has changed"; 885 localizedStrings["The “%s“ audit failed"] = "The “%s“ audit failed"; 886 localizedStrings["The “%s“ audit is unsupported"] = "The “%s“ audit is unsupported"; 887 localizedStrings["The “%s“ audit passed"] = "The “%s“ audit passed"; 888 localizedStrings["The “%s“ audit threw an error"] = "The “%s“ audit threw an error"; 889 localizedStrings["The “%s“ audit warned"] = "The “%s“ audit warned"; 852 890 localizedStrings["The “%s”\ntable is empty."] = "The “%s”\ntable is empty."; 853 891 localizedStrings["This action causes no visual change"] = "This action causes no visual change"; … … 940 978 localizedStrings["default"] = "default"; 941 979 localizedStrings["for changes to take effect"] = "for changes to take effect"; 980 localizedStrings["invalid JSON."] = "invalid JSON."; 942 981 localizedStrings["key"] = "key"; 943 982 localizedStrings["line "] = "line "; … … 952 991 localizedStrings["value"] = "value"; 953 992 localizedStrings["“%s“ Event Fired"] = "“%s“ Event Fired"; 993 localizedStrings["“%s“ must be a %s"] = "“%s“ must be a %s"; 994 localizedStrings["“%s“ must be an %s"] = "“%s“ must be an %s"; 954 995 localizedStrings["“%s” Profile Recorded"] = "“%s” Profile Recorded"; 955 996 localizedStrings["“%s” is invalid."] = "“%s” is invalid."; -
trunk/Source/WebInspectorUI/UserInterface/Base/Main.js
r237482 r237613 128 128 this.domDebuggerManager = new WI.DOMDebuggerManager; 129 129 this.canvasManager = new WI.CanvasManager; 130 this.auditManager = new WI.AuditManager; 130 131 131 132 // Enable the Console Agent after creating the singleton managers. … … 447 448 WI.CanvasTabContentView, 448 449 WI.LayersTabContentView, 450 WI.AuditTabContentView, 449 451 WI.ConsoleTabContentView, 450 452 WI.SearchTabContentView, … … 1114 1116 representedObject instanceof WI.IndexedDatabase || representedObject instanceof WI.IndexedDatabaseObjectStoreIndex) 1115 1117 return WI.StorageTabContentView; 1118 1119 if (representedObject instanceof WI.AuditTestCase || representedObject instanceof WI.AuditTestGroup 1120 || representedObject instanceof WI.AuditTestCaseResult || representedObject instanceof WI.AuditTestGroupResult) 1121 return WI.AuditTabContentView; 1116 1122 1117 1123 if (representedObject instanceof WI.CanvasCollection) -
trunk/Source/WebInspectorUI/UserInterface/Base/Setting.js
r236927 r237613 126 126 experimentalEnableLayersTab: new WI.Setting("experimental-enable-layers-tab", false), 127 127 experimentalEnableNewTabBar: new WI.Setting("experimental-enable-new-tab-bar", false), 128 experimentalEnableAuditTab: new WI.Setting("experimental-enable-audit-tab", false), 128 129 129 130 // DebugUI -
trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js
r237482 r237613 1373 1373 }); 1374 1374 1375 Object.defineProperty(Promise, "chain", 1376 { 1377 async value(callbacks, initialValue) 1378 { 1379 let results = []; 1380 for (let i = 0; i < callbacks.length; ++i) 1381 results.push(await callbacks[i](results.lastValue || initialValue || null, i)); 1382 return results; 1383 } 1384 }); 1385 1375 1386 Object.defineProperty(Promise, "delay", 1376 1387 { -
trunk/Source/WebInspectorUI/UserInterface/Controllers/AuditManager.js
r235873 r237613 30 30 super(); 31 31 32 this._test SuiteConstructors = [];33 this._re ports = new Map;32 this._tests = []; 33 this._results = []; 34 34 35 // Transforming all the constructors into AuditTestSuite instances.36 this._ testSuites = this._testSuiteConstructors.map(suite => {37 let newTestSuite = new suite;35 this._runningState = WI.AuditManager.RunningState.Inactive; 36 this._runningTests = []; 37 } 38 38 39 if (!(newTestSuite instanceof WI.AuditTestSuite)) 40 throw new Error("Audit test suites must be of instance WI.AuditTestSuite."); 39 static synthesizeError(message) 40 { 41 let consoleMessage = new WI.ConsoleMessage(WI.mainTarget, WI.ConsoleMessage.MessageSource.Other, WI.ConsoleMessage.MessageLevel.Error, WI.UIString("Audit test error: %s").format(message)); 42 consoleMessage.shouldRevealConsole = true; 41 43 42 return newTestSuite; 43 }); 44 WI.consoleLogViewController.appendConsoleMessage(consoleMessage); 44 45 } 45 46 46 47 // Public 47 48 48 get testSuites() { return this._testSuites.slice(); } 49 get reports() { return [...this._reports.values()]; } 49 get tests() { return this._tests; } 50 get results() { return this._results; } 51 get runningState() { return this._runningState; } 50 52 51 async runAuditTestByRepresentedObject(representedObject)53 async start(tests) 52 54 { 53 let auditReport = new WI.AuditReport(representedObject); 55 console.assert(this._runningState === WI.AuditManager.RunningState.Inactive); 56 if (this._runningState !== WI.AuditManager.RunningState.Inactive) 57 return; 54 58 55 if (representedObject instanceof WI.AuditTestCase) { 56 let auditResult = await this._runTestCase(representedObject); 57 auditReport.addResult(auditResult); 58 } else if (representedObject instanceof WI.AuditTestSuite) { 59 let testCases = representedObject.testCases; 60 // Start reducing from testCases[0]. 61 let result = testCases.slice(1).reduce((chain, testCase, index) => { 62 if (testCase.setup) { 63 let setup = testCase.setup.call(testCase, testCase.suite); 64 if (testCase.setup[Symbol.toStringTag] === "AsyncFunction") 65 return setup; 66 else 67 return new Promise(setup); 68 } 59 if (tests && tests.length) 60 tests = tests.filter((test) => typeof test === "object" && test instanceof WI.AuditTestBase); 61 else 62 tests = this._tests; 69 63 70 chain = chain.then((auditResult) => { 71 auditReport.addResult(auditResult); 72 return this._runTestCase(testCase); 73 }); 64 if (!tests.length) 65 return; 74 66 75 if (testCase.tearDown) { 76 let tearDown = testCase.tearDown.call(testCase, testCase.suite); 77 if (testCase.tearDown[Symbol.toStringTag] === "AsyncFunction") 78 return tearDown; 79 else 80 return new Promise(tearDown); 81 } 82 return chain; 83 }, this._runTestCase(testCases[0])); 67 this._runningState = WI.AuditManager.RunningState.Active; 68 this._runningTests = tests; 69 for (let test of this._runningTests) 70 test.clearResult(); 84 71 85 let lastAuditResult = await result; 86 auditReport.addResult(lastAuditResult); 72 this.dispatchEventToListeners(WI.AuditManager.Event.TestScheduled); 87 73 88 // Make AuditReport read-only after all the AuditResults have been received. 89 auditReport.close(); 90 } 74 await Promise.chain(this._runningTests.map((test) => () => this._runningState === WI.AuditManager.RunningState.Active ? test.start() : null)); 91 75 92 this._reports.set(representedObject.id, auditReport); 93 this.dispatchEventToListeners(WI.AuditManager.Event.NewReportAdded, {auditReport}); 76 let result = this._runningTests.map((test) => test.result).filter((result) => !!result); 94 77 95 return auditReport; 78 this._runningState = WI.AuditManager.RunningState.Inactive; 79 this._runningTests = []; 80 81 this._addResult(result); 96 82 } 97 83 98 addTestSuite(auditTestSuiteConstructor)84 stop() 99 85 { 100 if (this._testSuiteConstructors.indexOf(auditTestSuiteConstructor) >= 0) 101 throw new Error(`class ${auditTestSuiteConstructor.name} already exists.`); 86 console.assert(this._runningState === WI.AuditManager.RunningState.Active); 87 if (this._runningState !== WI.AuditManager.RunningState.Active) 88 return; 102 89 103 let auditTestSuite = new auditTestSuiteConstructor; 104 this._testSuiteConstructors.push(auditTestSuiteConstructor); 105 this._testSuites.push(auditTestSuite); 90 for (let test of this._runningTests) 91 test.stop(); 92 93 this._runningState = WI.AuditManager.RunningState.Stopping; 106 94 } 107 95 108 reportForId(reportId)96 import() 109 97 { 110 return this._reports.get(reportId); 98 WI.loadDataFromFile((data, filename) => { 99 if (!data) 100 return; 101 102 let payload = null; 103 try { 104 payload = JSON.parse(data); 105 } catch (e) { 106 WI.AuditManager.synthesizeError(e); 107 return; 108 } 109 110 let object = WI.AuditTestGroup.fromPayload(payload) || WI.AuditTestCase.fromPayload(payload); 111 if (!object) { 112 object = WI.AuditTestGroupResult.fromPayload(payload) || WI.AuditTestCaseResult.fromPayload(payload); 113 if (!object) { 114 WI.AuditManager.synthesizeError(WI.UIString("invalid JSON.")); 115 return; 116 } 117 } 118 119 if (object instanceof WI.AuditTestBase) 120 this._addTest(object); 121 else if (object instanceof WI.AuditTestResultBase) 122 this._addResult(object); 123 }); 111 124 } 112 125 113 removeAllReports()126 export(object) 114 127 { 115 this._reports.clear(); 128 console.assert(object instanceof WI.AuditTestCase || object instanceof WI.AuditTestGroup || object instanceof WI.AuditTestCaseResult || object instanceof WI.AuditTestGroupResult, object); 129 130 let filename = object.name; 131 if (object instanceof WI.AuditTestResultBase) 132 filename = WI.UIString("%s Result").format(filename); 133 134 let url = "web-inspector:///" + encodeURI(filename) + ".json"; 135 136 WI.saveDataToFile({ 137 url, 138 content: JSON.stringify(object), 139 forceSaveAs: true, 140 }); 116 141 } 117 142 118 143 // Private 119 144 120 async _runTestCase(testCase)145 _addTest(test) 121 146 { 122 let didRaiseException = false; 123 let result; 124 this.dispatchEventToListeners(WI.AuditManager.Event.TestStarted, {test: testCase}); 125 try { 126 result = await testCase.test.call(testCase, testCase.suite); 127 } catch (resultData) { 128 result = resultData; 129 didRaiseException = true; 130 } 131 this.dispatchEventToListeners(WI.AuditManager.Event.TestEnded, {test: testCase}); 132 return new WI.AuditResult(testCase, {result}, didRaiseException); 147 this._tests.push(test); 148 149 this.dispatchEventToListeners(WI.AuditManager.Event.TestAdded, {test}); 150 } 151 152 _addResult(result) 153 { 154 if (!result || (Array.isArray(result) && !result.length)) 155 return; 156 157 this._results.push(result); 158 159 this.dispatchEventToListeners(WI.AuditManager.Event.TestCompleted, { 160 result, 161 index: this._results.length - 1, 162 }); 133 163 } 134 164 }; 135 165 166 WI.AuditManager.RunningState = { 167 Inactive: "inactive", 168 Active: "active", 169 Stopping: "stopping", 170 }; 171 136 172 WI.AuditManager.Event = { 137 TestStarted: Symbol("test-started"), 138 TestEnded: Symbol("test-ended") 173 TestAdded: "audit-manager-test-added", 174 TestCompleted: "audit-manager-test-completed", 175 TestScheduled: "audit-manager-test-scheduled", 139 176 }; -
trunk/Source/WebInspectorUI/UserInterface/Main.html
r237605 r237613 32 32 33 33 <link rel="stylesheet" href="Views/ApplicationCacheFrameContentView.css"> 34 <link rel="stylesheet" href="Views/AuditNavigationSidebarPanel.css"> 35 <link rel="stylesheet" href="Views/AuditTestCaseContentView.css"> 36 <link rel="stylesheet" href="Views/AuditTestContentView.css"> 37 <link rel="stylesheet" href="Views/AuditTestGroupContentView.css"> 38 <link rel="stylesheet" href="Views/AuditTreeElement.css"> 34 39 <link rel="stylesheet" href="Views/BezierEditor.css"> 35 40 <link rel="stylesheet" href="Views/BoxModelDetailsSectionRow.css"> … … 441 446 <script src="Models/XHRBreakpoint.js"></script> 442 447 443 <script src="Models/AuditReport.js"></script> 444 <script src="Models/AuditResult.js"></script> 448 <script src="Models/AuditTestBase.js"></script> 445 449 <script src="Models/AuditTestCase.js"></script> 446 <script src="Models/AuditTestSuite.js"></script> 450 <script src="Models/AuditTestGroup.js"></script> 451 <script src="Models/AuditTestResultBase.js"></script> 452 <script src="Models/AuditTestCaseResult.js"></script> 453 <script src="Models/AuditTestGroupResult.js"></script> 447 454 448 455 <script src="Proxies/FormatterWorkerProxy.js"></script> … … 517 524 <script src="Views/StyleDetailsPanel.js"></script> 518 525 526 <script src="Views/AuditTabContentView.js"></script> 519 527 <script src="Views/CanvasTabContentView.js"></script> 520 528 <script src="Views/ConsoleTabContentView.js"></script> … … 547 555 <script src="Views/ApplicationCacheFrameTreeElement.js"></script> 548 556 <script src="Views/ApplicationCacheManifestTreeElement.js"></script> 557 <script src="Views/AuditNavigationSidebarPanel.js"></script> 558 <script src="Views/AuditTestContentView.js"></script> 559 <script src="Views/AuditTestCaseContentView.js"></script> 560 <script src="Views/AuditTestGroupContentView.js"></script> 561 <script src="Views/AuditTreeElement.js"></script> 549 562 <script src="Views/BezierEditor.js"></script> 550 563 <script src="Views/BoxModelDetailsSectionRow.js"></script> -
trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js
r235873 r237613 24 24 */ 25 25 26 WI.AuditTestCase = class AuditTestCase extends WI. Object26 WI.AuditTestCase = class AuditTestCase extends WI.AuditTestBase 27 27 { 28 constructor(suite, name, test, setup, tearDown, errorDetails = {}) 29 { 30 console.assert(suite instanceof WI.AuditTestSuite); 31 console.assert(typeof name === "string"); 32 33 if (setup) 34 console.assert(setup instanceof Function); 35 36 if (tearDown) 37 console.assert(tearDown instanceof Function); 38 39 if (test[Symbol.toStringTag] !== "AsyncFunction") 40 throw new Error("Test functions must be async functions."); 41 42 super(); 43 this._id = Symbol(name); 44 45 this._suite = suite; 46 this._name = name; 28 constructor(name, test, {description} = {}) 29 { 30 console.assert(typeof test === "string"); 31 32 super(name, {description}); 33 47 34 this._test = test; 48 this._setup = setup; 49 this._tearDown = tearDown; 50 this._errorDetails = errorDetails; 35 } 36 37 // Static 38 39 static fromPayload(payload) 40 { 41 if (typeof payload !== "object" || payload === null) 42 return null; 43 44 let {type, name, test, description} = payload; 45 46 if (type !== WI.AuditTestCase.TypeIdentifier) 47 return null; 48 49 if (typeof name !== "string") 50 return null; 51 52 if (typeof test !== "string") 53 return null; 54 55 let options = {}; 56 if (typeof description === "string") 57 options.description = description; 58 59 return new WI.AuditTestCase(name, test, options); 51 60 } 52 61 53 62 // Public 54 63 55 get id() { return this._id; }56 get name() { return this._name; }57 get suite() { return this._suite; }58 64 get test() { return this._test; } 59 get setup() { return this._setup; } 60 get tearDown() { return this._tearDown; } 61 get errorDetails() { return this._errorDetails; } 65 66 toJSON() 67 { 68 let json = super.toJSON(); 69 json.test = this._test; 70 return json; 71 } 72 73 // Protected 74 75 async run() 76 { 77 const levelStrings = Object.values(WI.AuditTestCaseResult.Level); 78 let level = null; 79 let data = {}; 80 81 function setLevel(newLevel) { 82 let newLevelIndex = levelStrings.indexOf(newLevel); 83 if (newLevelIndex < 0) { 84 addError(WI.UIString("Return string must be one of %s").format(JSON.stringify(levelStrings))); 85 return; 86 } 87 88 if (newLevelIndex <= levelStrings.indexOf(level)) 89 return; 90 91 level = newLevel; 92 } 93 94 function addError(value) { 95 setLevel(WI.AuditTestCaseResult.Level.Error); 96 97 if (!data.errors) 98 data.errors = []; 99 100 data.errors.push(value); 101 } 102 103 try { 104 let {result, wasThrown} = await RuntimeAgent.evaluate.invoke({ 105 expression: `(function() { "use strict"; return eval(${this._test})(); })()`, 106 objectGroup: "audit", 107 doNotPauseOnExceptionsAndMuteConsole: true, 108 }); 109 let remoteObject = WI.RemoteObject.fromPayload(result, WI.mainTarget); 110 111 if (wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error")) 112 addError(remoteObject.description); 113 else if (remoteObject.type === "boolean") 114 setLevel(remoteObject.value ? WI.AuditTestCaseResult.Level.Pass : WI.AuditTestCaseResult.Level.Fail); 115 else if (remoteObject.type === "string") 116 setLevel(remoteObject.value.trim().toLowerCase()); 117 else if (remoteObject.type === "object" && !remoteObject.subtype) { 118 const options = { 119 ownProperties: true, 120 }; 121 122 let properties = await new Promise((resolve, reject) => remoteObject.getPropertyDescriptorsAsObject(resolve, options)); 123 124 function checkResultProperty(key, type, subtype) { 125 if (!(key in properties)) 126 return null; 127 128 let property = properties[key].value; 129 if (!property) 130 return null; 131 132 function addErrorForValueType(valueType) { 133 let value = null; 134 if (valueType === "object" || valueType === "array") 135 value = WI.UIString("“%s“ must be an %s"); 136 else 137 value = WI.UIString("“%s“ must be a %s"); 138 addError(value.format(key, valueType)); 139 } 140 141 if (property.subtype !== subtype) { 142 addErrorForValueType(subtype); 143 return null; 144 } 145 146 if (property.type !== type) { 147 addErrorForValueType(type); 148 return null; 149 } 150 151 if (type === "boolean" || type === "string") 152 return property.value; 153 154 return property; 155 } 156 157 async function resultArrayForEach(key, callback) { 158 let array = checkResultProperty(key, "object", "array"); 159 if (!array) 160 return; 161 162 // `getPropertyDescriptorsAsObject` returns an object, meaning that if we 163 // want to iterate over `array` by index, we have to count. 164 let asObject = await new Promise((resolve, reject) => array.getPropertyDescriptorsAsObject(resolve, options)); 165 for (let i = 0; i < array.size; ++i) { 166 if (i in asObject) 167 await callback(asObject[i]); 168 } 169 } 170 171 let levelString = checkResultProperty("level", "string"); 172 if (levelString) 173 setLevel(levelString.trim().toLowerCase()); 174 175 if (checkResultProperty("pass", "boolean")) 176 setLevel(WI.AuditTestCaseResult.Level.Pass); 177 if (checkResultProperty("warn", "boolean")) 178 setLevel(WI.AuditTestCaseResult.Level.Warn); 179 if (checkResultProperty("fail", "boolean")) 180 setLevel(WI.AuditTestCaseResult.Level.Fail); 181 if (checkResultProperty("error", "boolean")) 182 setLevel(WI.AuditTestCaseResult.Level.Error); 183 if (checkResultProperty("unsupported", "boolean")) 184 setLevel(WI.AuditTestCaseResult.Level.Unsupported); 185 186 await resultArrayForEach("domNodes", async (item) => { 187 if (!item || !item.value || item.value.type !== "object" || item.value.subtype !== "node") { 188 addError(WI.UIString("All items in “%s“ must be valid DOM nodes").format(WI.unlocalizedString("domNodes"))); 189 return; 190 } 191 192 let domNodeId = await new Promise((resolve, reject) => item.value.pushNodeToFrontend(resolve)); 193 let domNode = WI.domManager.nodeForId(domNodeId); 194 if (!domNode) 195 return; 196 197 if (!data.domNodes) 198 data.domNodes = []; 199 data.domNodes.push(domNode); 200 }); 201 202 await resultArrayForEach("domAttributes", (item) => { 203 if (!item || !item.value || item.value.type !== "string" || !item.value.value.length) { 204 addError(WI.UIString("All items in “%s“ must be non-empty strings").format(WI.unlocalizedString("domAttributes"))); 205 return; 206 } 207 208 if (!data.domAttributes) 209 data.domAttributes = []; 210 data.domAttributes.push(item.value.value); 211 }); 212 213 await resultArrayForEach("errors", (item) => { 214 if (!item || !item.value || item.value.type !== "object" || item.value.subtype !== "error") { 215 addError(WI.UIString("All items in “%s“ must be error objects").format(WI.unlocalizedString("errors"))); 216 return; 217 } 218 219 addError(item.value.description); 220 }); 221 } else 222 addError(WI.UIString("Return value is not an object, string, or boolean")); 223 } catch (error) { 224 addError(error.message); 225 } 226 227 if (!level) 228 addError(WI.UIString("Missing result level")); 229 230 let options = { 231 description: this.description, 232 }; 233 if (!isEmptyObject(data)) 234 options.data = data; 235 this._result = new WI.AuditTestCaseResult(this.name, level, options); 236 } 62 237 }; 238 239 WI.AuditTestCase.TypeIdentifier = "test-case"; -
trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestResultBase.js
r237612 r237613 24 24 */ 25 25 26 WI.AuditTest Suite = class AuditTestSuite extends WI.Object26 WI.AuditTestResultBase = class AuditTestResultBase 27 27 { 28 constructor( identifier, name)28 constructor(name, {description} = {}) 29 29 { 30 super(); 31 this._id = Symbol(identifier); 30 console.assert(typeof name === "string"); 31 console.assert(!description || typeof description === "string"); 32 32 33 this._name = name; 33 this._testCases = new Map; 34 35 this._buildTestCasesFromDescriptors(); 34 this._description = description || null; 36 35 } 37 38 static testCaseDescriptors() { throw WI.NotImplementedError.subclassMustOverride(); }39 36 40 37 // Public 41 38 42 get id() { return this._id; }43 39 get name() { return this._name; } 44 get testCases() { 45 return [...this._testCases.values()]; 40 get description() { return this._description; } 41 42 get result() 43 { 44 return this; 46 45 } 47 46 48 // Private 47 get didPass() 48 { 49 throw WI.NotImplementedError.subclassMustOverride(); 50 } 49 51 50 _buildTestCasesFromDescriptors()52 get didWarn() 51 53 { 52 for (let descriptor of this.constructor.testCaseDescriptors()) { 53 if (typeof descriptor.name !== "string" || !descriptor.name) 54 throw new Error("Test name must be a valid string."); 54 throw WI.NotImplementedError.subclassMustOverride(); 55 } 55 56 56 let {name, test, setup, tearDown, errorDetails} = descriptor; 57 get didFail() 58 { 59 throw WI.NotImplementedError.subclassMustOverride(); 60 } 57 61 58 if (!(test instanceof Function) || test[Symbol.toStringTag] !== "AsyncFunction") 59 throw new Error("Test function must be an async function."); 62 get didError() 63 { 64 throw WI.NotImplementedError.subclassMustOverride(); 65 } 60 66 61 let testCaseInstance = new WI.AuditTestCase(this, name, test, setup, tearDown, errorDetails); 67 get unsupported() 68 { 69 throw WI.NotImplementedError.subclassMustOverride(); 70 } 62 71 63 this._testCases.set(testCaseInstance.id, testCaseInstance); 64 } 72 saveIdentityToCookie(cookie) 73 { 74 cookie["audit-" + this.constructor.TypeIdentifier + "-name"] = this._name; 75 } 76 77 toJSON() 78 { 79 let json = { 80 type: this.constructor.TypeIdentifier, 81 name: this._name, 82 }; 83 if (this._description) 84 json.description = this._description; 85 return json; 65 86 } 66 87 }; 67 68 WI.AuditTestSuite.Event = {69 NewAuditResultAvailable: Symbol("new-audit-result-available")70 }; -
trunk/Source/WebInspectorUI/UserInterface/Test.html
r237151 r237613 200 200 <script src="Models/XHRBreakpoint.js"></script> 201 201 202 <script src="Models/AuditReport.js"></script> 203 <script src="Models/AuditResult.js"></script> 202 <script src="Models/AuditTestBase.js"></script> 204 203 <script src="Models/AuditTestCase.js"></script> 205 <script src="Models/AuditTestSuite.js"></script> 204 <script src="Models/AuditTestGroup.js"></script> 205 <script src="Models/AuditTestResultBase.js"></script> 206 <script src="Models/AuditTestCaseResult.js"></script> 207 <script src="Models/AuditTestGroupResult.js"></script> 206 208 207 209 <script src="Proxies/FormatterWorkerProxy.js"></script> -
trunk/Source/WebInspectorUI/UserInterface/Test/Test.js
r236853 r237613 64 64 this.domDebuggerManager = new WI.DOMDebuggerManager; 65 65 this.canvasManager = new WI.CanvasManager; 66 this.auditManager = new WI.AuditManager; 66 67 67 68 document.addEventListener("DOMContentLoaded", this.contentLoaded); -
trunk/Source/WebInspectorUI/UserInterface/Views/AuditNavigationSidebarPanel.css
r237612 r237613 24 24 */ 25 25 26 WI.AuditResult = class AuditResult 27 { 28 constructor(testInstance, testResult, failed) 29 { 30 this._testResult = testResult; 31 this._failed = failed || false; 32 this._testName = testInstance.name; 33 this._errorDetails = testInstance.errorDetails; 34 this._logLevel = this._errorDetails.logLevel || WI.AuditResult.LogLevel.Passed; 35 this._errorTitle = this._errorDetails.title; 36 this._hint = this._errorDetails.hint; 37 this._documentation = this._errorDetails.documentation; 38 } 39 40 // Public 41 42 get testResult() { return this._testResult; } 43 get name() { return this._testName; } 44 get logLevel() { return this._logLevel; } 45 get failed() { return this._failed; } 46 }; 47 48 WI.AuditResult.LogLevel = { 49 Error: "error", 50 Warning: "warning", 51 Passed: "passed" 52 }; 26 .sidebar > .panel.navigation.audit > .content { 27 top: var(--navigation-bar-height); 28 } -
trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js
r236766 r237613 168 168 return new WI.ResourceCollectionContentView(representedObject, extraArguments); 169 169 170 if (representedObject instanceof WI.AuditTestCase || representedObject instanceof WI.AuditTestCaseResult) 171 return new WI.AuditTestCaseContentView(representedObject, extraArguments); 172 173 if (representedObject instanceof WI.AuditTestGroup || representedObject instanceof WI.AuditTestGroupResult) 174 return new WI.AuditTestGroupContentView(representedObject, extraArguments); 175 170 176 if (representedObject instanceof WI.Collection) 171 177 return new WI.CollectionContentView(representedObject, extraArguments); … … 295 301 return true; 296 302 if (representedObject instanceof WI.Recording) 303 return true; 304 if (representedObject instanceof WI.AuditTestCase || representedObject instanceof WI.AuditTestGroup 305 || representedObject instanceof WI.AuditTestCaseResult || representedObject instanceof WI.AuditTestGroupResult) 297 306 return true; 298 307 if (representedObject instanceof WI.Collection) -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js
r236766 r237613 48 48 this._subtreeBreakpointCount = 0; 49 49 50 this._highlightedAttributes = new Set; 50 51 this._recentlyModifiedAttributes = []; 51 52 this._boundNodeChangedAnimationEnd = this._nodeChangedAnimationEnd.bind(this); … … 267 268 { 268 269 this._recentlyModifiedAttributes.push({name}); 270 } 271 272 highlightAttribute(name) 273 { 274 this._highlightedAttributes.add(name); 269 275 } 270 276 … … 1328 1334 attribute.element = hasText ? attrValueElement : attrNameElement; 1329 1335 } 1336 1337 if (this._highlightedAttributes.has(name)) 1338 attrSpanElement.classList.add("highlight"); 1330 1339 } 1331 1340 -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.css
r237150 r237613 308 308 } 309 309 310 .tree-outline.dom li .highlight { 311 background-color: hsla(53, 83%, 53%, 0.2); 312 border-bottom: 1px solid hsl(47, 82%, 60%); 313 } 314 310 315 @media (prefers-dark-interface) { 311 316 .tree-outline.dom li.elements-drag-over .selection-area { -
trunk/Source/WebInspectorUI/UserInterface/Views/DividerNavigationItem.css
r236237 r237613 26 26 .navigation-bar .item.divider { 27 27 width: 1px; 28 28 height: 100%; 29 29 background-image: linear-gradient(hsl(0, 0%, 74%), hsl(0, 0%, 74%)); 30 30 background-size: 100% 16px; -
trunk/Source/WebInspectorUI/UserInterface/Views/Main.css
r237078 r237613 200 200 padding: 0 4px; 201 201 border-bottom: none; 202 vertical-align: middle;202 vertical-align: -3px; 203 203 } 204 204 -
trunk/Source/WebInspectorUI/UserInterface/Views/ScopeBarItem.js
r237593 r237613 26 26 WI.ScopeBarItem = class ScopeBarItem extends WI.Object 27 27 { 28 constructor(id, label, {className, exclusive, hidden} = {})28 constructor(id, label, {className, exclusive, independent, hidden} = {}) 29 29 { 30 30 super(); … … 40 40 this._label = label; 41 41 this._exclusive = !!exclusive; 42 this._independent = !!independent; 42 43 this._hidden = !!hidden; 43 44 … … 84 85 85 86 this.dispatchEventToListeners(WI.ScopeBarItem.Event.SelectionChanged, { 86 extendSelection: WI.modifierKeys.metaKey && !WI.modifierKeys.ctrlKey && !WI.modifierKeys.altKey && !WI.modifierKeys.shiftKey,87 extendSelection: this._independent || (WI.modifierKeys.metaKey && !WI.modifierKeys.ctrlKey && !WI.modifierKeys.altKey && !WI.modifierKeys.shiftKey), 87 88 }); 88 89 } -
trunk/Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.js
r236766 r237613 250 250 } 251 251 252 experimentalSettingsView.addSetting(WI.UIString("Audit:"), WI.settings.experimentalEnableAuditTab, WI.UIString("Enable Audit Tab")); 253 experimentalSettingsView.addSeparator(); 254 252 255 experimentalSettingsView.addSetting(WI.UIString("User Interface:"), WI.settings.experimentalEnableNewTabBar, WI.UIString("Enable New Tab Bar")); 253 256 experimentalSettingsView.addSeparator(); … … 269 272 listenForChange(WI.settings.experimentalEnableMultiplePropertiesSelection); 270 273 listenForChange(WI.settings.experimentalEnableLayersTab); 274 listenForChange(WI.settings.experimentalEnableAuditTab); 271 275 listenForChange(WI.settings.experimentalEnableNewTabBar); 272 276 -
trunk/Source/WebInspectorUI/UserInterface/Views/ToggleButtonNavigationItem.js
r229543 r237613 104 104 this.image = this._defaultImage; 105 105 } 106 107 if (this.buttonStyle === WI.ButtonNavigationItem.Style.Text || this.buttonStyle === WI.ButtonNavigationItem.Style.ImageAndText) 108 this.label = this.tooltip; 106 109 } 107 110
Note: See TracChangeset
for help on using the changeset viewer.