lighthouse 9.5.0-dev.20220424 → 9.5.0-dev.20220427
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 +52 -41
- package/dist/report/flow.js +3 -3
- package/dist/report/standalone.js +8 -8
- package/lighthouse-cli/cli-flags.js +1 -1
- package/lighthouse-cli/test/smokehouse/frontends/lib.js +1 -3
- package/lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js +1 -3
- package/lighthouse-cli/test/smokehouse/report-assert.js +1 -3
- package/lighthouse-core/audits/deprecations.js +14 -33
- package/lighthouse-core/audits/dobetterweb/doctype.js +20 -9
- package/lighthouse-core/audits/metrics/experimental-interaction-to-next-paint.js +84 -0
- package/lighthouse-core/computed/metrics/responsiveness.js +64 -0
- package/lighthouse-core/config/config-helpers.js +1 -1
- package/lighthouse-core/fraggle-rock/config/default-config.js +2 -0
- package/lighthouse-core/fraggle-rock/gather/base-artifacts.js +2 -2
- package/lighthouse-core/gather/gatherers/accessibility.js +16 -4
- package/lighthouse-core/gather/gatherers/dobetterweb/doctype.js +4 -2
- package/lighthouse-core/lib/arbitrary-equality-map.js +2 -2
- package/lighthouse-core/lib/i18n/i18n.js +2 -0
- package/lighthouse-core/lib/minify-trace.js +2 -0
- package/lighthouse-core/lib/tracehouse/trace-processor.js +29 -9
- package/lighthouse-core/runner.js +1 -1
- package/lighthouse-core/util-commonjs.js +3 -7
- package/package.json +4 -4
- package/readme.md +1 -1
- package/report/renderer/details-renderer.js +6 -5
- package/report/renderer/i18n.js +43 -29
- package/report/renderer/util.js +3 -7
- package/report/test/renderer/details-renderer-test.js +49 -0
- package/report/test/renderer/i18n-test.js +49 -20
- package/report/test/renderer/performance-category-renderer-test.js +11 -1
- package/shared/localization/locales/en-US.json +10 -1
- package/shared/localization/locales/en-XL.json +10 -1
- package/shared/localization/swap-locale.js +2 -1
- package/types/artifacts.d.ts +6 -0
|
@@ -78,9 +78,8 @@ export class DetailsRenderer {
|
|
|
78
78
|
* @return {Element}
|
|
79
79
|
*/
|
|
80
80
|
_renderBytes(details) {
|
|
81
|
-
// TODO: handle displayUnit once we have something other than '
|
|
82
|
-
|
|
83
|
-
const value = Util.i18n.formatBytesToKiB(details.value, details.granularity);
|
|
81
|
+
// TODO: handle displayUnit once we have something other than 'KiB'
|
|
82
|
+
const value = Util.i18n.formatBytesToKiB(details.value, details.granularity || 0.1);
|
|
84
83
|
const textEl = this._renderText(value);
|
|
85
84
|
textEl.title = Util.i18n.formatBytes(details.value);
|
|
86
85
|
return textEl;
|
|
@@ -91,9 +90,11 @@ export class DetailsRenderer {
|
|
|
91
90
|
* @return {Element}
|
|
92
91
|
*/
|
|
93
92
|
_renderMilliseconds(details) {
|
|
94
|
-
let value
|
|
93
|
+
let value;
|
|
95
94
|
if (details.displayUnit === 'duration') {
|
|
96
95
|
value = Util.i18n.formatDuration(details.value);
|
|
96
|
+
} else {
|
|
97
|
+
value = Util.i18n.formatMilliseconds(details.value, details.granularity || 10);
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
return this._renderText(value);
|
|
@@ -172,7 +173,7 @@ export class DetailsRenderer {
|
|
|
172
173
|
* @return {Element}
|
|
173
174
|
*/
|
|
174
175
|
_renderNumeric(details) {
|
|
175
|
-
const value = Util.i18n.formatNumber(details.value, details.granularity);
|
|
176
|
+
const value = Util.i18n.formatNumber(details.value, details.granularity || 0.1);
|
|
176
177
|
const element = this._dom.createElement('div', 'lh-numeric');
|
|
177
178
|
element.textContent = value;
|
|
178
179
|
return element;
|
package/report/renderer/i18n.js
CHANGED
|
@@ -31,26 +31,31 @@ export class I18n {
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* @param {number} number
|
|
34
|
-
* @param {number} granularity
|
|
35
|
-
* @param {Intl.NumberFormatOptions} opts
|
|
34
|
+
* @param {number|undefined} granularity
|
|
35
|
+
* @param {Intl.NumberFormatOptions=} opts
|
|
36
36
|
* @return {string}
|
|
37
37
|
*/
|
|
38
38
|
_formatNumberWithGranularity(number, granularity, opts = {}) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
if (granularity !== undefined) {
|
|
40
|
+
const log10 = -Math.log10(granularity);
|
|
41
|
+
if (!Number.isInteger(log10)) {
|
|
42
|
+
console.warn(`granularity of ${granularity} is invalid. Using 1 instead`);
|
|
43
|
+
granularity = 1;
|
|
44
|
+
}
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
if (granularity < 1) {
|
|
47
|
+
opts = {...opts};
|
|
48
|
+
opts.minimumFractionDigits = opts.maximumFractionDigits = Math.ceil(log10);
|
|
49
|
+
}
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
number = Math.round(number / granularity) * granularity;
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
// Avoid displaying a negative value that rounds to zero as "0".
|
|
54
|
+
if (Object.is(number, -0)) number = 0;
|
|
55
|
+
} else if (Math.abs(number) < 0.0005) {
|
|
56
|
+
// Also avoids "-0".
|
|
57
|
+
number = 0;
|
|
58
|
+
}
|
|
54
59
|
|
|
55
60
|
return new Intl.NumberFormat(this._locale, opts).format(number).replace(' ', NBSP2);
|
|
56
61
|
}
|
|
@@ -58,10 +63,12 @@ export class I18n {
|
|
|
58
63
|
/**
|
|
59
64
|
* Format number.
|
|
60
65
|
* @param {number} number
|
|
61
|
-
* @param {number=} granularity
|
|
66
|
+
* @param {number=} granularity Controls how coarse the displayed value is.
|
|
67
|
+
* If undefined, the number will be displayed as described
|
|
68
|
+
* by the Intl defaults: tinyurl.com/7s67w5x7
|
|
62
69
|
* @return {string}
|
|
63
70
|
*/
|
|
64
|
-
formatNumber(number, granularity
|
|
71
|
+
formatNumber(number, granularity) {
|
|
65
72
|
return this._formatNumberWithGranularity(number, granularity);
|
|
66
73
|
}
|
|
67
74
|
|
|
@@ -87,25 +94,28 @@ export class I18n {
|
|
|
87
94
|
|
|
88
95
|
/**
|
|
89
96
|
* @param {number} size
|
|
90
|
-
* @param {number=} granularity Controls how coarse the displayed value is
|
|
97
|
+
* @param {number=} granularity Controls how coarse the displayed value is.
|
|
98
|
+
* If undefined, the number will be displayed in full.
|
|
91
99
|
* @return {string}
|
|
92
100
|
*/
|
|
93
|
-
formatBytesToKiB(size, granularity =
|
|
101
|
+
formatBytesToKiB(size, granularity = undefined) {
|
|
94
102
|
return this._formatNumberWithGranularity(size / KiB, granularity) + `${NBSP2}KiB`;
|
|
95
103
|
}
|
|
96
104
|
|
|
97
105
|
/**
|
|
98
106
|
* @param {number} size
|
|
99
|
-
* @param {number=} granularity Controls how coarse the displayed value is
|
|
107
|
+
* @param {number=} granularity Controls how coarse the displayed value is.
|
|
108
|
+
* If undefined, the number will be displayed in full.
|
|
100
109
|
* @return {string}
|
|
101
110
|
*/
|
|
102
|
-
formatBytesToMiB(size, granularity =
|
|
111
|
+
formatBytesToMiB(size, granularity = undefined) {
|
|
103
112
|
return this._formatNumberWithGranularity(size / MiB, granularity) + `${NBSP2}MiB`;
|
|
104
113
|
}
|
|
105
114
|
|
|
106
115
|
/**
|
|
107
116
|
* @param {number} size
|
|
108
|
-
* @param {number=} granularity Controls how coarse the displayed value is
|
|
117
|
+
* @param {number=} granularity Controls how coarse the displayed value is.
|
|
118
|
+
* If undefined, the number will be displayed in full.
|
|
109
119
|
* @return {string}
|
|
110
120
|
*/
|
|
111
121
|
formatBytes(size, granularity = 1) {
|
|
@@ -118,10 +128,11 @@ export class I18n {
|
|
|
118
128
|
|
|
119
129
|
/**
|
|
120
130
|
* @param {number} size
|
|
121
|
-
* @param {number=} granularity Controls how coarse the displayed value is
|
|
131
|
+
* @param {number=} granularity Controls how coarse the displayed value is.
|
|
132
|
+
* If undefined, the number will be displayed in full.
|
|
122
133
|
* @return {string}
|
|
123
134
|
*/
|
|
124
|
-
formatBytesWithBestUnit(size, granularity =
|
|
135
|
+
formatBytesWithBestUnit(size, granularity = undefined) {
|
|
125
136
|
if (size >= MiB) return this.formatBytesToMiB(size, granularity);
|
|
126
137
|
if (size >= KiB) return this.formatBytesToKiB(size, granularity);
|
|
127
138
|
return this._formatNumberWithGranularity(size, granularity, {
|
|
@@ -133,10 +144,11 @@ export class I18n {
|
|
|
133
144
|
|
|
134
145
|
/**
|
|
135
146
|
* @param {number} size
|
|
136
|
-
* @param {number=} granularity Controls how coarse the displayed value is
|
|
147
|
+
* @param {number=} granularity Controls how coarse the displayed value is.
|
|
148
|
+
* If undefined, the number will be displayed in full.
|
|
137
149
|
* @return {string}
|
|
138
150
|
*/
|
|
139
|
-
formatKbps(size, granularity =
|
|
151
|
+
formatKbps(size, granularity = undefined) {
|
|
140
152
|
return this._formatNumberWithGranularity(size, granularity, {
|
|
141
153
|
style: 'unit',
|
|
142
154
|
unit: 'kilobit-per-second',
|
|
@@ -146,10 +158,11 @@ export class I18n {
|
|
|
146
158
|
|
|
147
159
|
/**
|
|
148
160
|
* @param {number} ms
|
|
149
|
-
* @param {number=} granularity Controls how coarse the displayed value is
|
|
161
|
+
* @param {number=} granularity Controls how coarse the displayed value is.
|
|
162
|
+
* If undefined, the number will be displayed in full.
|
|
150
163
|
* @return {string}
|
|
151
164
|
*/
|
|
152
|
-
formatMilliseconds(ms, granularity =
|
|
165
|
+
formatMilliseconds(ms, granularity = undefined) {
|
|
153
166
|
return this._formatNumberWithGranularity(ms, granularity, {
|
|
154
167
|
style: 'unit',
|
|
155
168
|
unit: 'millisecond',
|
|
@@ -159,10 +172,11 @@ export class I18n {
|
|
|
159
172
|
|
|
160
173
|
/**
|
|
161
174
|
* @param {number} ms
|
|
162
|
-
* @param {number=} granularity Controls how coarse the displayed value is
|
|
175
|
+
* @param {number=} granularity Controls how coarse the displayed value is.
|
|
176
|
+
* If undefined, the number will be displayed in full.
|
|
163
177
|
* @return {string}
|
|
164
178
|
*/
|
|
165
|
-
formatSeconds(ms, granularity =
|
|
179
|
+
formatSeconds(ms, granularity = undefined) {
|
|
166
180
|
return this._formatNumberWithGranularity(ms / 1000, granularity, {
|
|
167
181
|
style: 'unit',
|
|
168
182
|
unit: 'second',
|
package/report/renderer/util.js
CHANGED
|
@@ -429,11 +429,9 @@ class Util {
|
|
|
429
429
|
break;
|
|
430
430
|
case 'devtools': {
|
|
431
431
|
const {cpuSlowdownMultiplier, requestLatencyMs} = throttling;
|
|
432
|
-
// TODO: better api in i18n formatter such that this isn't needed.
|
|
433
|
-
const cpuGranularity = Number.isInteger(cpuSlowdownMultiplier) ? 1 : 0.1;
|
|
434
432
|
// eslint-disable-next-line max-len
|
|
435
|
-
cpuThrottling = `${Util.i18n.formatNumber(cpuSlowdownMultiplier
|
|
436
|
-
networkThrottling = `${Util.i18n.formatMilliseconds(requestLatencyMs
|
|
433
|
+
cpuThrottling = `${Util.i18n.formatNumber(cpuSlowdownMultiplier)}x slowdown (DevTools)`;
|
|
434
|
+
networkThrottling = `${Util.i18n.formatMilliseconds(requestLatencyMs)} HTTP RTT, ` +
|
|
437
435
|
`${Util.i18n.formatKbps(throttling.downloadThroughputKbps)} down, ` +
|
|
438
436
|
`${Util.i18n.formatKbps(throttling.uploadThroughputKbps)} up (DevTools)`;
|
|
439
437
|
|
|
@@ -447,10 +445,8 @@ class Util {
|
|
|
447
445
|
}
|
|
448
446
|
case 'simulate': {
|
|
449
447
|
const {cpuSlowdownMultiplier, rttMs, throughputKbps} = throttling;
|
|
450
|
-
// TODO: better api in i18n formatter such that this isn't needed.
|
|
451
|
-
const cpuGranularity = Number.isInteger(cpuSlowdownMultiplier) ? 1 : 0.1;
|
|
452
448
|
// eslint-disable-next-line max-len
|
|
453
|
-
cpuThrottling = `${Util.i18n.formatNumber(cpuSlowdownMultiplier
|
|
449
|
+
cpuThrottling = `${Util.i18n.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`;
|
|
454
450
|
networkThrottling = `${Util.i18n.formatMilliseconds(rttMs)} TCP RTT, ` +
|
|
455
451
|
`${Util.i18n.formatKbps(throughputKbps)} throughput (Simulated)`;
|
|
456
452
|
|
|
@@ -86,6 +86,55 @@ describe('DetailsRenderer', () => {
|
|
|
86
86
|
'--thumbnail not set');
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
+
it('renders with default granularity', () => {
|
|
90
|
+
const el = renderer.render({
|
|
91
|
+
type: 'table',
|
|
92
|
+
headings: [
|
|
93
|
+
{text: '', key: 'bytes', itemType: 'bytes'},
|
|
94
|
+
{text: '', key: 'numeric', itemType: 'numeric'},
|
|
95
|
+
{text: '', key: 'ms', itemType: 'ms'},
|
|
96
|
+
// Verify that 0 is ignored.
|
|
97
|
+
{text: '', key: 'ms', itemType: 'ms', granularity: 0},
|
|
98
|
+
],
|
|
99
|
+
items: [
|
|
100
|
+
{
|
|
101
|
+
bytes: 1234.567,
|
|
102
|
+
numeric: 1234.567,
|
|
103
|
+
ms: 1234.567,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
assert.equal(el.querySelectorAll('td').length, 4, 'did not render table cells');
|
|
109
|
+
assert.equal(el.querySelectorAll('td')[0].textContent, '1.2\xa0KiB');
|
|
110
|
+
assert.equal(el.querySelectorAll('td')[1].textContent, '1,234.6');
|
|
111
|
+
assert.equal(el.querySelectorAll('td')[2].textContent, '1,230\xa0ms');
|
|
112
|
+
assert.equal(el.querySelectorAll('td')[3].textContent, '1,230\xa0ms');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('renders with custom granularity', () => {
|
|
116
|
+
const el = renderer.render({
|
|
117
|
+
type: 'table',
|
|
118
|
+
headings: [
|
|
119
|
+
{text: '', key: 'bytes', itemType: 'bytes', granularity: 0.01},
|
|
120
|
+
{text: '', key: 'numeric', itemType: 'numeric', granularity: 100},
|
|
121
|
+
{text: '', key: 'ms', itemType: 'ms', granularity: 1},
|
|
122
|
+
],
|
|
123
|
+
items: [
|
|
124
|
+
{
|
|
125
|
+
bytes: 1234.567,
|
|
126
|
+
numeric: 1234.567,
|
|
127
|
+
ms: 1234.567,
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
assert.equal(el.querySelectorAll('td').length, 3, 'did not render table cells');
|
|
133
|
+
assert.equal(el.querySelectorAll('td')[0].textContent, '1.21\xa0KiB');
|
|
134
|
+
assert.equal(el.querySelectorAll('td')[1].textContent, '1,200');
|
|
135
|
+
assert.equal(el.querySelectorAll('td')[2].textContent, '1,235\xa0ms');
|
|
136
|
+
});
|
|
137
|
+
|
|
89
138
|
it('renders critical request chains', () => {
|
|
90
139
|
const details = {
|
|
91
140
|
type: 'criticalrequestchain',
|
|
@@ -21,9 +21,27 @@ 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.
|
|
26
|
-
assert.strictEqual(i18n.formatNumber(13000.456), '13,000.
|
|
24
|
+
assert.strictEqual(i18n.formatNumber(10), '10');
|
|
25
|
+
assert.strictEqual(i18n.formatNumber(100.01), '100.01');
|
|
26
|
+
assert.strictEqual(i18n.formatNumber(13000.456), '13,000.456');
|
|
27
|
+
assert.strictEqual(i18n.formatNumber(13000.456444), '13,000.456');
|
|
28
|
+
|
|
29
|
+
assert.strictEqual(i18n.formatNumber(10, 0.1), '10.0');
|
|
30
|
+
assert.strictEqual(i18n.formatNumber(100.01, 0.1), '100.0');
|
|
31
|
+
assert.strictEqual(i18n.formatNumber(13000.456, 0.1), '13,000.5');
|
|
32
|
+
|
|
33
|
+
assert.strictEqual(i18n.formatNumber(0), '0');
|
|
34
|
+
assert.strictEqual(i18n.formatNumber(-0), '0');
|
|
35
|
+
assert.strictEqual(i18n.formatNumber(-0, 0.1), '0.0');
|
|
36
|
+
assert.strictEqual(i18n.formatNumber(0.000001), '0');
|
|
37
|
+
assert.strictEqual(i18n.formatNumber(-0.000001), '0');
|
|
38
|
+
assert.strictEqual(i18n.formatNumber(0.000001, 0.1), '0.0');
|
|
39
|
+
assert.strictEqual(i18n.formatNumber(-0.000001, 0.1), '0.0');
|
|
40
|
+
|
|
41
|
+
assert.strictEqual(i18n.formatNumber(10), '10');
|
|
42
|
+
assert.strictEqual(i18n.formatNumber(100.01), '100.01');
|
|
43
|
+
assert.strictEqual(i18n.formatNumber(13000.456, 0.1), '13,000.5');
|
|
44
|
+
|
|
27
45
|
assert.strictEqual(i18n.formatInteger(10), '10');
|
|
28
46
|
assert.strictEqual(i18n.formatInteger(100.01), '100');
|
|
29
47
|
assert.strictEqual(i18n.formatInteger(13000.6), '13,001');
|
|
@@ -41,9 +59,10 @@ describe('util helpers', () => {
|
|
|
41
59
|
|
|
42
60
|
it('formats bytes', () => {
|
|
43
61
|
const i18n = new I18n('en', {...Util.UIStrings});
|
|
44
|
-
assert.equal(i18n.formatBytesToKiB(100), `0.
|
|
45
|
-
assert.equal(i18n.formatBytesToKiB(
|
|
46
|
-
assert.equal(i18n.formatBytesToKiB(
|
|
62
|
+
assert.equal(i18n.formatBytesToKiB(100), `0.098${NBSP}KiB`);
|
|
63
|
+
assert.equal(i18n.formatBytesToKiB(100, 0.1), `0.1${NBSP}KiB`);
|
|
64
|
+
assert.equal(i18n.formatBytesToKiB(2000, 0.1), `2.0${NBSP}KiB`);
|
|
65
|
+
assert.equal(i18n.formatBytesToKiB(1014 * 1024, 0.1), `1,014.0${NBSP}KiB`);
|
|
47
66
|
});
|
|
48
67
|
|
|
49
68
|
it('formats bytes with different granularities', () => {
|
|
@@ -59,11 +78,6 @@ describe('util helpers', () => {
|
|
|
59
78
|
assert.strictEqual(i18n.formatBytes(15.12345, granularity), `15${NBSP}bytes`);
|
|
60
79
|
assert.strictEqual(i18n.formatBytes(15.54321, granularity), `16${NBSP}bytes`);
|
|
61
80
|
|
|
62
|
-
granularity = 0.5;
|
|
63
|
-
assert.strictEqual(i18n.formatBytes(15.0, granularity), `15.0${NBSP}bytes`);
|
|
64
|
-
assert.strictEqual(i18n.formatBytes(15.12345, granularity), `15.0${NBSP}bytes`);
|
|
65
|
-
assert.strictEqual(i18n.formatBytes(15.54321, granularity), `15.5${NBSP}bytes`);
|
|
66
|
-
|
|
67
81
|
granularity = 0.1;
|
|
68
82
|
assert.strictEqual(i18n.formatBytes(15.0, granularity), `15.0${NBSP}bytes`);
|
|
69
83
|
assert.strictEqual(i18n.formatBytes(15.12345, granularity), `15.1${NBSP}bytes`);
|
|
@@ -75,6 +89,21 @@ describe('util helpers', () => {
|
|
|
75
89
|
assert.strictEqual(i18n.formatBytes(15.19999, granularity), `15.20${NBSP}bytes`);
|
|
76
90
|
});
|
|
77
91
|
|
|
92
|
+
it('formats bytes with invalid granularity', () => {
|
|
93
|
+
const i18n = new I18n('en', {...Util.UIStrings});
|
|
94
|
+
const granularity = 0.5;
|
|
95
|
+
const originalWarn = console.warn;
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
console.warn = () => {};
|
|
99
|
+
assert.strictEqual(i18n.formatBytes(15.0, granularity), `15${NBSP}bytes`);
|
|
100
|
+
assert.strictEqual(i18n.formatBytes(15.12345, granularity), `15${NBSP}bytes`);
|
|
101
|
+
assert.strictEqual(i18n.formatBytes(15.54321, granularity), `16${NBSP}bytes`);
|
|
102
|
+
} finally {
|
|
103
|
+
console.warn = originalWarn;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
78
107
|
it('formats kibibytes with different granularities', () => {
|
|
79
108
|
const i18n = new I18n('en', {...Util.UIStrings});
|
|
80
109
|
|
|
@@ -95,7 +124,7 @@ describe('util helpers', () => {
|
|
|
95
124
|
|
|
96
125
|
it('formats ms', () => {
|
|
97
126
|
const i18n = new I18n('en', {...Util.UIStrings});
|
|
98
|
-
assert.equal(i18n.formatMilliseconds(123), `120${NBSP}ms`);
|
|
127
|
+
assert.equal(i18n.formatMilliseconds(123, 10), `120${NBSP}ms`);
|
|
99
128
|
assert.equal(i18n.formatMilliseconds(2456.5, 0.1), `2,456.5${NBSP}ms`);
|
|
100
129
|
assert.equal(i18n.formatMilliseconds(0.000001), `0${NBSP}ms`);
|
|
101
130
|
assert.equal(i18n.formatMilliseconds(-0.000001), `0${NBSP}ms`);
|
|
@@ -129,10 +158,10 @@ describe('util helpers', () => {
|
|
|
129
158
|
const number = 12346.858558;
|
|
130
159
|
|
|
131
160
|
const i18n = new I18n('de', {...Util.UIStrings});
|
|
132
|
-
assert.strictEqual(i18n.formatNumber(number), '12.346,
|
|
133
|
-
assert.strictEqual(i18n.formatBytesToKiB(number), `12,1${NBSP}KiB`);
|
|
134
|
-
assert.strictEqual(i18n.formatMilliseconds(number), `12.350${NBSP}ms`);
|
|
135
|
-
assert.strictEqual(i18n.formatSeconds(number), `12,
|
|
161
|
+
assert.strictEqual(i18n.formatNumber(number), '12.346,859');
|
|
162
|
+
assert.strictEqual(i18n.formatBytesToKiB(number, 0.1), `12,1${NBSP}KiB`);
|
|
163
|
+
assert.strictEqual(i18n.formatMilliseconds(number, 10), `12.350${NBSP}ms`);
|
|
164
|
+
assert.strictEqual(i18n.formatSeconds(number), `12,347${NBSP}Sek.`);
|
|
136
165
|
});
|
|
137
166
|
|
|
138
167
|
it('uses decimal comma with en-XA test locale', () => {
|
|
@@ -140,10 +169,10 @@ describe('util helpers', () => {
|
|
|
140
169
|
const number = 12346.858558;
|
|
141
170
|
|
|
142
171
|
const i18n = new I18n('en-XA', {...Util.UIStrings});
|
|
143
|
-
assert.strictEqual(i18n.formatNumber(number), '12.346,
|
|
144
|
-
assert.strictEqual(i18n.formatBytesToKiB(number), `12,1${NBSP}KiB`);
|
|
145
|
-
assert.strictEqual(i18n.formatMilliseconds(number), `12.
|
|
146
|
-
assert.strictEqual(i18n.formatSeconds(number), `12
|
|
172
|
+
assert.strictEqual(i18n.formatNumber(number), '12.346,859');
|
|
173
|
+
assert.strictEqual(i18n.formatBytesToKiB(number, 0.1), `12,1${NBSP}KiB`);
|
|
174
|
+
assert.strictEqual(i18n.formatMilliseconds(number, 100), `12.300${NBSP}ms`);
|
|
175
|
+
assert.strictEqual(i18n.formatSeconds(number, 1), `12${NBSP}Sek.`);
|
|
147
176
|
});
|
|
148
177
|
|
|
149
178
|
it('should not crash on unknown locales', () => {
|
|
@@ -328,7 +328,7 @@ Array [
|
|
|
328
328
|
}
|
|
329
329
|
});
|
|
330
330
|
|
|
331
|
-
it('uses null if the metric is
|
|
331
|
+
it('uses null if the metric\'s value is undefined', () => {
|
|
332
332
|
const categoryClone = JSON.parse(JSON.stringify(category));
|
|
333
333
|
const lcp = categoryClone.auditRefs.find(audit => audit.id === 'largest-contentful-paint');
|
|
334
334
|
lcp.result.numericValue = undefined;
|
|
@@ -336,6 +336,16 @@ Array [
|
|
|
336
336
|
const href = renderer._getScoringCalculatorHref(categoryClone.auditRefs);
|
|
337
337
|
expect(href).toContain('LCP=null');
|
|
338
338
|
});
|
|
339
|
+
|
|
340
|
+
it('uses null if the metric\'s value is null (LR)', () => {
|
|
341
|
+
const categoryClone = JSON.parse(JSON.stringify(category));
|
|
342
|
+
const lcp = categoryClone.auditRefs.find(audit => audit.id === 'largest-contentful-paint');
|
|
343
|
+
// In LR, we think there might be some case where undefined becomes null, but we can't prove it.
|
|
344
|
+
lcp.result.numericValue = null;
|
|
345
|
+
lcp.result.score = null;
|
|
346
|
+
const href = renderer._getScoringCalculatorHref(categoryClone.auditRefs);
|
|
347
|
+
expect(href).toContain('LCP=null');
|
|
348
|
+
});
|
|
339
349
|
});
|
|
340
350
|
|
|
341
351
|
// This is done all in CSS, but tested here.
|
|
@@ -777,7 +777,7 @@
|
|
|
777
777
|
"message": "Specifying a doctype prevents the browser from switching to quirks-mode. [Learn more](https://web.dev/doctype/)."
|
|
778
778
|
},
|
|
779
779
|
"lighthouse-core/audits/dobetterweb/doctype.js | explanationBadDoctype": {
|
|
780
|
-
"message": "Doctype name must be the
|
|
780
|
+
"message": "Doctype name must be the string `html`"
|
|
781
781
|
},
|
|
782
782
|
"lighthouse-core/audits/dobetterweb/doctype.js | explanationNoDoctype": {
|
|
783
783
|
"message": "Document must contain a doctype"
|
|
@@ -788,6 +788,9 @@
|
|
|
788
788
|
"lighthouse-core/audits/dobetterweb/doctype.js | explanationSystemId": {
|
|
789
789
|
"message": "Expected systemId to be an empty string"
|
|
790
790
|
},
|
|
791
|
+
"lighthouse-core/audits/dobetterweb/doctype.js | explanationWrongDoctype": {
|
|
792
|
+
"message": "Document contains a doctype that triggers quirks-mode"
|
|
793
|
+
},
|
|
791
794
|
"lighthouse-core/audits/dobetterweb/doctype.js | failureTitle": {
|
|
792
795
|
"message": "Page lacks the HTML doctype, thus triggering quirks-mode"
|
|
793
796
|
},
|
|
@@ -1187,6 +1190,9 @@
|
|
|
1187
1190
|
"lighthouse-core/audits/metrics/cumulative-layout-shift.js | description": {
|
|
1188
1191
|
"message": "Cumulative Layout Shift measures the movement of visible elements within the viewport. [Learn more](https://web.dev/cls/)."
|
|
1189
1192
|
},
|
|
1193
|
+
"lighthouse-core/audits/metrics/experimental-interaction-to-next-paint.js | description": {
|
|
1194
|
+
"message": "Interaction to Next Paint measures page responsiveness, how long it takes the page to visibly respond to user input. [Learn more](https://web.dev/inp/)."
|
|
1195
|
+
},
|
|
1190
1196
|
"lighthouse-core/audits/metrics/first-contentful-paint.js | description": {
|
|
1191
1197
|
"message": "First Contentful Paint marks the time at which the first text or image is painted. [Learn more](https://web.dev/first-contentful-paint/)."
|
|
1192
1198
|
},
|
|
@@ -1958,6 +1964,9 @@
|
|
|
1958
1964
|
"lighthouse-core/lib/i18n/i18n.js | imageResourceType": {
|
|
1959
1965
|
"message": "Image"
|
|
1960
1966
|
},
|
|
1967
|
+
"lighthouse-core/lib/i18n/i18n.js | interactionToNextPaint": {
|
|
1968
|
+
"message": "Interaction to Next Paint"
|
|
1969
|
+
},
|
|
1961
1970
|
"lighthouse-core/lib/i18n/i18n.js | interactiveMetric": {
|
|
1962
1971
|
"message": "Time to Interactive"
|
|
1963
1972
|
},
|
|
@@ -777,7 +777,7 @@
|
|
|
777
777
|
"message": "Ŝṕêćîf́ŷín̂ǵ â d́ôćt̂ýp̂é p̂ŕêv́êńt̂ś t̂h́ê b́r̂óŵśêŕ f̂ŕôḿ ŝẃît́ĉh́îńĝ t́ô q́ûír̂ḱŝ-ḿôd́ê. [Ĺêár̂ń m̂ór̂é](https://web.dev/doctype/)."
|
|
778
778
|
},
|
|
779
779
|
"lighthouse-core/audits/dobetterweb/doctype.js | explanationBadDoctype": {
|
|
780
|
-
"message": "D̂óĉt́ŷṕê ńâḿê ḿûśt̂ b́ê t́ĥé
|
|
780
|
+
"message": "D̂óĉt́ŷṕê ńâḿê ḿûśt̂ b́ê t́ĥé ŝt́r̂ín̂ǵ `html`"
|
|
781
781
|
},
|
|
782
782
|
"lighthouse-core/audits/dobetterweb/doctype.js | explanationNoDoctype": {
|
|
783
783
|
"message": "D̂óĉúm̂én̂t́ m̂úŝt́ ĉón̂t́âín̂ á d̂óĉt́ŷṕê"
|
|
@@ -788,6 +788,9 @@
|
|
|
788
788
|
"lighthouse-core/audits/dobetterweb/doctype.js | explanationSystemId": {
|
|
789
789
|
"message": "Êx́p̂éĉt́êd́ ŝýŝt́êḿÎd́ t̂ó b̂é âń êḿp̂t́ŷ śt̂ŕîńĝ"
|
|
790
790
|
},
|
|
791
|
+
"lighthouse-core/audits/dobetterweb/doctype.js | explanationWrongDoctype": {
|
|
792
|
+
"message": "D̂óĉúm̂én̂t́ ĉón̂t́âín̂ś â d́ôćt̂ýp̂é t̂h́ât́ t̂ŕîǵĝér̂ś q̂úîŕk̂ś-m̂ód̂é"
|
|
793
|
+
},
|
|
791
794
|
"lighthouse-core/audits/dobetterweb/doctype.js | failureTitle": {
|
|
792
795
|
"message": "P̂áĝé l̂áĉḱŝ t́ĥé ĤT́M̂Ĺ d̂óĉt́ŷṕê, t́ĥúŝ t́r̂íĝǵêŕîńĝ q́ûír̂ḱŝ-ḿôd́ê"
|
|
793
796
|
},
|
|
@@ -1187,6 +1190,9 @@
|
|
|
1187
1190
|
"lighthouse-core/audits/metrics/cumulative-layout-shift.js | description": {
|
|
1188
1191
|
"message": "Ĉúm̂úl̂át̂ív̂é L̂áŷóût́ Ŝh́îf́t̂ ḿêáŝúr̂éŝ t́ĥé m̂óv̂ém̂én̂t́ ôf́ v̂íŝíb̂ĺê él̂ém̂én̂t́ŝ ẃît́ĥín̂ t́ĥé v̂íêẃp̂ór̂t́. [L̂éâŕn̂ ḿôŕê](https://web.dev/cls/)."
|
|
1189
1192
|
},
|
|
1193
|
+
"lighthouse-core/audits/metrics/experimental-interaction-to-next-paint.js | description": {
|
|
1194
|
+
"message": "Îńt̂ér̂áĉt́îón̂ t́ô Ńêx́t̂ Ṕâín̂t́ m̂éâśûŕêś p̂áĝé r̂éŝṕôńŝív̂én̂éŝś, ĥóŵ ĺôńĝ ít̂ t́âḱêś t̂h́ê ṕâǵê t́ô v́îśîb́l̂ý r̂éŝṕôńd̂ t́ô úŝér̂ ín̂ṕût́. [L̂éâŕn̂ ḿôŕê](https://web.dev/inp/)."
|
|
1195
|
+
},
|
|
1190
1196
|
"lighthouse-core/audits/metrics/first-contentful-paint.js | description": {
|
|
1191
1197
|
"message": "F̂ír̂śt̂ Ćôńt̂én̂t́f̂úl̂ Ṕâín̂t́ m̂ár̂ḱŝ t́ĥé t̂ím̂é ât́ ŵh́îćĥ t́ĥé f̂ír̂śt̂ t́êx́t̂ ór̂ ím̂áĝé îś p̂áîńt̂éd̂. [Ĺêár̂ń m̂ór̂é](https://web.dev/first-contentful-paint/)."
|
|
1192
1198
|
},
|
|
@@ -1958,6 +1964,9 @@
|
|
|
1958
1964
|
"lighthouse-core/lib/i18n/i18n.js | imageResourceType": {
|
|
1959
1965
|
"message": "Îḿâǵê"
|
|
1960
1966
|
},
|
|
1967
|
+
"lighthouse-core/lib/i18n/i18n.js | interactionToNextPaint": {
|
|
1968
|
+
"message": "Îńt̂ér̂áĉt́îón̂ t́ô Ńêx́t̂ Ṕâín̂t́"
|
|
1969
|
+
},
|
|
1961
1970
|
"lighthouse-core/lib/i18n/i18n.js | interactiveMetric": {
|
|
1962
1971
|
"message": "T̂ím̂é t̂ó Îńt̂ér̂áĉt́îv́ê"
|
|
1963
1972
|
},
|
package/types/artifacts.d.ts
CHANGED
|
@@ -238,6 +238,7 @@ declare module Artifacts {
|
|
|
238
238
|
interface Accessibility {
|
|
239
239
|
violations: Array<AxeRuleResult>;
|
|
240
240
|
notApplicable: Array<Pick<AxeRuleResult, 'id'>>;
|
|
241
|
+
passes: Array<Pick<AxeRuleResult, 'id'>>;
|
|
241
242
|
incomplete: Array<AxeRuleResult>;
|
|
242
243
|
version: string;
|
|
243
244
|
}
|
|
@@ -251,6 +252,7 @@ declare module Artifacts {
|
|
|
251
252
|
name: string;
|
|
252
253
|
publicId: string;
|
|
253
254
|
systemId: string;
|
|
255
|
+
documentCompatMode: string;
|
|
254
256
|
}
|
|
255
257
|
|
|
256
258
|
interface DOMStats {
|
|
@@ -960,6 +962,7 @@ export interface TraceEvent {
|
|
|
960
962
|
documentLoaderURL?: string;
|
|
961
963
|
frames?: {
|
|
962
964
|
frame: string;
|
|
965
|
+
url: string;
|
|
963
966
|
parent?: string;
|
|
964
967
|
processId?: number;
|
|
965
968
|
}[];
|
|
@@ -996,6 +999,9 @@ export interface TraceEvent {
|
|
|
996
999
|
compositeFailed?: number;
|
|
997
1000
|
unsupportedProperties?: string[];
|
|
998
1001
|
size?: number;
|
|
1002
|
+
/** Responsiveness data. */
|
|
1003
|
+
interactionType?: 'drag'|'keyboard'|'tapOrClick';
|
|
1004
|
+
maxDuration?: number;
|
|
999
1005
|
};
|
|
1000
1006
|
frame?: string;
|
|
1001
1007
|
name?: string;
|