lighthouse 11.7.0-dev.20240408 → 11.7.0-dev.20240410
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/cli/cli-flags.js +3 -3
- package/cli/test/smokehouse/config/exclusions.js +1 -0
- package/cli/test/smokehouse/core-tests.js +4 -16
- package/cli/test/smokehouse/frontends/smokehouse-bin.js +2 -2
- package/core/audits/redirects-http.d.ts +19 -0
- package/core/audits/redirects-http.js +75 -0
- package/core/config/default-config.js +10 -52
- package/core/gather/driver/target-manager.js +1 -1
- package/core/gather/driver/wait-for-condition.js +2 -3
- package/core/gather/driver.js +1 -0
- package/core/gather/session.d.ts +8 -0
- package/core/gather/session.js +12 -0
- package/core/lib/lantern/network-node.js +28 -4
- package/core/runner.js +18 -23
- package/dist/report/bundle.esm.js +11 -95
- package/dist/report/flow.js +16 -100
- package/dist/report/standalone.js +12 -96
- package/flow-report/src/help-dialog.tsx +0 -1
- package/flow-report/src/i18n/i18n.d.ts +0 -4
- package/flow-report/src/i18n/ui-strings.d.ts +0 -1
- package/flow-report/src/i18n/ui-strings.js +0 -2
- package/package.json +1 -1
- package/readme.md +2 -2
- package/report/assets/styles.css +1 -43
- package/report/assets/templates.html +0 -95
- package/report/renderer/components.d.ts +2 -2
- package/report/renderer/components.js +2 -103
- package/report/renderer/report-renderer.js +2 -12
- package/report/renderer/report-ui-features.js +1 -1
- package/report/renderer/report-utils.d.ts +0 -1
- package/report/renderer/report-utils.js +0 -3
- package/shared/localization/locales/ar-XB.json +0 -174
- package/shared/localization/locales/ar.json +0 -174
- package/shared/localization/locales/bg.json +0 -174
- package/shared/localization/locales/ca.json +0 -174
- package/shared/localization/locales/cs.json +0 -174
- package/shared/localization/locales/da.json +0 -174
- package/shared/localization/locales/de.json +0 -174
- package/shared/localization/locales/el.json +0 -174
- package/shared/localization/locales/en-GB.json +0 -174
- package/shared/localization/locales/en-US.json +9 -177
- package/shared/localization/locales/en-XA.json +0 -174
- package/shared/localization/locales/en-XL.json +9 -177
- package/shared/localization/locales/es-419.json +0 -174
- package/shared/localization/locales/es.json +0 -174
- package/shared/localization/locales/fi.json +0 -174
- package/shared/localization/locales/fil.json +0 -174
- package/shared/localization/locales/fr.json +0 -174
- package/shared/localization/locales/he.json +0 -174
- package/shared/localization/locales/hi.json +0 -174
- package/shared/localization/locales/hr.json +0 -174
- package/shared/localization/locales/hu.json +0 -174
- package/shared/localization/locales/id.json +0 -174
- package/shared/localization/locales/it.json +0 -174
- package/shared/localization/locales/ja.json +0 -174
- package/shared/localization/locales/ko.json +0 -174
- package/shared/localization/locales/lt.json +0 -174
- package/shared/localization/locales/lv.json +0 -174
- package/shared/localization/locales/nl.json +0 -174
- package/shared/localization/locales/no.json +0 -174
- package/shared/localization/locales/pl.json +0 -174
- package/shared/localization/locales/pt-PT.json +0 -174
- package/shared/localization/locales/pt.json +0 -174
- package/shared/localization/locales/ro.json +0 -174
- package/shared/localization/locales/ru.json +0 -174
- package/shared/localization/locales/sk.json +0 -174
- package/shared/localization/locales/sl.json +0 -174
- package/shared/localization/locales/sr-Latn.json +0 -174
- package/shared/localization/locales/sr.json +0 -174
- package/shared/localization/locales/sv.json +0 -174
- package/shared/localization/locales/ta.json +0 -174
- package/shared/localization/locales/te.json +0 -174
- package/shared/localization/locales/th.json +0 -174
- package/shared/localization/locales/tr.json +0 -174
- package/shared/localization/locales/uk.json +0 -174
- package/shared/localization/locales/vi.json +0 -174
- package/shared/localization/locales/zh-HK.json +0 -174
- package/shared/localization/locales/zh-TW.json +0 -174
- package/shared/localization/locales/zh.json +0 -174
- package/types/artifacts.d.ts +0 -27
- package/types/audit.d.ts +0 -10
- package/types/gatherer.d.ts +1 -0
- package/types/internal/smokehouse.d.ts +1 -1
- package/core/audits/content-width.d.ts +0 -17
- package/core/audits/content-width.js +0 -76
- package/core/audits/installable-manifest.d.ts +0 -111
- package/core/audits/installable-manifest.js +0 -248
- package/core/audits/manual/pwa-cross-browser.d.ts +0 -12
- package/core/audits/manual/pwa-cross-browser.js +0 -40
- package/core/audits/manual/pwa-each-page-has-url.d.ts +0 -12
- package/core/audits/manual/pwa-each-page-has-url.js +0 -38
- package/core/audits/manual/pwa-page-transitions.d.ts +0 -12
- package/core/audits/manual/pwa-page-transitions.js +0 -38
- package/core/audits/maskable-icon.d.ts +0 -25
- package/core/audits/maskable-icon.js +0 -70
- package/core/audits/multi-check-audit.d.ts +0 -28
- package/core/audits/multi-check-audit.js +0 -82
- package/core/audits/splash-screen.d.ts +0 -37
- package/core/audits/splash-screen.js +0 -98
- package/core/audits/themed-omnibox.d.ts +0 -42
- package/core/audits/themed-omnibox.js +0 -102
- package/core/computed/manifest-values.d.ts +0 -24
- package/core/computed/manifest-values.js +0 -136
- package/core/gather/gatherers/installability-errors.d.ts +0 -17
- package/core/gather/gatherers/installability-errors.js +0 -56
- package/core/gather/gatherers/web-app-manifest.d.ts +0 -32
- package/core/gather/gatherers/web-app-manifest.js +0 -106
- package/report/renderer/pwa-category-renderer.d.ts +0 -55
- package/report/renderer/pwa-category-renderer.js +0 -184
- package/third-party/chromium-synchronization/installability-errors-test.js +0 -79
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2021 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import log from 'lighthouse-logger';
|
|
8
|
-
|
|
9
|
-
import {parseManifest} from '../../lib/manifest-parser.js';
|
|
10
|
-
import BaseGatherer from '../base-gatherer.js';
|
|
11
|
-
|
|
12
|
-
class WebAppManifest extends BaseGatherer {
|
|
13
|
-
/** @type {LH.Gatherer.GathererMeta} */
|
|
14
|
-
meta = {
|
|
15
|
-
supportedModes: ['snapshot', 'navigation'],
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @param {LH.Gatherer.ProtocolSession} session
|
|
20
|
-
* @return {Promise<{url: string, data: string}|null>}
|
|
21
|
-
*/
|
|
22
|
-
static async fetchAppManifest(session) {
|
|
23
|
-
// In all environments but LR, Page.getAppManifest finishes very quickly.
|
|
24
|
-
// In LR, there is a bug that causes this command to hang until outgoing
|
|
25
|
-
// requests finish. This has been seen in long polling (where it will never
|
|
26
|
-
// return) and when other requests take a long time to finish. We allow 10 seconds
|
|
27
|
-
// for outgoing requests to finish. Anything more, and we continue the run without
|
|
28
|
-
// a manifest.
|
|
29
|
-
// Googlers, see: http://b/124008171
|
|
30
|
-
session.setNextProtocolTimeout(10000);
|
|
31
|
-
let response;
|
|
32
|
-
try {
|
|
33
|
-
response = await session.sendCommand('Page.getAppManifest');
|
|
34
|
-
} catch (err) {
|
|
35
|
-
if (err.code === 'PROTOCOL_TIMEOUT') {
|
|
36
|
-
// LR will timeout fetching the app manifest in some cases, move on without one.
|
|
37
|
-
// https://github.com/GoogleChrome/lighthouse/issues/7147#issuecomment-461210921
|
|
38
|
-
log.error('WebAppManifest', 'Failed fetching manifest', err);
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
throw err;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let data = response.data;
|
|
46
|
-
|
|
47
|
-
// We're not reading `response.errors` however it may contain critical and noncritical
|
|
48
|
-
// errors from Blink's manifest parser:
|
|
49
|
-
// https://chromedevtools.github.io/debugger-protocol-viewer/tot/Page/#type-AppManifestError
|
|
50
|
-
if (!data) {
|
|
51
|
-
// If the data is empty, the page had no manifest.
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const BOM_LENGTH = 3;
|
|
56
|
-
const BOM_FIRSTCHAR = 65279;
|
|
57
|
-
const isBomEncoded = data.charCodeAt(0) === BOM_FIRSTCHAR;
|
|
58
|
-
|
|
59
|
-
if (isBomEncoded) {
|
|
60
|
-
data = Buffer.from(data)
|
|
61
|
-
.slice(BOM_LENGTH)
|
|
62
|
-
.toString();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return {...response, data};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Uses the debugger protocol to fetch the manifest from within the context of
|
|
70
|
-
* the target page, reusing any credentials, emulation, etc, already established
|
|
71
|
-
* there.
|
|
72
|
-
*
|
|
73
|
-
* Returns the parsed manifest or null if the page had no manifest. If the manifest
|
|
74
|
-
* was unparseable as JSON, manifest.value will be undefined and manifest.warning
|
|
75
|
-
* will have the reason. See manifest-parser.js for more information.
|
|
76
|
-
*
|
|
77
|
-
* @param {LH.Gatherer.ProtocolSession} session
|
|
78
|
-
* @param {string} pageUrl
|
|
79
|
-
* @return {Promise<LH.Artifacts.Manifest|null>}
|
|
80
|
-
*/
|
|
81
|
-
static async getWebAppManifest(session, pageUrl) {
|
|
82
|
-
const status = {msg: 'Get webapp manifest', id: 'lh:gather:getWebAppManifest'};
|
|
83
|
-
log.time(status);
|
|
84
|
-
const response = await WebAppManifest.fetchAppManifest(session);
|
|
85
|
-
if (!response) return null;
|
|
86
|
-
const manifest = parseManifest(response.data, response.url, pageUrl);
|
|
87
|
-
log.timeEnd(status);
|
|
88
|
-
return manifest;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* @param {LH.Gatherer.Context} context
|
|
93
|
-
* @return {Promise<LH.Artifacts['WebAppManifest']>}
|
|
94
|
-
*/
|
|
95
|
-
async getArtifact(context) {
|
|
96
|
-
const driver = context.driver;
|
|
97
|
-
const {finalDisplayedUrl} = context.baseArtifacts.URL;
|
|
98
|
-
try {
|
|
99
|
-
return await WebAppManifest.getWebAppManifest(driver.defaultSession, finalDisplayedUrl);
|
|
100
|
-
} catch {
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export default WebAppManifest;
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
export class PwaCategoryRenderer extends CategoryRenderer {
|
|
2
|
-
/**
|
|
3
|
-
* Alters SVG id references so multiple instances of an SVG element can coexist
|
|
4
|
-
* in a single page. If `svgRoot` has a `<defs>` block, gives all elements defined
|
|
5
|
-
* in it unique ids, then updates id references (`<use xlink:href="...">`,
|
|
6
|
-
* `fill="url(#...)"`) to the altered ids in all descendents of `svgRoot`.
|
|
7
|
-
* @param {SVGElement} svgRoot
|
|
8
|
-
*/
|
|
9
|
-
static _makeSvgReferencesUnique(svgRoot: SVGElement): void;
|
|
10
|
-
/**
|
|
11
|
-
* @param {LH.ReportResult.Category} category
|
|
12
|
-
* @param {Object<string, LH.Result.ReportGroup>} [groupDefinitions]
|
|
13
|
-
* @return {Element}
|
|
14
|
-
*/
|
|
15
|
-
render(category: LH.ReportResult.Category, groupDefinitions?: {
|
|
16
|
-
[x: string]: import("../../types/lhr/lhr.js").default.ReportGroup;
|
|
17
|
-
} | undefined): Element;
|
|
18
|
-
/**
|
|
19
|
-
* @param {LH.ReportResult.Category} category
|
|
20
|
-
* @param {Record<string, LH.Result.ReportGroup>} groupDefinitions
|
|
21
|
-
* @return {DocumentFragment}
|
|
22
|
-
*/
|
|
23
|
-
renderCategoryScore(category: LH.ReportResult.Category, groupDefinitions: Record<string, LH.Result.ReportGroup>): DocumentFragment;
|
|
24
|
-
/**
|
|
25
|
-
* Returns the group IDs found in auditRefs.
|
|
26
|
-
* @param {Array<LH.ReportResult.AuditRef>} auditRefs
|
|
27
|
-
* @return {!Set<string>}
|
|
28
|
-
*/
|
|
29
|
-
_getGroupIds(auditRefs: Array<LH.ReportResult.AuditRef>): Set<string>;
|
|
30
|
-
/**
|
|
31
|
-
* Returns the group IDs whose audits are all considered passing.
|
|
32
|
-
* @param {Array<LH.ReportResult.AuditRef>} auditRefs
|
|
33
|
-
* @return {Set<string>}
|
|
34
|
-
*/
|
|
35
|
-
_getPassingGroupIds(auditRefs: Array<LH.ReportResult.AuditRef>): Set<string>;
|
|
36
|
-
/**
|
|
37
|
-
* Returns a tooltip string summarizing group pass rates.
|
|
38
|
-
* @param {Array<LH.ReportResult.AuditRef>} auditRefs
|
|
39
|
-
* @param {Record<string, LH.Result.ReportGroup>} groupDefinitions
|
|
40
|
-
* @return {string}
|
|
41
|
-
*/
|
|
42
|
-
_getGaugeTooltip(auditRefs: Array<LH.ReportResult.AuditRef>, groupDefinitions: Record<string, LH.Result.ReportGroup>): string;
|
|
43
|
-
/**
|
|
44
|
-
* Render non-manual audits in groups, giving a badge to any group that has
|
|
45
|
-
* all passing audits.
|
|
46
|
-
* @param {Array<LH.ReportResult.AuditRef>} auditRefs
|
|
47
|
-
* @param {Object<string, LH.Result.ReportGroup>} groupDefinitions
|
|
48
|
-
* @return {Element}
|
|
49
|
-
*/
|
|
50
|
-
_renderAudits(auditRefs: Array<LH.ReportResult.AuditRef>, groupDefinitions: {
|
|
51
|
-
[x: string]: LH.Result.ReportGroup;
|
|
52
|
-
}): Element;
|
|
53
|
-
}
|
|
54
|
-
import { CategoryRenderer } from './category-renderer.js';
|
|
55
|
-
//# sourceMappingURL=pwa-category-renderer.d.ts.map
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2018 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import {CategoryRenderer} from './category-renderer.js';
|
|
8
|
-
import {ReportUtils} from './report-utils.js';
|
|
9
|
-
import {Globals} from './report-globals.js';
|
|
10
|
-
|
|
11
|
-
export class PwaCategoryRenderer extends CategoryRenderer {
|
|
12
|
-
/**
|
|
13
|
-
* @param {LH.ReportResult.Category} category
|
|
14
|
-
* @param {Object<string, LH.Result.ReportGroup>} [groupDefinitions]
|
|
15
|
-
* @return {Element}
|
|
16
|
-
*/
|
|
17
|
-
render(category, groupDefinitions = {}) {
|
|
18
|
-
const categoryElem = this.dom.createElement('div', 'lh-category');
|
|
19
|
-
categoryElem.id = category.id;
|
|
20
|
-
// Deprecation warning banner.
|
|
21
|
-
const pwaMessageContainer = this.dom.createComponent('warningsToplevel');
|
|
22
|
-
const pwaMessageEl = this.dom.find('.lh-warnings__msg', pwaMessageContainer);
|
|
23
|
-
pwaMessageEl.append(this.dom.convertMarkdownLinkSnippets(Globals.strings.pwaRemovalMessage));
|
|
24
|
-
|
|
25
|
-
categoryElem.append(pwaMessageContainer);
|
|
26
|
-
categoryElem.append(this.renderCategoryHeader(category, groupDefinitions));
|
|
27
|
-
|
|
28
|
-
const auditRefs = category.auditRefs;
|
|
29
|
-
|
|
30
|
-
// Regular audits aren't split up into pass/fail/notApplicable clumps, they're
|
|
31
|
-
// all put in a top-level clump that isn't expandable/collapsible.
|
|
32
|
-
const regularAuditRefs = auditRefs.filter(ref => ref.result.scoreDisplayMode !== 'manual');
|
|
33
|
-
const auditsElem = this._renderAudits(regularAuditRefs, groupDefinitions);
|
|
34
|
-
categoryElem.append(auditsElem);
|
|
35
|
-
|
|
36
|
-
// Manual audits are still in a manual clump.
|
|
37
|
-
const manualAuditRefs = auditRefs.filter(ref => ref.result.scoreDisplayMode === 'manual');
|
|
38
|
-
const manualElem = this.renderClump('manual', {
|
|
39
|
-
auditRefsOrEls: manualAuditRefs,
|
|
40
|
-
description: category.manualDescription,
|
|
41
|
-
openByDefault: true,
|
|
42
|
-
});
|
|
43
|
-
categoryElem.append(manualElem);
|
|
44
|
-
|
|
45
|
-
return categoryElem;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* @param {LH.ReportResult.Category} category
|
|
50
|
-
* @param {Record<string, LH.Result.ReportGroup>} groupDefinitions
|
|
51
|
-
* @return {DocumentFragment}
|
|
52
|
-
*/
|
|
53
|
-
renderCategoryScore(category, groupDefinitions) {
|
|
54
|
-
// Defer to parent-gauge style if category error.
|
|
55
|
-
if (category.score === null) {
|
|
56
|
-
return super.renderScoreGauge(category, groupDefinitions);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const tmpl = this.dom.createComponent('gaugePwa');
|
|
60
|
-
const wrapper = this.dom.find('a.lh-gauge--pwa__wrapper', tmpl);
|
|
61
|
-
|
|
62
|
-
// Correct IDs in case multiple instances end up in the page.
|
|
63
|
-
const svgRoot = tmpl.querySelector('svg');
|
|
64
|
-
if (!svgRoot) throw new Error('no SVG element found in PWA score gauge template');
|
|
65
|
-
PwaCategoryRenderer._makeSvgReferencesUnique(svgRoot);
|
|
66
|
-
|
|
67
|
-
const allGroups = this._getGroupIds(category.auditRefs);
|
|
68
|
-
const passingGroupIds = this._getPassingGroupIds(category.auditRefs);
|
|
69
|
-
|
|
70
|
-
if (passingGroupIds.size === allGroups.size) {
|
|
71
|
-
wrapper.classList.add('lh-badged--all');
|
|
72
|
-
} else {
|
|
73
|
-
for (const passingGroupId of passingGroupIds) {
|
|
74
|
-
wrapper.classList.add(`lh-badged--${passingGroupId}`);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
this.dom.find('.lh-gauge__label', tmpl).textContent = category.title;
|
|
79
|
-
wrapper.title = this._getGaugeTooltip(category.auditRefs, groupDefinitions);
|
|
80
|
-
return tmpl;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Returns the group IDs found in auditRefs.
|
|
85
|
-
* @param {Array<LH.ReportResult.AuditRef>} auditRefs
|
|
86
|
-
* @return {!Set<string>}
|
|
87
|
-
*/
|
|
88
|
-
_getGroupIds(auditRefs) {
|
|
89
|
-
const groupIds = auditRefs.map(ref => ref.group).filter(/** @return {g is string} */ g => !!g);
|
|
90
|
-
return new Set(groupIds);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Returns the group IDs whose audits are all considered passing.
|
|
95
|
-
* @param {Array<LH.ReportResult.AuditRef>} auditRefs
|
|
96
|
-
* @return {Set<string>}
|
|
97
|
-
*/
|
|
98
|
-
_getPassingGroupIds(auditRefs) {
|
|
99
|
-
const uniqueGroupIds = this._getGroupIds(auditRefs);
|
|
100
|
-
|
|
101
|
-
// Remove any that have a failing audit.
|
|
102
|
-
for (const auditRef of auditRefs) {
|
|
103
|
-
if (!ReportUtils.showAsPassed(auditRef.result) && auditRef.group) {
|
|
104
|
-
uniqueGroupIds.delete(auditRef.group);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return uniqueGroupIds;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Returns a tooltip string summarizing group pass rates.
|
|
113
|
-
* @param {Array<LH.ReportResult.AuditRef>} auditRefs
|
|
114
|
-
* @param {Record<string, LH.Result.ReportGroup>} groupDefinitions
|
|
115
|
-
* @return {string}
|
|
116
|
-
*/
|
|
117
|
-
_getGaugeTooltip(auditRefs, groupDefinitions) {
|
|
118
|
-
const groupIds = this._getGroupIds(auditRefs);
|
|
119
|
-
|
|
120
|
-
const tips = [];
|
|
121
|
-
for (const groupId of groupIds) {
|
|
122
|
-
const groupAuditRefs = auditRefs.filter(ref => ref.group === groupId);
|
|
123
|
-
const auditCount = groupAuditRefs.length;
|
|
124
|
-
const passedCount = groupAuditRefs.filter(ref => ReportUtils.showAsPassed(ref.result)).length;
|
|
125
|
-
|
|
126
|
-
const title = groupDefinitions[groupId].title;
|
|
127
|
-
tips.push(`${title}: ${passedCount}/${auditCount}`);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return tips.join(', ');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Render non-manual audits in groups, giving a badge to any group that has
|
|
135
|
-
* all passing audits.
|
|
136
|
-
* @param {Array<LH.ReportResult.AuditRef>} auditRefs
|
|
137
|
-
* @param {Object<string, LH.Result.ReportGroup>} groupDefinitions
|
|
138
|
-
* @return {Element}
|
|
139
|
-
*/
|
|
140
|
-
_renderAudits(auditRefs, groupDefinitions) {
|
|
141
|
-
const auditsElem = this.renderUnexpandableClump(auditRefs, groupDefinitions);
|
|
142
|
-
|
|
143
|
-
// Add a 'badged' class to group if all audits in that group pass.
|
|
144
|
-
const passsingGroupIds = this._getPassingGroupIds(auditRefs);
|
|
145
|
-
for (const groupId of passsingGroupIds) {
|
|
146
|
-
const groupElem = this.dom.find(`.lh-audit-group--${groupId}`, auditsElem);
|
|
147
|
-
groupElem.classList.add('lh-badged');
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return auditsElem;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Alters SVG id references so multiple instances of an SVG element can coexist
|
|
155
|
-
* in a single page. If `svgRoot` has a `<defs>` block, gives all elements defined
|
|
156
|
-
* in it unique ids, then updates id references (`<use xlink:href="...">`,
|
|
157
|
-
* `fill="url(#...)"`) to the altered ids in all descendents of `svgRoot`.
|
|
158
|
-
* @param {SVGElement} svgRoot
|
|
159
|
-
*/
|
|
160
|
-
static _makeSvgReferencesUnique(svgRoot) {
|
|
161
|
-
const defsEl = svgRoot.querySelector('defs');
|
|
162
|
-
if (!defsEl) return;
|
|
163
|
-
|
|
164
|
-
const idSuffix = Globals.getUniqueSuffix();
|
|
165
|
-
const elementsToUpdate = defsEl.querySelectorAll('[id]');
|
|
166
|
-
for (const el of elementsToUpdate) {
|
|
167
|
-
const oldId = el.id;
|
|
168
|
-
const newId = `${oldId}-${idSuffix}`;
|
|
169
|
-
el.id = newId;
|
|
170
|
-
|
|
171
|
-
// Update all <use>s.
|
|
172
|
-
const useEls = svgRoot.querySelectorAll(`use[href="#${oldId}"]`);
|
|
173
|
-
for (const useEl of useEls) {
|
|
174
|
-
useEl.setAttribute('href', `#${newId}`);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Update all fill="url(#...)"s.
|
|
178
|
-
const fillEls = svgRoot.querySelectorAll(`[fill="url(#${oldId})"]`);
|
|
179
|
-
for (const fillEl of fillEls) {
|
|
180
|
-
fillEl.setAttribute('fill', `url(#${newId})`);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2020 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
'use strict';
|
|
7
|
-
|
|
8
|
-
import fetch from 'node-fetch';
|
|
9
|
-
|
|
10
|
-
import {UIStrings} from '../../core/audits/installable-manifest.js';
|
|
11
|
-
|
|
12
|
-
describe('installabilityErrors', () => {
|
|
13
|
-
let chromiumErrorIds;
|
|
14
|
-
|
|
15
|
-
before(async () => {
|
|
16
|
-
const installableLoggingGitTilesUrl =
|
|
17
|
-
'https://chromium.googlesource.com/chromium/src/+/main/components/webapps/browser/installable/installable_logging.cc?format=TEXT';
|
|
18
|
-
const resp = await fetch(installableLoggingGitTilesUrl);
|
|
19
|
-
if (!resp.ok) {
|
|
20
|
-
throw new Error(`Chromium source fetch failed: ${resp.status} ${resp.statusText}`);
|
|
21
|
-
}
|
|
22
|
-
const base64 = await resp.text();
|
|
23
|
-
const buff = Buffer.from(base64, 'base64');
|
|
24
|
-
const text = buff.toString('utf-8');
|
|
25
|
-
|
|
26
|
-
// Apply some *beautiful* regexes to parse the C++ of https://chromium.googlesource.com/chromium/src/+/main/chrome/browser/installable/installable_logging.cc
|
|
27
|
-
const handledErrorConsts = [...text.matchAll(/error_id = (k.*?);/g)].map(([_, match]) => match);
|
|
28
|
-
const errorConstsToIdsCode = [...text.matchAll(/static const char k.*?Id\[\](.|\n)*?;/g)].map(
|
|
29
|
-
([match]) => match.replace(/\n/, '')
|
|
30
|
-
);
|
|
31
|
-
const errorConstsToIds = errorConstsToIdsCode.map(txt => [
|
|
32
|
-
txt.match(/char (k.*?)\[/)[1],
|
|
33
|
-
txt.match(/ "(.*?)"/)[1],
|
|
34
|
-
]);
|
|
35
|
-
const errorConstsToIdsDict = Object.fromEntries(errorConstsToIds);
|
|
36
|
-
|
|
37
|
-
chromiumErrorIds = handledErrorConsts.map(varName => {
|
|
38
|
-
if (!errorConstsToIdsDict[varName]) throw new Error(`Error const (${varName}) not found!`);
|
|
39
|
-
return errorConstsToIdsDict[varName];
|
|
40
|
-
}).sort();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should notify us if something changed', () => {
|
|
44
|
-
expect(chromiumErrorIds).toMatchInlineSnapshot(`
|
|
45
|
-
Array [
|
|
46
|
-
"already-installed",
|
|
47
|
-
"cannot-download-icon",
|
|
48
|
-
"ids-do-not-match",
|
|
49
|
-
"in-incognito",
|
|
50
|
-
"manifest-display-not-supported",
|
|
51
|
-
"manifest-display-override-not-supported",
|
|
52
|
-
"manifest-location-changed",
|
|
53
|
-
"manifest-missing-name-or-short-name",
|
|
54
|
-
"manifest-missing-suitable-icon",
|
|
55
|
-
"manifest-parsing-or-network-error",
|
|
56
|
-
"no-acceptable-icon",
|
|
57
|
-
"no-icon-available",
|
|
58
|
-
"no-id-specified",
|
|
59
|
-
"no-manifest",
|
|
60
|
-
"no-url-for-service-worker",
|
|
61
|
-
"not-from-secure-origin",
|
|
62
|
-
"not-offline-capable",
|
|
63
|
-
"pipeline-restarted",
|
|
64
|
-
"platform-not-supported-on-android",
|
|
65
|
-
"prefer-related-applications",
|
|
66
|
-
"prefer-related-applications-only-beta-stable",
|
|
67
|
-
"start-url-not-valid",
|
|
68
|
-
"url-not-supported-for-webapk",
|
|
69
|
-
]
|
|
70
|
-
`);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('are each handled explicitly in the gatherer', () => {
|
|
74
|
-
const errorStrings = Object.keys(UIStrings)
|
|
75
|
-
.filter(key => chromiumErrorIds.includes(key))
|
|
76
|
-
.sort();
|
|
77
|
-
expect(errorStrings).toEqual(chromiumErrorIds);
|
|
78
|
-
});
|
|
79
|
-
});
|