lighthouse 8.5.1 → 8.6.0-dev.20211016
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/changelog.md +5490 -0
- package/dist/report/flow.js +35 -12
- package/dist/report/standalone.js +20 -21
- package/flow-report/.eslintrc.cjs +49 -0
- package/flow-report/assets/styles.css +272 -9
- package/flow-report/jest.config.js +1 -1
- package/flow-report/package.json +4 -0
- package/flow-report/src/app.tsx +31 -9
- package/flow-report/src/common.tsx +86 -7
- package/flow-report/src/header.tsx +88 -0
- package/flow-report/src/help-dialog.tsx +120 -0
- package/flow-report/src/i18n/i18n.tsx +52 -0
- package/flow-report/src/i18n/localized-strings.js +11 -0
- package/flow-report/src/i18n/ui-strings.js +134 -0
- package/flow-report/src/icons.tsx +20 -3
- package/flow-report/src/sidebar/sidebar.tsx +11 -16
- package/flow-report/src/summary/category.tsx +39 -24
- package/flow-report/src/summary/summary.tsx +35 -32
- package/flow-report/src/topbar.tsx +54 -4
- package/flow-report/src/util.ts +26 -1
- package/flow-report/src/wrappers/report-renderer.tsx +1 -1
- package/flow-report/src/wrappers/report.tsx +6 -21
- package/flow-report/test/app-test.tsx +17 -13
- package/flow-report/test/common-test.tsx +89 -0
- package/flow-report/test/header-test.tsx +55 -0
- package/flow-report/test/sample-flow.ts +17 -0
- package/flow-report/test/setup/env-setup.ts +1 -0
- package/flow-report/test/sidebar/flow-test.tsx +6 -12
- package/flow-report/test/sidebar/sidebar-test.tsx +7 -13
- package/flow-report/test/summary/category-test.tsx +83 -34
- package/flow-report/test/summary/summary-test.tsx +12 -18
- package/flow-report/test/topbar-test.tsx +68 -0
- package/flow-report/test/util-test.tsx +1 -12
- package/flow-report/tsconfig.json +2 -0
- package/flow-report/types/flow-report.d.ts +2 -1
- package/jest.config.js +1 -15
- package/lighthouse-cli/bin.js +5 -0
- package/lighthouse-cli/cli-flags.js +10 -3
- package/lighthouse-cli/commands/commands.js +1 -0
- package/lighthouse-cli/commands/list-locales.js +16 -0
- package/lighthouse-cli/run.js +2 -2
- package/lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js +0 -0
- package/lighthouse-cli/test/smokehouse/report-assert.js +20 -4
- package/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +2 -1
- package/lighthouse-core/audits/byte-efficiency/unused-javascript.js +1 -1
- package/lighthouse-core/audits/seo/crawlable-anchors.js +10 -12
- package/lighthouse-core/computed/js-bundles.js +1 -2
- package/lighthouse-core/computed/unused-javascript-summary.js +3 -3
- package/lighthouse-core/config/config-helpers.js +1 -0
- package/lighthouse-core/config/config.js +2 -2
- package/lighthouse-core/config/default-config.js +5 -0
- package/lighthouse-core/fraggle-rock/api.js +10 -0
- package/lighthouse-core/fraggle-rock/config/filters.js +22 -3
- package/lighthouse-core/fraggle-rock/gather/driver.js +4 -0
- package/lighthouse-core/fraggle-rock/gather/navigation-runner.js +2 -2
- package/lighthouse-core/fraggle-rock/user-flow.js +35 -6
- package/lighthouse-core/gather/driver/navigation.js +5 -0
- package/lighthouse-core/gather/driver/prepare.js +14 -0
- package/lighthouse-core/gather/driver/storage.js +5 -0
- package/lighthouse-core/gather/gather-runner.js +2 -2
- package/lighthouse-core/gather/gatherers/dobetterweb/response-compression.js +5 -1
- package/lighthouse-core/gather/gatherers/full-page-screenshot.js +30 -24
- package/lighthouse-core/lib/cdt/Platform.js +55 -0
- package/lighthouse-core/lib/cdt/SDK.js +3 -123
- package/lighthouse-core/lib/cdt/generated/SourceMap.js +148 -312
- package/lighthouse-core/lib/csp-evaluator.js +2 -1
- package/lighthouse-core/lib/i18n/README.md +6 -6
- package/lighthouse-core/lib/i18n/i18n.js +26 -348
- package/lighthouse-core/lib/page-functions.js +4 -4
- package/lighthouse-core/lib/stack-packs.js +1 -13
- package/lighthouse-core/runner.js +6 -6
- package/lighthouse-core/scripts/manual-chrome-launcher.js +4 -1
- package/lighthouse-core/scripts/package.json +4 -0
- package/lighthouse-core/util-commonjs.js +20 -4
- package/package.json +19 -16
- package/readme.md +1 -1
- package/report/assets/standalone-template.html +0 -1
- package/report/assets/styles.css +16 -41
- package/report/assets/templates.html +42 -4
- package/report/clients/psi.js +1 -0
- package/report/clients/standalone.js +1 -2
- package/report/generator/file-namer.js +17 -8
- package/report/generator/report-generator.js +0 -1
- package/report/renderer/category-renderer.js +4 -16
- package/report/renderer/components.js +107 -71
- package/report/renderer/dom.js +19 -0
- package/report/renderer/logger.js +35 -2
- package/report/renderer/performance-category-renderer.js +23 -21
- package/report/renderer/pwa-category-renderer.js +1 -2
- package/report/renderer/report-renderer.js +21 -0
- package/report/renderer/report-ui-features.js +7 -19
- package/report/renderer/swap-locale-feature.js +82 -0
- package/report/renderer/util.js +20 -4
- package/report/test/clients/psi-test.js +0 -4
- package/report/test/generator/file-namer-test.js +2 -2
- package/report/test/renderer/category-renderer-test.js +1 -1
- package/report/test/renderer/performance-category-renderer-test.js +12 -0
- package/report/test/renderer/report-renderer-axe-test.js +86 -0
- package/report/test/renderer/report-renderer-test.js +0 -55
- package/report/test/renderer/util-test.js +68 -8
- package/report/test-assets/faux-psi-template.html +0 -1
- package/report/tsconfig.json +2 -1
- package/report/types/html-renderer.d.ts +2 -1
- package/root.js +18 -0
- package/shared/localization/format.js +455 -0
- package/{lighthouse-core/lib/cdt/Common.js → shared/localization/i18n-module.js} +3 -8
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/ar-XB.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/ar.json +141 -6
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/bg.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/ca.json +140 -5
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/cs.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/da.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/de.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/el.json +141 -6
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/en-GB.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/en-US.json +129 -0
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/en-XA.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/en-XL.json +129 -0
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/es-419.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/es.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/fi.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/fil.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/fr.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/he.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/hi.json +142 -7
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/hr.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/hu.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/id.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/it.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/ja.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/ko.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/lt.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/lv.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/nl.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/no.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/pl.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/pt-PT.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/pt.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/ro.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/ru.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/sk.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/sl.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/sr-Latn.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/sr.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/sv.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/ta.json +146 -11
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/te.json +179 -44
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/th.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/tr.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/uk.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/vi.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/zh-HK.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/zh-TW.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales/zh.json +139 -4
- package/{lighthouse-core/lib/i18n → shared/localization}/locales.js +8 -1
- package/shared/localization/swap-flow-locale.js +20 -0
- package/{lighthouse-core/lib/i18n → shared/localization}/swap-locale.js +9 -7
- package/shared/test/localization/format-test.js +421 -0
- package/shared/test/localization/locales-test.js +47 -0
- package/shared/test/localization/swap-locale-test.js +140 -0
- package/shared/tsconfig.json +22 -0
- package/{lighthouse-core/lib → shared}/type-verifiers.js +0 -0
- package/shared/types/shared.d.ts +24 -0
- package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +5 -3
- package/third-party/chromium-synchronization/installability-errors-test.js +2 -1
- package/tsconfig-all.json +1 -0
- package/tsconfig-base.json +1 -1
- package/tsconfig.json +2 -3
- package/types/config.d.ts +1 -0
- package/types/es-main.d.ts +18 -0
- package/types/externs.d.ts +2 -0
- package/types/lhr/flow.d.ts +7 -0
- package/types/lhr/i18n.d.ts +0 -3
|
@@ -28,7 +28,7 @@ import {toggleDarkTheme} from './features-util.js';
|
|
|
28
28
|
import {openTreemap} from './open-tab.js';
|
|
29
29
|
import {TopbarFeatures} from './topbar-features.js';
|
|
30
30
|
import {Util} from './util.js';
|
|
31
|
-
import {
|
|
31
|
+
import {getLhrFilenamePrefix} from '../generator/file-namer.js';
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* @param {HTMLTableElement} tableEl
|
|
@@ -324,25 +324,13 @@ export class ReportUIFeatures {
|
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
/**
|
|
327
|
-
*
|
|
328
|
-
*
|
|
327
|
+
* DevTools uses its own file manager to download files, so it redefines this function.
|
|
328
|
+
* Wrapper is necessary so DevTools can still override this function.
|
|
329
|
+
*
|
|
330
|
+
* @param {Blob|File} blob
|
|
329
331
|
*/
|
|
330
332
|
_saveFile(blob) {
|
|
331
|
-
const filename =
|
|
332
|
-
|
|
333
|
-
fetchTime: this.json.fetchTime,
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
const ext = blob.type.match('json') ? '.json' : '.html';
|
|
337
|
-
|
|
338
|
-
const a = this._dom.createElement('a');
|
|
339
|
-
a.download = `${filename}${ext}`;
|
|
340
|
-
this._dom.safelySetBlobHref(a, blob);
|
|
341
|
-
this._document.body.appendChild(a); // Firefox requires anchor to be in the DOM.
|
|
342
|
-
a.click();
|
|
343
|
-
|
|
344
|
-
// cleanup.
|
|
345
|
-
this._document.body.removeChild(a);
|
|
346
|
-
setTimeout(() => URL.revokeObjectURL(a.href), 500);
|
|
333
|
+
const filename = getLhrFilenamePrefix(this.json);
|
|
334
|
+
this._dom.saveFile(blob, filename);
|
|
347
335
|
}
|
|
348
336
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright 2021 The Lighthouse Authors. All Rights Reserved.
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
4
|
+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
5
|
+
*/
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @fileoverview Creates a <select> element, filled with all supported locales
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** @typedef {import('./dom.js').DOM} DOM */
|
|
13
|
+
/** @typedef {import('./report-ui-features').ReportUIFeatures} ReportUIFeatures */
|
|
14
|
+
|
|
15
|
+
export class SwapLocaleFeature {
|
|
16
|
+
/**
|
|
17
|
+
* @param {ReportUIFeatures} reportUIFeatures
|
|
18
|
+
* @param {DOM} dom
|
|
19
|
+
* @param {{onLocaleSelected: (localeModuleName: LH.Locale) => Promise<void>}} callbacks
|
|
20
|
+
* Specifiy the URL where the i18n module script can be found, and the URLS for the locale JSON files.
|
|
21
|
+
*/
|
|
22
|
+
constructor(reportUIFeatures, dom, callbacks) {
|
|
23
|
+
this._reportUIFeatures = reportUIFeatures;
|
|
24
|
+
this._dom = dom;
|
|
25
|
+
this._localeSelectedCallback = callbacks.onLocaleSelected;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {Array<LH.Locale>} locales
|
|
30
|
+
*/
|
|
31
|
+
enable(locales) {
|
|
32
|
+
if (!this._reportUIFeatures.json.i18n.icuMessagePaths) {
|
|
33
|
+
throw new Error('missing icuMessagePaths');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this._dom.find('.lh-tools-locale', this._dom.document()).classList.remove('lh-hidden');
|
|
37
|
+
|
|
38
|
+
const currentLocale = this._reportUIFeatures.json.configSettings.locale;
|
|
39
|
+
|
|
40
|
+
const containerEl = this._dom.find('.lh-tools-locale__selector-wrapper', this._dom.document());
|
|
41
|
+
containerEl.removeAttribute('aria-hidden');
|
|
42
|
+
const selectEl = this._dom.createChildOf(containerEl, 'select', 'lh-locale-selector');
|
|
43
|
+
selectEl.name = 'lh-locale-list';
|
|
44
|
+
selectEl.setAttribute('role', 'menuitem');
|
|
45
|
+
|
|
46
|
+
const toggleEl = this._dom.find('.lh-tool-locale__button', this._dom.document());
|
|
47
|
+
toggleEl.addEventListener('click', () => {
|
|
48
|
+
toggleEl.classList.toggle('lh-active');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
for (const locale of locales) {
|
|
52
|
+
const optionEl = this._dom.createChildOf(selectEl, 'option', '');
|
|
53
|
+
optionEl.value = locale;
|
|
54
|
+
if (locale === currentLocale) optionEl.selected = true;
|
|
55
|
+
|
|
56
|
+
// @ts-expect-error: waiting for typescript 4.5. Might need to add "ES2020.Intl"
|
|
57
|
+
// to tsconfig libs.
|
|
58
|
+
// https://github.com/microsoft/TypeScript/pull/44022#issuecomment-915087098
|
|
59
|
+
if (window.Intl && Intl.DisplayNames) {
|
|
60
|
+
// @ts-expect-error
|
|
61
|
+
const currentLocaleDisplay = new Intl.DisplayNames([currentLocale], {type: 'language'});
|
|
62
|
+
// @ts-expect-error
|
|
63
|
+
const optionLocaleDisplay = new Intl.DisplayNames([locale], {type: 'language'});
|
|
64
|
+
|
|
65
|
+
const optionLocaleName = optionLocaleDisplay.of(locale);
|
|
66
|
+
const currentLocaleName = currentLocaleDisplay.of(locale);
|
|
67
|
+
if (optionLocaleName !== currentLocaleName) {
|
|
68
|
+
optionEl.textContent = `${optionLocaleName} – ${currentLocaleName}`;
|
|
69
|
+
} else {
|
|
70
|
+
optionEl.textContent = currentLocaleName;
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
optionEl.textContent = locale;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
selectEl.addEventListener('change', () => {
|
|
78
|
+
const locale = /** @type {LH.Locale} */ (selectEl.value);
|
|
79
|
+
this._localeSelectedCallback(locale);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
package/report/renderer/util.js
CHANGED
|
@@ -518,15 +518,31 @@ export class Util {
|
|
|
518
518
|
* @param {LH.ReportResult.Category} category
|
|
519
519
|
*/
|
|
520
520
|
static calculateCategoryFraction(category) {
|
|
521
|
-
|
|
522
|
-
|
|
521
|
+
let numPassableAudits = 0;
|
|
523
522
|
let numPassed = 0;
|
|
523
|
+
let numInformative = 0;
|
|
524
524
|
let totalWeight = 0;
|
|
525
525
|
for (const auditRef of category.auditRefs) {
|
|
526
|
+
const auditPassed = Util.showAsPassed(auditRef.result);
|
|
527
|
+
const notDisplayed = !auditRef.group && category.id === 'performance';
|
|
528
|
+
|
|
529
|
+
// Don't count the audit if it's manual, N/A, or isn't displayed.
|
|
530
|
+
if (notDisplayed ||
|
|
531
|
+
auditRef.result.scoreDisplayMode === 'manual' ||
|
|
532
|
+
auditRef.result.scoreDisplayMode === 'notApplicable') {
|
|
533
|
+
continue;
|
|
534
|
+
} else if (auditRef.result.scoreDisplayMode === 'informative') {
|
|
535
|
+
if (!auditPassed) {
|
|
536
|
+
++numInformative;
|
|
537
|
+
}
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
++numPassableAudits;
|
|
526
542
|
totalWeight += auditRef.weight;
|
|
527
|
-
if (
|
|
543
|
+
if (auditPassed) numPassed++;
|
|
528
544
|
}
|
|
529
|
-
return {numPassed,
|
|
545
|
+
return {numPassed, numPassableAudits, numInformative, totalWeight};
|
|
530
546
|
}
|
|
531
547
|
}
|
|
532
548
|
|
|
@@ -67,8 +67,6 @@ describe('PSI', () => {
|
|
|
67
67
|
// Check that the report exists and has some content.
|
|
68
68
|
assert.ok(result.perfCategoryEl instanceof document.defaultView.Element);
|
|
69
69
|
assert.ok(result.perfCategoryEl.outerHTML.length > 50000, 'perfCategory HTML is populated');
|
|
70
|
-
assert.ok(!result.perfCategoryEl.outerHTML.includes('lh-permalink'),
|
|
71
|
-
'PSI\'s perfCategory HTML doesn\'t include a lh-permalink element');
|
|
72
70
|
// Assume using default locale.
|
|
73
71
|
const title = result.perfCategoryEl.querySelector('.lh-audit-group--metrics')
|
|
74
72
|
.querySelector('.lh-audit-group__title').textContent;
|
|
@@ -83,8 +81,6 @@ describe('PSI', () => {
|
|
|
83
81
|
|
|
84
82
|
assert.ok(result.perfCategoryEl instanceof document.defaultView.Element);
|
|
85
83
|
assert.ok(result.perfCategoryEl.outerHTML.length > 50000, 'perfCategory HTML is populated');
|
|
86
|
-
assert.ok(!result.perfCategoryEl.outerHTML.includes('lh-permalink'),
|
|
87
|
-
'PSI\'s perfCategory HTML doesn\'t include a lh-permalink element');
|
|
88
84
|
|
|
89
85
|
assert.equal(typeof result.finalScreenshotDataUri, 'string');
|
|
90
86
|
assert.ok(result.finalScreenshotDataUri.startsWith('data:image/jpeg;base64,'));
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const assert = require('assert').strict;
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const getLhrFilenamePrefix = require('../../generator/file-namer.js').getLhrFilenamePrefix;
|
|
11
11
|
|
|
12
12
|
/* eslint-env jest */
|
|
13
13
|
describe('file-namer helper', () => {
|
|
@@ -16,7 +16,7 @@ describe('file-namer helper', () => {
|
|
|
16
16
|
finalUrl: 'https://testexample.com',
|
|
17
17
|
fetchTime: '2017-01-06T02:34:56.217Z',
|
|
18
18
|
};
|
|
19
|
-
const str =
|
|
19
|
+
const str = getLhrFilenamePrefix(results);
|
|
20
20
|
// we want the filename to match user timezone, however these tests will run on multiple TZs
|
|
21
21
|
assert.ok(str.startsWith('testexample.com'), 'hostname is missing');
|
|
22
22
|
assert.ok(str.includes('2017-'), 'full year is missing');
|
|
@@ -297,7 +297,7 @@ describe('CategoryRenderer', () => {
|
|
|
297
297
|
);
|
|
298
298
|
|
|
299
299
|
const gauge = categoryDOM.querySelector('.lh-fraction__content');
|
|
300
|
-
assert.equal(gauge.textContent.trim(), '
|
|
300
|
+
assert.equal(gauge.textContent.trim(), '13/18', 'fraction is included');
|
|
301
301
|
|
|
302
302
|
const score = categoryDOM.querySelector('.lh-category-header');
|
|
303
303
|
const title = score.querySelector('.lh-fraction__label');
|
|
@@ -69,6 +69,18 @@ describe('PerfCategoryRenderer', () => {
|
|
|
69
69
|
assert.equal(timelineElements.length + nontimelineElements.length, metricAudits.length);
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
+
it('does not render metrics section if no metric group audits', () => {
|
|
73
|
+
// Remove metrics from category
|
|
74
|
+
const newCategory = JSON.parse(JSON.stringify(category));
|
|
75
|
+
newCategory.auditRefs = category.auditRefs.filter(audit => audit.group !== 'metrics');
|
|
76
|
+
|
|
77
|
+
const categoryDOM = renderer.render(newCategory, sampleResults.categoryGroups);
|
|
78
|
+
const sections = categoryDOM.querySelectorAll('.lh-category > .lh-audit-group');
|
|
79
|
+
const metricSection = categoryDOM.querySelector('.lh-audit-group--metrics');
|
|
80
|
+
assert.ok(!metricSection);
|
|
81
|
+
assert.equal(sections.length, 4);
|
|
82
|
+
});
|
|
83
|
+
|
|
72
84
|
it('renders the metrics variance disclaimer as markdown', () => {
|
|
73
85
|
const categoryDOM = renderer.render(category, sampleResults.categoryGroups);
|
|
74
86
|
const disclaimerEl =
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright 2021 The Lighthouse Authors. All Rights Reserved.
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
4
|
+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
5
|
+
*/
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
/* eslint-env jest */
|
|
9
|
+
|
|
10
|
+
import jsdom from 'jsdom';
|
|
11
|
+
|
|
12
|
+
import {Util} from '../../renderer/util.js';
|
|
13
|
+
import {DOM} from '../../renderer/dom.js';
|
|
14
|
+
import {DetailsRenderer} from '../../renderer/details-renderer.js';
|
|
15
|
+
import {CategoryRenderer} from '../../renderer/category-renderer.js';
|
|
16
|
+
import {ReportRenderer} from '../../renderer/report-renderer.js';
|
|
17
|
+
import sampleResultsOrig from '../../../lighthouse-core/test/results/sample_v2.json';
|
|
18
|
+
|
|
19
|
+
describe('ReportRendererAxe', () => {
|
|
20
|
+
describe('with aXe', () => {
|
|
21
|
+
let axe;
|
|
22
|
+
let renderer;
|
|
23
|
+
let sampleResults;
|
|
24
|
+
|
|
25
|
+
beforeAll(async () => {
|
|
26
|
+
const {window} = new jsdom.JSDOM();
|
|
27
|
+
const dom = new DOM(window.document);
|
|
28
|
+
const detailsRenderer = new DetailsRenderer(dom);
|
|
29
|
+
const categoryRenderer = new CategoryRenderer(dom, detailsRenderer);
|
|
30
|
+
renderer = new ReportRenderer(dom, categoryRenderer);
|
|
31
|
+
sampleResults = Util.prepareReportResult(sampleResultsOrig);
|
|
32
|
+
|
|
33
|
+
// Needed by axe-core
|
|
34
|
+
// https://github.com/dequelabs/axe-core/blob/581c441c/doc/examples/jsdom/test/a11y.js#L24
|
|
35
|
+
global.window = global.self = window;
|
|
36
|
+
global.Node = global.self.Node;
|
|
37
|
+
global.Element = global.self.Element;
|
|
38
|
+
|
|
39
|
+
// axe-core must be imported after the global polyfills
|
|
40
|
+
axe = (await import('axe-core')).default;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
afterAll(() => {
|
|
44
|
+
global.window = undefined;
|
|
45
|
+
global.Node = undefined;
|
|
46
|
+
global.Element = undefined;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('renders without axe violations', () => {
|
|
50
|
+
const container = renderer._dom._document.createElement('main');
|
|
51
|
+
const output = renderer.renderReport(sampleResults, container);
|
|
52
|
+
|
|
53
|
+
renderer._dom._document.body.appendChild(container);
|
|
54
|
+
|
|
55
|
+
const config = {
|
|
56
|
+
rules: {
|
|
57
|
+
// Reports may have duplicate ids
|
|
58
|
+
// https://github.com/GoogleChrome/lighthouse/issues/9432
|
|
59
|
+
'duplicate-id': {enabled: false},
|
|
60
|
+
'duplicate-id-aria': {enabled: false},
|
|
61
|
+
'landmark-no-duplicate-contentinfo': {enabled: false},
|
|
62
|
+
// The following rules are disable for axe-core + jsdom compatibility
|
|
63
|
+
// https://github.com/dequelabs/axe-core/tree/b573b1c1/doc/examples/jest_react#to-run-the-example
|
|
64
|
+
'color-contrast': {enabled: false},
|
|
65
|
+
'link-in-text-block': {enabled: false},
|
|
66
|
+
// Report has empty links prior to i18n-ing.
|
|
67
|
+
'link-name': {enabled: false},
|
|
68
|
+
// May not be a real issue. https://github.com/dequelabs/axe-core/issues/2958
|
|
69
|
+
'nested-interactive': {enabled: false},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return new Promise(resolve => {
|
|
74
|
+
axe.run(output, config, (error, {violations}) => {
|
|
75
|
+
expect(error).toBeNull();
|
|
76
|
+
expect(violations).toEqual([]);
|
|
77
|
+
resolve();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
// This test takes 40s on fast hardware, and 50-60s on GHA.
|
|
81
|
+
// https://github.com/dequelabs/axe-core/tree/b573b1c1/doc/examples/jest_react#timeout-issues
|
|
82
|
+
},
|
|
83
|
+
/* timeout= */ 100 * 1000
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -233,59 +233,4 @@ describe('ReportRenderer', () => {
|
|
|
233
233
|
.querySelectorAll('.lh-audit--notapplicable').length;
|
|
234
234
|
assert.strictEqual(notApplicableCount, notApplicableElementCount);
|
|
235
235
|
});
|
|
236
|
-
|
|
237
|
-
describe('axe-core', () => {
|
|
238
|
-
let axe;
|
|
239
|
-
|
|
240
|
-
beforeAll(async () =>{
|
|
241
|
-
// Needed by axe-core
|
|
242
|
-
// https://github.com/dequelabs/axe-core/blob/581c441c/doc/examples/jsdom/test/a11y.js#L24
|
|
243
|
-
global.window = global.self;
|
|
244
|
-
global.Node = global.self.Node;
|
|
245
|
-
global.Element = global.self.Element;
|
|
246
|
-
|
|
247
|
-
// axe-core must be imported after the global polyfills
|
|
248
|
-
axe = (await import('axe-core')).default;
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
afterAll(() => {
|
|
252
|
-
global.window = undefined;
|
|
253
|
-
global.Node = undefined;
|
|
254
|
-
global.Element = undefined;
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('renders without axe violations', () => {
|
|
258
|
-
const container = renderer._dom._document.createElement('main');
|
|
259
|
-
const output = renderer.renderReport(sampleResults, container);
|
|
260
|
-
renderer._dom._document.body.appendChild(container);
|
|
261
|
-
|
|
262
|
-
const config = {
|
|
263
|
-
rules: {
|
|
264
|
-
// Reports may have duplicate ids
|
|
265
|
-
// https://github.com/GoogleChrome/lighthouse/issues/9432
|
|
266
|
-
'duplicate-id': {enabled: false},
|
|
267
|
-
'duplicate-id-aria': {enabled: false},
|
|
268
|
-
'landmark-no-duplicate-contentinfo': {enabled: false},
|
|
269
|
-
// The following rules are disable for axe-core + jsdom compatibility
|
|
270
|
-
// https://github.com/dequelabs/axe-core/tree/b573b1c1/doc/examples/jest_react#to-run-the-example
|
|
271
|
-
'color-contrast': {enabled: false},
|
|
272
|
-
'link-in-text-block': {enabled: false},
|
|
273
|
-
// Report has empty links prior to i18n-ing.
|
|
274
|
-
'link-name': {enabled: false},
|
|
275
|
-
// May not be a real issue. https://github.com/dequelabs/axe-core/issues/2958
|
|
276
|
-
'nested-interactive': {enabled: false},
|
|
277
|
-
},
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
return new Promise(resolve => {
|
|
281
|
-
axe.run(output, config, (error, {violations}) => {
|
|
282
|
-
expect(error).toBeNull();
|
|
283
|
-
expect(violations).toEqual([]);
|
|
284
|
-
resolve();
|
|
285
|
-
});
|
|
286
|
-
});
|
|
287
|
-
// This test takes 40s on fast hardware, and 50-60s on GHA.
|
|
288
|
-
// https://github.com/dequelabs/axe-core/tree/b573b1c1/doc/examples/jest_react#timeout-issues
|
|
289
|
-
}, /* timeout= */ 100 * 1000);
|
|
290
|
-
});
|
|
291
236
|
});
|
|
@@ -399,17 +399,77 @@ describe('util helpers', () => {
|
|
|
399
399
|
describe('#calculateCategoryFraction', () => {
|
|
400
400
|
it('returns passed audits and total audits', () => {
|
|
401
401
|
const category = {
|
|
402
|
+
id: 'performance',
|
|
402
403
|
auditRefs: [
|
|
403
|
-
{weight: 3, result: {score: 1, scoreDisplayMode: 'binary'}},
|
|
404
|
-
{weight: 2, result: {score: 1, scoreDisplayMode: 'binary'}},
|
|
405
|
-
{weight: 0, result: {score: 1, scoreDisplayMode: 'binary'}},
|
|
406
|
-
{weight: 1, result: {score: 0, scoreDisplayMode: 'binary'}},
|
|
404
|
+
{weight: 3, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
|
|
405
|
+
{weight: 2, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
|
|
406
|
+
{weight: 0, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
|
|
407
|
+
{weight: 1, result: {score: 0, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
|
|
407
408
|
],
|
|
408
409
|
};
|
|
409
|
-
const
|
|
410
|
-
expect(
|
|
411
|
-
|
|
412
|
-
|
|
410
|
+
const fraction = Util.calculateCategoryFraction(category);
|
|
411
|
+
expect(fraction).toEqual({
|
|
412
|
+
numPassableAudits: 4,
|
|
413
|
+
numPassed: 3,
|
|
414
|
+
numInformative: 0,
|
|
415
|
+
totalWeight: 6,
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
it('ignores manual audits, N/A audits, and performance audits with no group', () => {
|
|
420
|
+
const category = {
|
|
421
|
+
id: 'performance',
|
|
422
|
+
auditRefs: [
|
|
423
|
+
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
|
|
424
|
+
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}},
|
|
425
|
+
{weight: 1, result: {score: 0, scoreDisplayMode: 'manual'}, group: 'diagnostics'},
|
|
426
|
+
{weight: 1, result: {score: 0, scoreDisplayMode: 'notApplicable'}, group: 'diagnostics'},
|
|
427
|
+
],
|
|
428
|
+
};
|
|
429
|
+
const fraction = Util.calculateCategoryFraction(category);
|
|
430
|
+
expect(fraction).toEqual({
|
|
431
|
+
numPassableAudits: 1,
|
|
432
|
+
numPassed: 1,
|
|
433
|
+
numInformative: 0,
|
|
434
|
+
totalWeight: 1,
|
|
435
|
+
});
|
|
436
|
+
});
|
|
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
|
+
it('tracks informative audits separately', () => {
|
|
457
|
+
const category = {
|
|
458
|
+
id: 'performance',
|
|
459
|
+
auditRefs: [
|
|
460
|
+
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
|
|
461
|
+
{weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
|
|
462
|
+
{weight: 0, result: {score: 1, scoreDisplayMode: 'informative'}, group: 'diagnostics'},
|
|
463
|
+
{weight: 1, result: {score: 0, scoreDisplayMode: 'informative'}, group: 'diagnostics'},
|
|
464
|
+
],
|
|
465
|
+
};
|
|
466
|
+
const fraction = Util.calculateCategoryFraction(category);
|
|
467
|
+
expect(fraction).toEqual({
|
|
468
|
+
numPassableAudits: 2,
|
|
469
|
+
numPassed: 2,
|
|
470
|
+
numInformative: 2,
|
|
471
|
+
totalWeight: 2,
|
|
472
|
+
});
|
|
413
473
|
});
|
|
414
474
|
});
|
|
415
475
|
});
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
<meta charset="utf-8">
|
|
17
17
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
|
18
18
|
<title>Faux PageSpeed Report</title>
|
|
19
|
-
<style>/*%%LIGHTHOUSE_CSS%%*/</style>
|
|
20
19
|
|
|
21
20
|
<style>
|
|
22
21
|
/* Inspired by https://codepen.io/markcaron/pen/MvGRYV?editors=1100 but improved. s*/
|
package/report/tsconfig.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import AuditDetails from '../../types/lhr/audit-details';
|
|
8
|
-
import {FormattedIcu as FormattedIcu_} from '../../types/lhr/i18n';
|
|
8
|
+
import {FormattedIcu as FormattedIcu_, IcuMessage as IcuMessage_} from '../../types/lhr/i18n';
|
|
9
9
|
import LHResult from '../../types/lhr/lhr';
|
|
10
10
|
import ReportResult_ from './report-result';
|
|
11
11
|
import * as Settings from '../../types/lhr/settings';
|
|
@@ -17,6 +17,7 @@ declare global {
|
|
|
17
17
|
export import Result = LHResult;
|
|
18
18
|
export import ReportResult = ReportResult_;
|
|
19
19
|
export import Locale = Settings.Locale;
|
|
20
|
+
export type IcuMessage = IcuMessage_;
|
|
20
21
|
export type FormattedIcu<T> = FormattedIcu_<T>;
|
|
21
22
|
|
|
22
23
|
module Audit {
|
package/root.js
CHANGED
|
@@ -5,6 +5,24 @@
|
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const url = require('url');
|
|
11
|
+
|
|
12
|
+
// import {dirname} from 'path';
|
|
13
|
+
// import {fileURLToPath} from 'url';
|
|
14
|
+
|
|
8
15
|
module.exports = {
|
|
9
16
|
LH_ROOT: __dirname,
|
|
17
|
+
/**
|
|
18
|
+
* Return parsed json object.
|
|
19
|
+
* Resolves path relative to importMeta.url (if provided) or LH_ROOT (if not provided).
|
|
20
|
+
* @param {string} filePath Can be an absolute or relative path.
|
|
21
|
+
* @param {ImportMeta=} importMeta
|
|
22
|
+
*/
|
|
23
|
+
readJson(filePath, importMeta) {
|
|
24
|
+
const dir = importMeta ? path.dirname(url.fileURLToPath(importMeta.url)) : __dirname;
|
|
25
|
+
filePath = path.resolve(dir, filePath);
|
|
26
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
27
|
+
},
|
|
10
28
|
};
|