Diff
Modified: trunk/LayoutTests/ChangeLog (237643 => 237644)
--- trunk/LayoutTests/ChangeLog 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/LayoutTests/ChangeLog 2018-10-31 18:25:54 UTC (rev 237644)
@@ -1,3 +1,18 @@
+2018-10-31 Devin Rousso <drou...@apple.com>
+
+ Web Inspector: Audit: show metadata for results
+ https://bugs.webkit.org/show_bug.cgi?id=190853
+ <rdar://problem/45527623>
+
+ Reviewed by Brian Burg.
+
+ * inspector/model/auditTestCaseResult-expected.txt:
+ * inspector/model/auditTestCaseResult.html:
+ * inspector/model/auditTestGroupResult-expected.txt:
+ * inspector/model/auditTestGroupResult.html:
+ * inspector/unit-tests/string-utilities-expected.txt:
+ * inspector/unit-tests/string-utilities.html:
+
2018-10-31 Eric Carlson <eric.carl...@apple.com>
[MediaStream] Don't reveal device IDs until the user has granted permission to capture
Modified: trunk/LayoutTests/inspector/model/auditTestCaseResult-expected.txt (237643 => 237644)
--- trunk/LayoutTests/inspector/model/auditTestCaseResult-expected.txt 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/LayoutTests/inspector/model/auditTestCaseResult-expected.txt 2018-10-31 18:25:54 UTC (rev 237644)
@@ -52,6 +52,11 @@
"errors": [
"validWithValidSubOptionals test result error"
]
+ },
+ "metadata": {
+ "startTimestamp": "0001-01-01T00:00:00.000Z",
+ "endTimestamp": "0002-01-01T00:00:00.000Z",
+ "url": "validWithValidSubOptionals test result url"
}
}
Modified: trunk/LayoutTests/inspector/model/auditTestCaseResult.html (237643 => 237644)
--- trunk/LayoutTests/inspector/model/auditTestCaseResult.html 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/LayoutTests/inspector/model/auditTestCaseResult.html 2018-10-31 18:25:54 UTC (rev 237644)
@@ -54,6 +54,7 @@
description: null,
level: WI.AuditTestCaseResult.Level.Pass,
data: null,
+ metadata: null,
},
},
{
@@ -68,6 +69,11 @@
domAttributes: null,
errors: null,
},
+ metadata: {
+ startTimestamp: null,
+ endTimestamp: null,
+ url: null,
+ },
},
},
{
@@ -82,6 +88,11 @@
domAttributes: ["validWithValidSubOptionals test result domAttribute"],
errors: ["validWithValidSubOptionals test result error"],
},
+ metadata: {
+ startTimestamp: "1",
+ endTimestamp: "2",
+ url: "validWithValidSubOptionals test result url",
+ },
},
},
];
Modified: trunk/LayoutTests/inspector/model/auditTestGroupResult-expected.txt (237643 => 237644)
--- trunk/LayoutTests/inspector/model/auditTestGroupResult-expected.txt 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/LayoutTests/inspector/model/auditTestGroupResult-expected.txt 2018-10-31 18:25:54 UTC (rev 237644)
@@ -67,6 +67,11 @@
"errors": [
"validWithValidOptionals test result error"
]
+ },
+ "metadata": {
+ "startTimestamp": "0001-01-01T00:00:00.000Z",
+ "endTimestamp": "0002-01-01T00:00:00.000Z",
+ "url": "validWithValidOptionals test result url"
}
}
]
@@ -98,6 +103,11 @@
"errors": [
"validNested nested test result error"
]
+ },
+ "metadata": {
+ "startTimestamp": "0001-01-01T00:00:00.000Z",
+ "endTimestamp": "0002-01-01T00:00:00.000Z",
+ "url": "validNested nested test result url"
}
}
]
@@ -117,6 +127,11 @@
"errors": [
"validNested test result error"
]
+ },
+ "metadata": {
+ "startTimestamp": "0003-01-01T00:00:00.000Z",
+ "endTimestamp": "0004-01-01T00:00:00.000Z",
+ "url": "validNested test result url"
}
}
]
Modified: trunk/LayoutTests/inspector/model/auditTestGroupResult.html (237643 => 237644)
--- trunk/LayoutTests/inspector/model/auditTestGroupResult.html 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/LayoutTests/inspector/model/auditTestGroupResult.html 2018-10-31 18:25:54 UTC (rev 237644)
@@ -83,6 +83,7 @@
description: null,
level: WI.AuditTestCaseResult.Level.Pass,
data: null,
+ metadata: null,
},
],
},
@@ -104,6 +105,11 @@
domAttributes: ["validWithValidOptionals test result domAttribute"],
errors: ["validWithValidOptionals test result error"],
},
+ metadata: {
+ startTimestamp: "1",
+ endTimestamp: "2",
+ url: "validWithValidOptionals test result url",
+ },
},
],
},
@@ -130,6 +136,11 @@
domAttributes: ["validNested nested test result domAttribute"],
errors: ["validNested nested test result error"],
},
+ metadata: {
+ startTimestamp: "1",
+ endTimestamp: "2",
+ url: "validNested nested test result url",
+ },
},
],
},
@@ -143,6 +154,11 @@
domAttributes: ["validNested test result domAttribute"],
errors: ["validNested test result error"],
},
+ metadata: {
+ startTimestamp: "3",
+ endTimestamp: "4",
+ url: "validNested test result url",
+ },
},
],
},
Modified: trunk/LayoutTests/inspector/unit-tests/string-utilities-expected.txt (237643 => 237644)
--- trunk/LayoutTests/inspector/unit-tests/string-utilities-expected.txt 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/LayoutTests/inspector/unit-tests/string-utilities-expected.txt 2018-10-31 18:25:54 UTC (rev 237644)
@@ -46,6 +46,11 @@
PASS: Last line of a string with a traling line break should be empty.
PASS: Last line of an empty string is the same empty string.
+-- Running test case: String.prototype.truncateStart
+PASS: String stays the same.
+PASS: Ellipsis is inserted before the third character.
+PASS: Ellipsis is inserted before the fourth character.
+
-- Running test case: String.prototype.truncateMiddle
PASS: String stays the same.
PASS: Ellipsis is inserted in the middle.
@@ -53,7 +58,7 @@
-- Running test case: String.prototype.truncateEnd
PASS: String stays the same.
-PASS: Ellipsis is inserted in the middle.
+PASS: Ellipsis is inserted after the fourth character.
PASS: Ellipsis is inserted after the third character.
-- Running test case: String.prototype.escapeCharacters
Modified: trunk/LayoutTests/inspector/unit-tests/string-utilities.html (237643 => 237644)
--- trunk/LayoutTests/inspector/unit-tests/string-utilities.html 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/LayoutTests/inspector/unit-tests/string-utilities.html 2018-10-31 18:25:54 UTC (rev 237644)
@@ -79,6 +79,17 @@
});
suite.addTestCase({
+ name: "String.prototype.truncateStart",
+ test() {
+ const ellipsis = "\u2026";
+ InspectorTest.expectEqual("abcdef".truncateStart(6), "abcdef", "String stays the same.");
+ InspectorTest.expectEqual("abcdef".truncateStart(5), ellipsis + "cdef", "Ellipsis is inserted before the third character.");
+ InspectorTest.expectEqual("abcdef".truncateStart(4), ellipsis + "def", "Ellipsis is inserted before the fourth character.");
+ return true;
+ }
+ });
+
+ suite.addTestCase({
name: "String.prototype.truncateMiddle",
test() {
const ellipsis = "\u2026";
@@ -94,7 +105,7 @@
test() {
const ellipsis = "\u2026";
InspectorTest.expectEqual("abcdef".truncateEnd(6), "abcdef", "String stays the same.");
- InspectorTest.expectEqual("abcdef".truncateEnd(5), "abcd" + ellipsis, "Ellipsis is inserted in the middle.");
+ InspectorTest.expectEqual("abcdef".truncateEnd(5), "abcd" + ellipsis, "Ellipsis is inserted after the fourth character.");
InspectorTest.expectEqual("abcdef".truncateEnd(4), "abc" + ellipsis, "Ellipsis is inserted after the third character.");
return true;
}
Modified: trunk/Source/WebInspectorUI/ChangeLog (237643 => 237644)
--- trunk/Source/WebInspectorUI/ChangeLog 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/Source/WebInspectorUI/ChangeLog 2018-10-31 18:25:54 UTC (rev 237644)
@@ -1,3 +1,46 @@
+2018-10-31 Devin Rousso <drou...@apple.com>
+
+ Web Inspector: Audit: show metadata for results
+ https://bugs.webkit.org/show_bug.cgi?id=190853
+ <rdar://problem/45527623>
+
+ Reviewed by Brian Burg.
+
+ * UserInterface/Models/AuditTestCase.js:
+ (WI.AuditTestCase.prototype.async run):
+ Capture timestamps around the `RunetimeAgent.evaluate` call, as well as the URL of the page.
+
+ * UserInterface/Models/AuditTestCaseResult.js:
+ (WI.AuditTestCaseResult):
+ (WI.AuditTestCaseResult.fromPayload):
+ (WI.AuditTestCaseResult.prototype.get metadata): Added.
+ (WI.AuditTestCaseResult.prototype.toJSON):
+
+ * UserInterface/Views/AuditTestCaseContentView.js:
+ (WI.AuditTestCaseContentView.prototype.initialLayout):
+ (WI.AuditTestCaseContentView.prototype.layout):
+ * UserInterface/Views/AuditTestCaseContentView.css:
+ (.content-view.audit-test-case > header h1): Added.
+ (.content-view.audit-test-case > header h1 > img): Added.
+ (.content-view.audit-test-case > header > .metadata): Added.
+ (.content-view.audit-test-case > header > .metadata > .source > time): Added.
+ (.content-view.audit-test-case > header > .metadata > .source > a): Added.
+ (.content-view.audit-test-case > header > .metadata > .duration): Added.
+ (.content-view.audit-test-case > header > h1): Deleted.
+ (.content-view.audit-test-case > header > h1 > img): Deleted.
+ Display any metadata information where the `WI.ScopeBar` is for `WI.AuditTestGroupContentView`s.
+
+ * UserInterface/Views/AuditTestContentView.css:
+ (.content-view.audit-test > header):
+ (.content-view.audit-test > header > .information): Added.
+ * UserInterface/Views/AuditTestGroupContentView.css:
+ (.content-view.audit-test-group > header):
+ (.content-view.audit-test-group > header > .percentage-pass):
+ (.content-view.audit-test-group > header > .information): Deleted.
+ Move common CSS rules to common parent class.
+
+ * UserInterface/Base/Utilities.js:
+
2018-10-30 Devin Rousso <drou...@apple.com>
Web Inspector: Audit: create Audit Tab
Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js (237643 => 237644)
--- trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js 2018-10-31 18:25:54 UTC (rev 237644)
@@ -582,6 +582,18 @@
}
});
+Object.defineProperty(String.prototype, "truncateStart",
+{
+ value(maxLength)
+ {
+ "use strict";
+
+ if (this.length <= maxLength)
+ return this;
+ return ellipsis + this.substr(this.length - maxLength + 1);
+ }
+});
+
Object.defineProperty(String.prototype, "truncateMiddle",
{
value(maxLength)
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js (237643 => 237644)
--- trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js 2018-10-31 18:25:54 UTC (rev 237644)
@@ -77,6 +77,11 @@
const levelStrings = Object.values(WI.AuditTestCaseResult.Level);
let level = null;
let data = ""
+ let metadata = {
+ url: WI.networkManager.mainFrame.url,
+ startTimestamp: null,
+ endTimestamp: null,
+ };
function setLevel(newLevel) {
let newLevelIndex = levelStrings.indexOf(newLevel);
@@ -100,15 +105,19 @@
data.errors.push(value);
}
+ let evaluateArguments = {
+ _expression_: `(function() { "use strict"; return eval(${this._test})(); })()`,
+ objectGroup: "audit",
+ doNotPauseOnExceptionsAndMuteConsole: true,
+ };
+
try {
- let {result, wasThrown} = await RuntimeAgent.evaluate.invoke({
- _expression_: `(function() { "use strict"; return eval(${this._test})(); })()`,
- objectGroup: "audit",
- doNotPauseOnExceptionsAndMuteConsole: true,
- });
- let remoteObject = WI.RemoteObject.fromPayload(result, WI.mainTarget);
+ metadata.startTimestamp = new Date;
+ let evaluateResponse = await RuntimeAgent.evaluate.invoke(evaluateArguments);
+ metadata.endTimestamp = new Date;
- if (wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error"))
+ let remoteObject = WI.RemoteObject.fromPayload(evaluateResponse.result, WI.mainTarget);
+ if (evaluateResponse.wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error"))
addError(remoteObject.description);
else if (remoteObject.type === "boolean")
setLevel(remoteObject.value ? WI.AuditTestCaseResult.Level.Pass : WI.AuditTestCaseResult.Level.Fail);
@@ -221,6 +230,7 @@
} else
addError(WI.UIString("Return value is not an object, string, or boolean"));
} catch (error) {
+ metadata.endTimestamp = new Date;
addError(error.message);
}
@@ -229,6 +239,7 @@
let options = {
description: this.description,
+ metadata,
};
if (!isEmptyObject(data))
options.data = ""
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js (237643 => 237644)
--- trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js 2018-10-31 18:25:54 UTC (rev 237644)
@@ -25,15 +25,17 @@
WI.AuditTestCaseResult = class AuditTestCaseResult extends WI.AuditTestResultBase
{
- constructor(name, level, {data, description} = {})
+ constructor(name, level, {description, data, metadata} = {})
{
console.assert(Object.values(WI.AuditTestCaseResult.Level).includes(level));
console.assert(!data || typeof data ="" "object");
+ console.assert(!metadata || typeof metadata === "object");
super(name, {description});
this._level = level;
this._data = data || {};
+ this._metadata = metadata || {};
}
// Static
@@ -43,7 +45,7 @@
if (typeof payload !== "object" || payload === null)
return null;
- let {type, name, description, level, data} = payload;
+ let {type, name, description, level, data, metadata} = payload;
if (type !== WI.AuditTestCaseResult.TypeIdentifier)
return null;
@@ -56,25 +58,50 @@
if (typeof data !== "object" || data ="" null)
data = ""
+ else {
+ function checkArray(key) {
+ if (!data[key])
+ return;
- function checkArray(key) {
- if (!data[key])
- return;
+ if (!Array.isArray(data[key]))
+ data[key] = [];
- if (!Array.isArray(data[key]))
- data[key] = [];
+ data[key] = data[key].filter((item) => typeof item === "string");
+ }
+ checkArray("domNodes");
+ checkArray("domAttributes");
+ checkArray("errors");
+ }
- data[key] = data[key].filter((item) => typeof item === "string");
+ if (typeof metadata !== "object" || metadata === null)
+ metadata = {};
+ else {
+ metadata.startTimestamp = typeof metadata.startTimestamp === "string" ? new Date(metadata.startTimestamp) : null;
+ metadata.endTimestamp = typeof metadata.endTimestamp === "string" ? new Date(metadata.endTimestamp) : null;
+ metadata.url = "" metadata.url ="" "string" ? metadata.url : null;
}
- checkArray("domNodes");
- checkArray("domAttributes");
- checkArray("errors");
let options = {};
if (typeof description === "string")
options.description = description;
- if (!isEmptyObject(data))
- options.data = ""
+ if (!isEmptyObject(data)) {
+ options.data = ""
+ if (data.domNodes && data.domNodes.length)
+ options.data.domNodes = data.domNodes;
+ if (data.domAttributes && data.domAttributes.length)
+ options.data.domAttributes = data.domAttributes;
+ if (data.errors && data.errors.length)
+ options.data.errors = data.errors;
+ }
+ if (!isEmptyObject(metadata)) {
+ options.metadata = {};
+ if (metadata.startTimestamp && !isNaN(metadata.startTimestamp))
+ options.metadata.startTimestamp = metadata.startTimestamp;
+ if (metadata.endTimestamp && !isNaN(metadata.endTimestamp))
+ options.metadata.endTimestamp = metadata.endTimestamp;
+ if (metadata.url)
+ options.metadata.url = ""
+ }
return new WI.AuditTestCaseResult(name, level, options);
}
@@ -82,6 +109,7 @@
get level() { return this._level; }
get data() { return this._data; }
+ get metadata() { return this._metadata; }
get result()
{
@@ -129,6 +157,16 @@
if (!isEmptyObject(data))
json.data = ""
+ let metadata = {};
+ if (this._metadata.startTimestamp && !isNaN(this._metadata.startTimestamp))
+ metadata.startTimestamp = this._metadata.startTimestamp;
+ if (this._metadata.endTimestamp && !isNaN(this._metadata.endTimestamp))
+ metadata.endTimestamp = this._metadata.endTimestamp;
+ if (this._metadata.url)
+ metadata.url = ""
+ if (!isEmptyObject(metadata))
+ json.metadata = metadata;
+
return json;
}
};
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css (237643 => 237644)
--- trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css 2018-10-31 18:25:54 UTC (rev 237644)
@@ -37,12 +37,12 @@
margin-top: var(--audit-test-vertical-space);
}
-.content-view.audit-test-case > header > h1 {
+.content-view.audit-test-case > header h1 {
display: flex;
align-items: center;
}
-.content-view.audit-test-case > header > h1 > img {
+.content-view.audit-test-case > header h1 > img {
width: 1em;
height: 1em;
min-width: 16px;
@@ -50,6 +50,30 @@
-webkit-margin-end: 4px;
}
+.content-view.audit-test-case > header > .metadata {
+ display: flex;
+ align-items: center;
+ text-align: end;
+}
+
+.content-view.audit-test-case > header > .metadata > .source > time {
+ display: block;
+ font-style: italic;
+ white-space: nowrap;
+}
+
+.content-view.audit-test-case > header > .metadata > .source > a {
+ display: block;
+}
+
+.content-view.audit-test-case > header > .metadata > .duration {
+ display: inline-block;
+ width: var(--metadata-width);
+ -webkit-margin-start: var(--audit-test-horizontal-space);
+ font-size: 12px;
+ font-weight: bold;
+}
+
.content-view.audit-test-case > section > :not(.message-text-view) {
margin-right: var(--audit-test-horizontal-space);
margin-left: var(--audit-test-horizontal-space);
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js (237643 => 237644)
--- trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js 2018-10-31 18:25:54 UTC (rev 237644)
@@ -40,16 +40,22 @@
{
super.initialLayout();
- let nameElement = this.headerView.element.appendChild(document.createElement("h1"));
+ let informationContainer = this.headerView.element.appendChild(document.createElement("div"));
+ informationContainer.classList.add("information");
+ let nameElement = informationContainer.appendChild(document.createElement("h1"));
+
this._resultImageElement = nameElement.appendChild(document.createElement("img"));
nameElement.appendChild(document.createTextNode(this.representedObject.name));
if (this.representedObject.description) {
- let descriptionElement = this.headerView.element.appendChild(document.createElement("p"));
+ let descriptionElement = informationContainer.appendChild(document.createElement("p"));
descriptionElement.textContent = this.representedObject.description;
}
+
+ this._metadataElement = this.headerView.element.appendChild(document.createElement("div"));
+ this._metadataElement.classList.add("metadata");
}
layout()
@@ -60,6 +66,7 @@
super.layout();
this._resultImageElement.src = ""
+ this._metadataElement.removeChildren();
this.contentView.element.removeChildren();
@@ -86,6 +93,34 @@
else if (result.unsupported)
this._resultImageElement.src = ""
+ let metadata = result.metadata;
+ if (metadata) {
+ let sourceContainer = this._metadataElement.appendChild(document.createElement("div"));
+ sourceContainer.classList.add("source");
+
+ if (metadata.startTimestamp) {
+ let timeElement = sourceContainer.appendChild(document.createElement("time"));
+ timeElement.datetime = metadata.startTimestamp.toISOString();
+ timeElement.textContent = metadata.startTimestamp.toLocaleString();
+
+ if (metadata.endTimestamp) {
+ let durationElement = this._metadataElement.appendChild(document.createElement("span"));
+ durationElement.classList.add("duration");
+ durationElement.textContent = Number.secondsToString((metadata.endTimestamp - metadata.startTimestamp) / 1000);
+ }
+ }
+
+ if (metadata.url && metadata.url !== WI.networkManager.mainFrame.url) {
+ let url = "" URL(metadata.url);
+ let origin = url.origin;
+ if (url.pathname.startsWith("/"))
+ origin += "/";
+ let linkElement = WI.linkifyURLAsNode(url.href, origin + url.href.substring(origin.length).truncateStart(20));
+ linkElement.title = url.href;
+ sourceContainer.appendChild(linkElement);
+ }
+ }
+
let resultData = result.data;
if (resultData.domNodes && resultData.domNodes.length) {
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestContentView.css (237643 => 237644)
--- trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestContentView.css 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestContentView.css 2018-10-31 18:25:54 UTC (rev 237644)
@@ -52,9 +52,17 @@
}
.content-view.audit-test > header {
+ display: flex;
+ align-items: center;
padding: var(--audit-test-vertical-space) var(--audit-test-horizontal-space);
+
+ --metadata-width: 60px;
}
+.content-view.audit-test > header > .information {
+ flex-grow: 1;
+}
+
.content-view.audit-test > header p {
margin: 4px 0 0;
}
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestGroupContentView.css (237643 => 237644)
--- trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestGroupContentView.css 2018-10-31 17:26:49 UTC (rev 237643)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestGroupContentView.css 2018-10-31 18:25:54 UTC (rev 237644)
@@ -28,8 +28,6 @@
}
.content-view.audit-test-group > header {
- display: flex;
- align-items: center;
margin-top: -1px;
border-top: 1px solid var(--border-color);
}
@@ -61,10 +59,6 @@
padding-left: calc(var(--audit-test-horizontal-space) / 2);
}
-.content-view.audit-test-group > header > .information {
- flex-grow: 1;
-}
-
.content-view.audit-test-group > header > .information > p {
font-size: 1.25em;
}
@@ -125,8 +119,8 @@
}
.content-view.audit-test-group > header > .percentage-pass {
+ width: var(--metadata-width);
-webkit-margin-start: var(--audit-test-horizontal-space);
- width: 60px;
font-size: 24px;
text-align: center;
font-weight: bold;