lighthouse 8.6.0-dev.20211030 → 8.6.0-dev.20211103
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/flow.js +13 -13
- package/dist/report/standalone.js +41 -35
- package/flow-report/.eslintrc.cjs +2 -0
- package/flow-report/assets/standalone-flow-template.html +3 -2
- package/flow-report/assets/styles.css +1 -1
- package/flow-report/src/app.tsx +10 -11
- package/flow-report/src/common.tsx +22 -9
- package/flow-report/src/header.tsx +3 -3
- package/flow-report/src/i18n/i18n.tsx +10 -6
- package/flow-report/src/icons.tsx +30 -9
- package/flow-report/src/sidebar/flow.tsx +3 -3
- package/flow-report/src/sidebar/sidebar.tsx +30 -11
- package/flow-report/src/summary/category.tsx +9 -4
- package/flow-report/src/summary/summary.tsx +9 -3
- package/flow-report/src/util.ts +31 -19
- package/flow-report/src/wrappers/report-renderer.tsx +10 -3
- package/flow-report/src/wrappers/report.tsx +19 -10
- package/flow-report/standalone-flow.tsx +4 -3
- package/flow-report/test/common-test.tsx +25 -10
- package/flow-report/test/header-test.tsx +6 -6
- package/flow-report/test/setup/env-setup.ts +1 -1
- package/flow-report/test/sidebar/sidebar-test.tsx +43 -1
- package/flow-report/test/summary/category-test.tsx +5 -5
- package/flow-report/test/util-test.tsx +32 -11
- package/lighthouse-cli/.eslintrc.cjs +2 -0
- package/lighthouse-cli/cli-flags.js +1 -1
- package/lighthouse-cli/test/smokehouse/lighthouse-runners/bundle.js +4 -2
- package/lighthouse-cli/test/smokehouse/smokehouse.js +1 -1
- package/lighthouse-core/audits/audit.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-total-blocking-time.js +3 -4
- package/lighthouse-core/computed/metrics/tbt-utils.js +57 -0
- package/lighthouse-core/computed/metrics/total-blocking-time.js +3 -53
- package/lighthouse-core/computed/resource-summary.js +1 -1
- package/lighthouse-core/config/config-helpers.js +20 -10
- package/lighthouse-core/config/default-config.js +59 -55
- package/lighthouse-core/fraggle-rock/config/default-config.js +1 -1
- package/lighthouse-core/fraggle-rock/gather/base-gatherer.js +6 -1
- package/lighthouse-core/gather/connections/cri.js +1 -1
- package/lighthouse-core/gather/gatherers/dobetterweb/response-compression.js +1 -0
- package/lighthouse-core/lib/asset-saver.js +4 -1
- package/lighthouse-core/lib/lh-env.js +2 -0
- package/lighthouse-core/lib/proto-preprocessor.js +14 -2
- package/lighthouse-core/lib/tappable-rects.js +8 -15
- package/lighthouse-core/lib/url-shim.js +1 -1
- package/lighthouse-core/runner.js +1 -1
- package/lighthouse-core/util-commonjs.js +25 -11
- package/package.json +11 -8
- package/report/.eslintrc.cjs +2 -0
- package/report/assets/standalone-template.html +2 -3
- package/report/assets/styles.css +227 -251
- package/report/assets/templates.html +19 -29
- package/report/clients/bundle.js +1 -0
- package/report/clients/standalone.js +6 -15
- package/report/renderer/api.js +32 -0
- package/report/renderer/category-renderer.js +22 -18
- package/report/renderer/components.js +46 -79
- package/report/renderer/crc-details-renderer.js +15 -12
- package/report/renderer/dom.js +16 -1
- package/report/renderer/drop-down-menu.js +2 -2
- package/report/renderer/element-screenshot-renderer.js +8 -8
- package/report/renderer/features-util.js +1 -1
- package/report/renderer/open-tab.js +9 -3
- package/report/renderer/performance-category-renderer.js +51 -24
- package/report/renderer/report-renderer.js +34 -10
- package/report/renderer/report-ui-features.js +36 -33
- package/report/renderer/swap-locale-feature.js +3 -3
- package/report/renderer/topbar-features.js +19 -21
- package/report/renderer/util.js +26 -11
- package/report/test/clients/bundle-test.js +3 -0
- package/report/test/renderer/category-renderer-test.js +2 -2
- package/report/test/renderer/performance-category-renderer-test.js +35 -9
- package/report/test/renderer/report-renderer-axe-test.js +5 -2
- package/report/test/renderer/report-renderer-test.js +14 -11
- package/report/test/renderer/report-ui-features-test.js +14 -10
- package/report/test/renderer/util-test.js +13 -31
- package/report/test-assets/faux-psi-template.html +2 -7
- package/report/test-assets/faux-psi.js +20 -39
- package/report/types/html-renderer.d.ts +2 -0
- package/report/types/report-renderer.d.ts +23 -0
- package/shared/localization/format.js +9 -4
- package/shared/localization/locales/ar-XB.json +0 -15
- package/shared/localization/locales/ar.json +0 -15
- package/shared/localization/locales/bg.json +0 -15
- package/shared/localization/locales/ca.json +0 -15
- package/shared/localization/locales/cs.json +0 -15
- package/shared/localization/locales/da.json +0 -15
- package/shared/localization/locales/de.json +0 -15
- package/shared/localization/locales/el.json +0 -15
- package/shared/localization/locales/en-GB.json +0 -15
- package/shared/localization/locales/en-US.json +19 -16
- package/shared/localization/locales/en-XA.json +0 -15
- package/shared/localization/locales/en-XL.json +19 -16
- package/shared/localization/locales/es-419.json +0 -15
- package/shared/localization/locales/es.json +0 -15
- package/shared/localization/locales/fi.json +0 -15
- package/shared/localization/locales/fil.json +0 -15
- package/shared/localization/locales/fr.json +0 -15
- package/shared/localization/locales/he.json +0 -15
- package/shared/localization/locales/hi.json +0 -15
- package/shared/localization/locales/hr.json +0 -15
- package/shared/localization/locales/hu.json +0 -15
- package/shared/localization/locales/id.json +0 -15
- package/shared/localization/locales/it.json +0 -15
- package/shared/localization/locales/ja.json +0 -15
- package/shared/localization/locales/ko.json +0 -15
- package/shared/localization/locales/lt.json +0 -15
- package/shared/localization/locales/lv.json +0 -15
- package/shared/localization/locales/nl.json +0 -15
- package/shared/localization/locales/no.json +0 -15
- package/shared/localization/locales/pl.json +0 -15
- package/shared/localization/locales/pt-PT.json +0 -15
- package/shared/localization/locales/pt.json +0 -15
- package/shared/localization/locales/ro.json +0 -15
- package/shared/localization/locales/ru.json +0 -15
- package/shared/localization/locales/sk.json +0 -15
- package/shared/localization/locales/sl.json +0 -15
- package/shared/localization/locales/sr-Latn.json +0 -15
- package/shared/localization/locales/sr.json +0 -15
- package/shared/localization/locales/sv.json +0 -15
- package/shared/localization/locales/ta.json +0 -15
- package/shared/localization/locales/te.json +0 -15
- package/shared/localization/locales/th.json +0 -15
- package/shared/localization/locales/tr.json +0 -15
- package/shared/localization/locales/uk.json +0 -15
- package/shared/localization/locales/vi.json +0 -15
- package/shared/localization/locales/zh-HK.json +0 -15
- package/shared/localization/locales/zh-TW.json +0 -15
- package/shared/localization/locales/zh.json +0 -15
- package/third-party/chromium-synchronization/installability-errors-test.js +2 -0
- package/types/lhr/flow.d.ts +3 -2
- package/types/rollup-plugin-postprocess.d.ts +10 -0
- package/lighthouse-core/audits/dobetterweb/external-anchors-use-rel-noopener.js +0 -96
|
@@ -24,8 +24,6 @@ export class TopbarFeatures {
|
|
|
24
24
|
this.lhr; // eslint-disable-line no-unused-expressions
|
|
25
25
|
this._reportUIFeatures = reportUIFeatures;
|
|
26
26
|
this._dom = dom;
|
|
27
|
-
/** @type {Document} */
|
|
28
|
-
this._document = this._dom.document();
|
|
29
27
|
this._dropDownMenu = new DropDownMenu(this._dom);
|
|
30
28
|
this._copyAttempt = false;
|
|
31
29
|
/** @type {HTMLElement} */
|
|
@@ -48,19 +46,19 @@ export class TopbarFeatures {
|
|
|
48
46
|
*/
|
|
49
47
|
enable(lhr) {
|
|
50
48
|
this.lhr = lhr;
|
|
51
|
-
this.
|
|
52
|
-
this.
|
|
49
|
+
this._dom.rootEl.addEventListener('keyup', this.onKeyUp);
|
|
50
|
+
this._dom.document().addEventListener('copy', this.onCopy);
|
|
53
51
|
this._dropDownMenu.setup(this.onDropDownMenuClick);
|
|
54
52
|
this._setUpCollapseDetailsAfterPrinting();
|
|
55
53
|
|
|
56
|
-
const topbarLogo = this._dom.find('.lh-topbar__logo', this.
|
|
54
|
+
const topbarLogo = this._dom.find('.lh-topbar__logo', this._dom.rootEl);
|
|
57
55
|
topbarLogo.addEventListener('click', () => toggleDarkTheme(this._dom));
|
|
58
56
|
|
|
59
57
|
// There is only a sticky header when at least 2 categories are present.
|
|
60
58
|
if (Object.keys(this.lhr.categories).length >= 2) {
|
|
61
59
|
this._setupStickyHeaderElements();
|
|
62
|
-
const
|
|
63
|
-
const elToAddScrollListener = this._getScrollParent(
|
|
60
|
+
const reportRootEl = this._dom.rootEl;
|
|
61
|
+
const elToAddScrollListener = this._getScrollParent(reportRootEl);
|
|
64
62
|
elToAddScrollListener.addEventListener('scroll', this._updateStickyHeaderOnScroll);
|
|
65
63
|
|
|
66
64
|
// Use ResizeObserver where available.
|
|
@@ -70,7 +68,7 @@ export class TopbarFeatures {
|
|
|
70
68
|
// For now, limit to DevTools.
|
|
71
69
|
if (this._dom.isDevTools()) {
|
|
72
70
|
const resizeObserver = new window.ResizeObserver(this._updateStickyHeaderOnScroll);
|
|
73
|
-
resizeObserver.observe(
|
|
71
|
+
resizeObserver.observe(reportRootEl);
|
|
74
72
|
} else {
|
|
75
73
|
window.addEventListener('resize', this._updateStickyHeaderOnScroll);
|
|
76
74
|
}
|
|
@@ -112,7 +110,7 @@ export class TopbarFeatures {
|
|
|
112
110
|
try {
|
|
113
111
|
this._reportUIFeatures._saveFile(new Blob([htmlStr], {type: 'text/html'}));
|
|
114
112
|
} catch (e) {
|
|
115
|
-
this._dom.fireEventOn('lh-log', this.
|
|
113
|
+
this._dom.fireEventOn('lh-log', this._dom.document(), {
|
|
116
114
|
cmd: 'error', msg: 'Could not export as HTML. ' + e.message,
|
|
117
115
|
});
|
|
118
116
|
}
|
|
@@ -152,7 +150,7 @@ export class TopbarFeatures {
|
|
|
152
150
|
e.preventDefault();
|
|
153
151
|
e.clipboardData.setData('text/plain', JSON.stringify(this.lhr, null, 2));
|
|
154
152
|
|
|
155
|
-
this._dom.fireEventOn('lh-log', this.
|
|
153
|
+
this._dom.fireEventOn('lh-log', this._dom.document(), {
|
|
156
154
|
cmd: 'log', msg: 'Report JSON copied to clipboard',
|
|
157
155
|
});
|
|
158
156
|
}
|
|
@@ -164,28 +162,28 @@ export class TopbarFeatures {
|
|
|
164
162
|
* Copies the report JSON to the clipboard (if supported by the browser).
|
|
165
163
|
*/
|
|
166
164
|
onCopyButtonClick() {
|
|
167
|
-
this._dom.fireEventOn('lh-analytics', this.
|
|
165
|
+
this._dom.fireEventOn('lh-analytics', this._dom.document(), {
|
|
168
166
|
cmd: 'send',
|
|
169
167
|
fields: {hitType: 'event', eventCategory: 'report', eventAction: 'copy'},
|
|
170
168
|
});
|
|
171
169
|
|
|
172
170
|
try {
|
|
173
|
-
if (this.
|
|
171
|
+
if (this._dom.document().queryCommandSupported('copy')) {
|
|
174
172
|
this._copyAttempt = true;
|
|
175
173
|
|
|
176
174
|
// Note: In Safari 10.0.1, execCommand('copy') returns true if there's
|
|
177
175
|
// a valid text selection on the page. See http://caniuse.com/#feat=clipboard.
|
|
178
|
-
if (!this.
|
|
176
|
+
if (!this._dom.document().execCommand('copy')) {
|
|
179
177
|
this._copyAttempt = false; // Prevent event handler from seeing this as a copy attempt.
|
|
180
178
|
|
|
181
|
-
this._dom.fireEventOn('lh-log', this.
|
|
179
|
+
this._dom.fireEventOn('lh-log', this._dom.document(), {
|
|
182
180
|
cmd: 'warn', msg: 'Your browser does not support copy to clipboard.',
|
|
183
181
|
});
|
|
184
182
|
}
|
|
185
183
|
}
|
|
186
184
|
} catch (e) {
|
|
187
185
|
this._copyAttempt = false;
|
|
188
|
-
this._dom.fireEventOn('lh-log', this.
|
|
186
|
+
this._dom.fireEventOn('lh-log', this._dom.document(), {cmd: 'log', msg: e.message});
|
|
189
187
|
}
|
|
190
188
|
}
|
|
191
189
|
|
|
@@ -206,7 +204,7 @@ export class TopbarFeatures {
|
|
|
206
204
|
* open a `<details>` element.
|
|
207
205
|
*/
|
|
208
206
|
expandAllDetails() {
|
|
209
|
-
const details = this._dom.findAll('.lh-categories details', this.
|
|
207
|
+
const details = this._dom.findAll('.lh-categories details', this._dom.rootEl);
|
|
210
208
|
details.map(detail => detail.open = true);
|
|
211
209
|
}
|
|
212
210
|
|
|
@@ -215,7 +213,7 @@ export class TopbarFeatures {
|
|
|
215
213
|
* open a `<details>` element.
|
|
216
214
|
*/
|
|
217
215
|
collapseAllDetails() {
|
|
218
|
-
const details = this._dom.findAll('.lh-categories details', this.
|
|
216
|
+
const details = this._dom.findAll('.lh-categories details', this._dom.rootEl);
|
|
219
217
|
details.map(detail => detail.open = false);
|
|
220
218
|
}
|
|
221
219
|
|
|
@@ -274,9 +272,9 @@ export class TopbarFeatures {
|
|
|
274
272
|
}
|
|
275
273
|
|
|
276
274
|
_setupStickyHeaderElements() {
|
|
277
|
-
this.topbarEl = this._dom.find('div.lh-topbar', this.
|
|
278
|
-
this.scoreScaleEl = this._dom.find('div.lh-scorescale', this.
|
|
279
|
-
this.stickyHeaderEl = this._dom.find('div.lh-sticky-header', this.
|
|
275
|
+
this.topbarEl = this._dom.find('div.lh-topbar', this._dom.rootEl);
|
|
276
|
+
this.scoreScaleEl = this._dom.find('div.lh-scorescale', this._dom.rootEl);
|
|
277
|
+
this.stickyHeaderEl = this._dom.find('div.lh-sticky-header', this._dom.rootEl);
|
|
280
278
|
|
|
281
279
|
// Highlighter will be absolutely positioned at first gauge, then transformed on scroll.
|
|
282
280
|
this.highlightEl = this._dom.createChildOf(this.stickyHeaderEl, 'div', 'lh-highlighter');
|
|
@@ -290,7 +288,7 @@ export class TopbarFeatures {
|
|
|
290
288
|
|
|
291
289
|
// Highlight mini gauge when section is in view.
|
|
292
290
|
// In view = the last category that starts above the middle of the window.
|
|
293
|
-
const categoryEls = Array.from(this.
|
|
291
|
+
const categoryEls = Array.from(this._dom.rootEl.querySelectorAll('.lh-category'));
|
|
294
292
|
const categoriesAboveTheMiddle =
|
|
295
293
|
categoryEls.filter(el => el.getBoundingClientRect().top - window.innerHeight / 2 < 0);
|
|
296
294
|
const highlightIndex =
|
package/report/renderer/util.js
CHANGED
|
@@ -38,7 +38,11 @@ const listOfTlds = [
|
|
|
38
38
|
'web', 'spb', 'blog', 'jus', 'kiev', 'mil', 'wi', 'qc', 'ca', 'bel', 'on',
|
|
39
39
|
];
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
class Util {
|
|
42
|
+
/** @type {I18n<typeof UIStrings>} */
|
|
43
|
+
// @ts-expect-error: Is set in report renderer.
|
|
44
|
+
static i18n = null;
|
|
45
|
+
|
|
42
46
|
static get PASS_THRESHOLD() {
|
|
43
47
|
return PASS_THRESHOLD;
|
|
44
48
|
}
|
|
@@ -417,7 +421,7 @@ export class Util {
|
|
|
417
421
|
throttling.downloadThroughputKbps === 1.6 * 1024 * 0.9 &&
|
|
418
422
|
throttling.uploadThroughputKbps === 750 * 0.9;
|
|
419
423
|
};
|
|
420
|
-
summary =
|
|
424
|
+
summary = isSlow4G() ? Util.i18n.strings.runtimeSlow4g : Util.i18n.strings.runtimeCustom;
|
|
421
425
|
break;
|
|
422
426
|
}
|
|
423
427
|
case 'simulate': {
|
|
@@ -429,7 +433,7 @@ export class Util {
|
|
|
429
433
|
const isSlow4G = () => {
|
|
430
434
|
return rttMs === 150 && throughputKbps === 1.6 * 1024;
|
|
431
435
|
};
|
|
432
|
-
summary = isSlow4G() ?
|
|
436
|
+
summary = isSlow4G() ? Util.i18n.strings.runtimeSlow4g : Util.i18n.strings.runtimeCustom;
|
|
433
437
|
break;
|
|
434
438
|
}
|
|
435
439
|
default:
|
|
@@ -516,10 +520,9 @@ export class Util {
|
|
|
516
520
|
let totalWeight = 0;
|
|
517
521
|
for (const auditRef of category.auditRefs) {
|
|
518
522
|
const auditPassed = Util.showAsPassed(auditRef.result);
|
|
519
|
-
const notDisplayed = !auditRef.group && category.id === 'performance';
|
|
520
523
|
|
|
521
524
|
// Don't count the audit if it's manual, N/A, or isn't displayed.
|
|
522
|
-
if (
|
|
525
|
+
if (auditRef.group === 'hidden' ||
|
|
523
526
|
auditRef.result.scoreDisplayMode === 'manual' ||
|
|
524
527
|
auditRef.result.scoreDisplayMode === 'notApplicable') {
|
|
525
528
|
continue;
|
|
@@ -555,14 +558,10 @@ Util.getUniqueSuffix = (() => {
|
|
|
555
558
|
};
|
|
556
559
|
})();
|
|
557
560
|
|
|
558
|
-
/** @type {I18n<typeof Util['UIStrings']>} */
|
|
559
|
-
// @ts-expect-error: Is set in report renderer.
|
|
560
|
-
Util.i18n = null;
|
|
561
|
-
|
|
562
561
|
/**
|
|
563
562
|
* Report-renderer-specific strings.
|
|
564
563
|
*/
|
|
565
|
-
|
|
564
|
+
const UIStrings = {
|
|
566
565
|
/** Disclaimer shown to users below the metric values (First Contentful Paint, Time to Interactive, etc) to warn them that the numbers they see will likely change slightly the next time they run Lighthouse. */
|
|
567
566
|
varianceDisclaimer: 'Values are estimated and may vary. The [performance score is calculated](https://web.dev/performance-scoring/) directly from these metrics.',
|
|
568
567
|
/** Text link pointing to an interactive calculator that explains Lighthouse scoring. The link text should be fairly short. */
|
|
@@ -662,6 +661,22 @@ Util.UIStrings = {
|
|
|
662
661
|
|
|
663
662
|
/** Descriptive explanation for environment throttling that was provided by the runtime environment instead of provided by Lighthouse throttling. */
|
|
664
663
|
throttlingProvided: 'Provided by environment',
|
|
664
|
+
/** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Show' and 'Hide'. */
|
|
665
|
+
show: 'Show',
|
|
666
|
+
/** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Show' and 'Hide'. */
|
|
667
|
+
hide: 'Hide',
|
|
668
|
+
/** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Expand view' and 'Collapse view'. */
|
|
669
|
+
expandView: 'Expand view',
|
|
670
|
+
/** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Expand view' and 'Collapse view'. */
|
|
671
|
+
collapseView: 'Collapse view',
|
|
672
|
+
/** Label indicating that Lighthouse throttled the page to emulate a slow 4G network connection. */
|
|
673
|
+
runtimeSlow4g: 'Slow 4G throttling',
|
|
674
|
+
/** Label indicating that Lighthouse throttled the page using custom throttling settings. */
|
|
675
|
+
runtimeCustom: 'Custom throttling',
|
|
665
676
|
};
|
|
677
|
+
Util.UIStrings = UIStrings;
|
|
666
678
|
|
|
667
|
-
export
|
|
679
|
+
export {
|
|
680
|
+
Util,
|
|
681
|
+
UIStrings,
|
|
682
|
+
};
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import fs from 'fs';
|
|
10
10
|
|
|
11
11
|
import jsdom from 'jsdom';
|
|
12
|
+
import {jest} from '@jest/globals';
|
|
12
13
|
|
|
13
14
|
import * as lighthouseRenderer from '../../clients/bundle.js';
|
|
14
15
|
import {LH_ROOT} from '../../../root.js';
|
|
@@ -22,6 +23,8 @@ const sampleResultsStr =
|
|
|
22
23
|
describe('lighthouseRenderer bundle', () => {
|
|
23
24
|
let document;
|
|
24
25
|
beforeAll(() => {
|
|
26
|
+
global.console.warn = jest.fn();
|
|
27
|
+
|
|
25
28
|
const {window} = new jsdom.JSDOM();
|
|
26
29
|
document = window.document;
|
|
27
30
|
|
|
@@ -197,8 +197,8 @@ describe('CategoryRenderer', () => {
|
|
|
197
197
|
'score shows informative and dash icon');
|
|
198
198
|
|
|
199
199
|
assert.ok(pwaCategory.manualDescription);
|
|
200
|
-
const description = categoryDOM
|
|
201
|
-
.querySelector('.lh-
|
|
200
|
+
const description = categoryDOM.querySelector('.lh-clump--manual').closest('.lh-audit-group')
|
|
201
|
+
.querySelector('.lh-audit-group__description').textContent;
|
|
202
202
|
// may need to be adjusted if description includes a link at the beginning
|
|
203
203
|
assert.ok(description.startsWith(pwaCategory.manualDescription.substring(0, 20)),
|
|
204
204
|
'no manual description');
|
|
@@ -96,11 +96,23 @@ describe('PerfCategoryRenderer', () => {
|
|
|
96
96
|
assert.strictEqual(new URL(calcLink.href).hostname, 'googlechrome.github.io');
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
+
it('ignores hidden audits', () => {
|
|
100
|
+
const categoryDOM = renderer.render(category, sampleResults.categoryGroups);
|
|
101
|
+
|
|
102
|
+
const hiddenAudits = category.auditRefs.filter(audit => audit.group === 'hidden');
|
|
103
|
+
const auditElements = [...categoryDOM.querySelectorAll('.lh-audit')];
|
|
104
|
+
const matchingElements = auditElements
|
|
105
|
+
.filter(el => hiddenAudits.some(audit => audit.id === el.id));
|
|
106
|
+
expect(matchingElements).toHaveLength(0);
|
|
107
|
+
});
|
|
108
|
+
|
|
99
109
|
it('renders the failing performance opportunities', () => {
|
|
100
110
|
const categoryDOM = renderer.render(category, sampleResults.categoryGroups);
|
|
101
111
|
|
|
102
|
-
const oppAudits = category.auditRefs.filter(audit =>
|
|
103
|
-
|
|
112
|
+
const oppAudits = category.auditRefs.filter(audit =>
|
|
113
|
+
audit.result.details &&
|
|
114
|
+
audit.result.details.type === 'opportunity' &&
|
|
115
|
+
!Util.showAsPassed(audit.result));
|
|
104
116
|
const oppElements = [...categoryDOM.querySelectorAll('.lh-audit--load-opportunity')];
|
|
105
117
|
expect(oppElements.map(e => e.id).sort()).toEqual(oppAudits.map(a => a.id).sort());
|
|
106
118
|
expect(oppElements.length).toBeGreaterThan(0);
|
|
@@ -120,10 +132,14 @@ describe('PerfCategoryRenderer', () => {
|
|
|
120
132
|
it('renders performance opportunities with an errorMessage', () => {
|
|
121
133
|
const auditWithError = {
|
|
122
134
|
score: 0,
|
|
123
|
-
group: 'load-opportunities',
|
|
124
135
|
result: {
|
|
125
136
|
score: null, scoreDisplayMode: 'error', errorMessage: 'Yikes!!', title: 'Bug #2',
|
|
126
137
|
description: '',
|
|
138
|
+
details: {
|
|
139
|
+
overallSavingsMs: 0,
|
|
140
|
+
items: [],
|
|
141
|
+
type: 'opportunity',
|
|
142
|
+
},
|
|
127
143
|
},
|
|
128
144
|
};
|
|
129
145
|
|
|
@@ -137,10 +153,14 @@ describe('PerfCategoryRenderer', () => {
|
|
|
137
153
|
it('renders performance opportunities\' explanation', () => {
|
|
138
154
|
const auditWithExplanation = {
|
|
139
155
|
score: 0,
|
|
140
|
-
group: 'load-opportunities',
|
|
141
156
|
result: {
|
|
142
157
|
score: 0, scoreDisplayMode: 'numeric',
|
|
143
158
|
numericValue: 100, explanation: 'Yikes!!', title: 'Bug #2', description: '',
|
|
159
|
+
details: {
|
|
160
|
+
overallSavingsMs: 0,
|
|
161
|
+
items: [],
|
|
162
|
+
type: 'opportunity',
|
|
163
|
+
},
|
|
144
164
|
},
|
|
145
165
|
};
|
|
146
166
|
|
|
@@ -159,7 +179,9 @@ describe('PerfCategoryRenderer', () => {
|
|
|
159
179
|
'.lh-category > .lh-audit-group.lh-audit-group--diagnostics');
|
|
160
180
|
|
|
161
181
|
const diagnosticAuditIds = category.auditRefs.filter(audit => {
|
|
162
|
-
return audit.group
|
|
182
|
+
return !audit.group &&
|
|
183
|
+
!(audit.result.details && audit.result.details.type === 'opportunity') &&
|
|
184
|
+
!Util.showAsPassed(audit.result);
|
|
163
185
|
}).map(audit => audit.id).sort();
|
|
164
186
|
assert.ok(diagnosticAuditIds.length > 0);
|
|
165
187
|
|
|
@@ -170,11 +192,11 @@ describe('PerfCategoryRenderer', () => {
|
|
|
170
192
|
|
|
171
193
|
it('renders the passed audits', () => {
|
|
172
194
|
const categoryDOM = renderer.render(category, sampleResults.categoryGroups);
|
|
173
|
-
const passedSection = categoryDOM.querySelector('.lh-
|
|
195
|
+
const passedSection = categoryDOM.querySelector('.lh-clump--passed');
|
|
174
196
|
|
|
175
197
|
const passedAudits = category.auditRefs.filter(audit =>
|
|
176
|
-
audit.group &&
|
|
177
|
-
|
|
198
|
+
!audit.group &&
|
|
199
|
+
Util.showAsPassed(audit.result));
|
|
178
200
|
const passedElements = passedSection.querySelectorAll('.lh-audit');
|
|
179
201
|
assert.equal(passedElements.length, passedAudits.length);
|
|
180
202
|
});
|
|
@@ -187,10 +209,14 @@ describe('PerfCategoryRenderer', () => {
|
|
|
187
209
|
it('handles erroring opportunities', () => {
|
|
188
210
|
const auditWithDebug = {
|
|
189
211
|
score: 0,
|
|
190
|
-
group: 'load-opportunities',
|
|
191
212
|
result: {
|
|
192
213
|
error: true, score: 0,
|
|
193
214
|
numericValue: 100, explanation: 'Yikes!!', title: 'Bug #2',
|
|
215
|
+
details: {
|
|
216
|
+
overallSavingsMs: 0,
|
|
217
|
+
items: [],
|
|
218
|
+
type: 'opportunity',
|
|
219
|
+
},
|
|
194
220
|
},
|
|
195
221
|
};
|
|
196
222
|
const wastedMs = renderer._getWastedMs(auditWithDebug);
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
/* eslint-env jest */
|
|
9
9
|
|
|
10
10
|
import jsdom from 'jsdom';
|
|
11
|
+
import {jest} from '@jest/globals';
|
|
11
12
|
|
|
12
13
|
import {Util} from '../../renderer/util.js';
|
|
13
14
|
import {DOM} from '../../renderer/dom.js';
|
|
@@ -23,6 +24,8 @@ describe('ReportRendererAxe', () => {
|
|
|
23
24
|
let sampleResults;
|
|
24
25
|
|
|
25
26
|
beforeAll(async () => {
|
|
27
|
+
global.console.warn = jest.fn();
|
|
28
|
+
|
|
26
29
|
const {window} = new jsdom.JSDOM();
|
|
27
30
|
const dom = new DOM(window.document);
|
|
28
31
|
const detailsRenderer = new DetailsRenderer(dom);
|
|
@@ -47,10 +50,10 @@ describe('ReportRendererAxe', () => {
|
|
|
47
50
|
});
|
|
48
51
|
|
|
49
52
|
it('renders without axe violations', async () => {
|
|
50
|
-
const container = renderer._dom.
|
|
53
|
+
const container = renderer._dom.document().createElement('main');
|
|
51
54
|
const output = renderer.renderReport(sampleResults, container);
|
|
52
55
|
|
|
53
|
-
renderer._dom.
|
|
56
|
+
renderer._dom.document().body.appendChild(container);
|
|
54
57
|
|
|
55
58
|
const config = {
|
|
56
59
|
rules: {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import {strict as assert} from 'assert';
|
|
11
11
|
|
|
12
12
|
import jsdom from 'jsdom';
|
|
13
|
+
import {jest} from '@jest/globals';
|
|
13
14
|
|
|
14
15
|
import {Util} from '../../renderer/util.js';
|
|
15
16
|
import URL from '../../../lighthouse-core/lib/url-shim.js';
|
|
@@ -26,6 +27,8 @@ describe('ReportRenderer', () => {
|
|
|
26
27
|
let sampleResults;
|
|
27
28
|
|
|
28
29
|
beforeAll(() => {
|
|
30
|
+
global.console.warn = jest.fn();
|
|
31
|
+
|
|
29
32
|
// Stub out matchMedia for Node.
|
|
30
33
|
global.matchMedia = function() {
|
|
31
34
|
return {
|
|
@@ -50,7 +53,7 @@ describe('ReportRenderer', () => {
|
|
|
50
53
|
|
|
51
54
|
describe('renderReport', () => {
|
|
52
55
|
it('should render a report', () => {
|
|
53
|
-
const container = renderer._dom.
|
|
56
|
+
const container = renderer._dom.document().body;
|
|
54
57
|
const output = renderer.renderReport(sampleResults, container);
|
|
55
58
|
assert.ok(output.querySelector('.lh-header-container'), 'has a header');
|
|
56
59
|
assert.ok(output.querySelector('.lh-report'), 'has report body');
|
|
@@ -60,7 +63,7 @@ describe('ReportRenderer', () => {
|
|
|
60
63
|
});
|
|
61
64
|
|
|
62
65
|
it('renders additional reports by replacing the existing one', () => {
|
|
63
|
-
const container = renderer._dom.
|
|
66
|
+
const container = renderer._dom.document().body;
|
|
64
67
|
const oldReport = Array.from(renderer.renderReport(sampleResults, container).children);
|
|
65
68
|
const newReport = Array.from(renderer.renderReport(sampleResults, container).children);
|
|
66
69
|
assert.ok(!oldReport.find(node => container.contains(node)), 'old report was removed');
|
|
@@ -86,11 +89,11 @@ describe('ReportRenderer', () => {
|
|
|
86
89
|
auditRefs: [],
|
|
87
90
|
};
|
|
88
91
|
|
|
89
|
-
const container = renderer._dom.
|
|
92
|
+
const container = renderer._dom.document().body;
|
|
90
93
|
const output = renderer.renderReport(sampleResultsCopy, container);
|
|
91
94
|
|
|
92
95
|
function isPWAGauge(el) {
|
|
93
|
-
return el.querySelector('.lh-gauge__label').textContent === '
|
|
96
|
+
return el.querySelector('.lh-gauge__label').textContent === 'PWA';
|
|
94
97
|
}
|
|
95
98
|
function isPluginGauge(el) {
|
|
96
99
|
return el.querySelector('.lh-gauge__label').textContent === 'Some Plugin';
|
|
@@ -126,7 +129,7 @@ describe('ReportRenderer', () => {
|
|
|
126
129
|
title: 'Some Plugin',
|
|
127
130
|
auditRefs: [],
|
|
128
131
|
};
|
|
129
|
-
const container = renderer._dom.
|
|
132
|
+
const container = renderer._dom.document().body;
|
|
130
133
|
const output = renderer.renderReport(sampleResultsCopy, container);
|
|
131
134
|
const scoresHeaderElem = output.querySelector('.lh-scores-header');
|
|
132
135
|
|
|
@@ -140,7 +143,7 @@ describe('ReportRenderer', () => {
|
|
|
140
143
|
});
|
|
141
144
|
|
|
142
145
|
it('should not mutate a report object', () => {
|
|
143
|
-
const container = renderer._dom.
|
|
146
|
+
const container = renderer._dom.document().body;
|
|
144
147
|
const originalResults = JSON.parse(JSON.stringify(sampleResults));
|
|
145
148
|
renderer.renderReport(sampleResults, container);
|
|
146
149
|
assert.deepStrictEqual(sampleResults, originalResults);
|
|
@@ -148,13 +151,13 @@ describe('ReportRenderer', () => {
|
|
|
148
151
|
|
|
149
152
|
it('renders no warning section when no lighthouseRunWarnings occur', () => {
|
|
150
153
|
const warningResults = Object.assign({}, sampleResults, {runWarnings: []});
|
|
151
|
-
const container = renderer._dom.
|
|
154
|
+
const container = renderer._dom.document().body;
|
|
152
155
|
const output = renderer.renderReport(warningResults, container);
|
|
153
156
|
assert.strictEqual(output.querySelector('.lh-warnings--toplevel'), null);
|
|
154
157
|
});
|
|
155
158
|
|
|
156
159
|
it('renders a warning section', () => {
|
|
157
|
-
const container = renderer._dom.
|
|
160
|
+
const container = renderer._dom.document().body;
|
|
158
161
|
const output = renderer.renderReport(sampleResults, container);
|
|
159
162
|
|
|
160
163
|
const warningEls = output.querySelectorAll('.lh-warnings--toplevel > ul > li');
|
|
@@ -165,7 +168,7 @@ describe('ReportRenderer', () => {
|
|
|
165
168
|
const warningResults = Object.assign({}, sampleResults, {
|
|
166
169
|
runWarnings: ['[I am a link](https://example.com/)'],
|
|
167
170
|
});
|
|
168
|
-
const container = renderer._dom.
|
|
171
|
+
const container = renderer._dom.document().body;
|
|
169
172
|
const output = renderer.renderReport(warningResults, container);
|
|
170
173
|
|
|
171
174
|
const warningEls = output.querySelectorAll('.lh-warnings--toplevel ul li a');
|
|
@@ -196,7 +199,7 @@ describe('ReportRenderer', () => {
|
|
|
196
199
|
// Make sure we have a channel in the LHR.
|
|
197
200
|
assert.ok(lhrChannel.length > 2);
|
|
198
201
|
|
|
199
|
-
const container = renderer._dom.
|
|
202
|
+
const container = renderer._dom.document().body;
|
|
200
203
|
const output = renderer.renderReport(sampleResults, container);
|
|
201
204
|
|
|
202
205
|
const DOCS_ORIGINS = ['https://developers.google.com', 'https://web.dev'];
|
|
@@ -225,7 +228,7 @@ describe('ReportRenderer', () => {
|
|
|
225
228
|
|
|
226
229
|
assert.ok(notApplicableCount > 20); // Make sure something's being tested.
|
|
227
230
|
|
|
228
|
-
const container = renderer._dom.
|
|
231
|
+
const container = renderer._dom.document().body;
|
|
229
232
|
const reportElement = renderer.renderReport(sampleResults, container);
|
|
230
233
|
const notApplicableElementCount = reportElement
|
|
231
234
|
.querySelectorAll('.lh-audit--notapplicable').length;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import {strict as assert} from 'assert';
|
|
11
11
|
|
|
12
12
|
import jsdom from 'jsdom';
|
|
13
|
+
import {jest} from '@jest/globals';
|
|
13
14
|
|
|
14
15
|
import reportAssets from '../../generator/report-assets.js';
|
|
15
16
|
import {Util} from '../../renderer/util.js';
|
|
@@ -33,13 +34,15 @@ describe('ReportUIFeatures', () => {
|
|
|
33
34
|
const categoryRenderer = new CategoryRenderer(dom, detailsRenderer);
|
|
34
35
|
const renderer = new ReportRenderer(dom, categoryRenderer);
|
|
35
36
|
const reportUIFeatures = new ReportUIFeatures(dom);
|
|
36
|
-
const container = dom.find('
|
|
37
|
+
const container = dom.find('body', dom.document());
|
|
37
38
|
renderer.renderReport(lhr, container);
|
|
38
39
|
reportUIFeatures.initFeatures(lhr);
|
|
39
40
|
return container;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
beforeAll(() => {
|
|
44
|
+
global.console.warn = jest.fn();
|
|
45
|
+
|
|
43
46
|
// Stub out matchMedia for Node.
|
|
44
47
|
global.matchMedia = function() {
|
|
45
48
|
return {
|
|
@@ -256,17 +259,15 @@ describe('ReportUIFeatures', () => {
|
|
|
256
259
|
.toThrowError('query #uses-rel-preconnect .lh-3p-filter-input not found');
|
|
257
260
|
});
|
|
258
261
|
|
|
259
|
-
it('filter is
|
|
260
|
-
const
|
|
261
|
-
dom.find('#render-blocking-resources .lh-3p-filter
|
|
262
|
-
expect(
|
|
263
|
-
expect(filterCheckbox.checked).toEqual(true);
|
|
262
|
+
it('filter is hidden when just third party resources', () => {
|
|
263
|
+
const filterControl =
|
|
264
|
+
dom.find('#render-blocking-resources .lh-3p-filter', container);
|
|
265
|
+
expect(filterControl.hidden).toEqual(true);
|
|
264
266
|
});
|
|
265
267
|
|
|
266
|
-
it('filter is
|
|
267
|
-
const
|
|
268
|
-
expect(
|
|
269
|
-
expect(filterCheckbox.checked).toEqual(false);
|
|
268
|
+
it('filter is hidden for just first party resources', () => {
|
|
269
|
+
const filterControl = dom.find('#uses-text-compression .lh-3p-filter', container);
|
|
270
|
+
expect(filterControl.hidden).toEqual(true);
|
|
270
271
|
});
|
|
271
272
|
});
|
|
272
273
|
});
|
|
@@ -515,6 +516,9 @@ describe('ReportUIFeatures', () => {
|
|
|
515
516
|
expect(render(lhr).querySelector('.lh-button.lh-report-icon--treemap')).toBeTruthy();
|
|
516
517
|
|
|
517
518
|
delete lhr.audits['script-treemap-data'];
|
|
519
|
+
const newAuditRefs = lhr.categories['performance'].auditRefs
|
|
520
|
+
.filter(a => a.id !== 'script-treemap-data');
|
|
521
|
+
lhr.categories['performance'].auditRefs = newAuditRefs;
|
|
518
522
|
expect(render(lhr).querySelector('.lh-button.lh-report-icon--treemap')).toBeNull();
|
|
519
523
|
});
|
|
520
524
|
});
|
|
@@ -401,10 +401,10 @@ describe('util helpers', () => {
|
|
|
401
401
|
const category = {
|
|
402
402
|
id: 'performance',
|
|
403
403
|
auditRefs: [
|
|
404
|
-
{weight: 3, result: {score: 1, scoreDisplayMode: 'binary'}, group: '
|
|
405
|
-
{weight: 2, result: {score: 1, scoreDisplayMode: 'binary'}, group: '
|
|
406
|
-
{weight: 0, result: {score: 1, scoreDisplayMode: 'binary'}, group: '
|
|
407
|
-
{weight: 1, result: {score: 0, scoreDisplayMode: 'binary'}, group: '
|
|
404
|
+
{weight: 3, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
|
|
405
|
+
{weight: 2, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
|
|
406
|
+
{weight: 0, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
|
|
407
|
+
{weight: 1, result: {score: 0, scoreDisplayMode: 'binary'}, group: 'metrics'},
|
|
408
408
|
],
|
|
409
409
|
};
|
|
410
410
|
const fraction = Util.calculateCategoryFraction(category);
|
|
@@ -416,14 +416,14 @@ describe('util helpers', () => {
|
|
|
416
416
|
});
|
|
417
417
|
});
|
|
418
418
|
|
|
419
|
-
it('ignores manual audits, N/A audits, and
|
|
419
|
+
it('ignores manual audits, N/A audits, and hidden audits', () => {
|
|
420
420
|
const category = {
|
|
421
421
|
id: 'performance',
|
|
422
422
|
auditRefs: [
|
|
423
|
-
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: '
|
|
424
|
-
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}},
|
|
425
|
-
{weight: 1, result: {score: 0, scoreDisplayMode: 'manual'}, group: '
|
|
426
|
-
{weight: 1, result: {score: 0, scoreDisplayMode: 'notApplicable'}, group: '
|
|
423
|
+
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
|
|
424
|
+
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'hidden'},
|
|
425
|
+
{weight: 1, result: {score: 0, scoreDisplayMode: 'manual'}, group: 'metrics'},
|
|
426
|
+
{weight: 1, result: {score: 0, scoreDisplayMode: 'notApplicable'}, group: 'metrics'},
|
|
427
427
|
],
|
|
428
428
|
};
|
|
429
429
|
const fraction = Util.calculateCategoryFraction(category);
|
|
@@ -435,32 +435,14 @@ describe('util helpers', () => {
|
|
|
435
435
|
});
|
|
436
436
|
});
|
|
437
437
|
|
|
438
|
-
it('does not ignore audits with no group in non-performance category', () => {
|
|
439
|
-
const category = {
|
|
440
|
-
id: 'seo',
|
|
441
|
-
auditRefs: [
|
|
442
|
-
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
|
|
443
|
-
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}},
|
|
444
|
-
{weight: 1, result: {score: 0, scoreDisplayMode: 'manual'}, group: 'diagnostics'},
|
|
445
|
-
],
|
|
446
|
-
};
|
|
447
|
-
const fraction = Util.calculateCategoryFraction(category);
|
|
448
|
-
expect(fraction).toEqual({
|
|
449
|
-
numPassableAudits: 2,
|
|
450
|
-
numPassed: 2,
|
|
451
|
-
numInformative: 0,
|
|
452
|
-
totalWeight: 2,
|
|
453
|
-
});
|
|
454
|
-
});
|
|
455
|
-
|
|
456
438
|
it('tracks informative audits separately', () => {
|
|
457
439
|
const category = {
|
|
458
440
|
id: 'performance',
|
|
459
441
|
auditRefs: [
|
|
460
|
-
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: '
|
|
461
|
-
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: '
|
|
462
|
-
{weight: 0, result: {score: 1, scoreDisplayMode: 'informative'}, group: '
|
|
463
|
-
{weight: 1, result: {score: 0, scoreDisplayMode: 'informative'}, group: '
|
|
442
|
+
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
|
|
443
|
+
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
|
|
444
|
+
{weight: 0, result: {score: 1, scoreDisplayMode: 'informative'}, group: 'metrics'},
|
|
445
|
+
{weight: 1, result: {score: 0, scoreDisplayMode: 'informative'}, group: 'metrics'},
|
|
464
446
|
],
|
|
465
447
|
};
|
|
466
448
|
const fraction = Util.calculateCategoryFraction(category);
|
|
@@ -66,7 +66,6 @@
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
.tab-panel {
|
|
69
|
-
padding: 30px 0;
|
|
70
69
|
border-top: 1px solid #ccc;
|
|
71
70
|
}
|
|
72
71
|
|
|
@@ -101,13 +100,9 @@ body {
|
|
|
101
100
|
<label for="tab2">Desktop</label>
|
|
102
101
|
|
|
103
102
|
<div class="tab-panels">
|
|
104
|
-
<section id="mobile" class="tab-panel">
|
|
105
|
-
<main></main>
|
|
106
|
-
</section>
|
|
103
|
+
<section id="mobile" class="tab-panel"></section>
|
|
107
104
|
|
|
108
|
-
<section id="desktop" class="tab-panel">
|
|
109
|
-
<main></main>
|
|
110
|
-
</section>
|
|
105
|
+
<section id="desktop" class="tab-panel"></section>
|
|
111
106
|
|
|
112
107
|
</div>
|
|
113
108
|
</div>
|