lighthouse 9.5.0-dev.20220418 → 9.5.0-dev.20220421
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/report/bundle.esm.js +117 -70
- package/dist/report/flow.js +23 -23
- package/dist/report/standalone.js +14 -14
- package/flow-report/src/summary/category.tsx +1 -1
- package/lighthouse-core/audits/accessibility/accesskeys.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-allowed-attr.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-command-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-hidden-body.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-hidden-focus.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-input-field-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-meter-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-progressbar-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-required-attr.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-required-children.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-required-parent.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-roles.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-toggle-field-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-tooltip-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-treeitem-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-valid-attr-value.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-valid-attr.js +1 -1
- package/lighthouse-core/audits/accessibility/button-name.js +1 -1
- package/lighthouse-core/audits/accessibility/bypass.js +1 -1
- package/lighthouse-core/audits/accessibility/color-contrast.js +1 -1
- package/lighthouse-core/audits/accessibility/definition-list.js +1 -1
- package/lighthouse-core/audits/accessibility/dlitem.js +1 -1
- package/lighthouse-core/audits/accessibility/document-title.js +1 -1
- package/lighthouse-core/audits/accessibility/duplicate-id-active.js +1 -1
- package/lighthouse-core/audits/accessibility/duplicate-id-aria.js +1 -1
- package/lighthouse-core/audits/accessibility/form-field-multiple-labels.js +1 -1
- package/lighthouse-core/audits/accessibility/frame-title.js +1 -1
- package/lighthouse-core/audits/accessibility/heading-order.js +1 -1
- package/lighthouse-core/audits/accessibility/html-has-lang.js +1 -1
- package/lighthouse-core/audits/accessibility/html-lang-valid.js +1 -1
- package/lighthouse-core/audits/accessibility/image-alt.js +1 -1
- package/lighthouse-core/audits/accessibility/input-image-alt.js +1 -1
- package/lighthouse-core/audits/accessibility/label.js +1 -1
- package/lighthouse-core/audits/accessibility/link-name.js +1 -1
- package/lighthouse-core/audits/accessibility/list.js +1 -1
- package/lighthouse-core/audits/accessibility/listitem.js +1 -1
- package/lighthouse-core/audits/accessibility/meta-refresh.js +1 -1
- package/lighthouse-core/audits/accessibility/meta-viewport.js +1 -1
- package/lighthouse-core/audits/accessibility/object-alt.js +1 -1
- package/lighthouse-core/audits/accessibility/tabindex.js +1 -1
- package/lighthouse-core/audits/accessibility/td-headers-attr.js +1 -1
- package/lighthouse-core/audits/accessibility/th-has-data-cells.js +1 -1
- package/lighthouse-core/audits/accessibility/valid-lang.js +1 -1
- package/lighthouse-core/audits/accessibility/video-caption.js +1 -1
- package/lighthouse-core/audits/byte-efficiency/legacy-javascript.js +1 -1
- package/lighthouse-core/config/default-config.js +1 -1
- package/lighthouse-core/fraggle-rock/gather/navigation-runner.js +16 -2
- package/lighthouse-core/index.js +2 -9
- package/lighthouse-core/util-commonjs.js +13 -7
- package/package.json +2 -2
- package/report/assets/styles.css +10 -5
- package/report/assets/templates.html +10 -9
- package/report/renderer/components.js +13 -12
- package/report/renderer/element-screenshot-renderer.js +0 -3
- package/report/renderer/i18n.js +91 -48
- package/report/renderer/util.js +13 -7
- package/report/test/renderer/element-screenshot-renderer-test.js +3 -3
- package/report/test/renderer/i18n-test.js +26 -7
- package/report/test/renderer/util-test.js +2 -2
- package/report/test-assets/faux-psi.js +2 -0
- package/shared/localization/locales/en-US.json +46 -46
- package/shared/localization/locales/en-XL.json +46 -46
- package/third-party/snyk/snapshot.json +2 -3
- package/types/config.d.ts +2 -0
package/report/renderer/i18n.js
CHANGED
|
@@ -21,9 +21,7 @@ export class I18n {
|
|
|
21
21
|
// When testing, use a locale with more exciting numeric formatting.
|
|
22
22
|
if (locale === 'en-XA') locale = 'de';
|
|
23
23
|
|
|
24
|
-
this.
|
|
25
|
-
this._numberFormatter = new Intl.NumberFormat(locale);
|
|
26
|
-
this._percentFormatter = new Intl.NumberFormat(locale, {style: 'percent'});
|
|
24
|
+
this._locale = locale;
|
|
27
25
|
this._strings = strings;
|
|
28
26
|
}
|
|
29
27
|
|
|
@@ -31,6 +29,32 @@ export class I18n {
|
|
|
31
29
|
return this._strings;
|
|
32
30
|
}
|
|
33
31
|
|
|
32
|
+
/**
|
|
33
|
+
* @param {number} number
|
|
34
|
+
* @param {number} granularity
|
|
35
|
+
* @param {Intl.NumberFormatOptions} opts
|
|
36
|
+
* @return {string}
|
|
37
|
+
*/
|
|
38
|
+
_formatNumberWithGranularity(number, granularity, opts = {}) {
|
|
39
|
+
opts = {...opts};
|
|
40
|
+
const log10 = -Math.log10(granularity);
|
|
41
|
+
if (!Number.isFinite(log10) || (granularity > 1 && !Number.isInteger(log10))) {
|
|
42
|
+
console.warn(`granularity of ${granularity} is invalid, defaulting to value of 1`);
|
|
43
|
+
granularity = 1;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (granularity < 1) {
|
|
47
|
+
opts.minimumFractionDigits = opts.maximumFractionDigits = Math.ceil(log10);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
number = Math.round(number / granularity) * granularity;
|
|
51
|
+
|
|
52
|
+
// Avoid displaying a negative value that rounds to zero as "0".
|
|
53
|
+
if (Object.is(number, -0)) number = 0;
|
|
54
|
+
|
|
55
|
+
return new Intl.NumberFormat(this._locale, opts).format(number).replace(' ', NBSP2);
|
|
56
|
+
}
|
|
57
|
+
|
|
34
58
|
/**
|
|
35
59
|
* Format number.
|
|
36
60
|
* @param {number} number
|
|
@@ -38,8 +62,18 @@ export class I18n {
|
|
|
38
62
|
* @return {string}
|
|
39
63
|
*/
|
|
40
64
|
formatNumber(number, granularity = 0.1) {
|
|
41
|
-
|
|
42
|
-
|
|
65
|
+
return this._formatNumberWithGranularity(number, granularity);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Format integer.
|
|
70
|
+
* Just like {@link formatNumber} but uses a granularity of 1, rounding to the nearest
|
|
71
|
+
* whole number.
|
|
72
|
+
* @param {number} number
|
|
73
|
+
* @return {string}
|
|
74
|
+
*/
|
|
75
|
+
formatInteger(number) {
|
|
76
|
+
return this._formatNumberWithGranularity(number, 1);
|
|
43
77
|
}
|
|
44
78
|
|
|
45
79
|
/**
|
|
@@ -48,7 +82,7 @@ export class I18n {
|
|
|
48
82
|
* @return {string}
|
|
49
83
|
*/
|
|
50
84
|
formatPercent(number) {
|
|
51
|
-
return this.
|
|
85
|
+
return new Intl.NumberFormat(this._locale, {style: 'percent'}).format(number);
|
|
52
86
|
}
|
|
53
87
|
|
|
54
88
|
/**
|
|
@@ -57,9 +91,7 @@ export class I18n {
|
|
|
57
91
|
* @return {string}
|
|
58
92
|
*/
|
|
59
93
|
formatBytesToKiB(size, granularity = 0.1) {
|
|
60
|
-
|
|
61
|
-
const kbs = formatter.format(Math.round(size / 1024 / granularity) * granularity);
|
|
62
|
-
return `${kbs}${NBSP2}KiB`;
|
|
94
|
+
return this._formatNumberWithGranularity(size / KiB, granularity) + `${NBSP2}KiB`;
|
|
63
95
|
}
|
|
64
96
|
|
|
65
97
|
/**
|
|
@@ -68,9 +100,7 @@ export class I18n {
|
|
|
68
100
|
* @return {string}
|
|
69
101
|
*/
|
|
70
102
|
formatBytesToMiB(size, granularity = 0.1) {
|
|
71
|
-
|
|
72
|
-
const kbs = formatter.format(Math.round(size / (1024 ** 2) / granularity) * granularity);
|
|
73
|
-
return `${kbs}${NBSP2}MiB`;
|
|
103
|
+
return this._formatNumberWithGranularity(size / MiB, granularity) + `${NBSP2}MiB`;
|
|
74
104
|
}
|
|
75
105
|
|
|
76
106
|
/**
|
|
@@ -79,9 +109,11 @@ export class I18n {
|
|
|
79
109
|
* @return {string}
|
|
80
110
|
*/
|
|
81
111
|
formatBytes(size, granularity = 1) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
112
|
+
return this._formatNumberWithGranularity(size, granularity, {
|
|
113
|
+
style: 'unit',
|
|
114
|
+
unit: 'byte',
|
|
115
|
+
unitDisplay: 'long',
|
|
116
|
+
});
|
|
85
117
|
}
|
|
86
118
|
|
|
87
119
|
/**
|
|
@@ -92,25 +124,23 @@ export class I18n {
|
|
|
92
124
|
formatBytesWithBestUnit(size, granularity = 0.1) {
|
|
93
125
|
if (size >= MiB) return this.formatBytesToMiB(size, granularity);
|
|
94
126
|
if (size >= KiB) return this.formatBytesToKiB(size, granularity);
|
|
95
|
-
return this.
|
|
127
|
+
return this._formatNumberWithGranularity(size, granularity, {
|
|
128
|
+
style: 'unit',
|
|
129
|
+
unit: 'byte',
|
|
130
|
+
unitDisplay: 'narrow',
|
|
131
|
+
});
|
|
96
132
|
}
|
|
97
133
|
|
|
98
134
|
/**
|
|
99
|
-
*
|
|
100
|
-
* @param {number} granularity Controls how coarse the displayed value is
|
|
101
|
-
* @return {
|
|
135
|
+
* @param {number} size
|
|
136
|
+
* @param {number=} granularity Controls how coarse the displayed value is, defaults to 1
|
|
137
|
+
* @return {string}
|
|
102
138
|
*/
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return new Intl.NumberFormat(this._numberDateLocale, {
|
|
111
|
-
...this._numberFormatter.resolvedOptions(),
|
|
112
|
-
maximumFractionDigits: numberOfFractionDigits,
|
|
113
|
-
minimumFractionDigits: numberOfFractionDigits,
|
|
139
|
+
formatKbps(size, granularity = 1) {
|
|
140
|
+
return this._formatNumberWithGranularity(size, granularity, {
|
|
141
|
+
style: 'unit',
|
|
142
|
+
unit: 'kilobit-per-second',
|
|
143
|
+
unitDisplay: 'short',
|
|
114
144
|
});
|
|
115
145
|
}
|
|
116
146
|
|
|
@@ -120,10 +150,11 @@ export class I18n {
|
|
|
120
150
|
* @return {string}
|
|
121
151
|
*/
|
|
122
152
|
formatMilliseconds(ms, granularity = 10) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
:
|
|
153
|
+
return this._formatNumberWithGranularity(ms, granularity, {
|
|
154
|
+
style: 'unit',
|
|
155
|
+
unit: 'millisecond',
|
|
156
|
+
unitDisplay: 'short',
|
|
157
|
+
});
|
|
127
158
|
}
|
|
128
159
|
|
|
129
160
|
/**
|
|
@@ -132,8 +163,11 @@ export class I18n {
|
|
|
132
163
|
* @return {string}
|
|
133
164
|
*/
|
|
134
165
|
formatSeconds(ms, granularity = 0.1) {
|
|
135
|
-
|
|
136
|
-
|
|
166
|
+
return this._formatNumberWithGranularity(ms / 1000, granularity, {
|
|
167
|
+
style: 'unit',
|
|
168
|
+
unit: 'second',
|
|
169
|
+
unitDisplay: 'short',
|
|
170
|
+
});
|
|
137
171
|
}
|
|
138
172
|
|
|
139
173
|
/**
|
|
@@ -153,10 +187,10 @@ export class I18n {
|
|
|
153
187
|
// and https://github.com/GoogleChrome/lighthouse/pull/9822
|
|
154
188
|
let formatter;
|
|
155
189
|
try {
|
|
156
|
-
formatter = new Intl.DateTimeFormat(this.
|
|
190
|
+
formatter = new Intl.DateTimeFormat(this._locale, options);
|
|
157
191
|
} catch (err) {
|
|
158
192
|
options.timeZone = 'UTC';
|
|
159
|
-
formatter = new Intl.DateTimeFormat(this.
|
|
193
|
+
formatter = new Intl.DateTimeFormat(this._locale, options);
|
|
160
194
|
}
|
|
161
195
|
|
|
162
196
|
return formatter.format(new Date(date));
|
|
@@ -168,6 +202,10 @@ export class I18n {
|
|
|
168
202
|
* @return {string}
|
|
169
203
|
*/
|
|
170
204
|
formatDuration(timeInMilliseconds) {
|
|
205
|
+
// There is a proposal for a Intl.DurationFormat.
|
|
206
|
+
// https://github.com/tc39/proposal-intl-duration-format
|
|
207
|
+
// Until then, we do things a bit more manually.
|
|
208
|
+
|
|
171
209
|
let timeInSeconds = timeInMilliseconds / 1000;
|
|
172
210
|
if (Math.round(timeInSeconds) === 0) {
|
|
173
211
|
return 'None';
|
|
@@ -176,19 +214,24 @@ export class I18n {
|
|
|
176
214
|
/** @type {Array<string>} */
|
|
177
215
|
const parts = [];
|
|
178
216
|
/** @type {Record<string, number>} */
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
217
|
+
const unitToSecondsPer = {
|
|
218
|
+
day: 60 * 60 * 24,
|
|
219
|
+
hour: 60 * 60,
|
|
220
|
+
minute: 60,
|
|
221
|
+
second: 1,
|
|
184
222
|
};
|
|
185
223
|
|
|
186
|
-
Object.keys(
|
|
187
|
-
const
|
|
188
|
-
const numberOfUnits = Math.floor(timeInSeconds /
|
|
224
|
+
Object.keys(unitToSecondsPer).forEach(unit => {
|
|
225
|
+
const secondsPerUnit = unitToSecondsPer[unit];
|
|
226
|
+
const numberOfUnits = Math.floor(timeInSeconds / secondsPerUnit);
|
|
189
227
|
if (numberOfUnits > 0) {
|
|
190
|
-
timeInSeconds -= numberOfUnits *
|
|
191
|
-
|
|
228
|
+
timeInSeconds -= numberOfUnits * secondsPerUnit;
|
|
229
|
+
const part = this._formatNumberWithGranularity(numberOfUnits, 1, {
|
|
230
|
+
style: 'unit',
|
|
231
|
+
unit,
|
|
232
|
+
unitDisplay: 'narrow',
|
|
233
|
+
});
|
|
234
|
+
parts.push(part);
|
|
192
235
|
}
|
|
193
236
|
});
|
|
194
237
|
|
package/report/renderer/util.js
CHANGED
|
@@ -429,10 +429,13 @@ class Util {
|
|
|
429
429
|
break;
|
|
430
430
|
case 'devtools': {
|
|
431
431
|
const {cpuSlowdownMultiplier, requestLatencyMs} = throttling;
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
432
|
+
// TODO: better api in i18n formatter such that this isn't needed.
|
|
433
|
+
const cpuGranularity = Number.isInteger(cpuSlowdownMultiplier) ? 1 : 0.1;
|
|
434
|
+
// eslint-disable-next-line max-len
|
|
435
|
+
cpuThrottling = `${Util.i18n.formatNumber(cpuSlowdownMultiplier, cpuGranularity)}x slowdown (DevTools)`;
|
|
436
|
+
networkThrottling = `${Util.i18n.formatMilliseconds(requestLatencyMs, 1)} HTTP RTT, ` +
|
|
437
|
+
`${Util.i18n.formatKbps(throttling.downloadThroughputKbps)} down, ` +
|
|
438
|
+
`${Util.i18n.formatKbps(throttling.uploadThroughputKbps)} up (DevTools)`;
|
|
436
439
|
|
|
437
440
|
const isSlow4G = () => {
|
|
438
441
|
return requestLatencyMs === 150 * 3.75 &&
|
|
@@ -444,9 +447,12 @@ class Util {
|
|
|
444
447
|
}
|
|
445
448
|
case 'simulate': {
|
|
446
449
|
const {cpuSlowdownMultiplier, rttMs, throughputKbps} = throttling;
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
+
// TODO: better api in i18n formatter such that this isn't needed.
|
|
451
|
+
const cpuGranularity = Number.isInteger(cpuSlowdownMultiplier) ? 1 : 0.1;
|
|
452
|
+
// eslint-disable-next-line max-len
|
|
453
|
+
cpuThrottling = `${Util.i18n.formatNumber(cpuSlowdownMultiplier, cpuGranularity)}x slowdown (Simulated)`;
|
|
454
|
+
networkThrottling = `${Util.i18n.formatMilliseconds(rttMs)} TCP RTT, ` +
|
|
455
|
+
`${Util.i18n.formatKbps(throughputKbps)} throughput (Simulated)`;
|
|
450
456
|
|
|
451
457
|
const isSlow4G = () => {
|
|
452
458
|
return rttMs === 150 && throughputKbps === 1.6 * 1024;
|
|
@@ -65,7 +65,8 @@ describe('ElementScreenshotRenderer', () => {
|
|
|
65
65
|
/* eslint-disable max-len */
|
|
66
66
|
expect(htmlFormatted).toMatchInlineSnapshot(`
|
|
67
67
|
"
|
|
68
|
-
<div class=\\"lh-element-screenshot__content\\"
|
|
68
|
+
<div class=\\"lh-element-screenshot__content\\">
|
|
69
|
+
<div class=\\"lh-element-screenshot__image\\" style=\\"width: 500px; height: 500px; background-position-y: 0px; background-position-x: 0px; background-size: 1000px 1000px;\\">
|
|
69
70
|
<div class=\\"lh-element-screenshot__mask\\" style=\\"width: 500px; height: 500px; clip-path: url(#clip-0);\\">
|
|
70
71
|
<svg height=\\"0\\" width=\\"0\\"> <defs>
|
|
71
72
|
<clipPath clipPathUnits=\\"objectBoundingBox\\" id=\\"clip-0\\">
|
|
@@ -73,8 +74,7 @@ describe('ElementScreenshotRenderer', () => {
|
|
|
73
74
|
<polygon points=\\"0,0.7 1,0.7 1,1 0,1\\"></polygon>
|
|
74
75
|
<polygon points=\\"0,0.1 0.1,0.1 0.1,0.7 0,0.7\\"></polygon>
|
|
75
76
|
<polygon points=\\"0.5,0.1 1,0.1 1,0.7 0.5,0.7\\"></polygon></clipPath> </defs> </svg> </div>
|
|
76
|
-
<div class=\\"lh-element-
|
|
77
|
-
<div class=\\"lh-element-screenshot__element-marker\\" style=\\"width: 200px; height: 300px; left: 50px; top: 50px;\\"></div> </div> "
|
|
77
|
+
<div class=\\"lh-element-screenshot__element-marker\\" style=\\"width: 200px; height: 300px; left: 50px; top: 50px;\\"></div> </div> </div> "
|
|
78
78
|
`);
|
|
79
79
|
/* eslint-enable max-len */
|
|
80
80
|
});
|
|
@@ -21,9 +21,12 @@ const NBSP = '\xa0';
|
|
|
21
21
|
describe('util helpers', () => {
|
|
22
22
|
it('formats a number', () => {
|
|
23
23
|
const i18n = new I18n('en', {...Util.UIStrings});
|
|
24
|
-
assert.strictEqual(i18n.formatNumber(10), '10');
|
|
25
|
-
assert.strictEqual(i18n.formatNumber(100.01), '100');
|
|
24
|
+
assert.strictEqual(i18n.formatNumber(10), '10.0');
|
|
25
|
+
assert.strictEqual(i18n.formatNumber(100.01), '100.0');
|
|
26
26
|
assert.strictEqual(i18n.formatNumber(13000.456), '13,000.5');
|
|
27
|
+
assert.strictEqual(i18n.formatInteger(10), '10');
|
|
28
|
+
assert.strictEqual(i18n.formatInteger(100.01), '100');
|
|
29
|
+
assert.strictEqual(i18n.formatInteger(13000.6), '13,001');
|
|
27
30
|
});
|
|
28
31
|
|
|
29
32
|
it('formats a date', () => {
|
|
@@ -100,9 +103,25 @@ describe('util helpers', () => {
|
|
|
100
103
|
|
|
101
104
|
it('formats a duration', () => {
|
|
102
105
|
const i18n = new I18n('en', {...Util.UIStrings});
|
|
103
|
-
assert.equal(i18n.formatDuration(60 * 1000),
|
|
104
|
-
assert.equal(i18n.formatDuration(60 * 60 * 1000 + 5000),
|
|
105
|
-
assert.equal(i18n.formatDuration(28 * 60 * 60 * 1000 + 5000),
|
|
106
|
+
assert.equal(i18n.formatDuration(60 * 1000), '1m');
|
|
107
|
+
assert.equal(i18n.formatDuration(60 * 60 * 1000 + 5000), '1h 5s');
|
|
108
|
+
assert.equal(i18n.formatDuration(28 * 60 * 60 * 1000 + 5000), '1d 4h 5s');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('formats a duration based on locale', () => {
|
|
112
|
+
let i18n = new I18n('de', {...Util.UIStrings});
|
|
113
|
+
assert.equal(i18n.formatDuration(60 * 1000), `1${NBSP}Min.`);
|
|
114
|
+
assert.equal(i18n.formatDuration(60 * 60 * 1000 + 5000), `1${NBSP}Std. 5${NBSP}Sek.`);
|
|
115
|
+
assert.equal(
|
|
116
|
+
i18n.formatDuration(28 * 60 * 60 * 1000 + 5000), `1${NBSP}T 4${NBSP}Std. 5${NBSP}Sek.`);
|
|
117
|
+
|
|
118
|
+
// Yes, this is actually backwards (s h d).
|
|
119
|
+
i18n = new I18n('ar', {...Util.UIStrings});
|
|
120
|
+
/* eslint-disable no-irregular-whitespace */
|
|
121
|
+
assert.equal(i18n.formatDuration(60 * 1000), `١${NBSP}د`);
|
|
122
|
+
assert.equal(i18n.formatDuration(60 * 60 * 1000 + 5000), `١${NBSP}س ٥${NBSP}ث`);
|
|
123
|
+
assert.equal(i18n.formatDuration(28 * 60 * 60 * 1000 + 5000), `١ ي ٤ س ٥ ث`);
|
|
124
|
+
/* eslint-enable no-irregular-whitespace */
|
|
106
125
|
});
|
|
107
126
|
|
|
108
127
|
it('formats numbers based on locale', () => {
|
|
@@ -113,7 +132,7 @@ describe('util helpers', () => {
|
|
|
113
132
|
assert.strictEqual(i18n.formatNumber(number), '12.346,9');
|
|
114
133
|
assert.strictEqual(i18n.formatBytesToKiB(number), `12,1${NBSP}KiB`);
|
|
115
134
|
assert.strictEqual(i18n.formatMilliseconds(number), `12.350${NBSP}ms`);
|
|
116
|
-
assert.strictEqual(i18n.formatSeconds(number), `12,3${NBSP}
|
|
135
|
+
assert.strictEqual(i18n.formatSeconds(number), `12,3${NBSP}Sek.`);
|
|
117
136
|
});
|
|
118
137
|
|
|
119
138
|
it('uses decimal comma with en-XA test locale', () => {
|
|
@@ -124,7 +143,7 @@ describe('util helpers', () => {
|
|
|
124
143
|
assert.strictEqual(i18n.formatNumber(number), '12.346,9');
|
|
125
144
|
assert.strictEqual(i18n.formatBytesToKiB(number), `12,1${NBSP}KiB`);
|
|
126
145
|
assert.strictEqual(i18n.formatMilliseconds(number), `12.350${NBSP}ms`);
|
|
127
|
-
assert.strictEqual(i18n.formatSeconds(number), `12,3${NBSP}
|
|
146
|
+
assert.strictEqual(i18n.formatSeconds(number), `12,3${NBSP}Sek.`);
|
|
128
147
|
});
|
|
129
148
|
|
|
130
149
|
it('should not crash on unknown locales', () => {
|
|
@@ -56,7 +56,7 @@ describe('util helpers', () => {
|
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
// eslint-disable-next-line max-len
|
|
59
|
-
assert.equal(descriptions.networkThrottling, '565\xa0ms HTTP RTT, 1,400\
|
|
59
|
+
assert.equal(descriptions.networkThrottling, '565\xa0ms HTTP RTT, 1,400\xa0kb/s down, 600\xa0kb/s up (DevTools)');
|
|
60
60
|
assert.equal(descriptions.cpuThrottling, '4.5x slowdown (DevTools)');
|
|
61
61
|
});
|
|
62
62
|
|
|
@@ -71,7 +71,7 @@ describe('util helpers', () => {
|
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
// eslint-disable-next-line max-len
|
|
74
|
-
assert.equal(descriptions.networkThrottling, '150\xa0ms TCP RTT, 1,600\
|
|
74
|
+
assert.equal(descriptions.networkThrottling, '150\xa0ms TCP RTT, 1,600\xa0kb/s throughput (Simulated)');
|
|
75
75
|
assert.equal(descriptions.cpuThrottling, '2x slowdown (Simulated)');
|
|
76
76
|
});
|
|
77
77
|
|
|
@@ -60,6 +60,8 @@ async function renderLHReport() {
|
|
|
60
60
|
metaItemsEl,
|
|
61
61
|
reportRootEl.querySelector('.lh-buttons')
|
|
62
62
|
);
|
|
63
|
+
reportRootEl.querySelector('.lh-metrics-container')?.closest('.lh-category')?.classList
|
|
64
|
+
.add('lh--hoisted-meta');
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
container.append(reportRootEl);
|