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.
Files changed (110) hide show
  1. package/cli/cli-flags.js +3 -3
  2. package/cli/test/smokehouse/config/exclusions.js +1 -0
  3. package/cli/test/smokehouse/core-tests.js +4 -16
  4. package/cli/test/smokehouse/frontends/smokehouse-bin.js +2 -2
  5. package/core/audits/redirects-http.d.ts +19 -0
  6. package/core/audits/redirects-http.js +75 -0
  7. package/core/config/default-config.js +10 -52
  8. package/core/gather/driver/target-manager.js +1 -1
  9. package/core/gather/driver/wait-for-condition.js +2 -3
  10. package/core/gather/driver.js +1 -0
  11. package/core/gather/session.d.ts +8 -0
  12. package/core/gather/session.js +12 -0
  13. package/core/lib/lantern/network-node.js +28 -4
  14. package/core/runner.js +18 -23
  15. package/dist/report/bundle.esm.js +11 -95
  16. package/dist/report/flow.js +16 -100
  17. package/dist/report/standalone.js +12 -96
  18. package/flow-report/src/help-dialog.tsx +0 -1
  19. package/flow-report/src/i18n/i18n.d.ts +0 -4
  20. package/flow-report/src/i18n/ui-strings.d.ts +0 -1
  21. package/flow-report/src/i18n/ui-strings.js +0 -2
  22. package/package.json +1 -1
  23. package/readme.md +2 -2
  24. package/report/assets/styles.css +1 -43
  25. package/report/assets/templates.html +0 -95
  26. package/report/renderer/components.d.ts +2 -2
  27. package/report/renderer/components.js +2 -103
  28. package/report/renderer/report-renderer.js +2 -12
  29. package/report/renderer/report-ui-features.js +1 -1
  30. package/report/renderer/report-utils.d.ts +0 -1
  31. package/report/renderer/report-utils.js +0 -3
  32. package/shared/localization/locales/ar-XB.json +0 -174
  33. package/shared/localization/locales/ar.json +0 -174
  34. package/shared/localization/locales/bg.json +0 -174
  35. package/shared/localization/locales/ca.json +0 -174
  36. package/shared/localization/locales/cs.json +0 -174
  37. package/shared/localization/locales/da.json +0 -174
  38. package/shared/localization/locales/de.json +0 -174
  39. package/shared/localization/locales/el.json +0 -174
  40. package/shared/localization/locales/en-GB.json +0 -174
  41. package/shared/localization/locales/en-US.json +9 -177
  42. package/shared/localization/locales/en-XA.json +0 -174
  43. package/shared/localization/locales/en-XL.json +9 -177
  44. package/shared/localization/locales/es-419.json +0 -174
  45. package/shared/localization/locales/es.json +0 -174
  46. package/shared/localization/locales/fi.json +0 -174
  47. package/shared/localization/locales/fil.json +0 -174
  48. package/shared/localization/locales/fr.json +0 -174
  49. package/shared/localization/locales/he.json +0 -174
  50. package/shared/localization/locales/hi.json +0 -174
  51. package/shared/localization/locales/hr.json +0 -174
  52. package/shared/localization/locales/hu.json +0 -174
  53. package/shared/localization/locales/id.json +0 -174
  54. package/shared/localization/locales/it.json +0 -174
  55. package/shared/localization/locales/ja.json +0 -174
  56. package/shared/localization/locales/ko.json +0 -174
  57. package/shared/localization/locales/lt.json +0 -174
  58. package/shared/localization/locales/lv.json +0 -174
  59. package/shared/localization/locales/nl.json +0 -174
  60. package/shared/localization/locales/no.json +0 -174
  61. package/shared/localization/locales/pl.json +0 -174
  62. package/shared/localization/locales/pt-PT.json +0 -174
  63. package/shared/localization/locales/pt.json +0 -174
  64. package/shared/localization/locales/ro.json +0 -174
  65. package/shared/localization/locales/ru.json +0 -174
  66. package/shared/localization/locales/sk.json +0 -174
  67. package/shared/localization/locales/sl.json +0 -174
  68. package/shared/localization/locales/sr-Latn.json +0 -174
  69. package/shared/localization/locales/sr.json +0 -174
  70. package/shared/localization/locales/sv.json +0 -174
  71. package/shared/localization/locales/ta.json +0 -174
  72. package/shared/localization/locales/te.json +0 -174
  73. package/shared/localization/locales/th.json +0 -174
  74. package/shared/localization/locales/tr.json +0 -174
  75. package/shared/localization/locales/uk.json +0 -174
  76. package/shared/localization/locales/vi.json +0 -174
  77. package/shared/localization/locales/zh-HK.json +0 -174
  78. package/shared/localization/locales/zh-TW.json +0 -174
  79. package/shared/localization/locales/zh.json +0 -174
  80. package/types/artifacts.d.ts +0 -27
  81. package/types/audit.d.ts +0 -10
  82. package/types/gatherer.d.ts +1 -0
  83. package/types/internal/smokehouse.d.ts +1 -1
  84. package/core/audits/content-width.d.ts +0 -17
  85. package/core/audits/content-width.js +0 -76
  86. package/core/audits/installable-manifest.d.ts +0 -111
  87. package/core/audits/installable-manifest.js +0 -248
  88. package/core/audits/manual/pwa-cross-browser.d.ts +0 -12
  89. package/core/audits/manual/pwa-cross-browser.js +0 -40
  90. package/core/audits/manual/pwa-each-page-has-url.d.ts +0 -12
  91. package/core/audits/manual/pwa-each-page-has-url.js +0 -38
  92. package/core/audits/manual/pwa-page-transitions.d.ts +0 -12
  93. package/core/audits/manual/pwa-page-transitions.js +0 -38
  94. package/core/audits/maskable-icon.d.ts +0 -25
  95. package/core/audits/maskable-icon.js +0 -70
  96. package/core/audits/multi-check-audit.d.ts +0 -28
  97. package/core/audits/multi-check-audit.js +0 -82
  98. package/core/audits/splash-screen.d.ts +0 -37
  99. package/core/audits/splash-screen.js +0 -98
  100. package/core/audits/themed-omnibox.d.ts +0 -42
  101. package/core/audits/themed-omnibox.js +0 -102
  102. package/core/computed/manifest-values.d.ts +0 -24
  103. package/core/computed/manifest-values.js +0 -136
  104. package/core/gather/gatherers/installability-errors.d.ts +0 -17
  105. package/core/gather/gatherers/installability-errors.js +0 -56
  106. package/core/gather/gatherers/web-app-manifest.d.ts +0 -32
  107. package/core/gather/gatherers/web-app-manifest.js +0 -106
  108. package/report/renderer/pwa-category-renderer.d.ts +0 -55
  109. package/report/renderer/pwa-category-renderer.js +0 -184
  110. package/third-party/chromium-synchronization/installability-errors-test.js +0 -79
package/cli/cli-flags.js CHANGED
@@ -53,8 +53,8 @@ function getYargsParser(manualArgv) {
53
53
  'lighthouse <url> --extra-headers=./path/to/file.json',
54
54
  'Path to JSON file of HTTP Header key/value pairs to send in requests')
55
55
  .example(
56
- 'lighthouse <url> --only-categories=performance,pwa',
57
- 'Only run the specified categories. Available categories: accessibility, best-practices, performance, pwa, seo')
56
+ 'lighthouse <url> --only-categories=performance,seo',
57
+ 'Only run the specified categories. Available categories: accessibility, best-practices, performance, seo')
58
58
 
59
59
  // We only have the single string positional argument, the url.
60
60
  .option('_', {
@@ -188,7 +188,7 @@ function getYargsParser(manualArgv) {
188
188
  array: true,
189
189
  type: 'string',
190
190
  coerce: splitCommaSeparatedValues,
191
- describe: 'Only run the specified categories. Available categories: accessibility, best-practices, performance, pwa, seo',
191
+ describe: 'Only run the specified categories. Available categories: accessibility, best-practices, performance, seo',
192
192
  },
193
193
  'skip-audits': {
194
194
  array: true,
@@ -20,6 +20,7 @@ const exclusions = {
20
20
  'redirects-client-paint-server', 'redirects-multiple-server',
21
21
  'redirects-single-server', 'redirects-single-client',
22
22
  'redirects-history-push-state', 'redirects-scripts',
23
+ 'redirects-http',
23
24
  // Disabled because these tests use settings that cannot be fully configured in
24
25
  // DevTools (e.g. throttling method "provided").
25
26
  'metrics-tricky-tti', 'metrics-tricky-tti-late-fcp', 'screenshot',
@@ -13,6 +13,7 @@ import dbw from './test-definitions/dobetterweb.js';
13
13
  import errorsExpiredSsl from './test-definitions/errors-expired-ssl.js';
14
14
  import errorsIframeExpiredSsl from './test-definitions/errors-iframe-expired-ssl.js';
15
15
  import errorsInfiniteLoop from './test-definitions/errors-infinite-loop.js';
16
+ import fontSize from './test-definitions/font-size.js';
16
17
  import formsAutoComplete from './test-definitions/forms-autocomplete.js';
17
18
  import fpsMax from './test-definitions/fps-max.js';
18
19
  import fpsMaxPassive from './test-definitions/fps-max-passive.js';
@@ -31,9 +32,6 @@ import metricsDelayedFcp from './test-definitions/metrics-delayed-fcp.js';
31
32
  import metricsDelayedLcp from './test-definitions/metrics-delayed-lcp.js';
32
33
  import metricsTrickyTti from './test-definitions/metrics-tricky-tti.js';
33
34
  import metricsTrickyTtiLateFcp from './test-definitions/metrics-tricky-tti-late-fcp.js';
34
- import offlineOnlineOnly from './test-definitions/offline-online-only.js';
35
- import offlineReady from './test-definitions/offline-ready.js';
36
- import offlineSwBroken from './test-definitions/offline-sw-broken.js';
37
35
  import oopifRequests from './test-definitions/oopif-requests.js';
38
36
  import oopifScripts from './test-definitions/oopif-scripts.js';
39
37
  import perfBudgets from './test-definitions/perf-budgets.js';
@@ -45,13 +43,9 @@ import perfFonts from './test-definitions/perf-fonts.js';
45
43
  import perfFrameMetrics from './test-definitions/perf-frame-metrics.js';
46
44
  import perfPreload from './test-definitions/perf-preload.js';
47
45
  import perfTraceElements from './test-definitions/perf-trace-elements.js';
48
- import pwaAirhorner from './test-definitions/pwa-airhorner.js';
49
- import pwaCaltrain from './test-definitions/pwa-caltrain.js';
50
- import pwaChromestatus from './test-definitions/pwa-chromestatus.js';
51
- import pwaRocks from './test-definitions/pwa-rocks.js';
52
- import pwaSvgomg from './test-definitions/pwa-svgomg.js';
53
46
  import redirectsClientPaintServer from './test-definitions/redirects-client-paint-server.js';
54
47
  import redirectsHistoryPushState from './test-definitions/redirects-history-push-state.js';
48
+ import redirectsHttp from './test-definitions/redirects-http.js';
55
49
  import redirectsMultipleServer from './test-definitions/redirects-multiple-server.js';
56
50
  import redirectsScripts from './test-definitions/redirects-scripts.js';
57
51
  import redirectsSelf from './test-definitions/redirects-self.js';
@@ -77,6 +71,7 @@ const smokeTests = [
77
71
  errorsExpiredSsl,
78
72
  errorsIframeExpiredSsl,
79
73
  errorsInfiniteLoop,
74
+ fontSize,
80
75
  formsAutoComplete,
81
76
  fpsMax,
82
77
  fpsMaxPassive,
@@ -95,9 +90,6 @@ const smokeTests = [
95
90
  metricsDelayedLcp,
96
91
  metricsTrickyTti,
97
92
  metricsTrickyTtiLateFcp,
98
- offlineOnlineOnly,
99
- offlineReady,
100
- offlineSwBroken,
101
93
  oopifRequests,
102
94
  oopifScripts,
103
95
  perfBudgets,
@@ -109,13 +101,9 @@ const smokeTests = [
109
101
  perfFrameMetrics,
110
102
  perfPreload,
111
103
  perfTraceElements,
112
- pwaAirhorner,
113
- pwaCaltrain,
114
- pwaChromestatus,
115
- pwaRocks,
116
- pwaSvgomg,
117
104
  redirectsClientPaintServer,
118
105
  redirectsHistoryPushState,
106
+ redirectsHttp,
119
107
  redirectsMultipleServer,
120
108
  redirectsScripts,
121
109
  redirectsSelf,
@@ -59,7 +59,7 @@ function getDefinitionsToRun(allTestDefns, requestedIds, excludedTests) {
59
59
  } else {
60
60
  smokes = allTestDefns.filter(test => {
61
61
  // Include all tests that *include* requested id.
62
- // e.g. a requested 'pwa' will match 'pwa-airhorner', 'pwa-caltrain', etc
62
+ // e.g. a requested 'perf' will match 'perf-preload', 'perf-trace-elements', etc
63
63
  return requestedIds.some(requestedId => test.id.includes(requestedId));
64
64
  });
65
65
  console.log(`Running ONLY smoketests for: ${smokes.map(t => t.id).join(' ')}\n`);
@@ -125,7 +125,7 @@ async function begin() {
125
125
  const rawArgv = y
126
126
  .help('help')
127
127
  .usage('node $0 [<options>] <test-ids>')
128
- .example('node $0 -j=1 pwa seo', 'run pwa and seo tests serially')
128
+ .example('node $0 -j=1 perf seo', 'run perf and seo tests serially')
129
129
  .option('_', {
130
130
  array: true,
131
131
  type: 'string',
@@ -0,0 +1,19 @@
1
+ export default RedirectsHTTP;
2
+ /**
3
+ * An audit for checking if a site starting on http redirects to https. The audit
4
+ * is marked not applicable if the requestedUrl is already https.
5
+ */
6
+ declare class RedirectsHTTP extends Audit {
7
+ /**
8
+ * @param {LH.Artifacts} artifacts
9
+ * @return {LH.Audit.Product}
10
+ */
11
+ static audit(artifacts: LH.Artifacts): LH.Audit.Product;
12
+ }
13
+ export namespace UIStrings {
14
+ const title: string;
15
+ const failureTitle: string;
16
+ const description: string;
17
+ }
18
+ import { Audit } from './audit.js';
19
+ //# sourceMappingURL=redirects-http.d.ts.map
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @license Copyright 2024 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
+
7
+ import {Audit} from './audit.js';
8
+ import * as i18n from '../lib/i18n/i18n.js';
9
+ import UrlUtils from '../lib/url-utils.js';
10
+
11
+ const UIStrings = {
12
+ /** Title of a Lighthouse audit that provides detail on HTTP to HTTPS redirects. This descriptive title is shown to users when HTTP traffic is redirected to HTTPS. */
13
+ title: 'Redirects HTTP traffic to HTTPS',
14
+ /** Title of a Lighthouse audit that provides detail on HTTP to HTTPS redirects. This descriptive title is shown to users when HTTP traffic is not redirected to HTTPS. */
15
+ failureTitle: 'Does not redirect HTTP traffic to HTTPS',
16
+ /** Description of a Lighthouse audit that tells the user why they should direct HTTP traffic to HTTPS. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */
17
+ description: 'Make sure that you redirect all HTTP ' +
18
+ 'traffic to HTTPS in order to enable secure web features for all your users. [Learn more](https://developer.chrome.com/docs/lighthouse/pwa/redirects-http/).',
19
+ };
20
+
21
+ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
22
+
23
+ /**
24
+ * An audit for checking if a site starting on http redirects to https. The audit
25
+ * is marked not applicable if the requestedUrl is already https.
26
+ */
27
+ class RedirectsHTTP extends Audit {
28
+ /**
29
+ * @return {LH.Audit.Meta}
30
+ */
31
+ static get meta() {
32
+ return {
33
+ id: 'redirects-http',
34
+ title: str_(UIStrings.title),
35
+ failureTitle: str_(UIStrings.failureTitle),
36
+ description: str_(UIStrings.description),
37
+ requiredArtifacts: ['URL'],
38
+ supportedModes: ['navigation'],
39
+ };
40
+ }
41
+
42
+ /**
43
+ * @param {LH.Artifacts} artifacts
44
+ * @return {LH.Audit.Product}
45
+ */
46
+ static audit(artifacts) {
47
+ if (!artifacts.URL.requestedUrl) {
48
+ throw new Error('Missing requestedUrl');
49
+ }
50
+
51
+ const requestedUrl = new URL(artifacts.URL.requestedUrl);
52
+ const finalDisplayedUrl = new URL(artifacts.URL.finalDisplayedUrl);
53
+
54
+ // Not applicable unless starting on http.
55
+ const startedInsecure = requestedUrl.protocol === 'http:';
56
+
57
+ // Relax requirements on localhost.
58
+ const isLocalhost = UrlUtils.isLikeLocalhost(finalDisplayedUrl.hostname);
59
+
60
+ if (!startedInsecure || isLocalhost) {
61
+ return {
62
+ score: null,
63
+ notApplicable: true,
64
+ };
65
+ }
66
+
67
+ const endedSecure = finalDisplayedUrl.protocol === 'https:';
68
+ return {
69
+ score: Number(endedSecure),
70
+ };
71
+ }
72
+ }
73
+
74
+ export default RedirectsHTTP;
75
+ export {UIStrings};
@@ -90,15 +90,6 @@ const UIStrings = {
90
90
  seoCrawlingGroupTitle: 'Crawling and Indexing',
91
91
  /** Description of the navigation section within the Search Engine Optimization (SEO) category. Within this section are audits with descriptive titles that highlight ways to make a website accessible to search engine crawlers. */
92
92
  seoCrawlingGroupDescription: 'To appear in search results, crawlers need access to your app.',
93
- /** Title of the Progressive Web Application (PWA) category of audits. This is displayed at the top of a list of audits focused on topics related to whether or not a site is a progressive web app, e.g. responds offline, uses a service worker, is on https, etc. Also used as a label of a score gauge. */
94
- pwaCategoryTitle: 'PWA',
95
- /** Description of the Progressive Web Application (PWA) category. This is displayed at the top of a list of audits focused on topics related to whether or not a site is a progressive web app, e.g. responds offline, uses a service worker, is on https, etc. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
96
- pwaCategoryDescription: 'These checks validate the aspects of a Progressive Web App. ' +
97
- '[Learn what makes a good Progressive Web App](https://web.dev/articles/pwa-checklist).',
98
- /** Description of the Progressive Web Application (PWA) manual checks category, containing a list of additional validators must be run by hand in order to check all PWA best practices. This is displayed at the top of a list of manually run audits focused on topics related to whether or not a site is a progressive web app, e.g. responds offline, uses a service worker, is on https, etc.. No character length limits. */
99
- pwaCategoryManualDescription: 'These checks are required by the baseline ' +
100
- '[PWA Checklist](https://web.dev/articles/pwa-checklist) but are ' +
101
- 'not automatically checked by Lighthouse. They do not affect your score but it\'s important that you verify them manually.',
102
93
  /** Title of the Best Practices category of audits. This is displayed at the top of a list of audits focused on topics related to following web development best practices and accepted guidelines. Also used as a label of a score gauge; try to limit to 20 characters. */
103
94
  bestPracticesCategoryTitle: 'Best Practices',
104
95
  /** Title of the Trust & Safety group of audits. This is displayed at the top of a list of audits focused on maintaining user trust and protecting security in web development. */
@@ -109,10 +100,6 @@ const UIStrings = {
109
100
  bestPracticesBrowserCompatGroupTitle: 'Browser Compatibility',
110
101
  /** Title of the General group of the Best Practices category. Within this section are the audits that don't belong to a specific group but are of general interest. */
111
102
  bestPracticesGeneralGroupTitle: 'General',
112
- /** Title of the Installable section of the web app category. Within this section are audits that check if Chrome supports installing the web site as an app on their device. */
113
- pwaInstallableGroupTitle: 'Installable',
114
- /** Title of the "PWA Optimized" section of the web app category. Within this section are audits that check if the developer has taken advantage of features to make their web page more enjoyable and engaging for the user. */
115
- pwaOptimizedGroupTitle: 'PWA Optimized',
116
103
  };
117
104
 
118
105
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -137,7 +124,6 @@ const defaultConfig = {
137
124
  {id: 'Inputs', gatherer: 'inputs'},
138
125
  {id: 'IFrameElements', gatherer: 'iframe-elements'},
139
126
  {id: 'ImageElements', gatherer: 'image-elements'},
140
- {id: 'InstallabilityErrors', gatherer: 'installability-errors'},
141
127
  {id: 'InspectorIssues', gatherer: 'inspector-issues'},
142
128
  {id: 'JsUsage', gatherer: 'js-usage'},
143
129
  {id: 'LinkElements', gatherer: 'link-elements'},
@@ -154,7 +140,6 @@ const defaultConfig = {
154
140
  {id: 'TagsBlockingFirstPaint', gatherer: 'dobetterweb/tags-blocking-first-paint'},
155
141
  {id: 'TraceElements', gatherer: 'trace-elements'},
156
142
  {id: 'ViewportDimensions', gatherer: 'viewport-dimensions'},
157
- {id: 'WebAppManifest', gatherer: 'web-app-manifest'},
158
143
 
159
144
  // Artifact copies are renamed for compatibility with legacy artifacts.
160
145
  {id: 'devtoolsLogs', gatherer: 'devtools-log-compat'},
@@ -168,6 +153,7 @@ const defaultConfig = {
168
153
  ],
169
154
  audits: [
170
155
  'is-on-https',
156
+ 'redirects-http',
171
157
  'viewport',
172
158
  'metrics/first-contentful-paint',
173
159
  'metrics/largest-contentful-paint',
@@ -185,11 +171,6 @@ const defaultConfig = {
185
171
  'user-timings',
186
172
  'critical-request-chains',
187
173
  'redirects',
188
- 'installable-manifest',
189
- 'splash-screen',
190
- 'themed-omnibox',
191
- 'maskable-icon',
192
- 'content-width',
193
174
  'image-aspect-ratio',
194
175
  'image-size-responsive',
195
176
  'deprecations',
@@ -219,9 +200,6 @@ const defaultConfig = {
219
200
  'prioritize-lcp-image',
220
201
  'csp-xss',
221
202
  'script-treemap-data',
222
- 'manual/pwa-cross-browser',
223
- 'manual/pwa-page-transitions',
224
- 'manual/pwa-each-page-has-url',
225
203
  'accessibility/accesskeys',
226
204
  'accessibility/aria-allowed-attr',
227
205
  'accessibility/aria-allowed-role',
@@ -344,12 +322,6 @@ const defaultConfig = {
344
322
  title: str_(UIStrings.diagnosticsGroupTitle),
345
323
  description: str_(UIStrings.diagnosticsGroupDescription),
346
324
  },
347
- 'pwa-installable': {
348
- title: str_(UIStrings.pwaInstallableGroupTitle),
349
- },
350
- 'pwa-optimized': {
351
- title: str_(UIStrings.pwaOptimizedGroupTitle),
352
- },
353
325
  'a11y-best-practices': {
354
326
  title: str_(UIStrings.a11yBestPracticesGroupTitle),
355
327
  description: str_(UIStrings.a11yBestPracticesGroupDescription),
@@ -574,6 +546,7 @@ const defaultConfig = {
574
546
  auditRefs: [
575
547
  // Trust & Safety
576
548
  {id: 'is-on-https', weight: 5, group: 'best-practices-trust-safety'},
549
+ {id: 'redirects-http', weight: 1, group: 'best-practices-trust-safety'},
577
550
  {id: 'geolocation-on-start', weight: 1, group: 'best-practices-trust-safety'},
578
551
  {id: 'notification-on-start', weight: 1, group: 'best-practices-trust-safety'},
579
552
  {id: 'csp-xss', weight: 0, group: 'best-practices-trust-safety'},
@@ -581,6 +554,8 @@ const defaultConfig = {
581
554
  {id: 'paste-preventing-inputs', weight: 3, group: 'best-practices-ux'},
582
555
  {id: 'image-aspect-ratio', weight: 1, group: 'best-practices-ux'},
583
556
  {id: 'image-size-responsive', weight: 1, group: 'best-practices-ux'},
557
+ {id: 'viewport', weight: 1, group: 'best-practices-ux'},
558
+ {id: 'font-size', weight: 1, group: 'best-practices-ux'},
584
559
  // Browser Compatibility
585
560
  {id: 'doctype', weight: 1, group: 'best-practices-browser-compat'},
586
561
  {id: 'charset', weight: 1, group: 'best-practices-browser-compat'},
@@ -599,42 +574,25 @@ const defaultConfig = {
599
574
  manualDescription: str_(UIStrings.seoCategoryManualDescription),
600
575
  supportedModes: ['navigation', 'snapshot'],
601
576
  auditRefs: [
602
- {id: 'viewport', weight: 1, group: 'seo-mobile'},
577
+ // Should be at least 31% of the score, such that this audit failing
578
+ // results in the SEO category failing.
579
+ // Solve for w:
580
+ // w / (w + T) >= 0.31
581
+ // where T is the sum of all the other weights.
582
+ {id: 'is-crawlable', weight: 93 / 23, group: 'seo-crawl'},
603
583
  {id: 'document-title', weight: 1, group: 'seo-content'},
604
584
  {id: 'meta-description', weight: 1, group: 'seo-content'},
605
585
  {id: 'http-status-code', weight: 1, group: 'seo-crawl'},
606
586
  {id: 'link-text', weight: 1, group: 'seo-content'},
607
587
  {id: 'crawlable-anchors', weight: 1, group: 'seo-crawl'},
608
- {id: 'is-crawlable', weight: 1, group: 'seo-crawl'},
609
588
  {id: 'robots-txt', weight: 1, group: 'seo-crawl'},
610
589
  {id: 'image-alt', weight: 1, group: 'seo-content'},
611
590
  {id: 'hreflang', weight: 1, group: 'seo-content'},
612
591
  {id: 'canonical', weight: 1, group: 'seo-content'},
613
- {id: 'font-size', weight: 1, group: 'seo-mobile'},
614
592
  // Manual audits
615
593
  {id: 'structured-data', weight: 0},
616
594
  ],
617
595
  },
618
- 'pwa': {
619
- title: str_(UIStrings.pwaCategoryTitle),
620
- description: str_(UIStrings.pwaCategoryDescription),
621
- manualDescription: str_(UIStrings.pwaCategoryManualDescription),
622
- supportedModes: ['navigation'],
623
- auditRefs: [
624
- // Installable
625
- {id: 'installable-manifest', weight: 2, group: 'pwa-installable'},
626
- // PWA Optimized
627
- {id: 'splash-screen', weight: 1, group: 'pwa-optimized'},
628
- {id: 'themed-omnibox', weight: 1, group: 'pwa-optimized'},
629
- {id: 'content-width', weight: 1, group: 'pwa-optimized'},
630
- {id: 'viewport', weight: 2, group: 'pwa-optimized'},
631
- {id: 'maskable-icon', weight: 1, group: 'pwa-optimized'},
632
- // Manual audits
633
- {id: 'pwa-cross-browser', weight: 0},
634
- {id: 'pwa-page-transitions', weight: 0},
635
- {id: 'pwa-each-page-has-url', weight: 0},
636
- ],
637
- },
638
596
  },
639
597
  };
640
598
 
@@ -180,7 +180,7 @@ class TargetManager extends ProtocolEventEmitter {
180
180
  throw err;
181
181
  } finally {
182
182
  // Resume the target if it was paused, but if it's unnecessary, we don't care about the error.
183
- await newSession.sendCommand('Runtime.runIfWaitingForDebugger').catch(() => {});
183
+ await newSession.sendCommandAndIgnore('Runtime.runIfWaitingForDebugger');
184
184
  }
185
185
  }
186
186
 
@@ -498,9 +498,8 @@ async function waitForFullyLoaded(session, networkMonitor, options) {
498
498
  if (await isPageHung(session)) {
499
499
  log.warn('waitFor', 'Page appears to be hung, killing JavaScript...');
500
500
  // We don't await these, as we want to exit with PAGE_HUNG
501
- void session.sendCommand('Emulation.setScriptExecutionDisabled', {value: true})
502
- .catch(_ => {});
503
- void session.sendCommand('Runtime.terminateExecution').catch(_ => {});
501
+ void session.sendCommandAndIgnore('Emulation.setScriptExecutionDisabled', {value: true});
502
+ void session.sendCommandAndIgnore('Runtime.terminateExecution');
504
503
  throw new LighthouseError(LighthouseError.errors.PAGE_HUNG);
505
504
  }
506
505
 
@@ -26,6 +26,7 @@ const throwingSession = {
26
26
  once: throwNotConnectedFn,
27
27
  off: throwNotConnectedFn,
28
28
  sendCommand: throwNotConnectedFn,
29
+ sendCommandAndIgnore: throwNotConnectedFn,
29
30
  dispose: throwNotConnectedFn,
30
31
  };
31
32
 
@@ -40,6 +40,14 @@ export class ProtocolSession extends ProtocolSession_base implements LH.Gatherer
40
40
  * @return {Promise<LH.CrdpCommands[C]['returnType']>}
41
41
  */
42
42
  sendCommand<C extends keyof import("puppeteer-core").ProtocolMapping.Commands>(method: C, ...params: import("puppeteer-core").ProtocolMapping.Commands[C]["paramsType"]): Promise<import("puppeteer-core").ProtocolMapping.Commands[C]["returnType"]>;
43
+ /**
44
+ * Send and if there's an error response, do not reject.
45
+ * @template {keyof LH.CrdpCommands} C
46
+ * @param {C} method
47
+ * @param {LH.CrdpCommands[C]['paramsType']} params
48
+ * @return {Promise<void>}
49
+ */
50
+ sendCommandAndIgnore<C_1 extends keyof import("puppeteer-core").ProtocolMapping.Commands>(method: C_1, ...params: import("puppeteer-core").ProtocolMapping.Commands[C_1]["paramsType"]): Promise<void>;
43
51
  /**
44
52
  * Disposes of a session so that it can no longer talk to Chrome.
45
53
  * @return {Promise<void>}
@@ -120,6 +120,18 @@ class ProtocolSession extends CrdpEventEmitter {
120
120
  });
121
121
  }
122
122
 
123
+ /**
124
+ * Send and if there's an error response, do not reject.
125
+ * @template {keyof LH.CrdpCommands} C
126
+ * @param {C} method
127
+ * @param {LH.CrdpCommands[C]['paramsType']} params
128
+ * @return {Promise<void>}
129
+ */
130
+ sendCommandAndIgnore(method, ...params) {
131
+ return this.sendCommand(method, ...params)
132
+ .catch(e => log.verbose('session', method, e.message)).then(_ => void 0);
133
+ }
134
+
123
135
  /**
124
136
  * Disposes of a session so that it can no longer talk to Chrome.
125
137
  * @return {Promise<void>}
@@ -7,8 +7,32 @@
7
7
  import * as Lantern from './types/lantern.js';
8
8
  import {NetworkRequestTypes} from './lantern.js';
9
9
  import {BaseNode} from './base-node.js';
10
- // TODO(15841): bring impl of isNonNetworkRequest inside lantern and remove this.
11
- import UrlUtils from '../url-utils.js';
10
+
11
+ const NON_NETWORK_SCHEMES = [
12
+ 'blob', // @see https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
13
+ 'data', // @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
14
+ 'intent', // @see https://developer.chrome.com/docs/multidevice/android/intents/
15
+ 'file', // @see https://en.wikipedia.org/wiki/File_URI_scheme
16
+ 'filesystem', // @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystem
17
+ 'chrome-extension',
18
+ ];
19
+
20
+ /**
21
+ * Use `NetworkRequest.isNonNetworkRequest(req)` if working with a request.
22
+ * Note: the `protocol` field from CDP can be 'h2', 'http', (not 'https'!) or it'll be url's scheme.
23
+ * https://source.chromium.org/chromium/chromium/src/+/main:content/browser/devtools/protocol/network_handler.cc;l=598-611;drc=56d4a9a9deb30be73adcee8737c73bcb2a5ab64f
24
+ * However, a `new URL(href).protocol` has a colon suffix.
25
+ * https://url.spec.whatwg.org/#dom-url-protocol
26
+ * A URL's `scheme` is specced as the `protocol` sans-colon, but isn't exposed on a URL object.
27
+ * This method can take all 3 of these string types as a parameter.
28
+ * @param {string} protocol Either a networkRequest's `protocol` per CDP or a `new URL(href).protocol`
29
+ * @return {boolean}
30
+ */
31
+ function isNonNetworkProtocol(protocol) {
32
+ // Strip off any colon
33
+ const urlScheme = protocol.includes(':') ? protocol.slice(0, protocol.indexOf(':')) : protocol;
34
+ return NON_NETWORK_SCHEMES.includes(urlScheme);
35
+ }
12
36
 
13
37
  /**
14
38
  * @template [T=any]
@@ -75,9 +99,9 @@ class NetworkNode extends BaseNode {
75
99
  */
76
100
  get isNonNetworkProtocol() {
77
101
  // The 'protocol' field in devtools a string more like a `scheme`
78
- return UrlUtils.isNonNetworkProtocol(this.request.protocol) ||
102
+ return isNonNetworkProtocol(this.request.protocol) ||
79
103
  // But `protocol` can fail to be populated if the request fails, so fallback to scheme.
80
- UrlUtils.isNonNetworkProtocol(this.request.parsedURL.scheme);
104
+ isNonNetworkProtocol(this.request.parsedURL.scheme);
81
105
  }
82
106
 
83
107
  /**
package/core/runner.js CHANGED
@@ -199,32 +199,27 @@ class Runner {
199
199
  data: sentryContext,
200
200
  });
201
201
 
202
- /** @type {LH.Artifacts} */
203
- let artifacts;
204
202
  if (settings.auditMode && !settings.gatherMode) {
205
203
  // No browser required, just load the artifacts from disk.
206
204
  const path = this._getDataSavePath(settings);
207
- artifacts = assetSaver.loadArtifacts(path);
208
- } else {
209
- const runnerStatus = {msg: 'Gather phase', id: 'lh:runner:gather'};
210
- log.time(runnerStatus, 'verbose');
211
-
212
- artifacts = await gatherFn({
213
- resolvedConfig: options.resolvedConfig,
214
- });
215
-
216
- log.timeEnd(runnerStatus);
217
-
218
- // If `gather` is run multiple times before `audit`, the timing entries for each `gather` can pollute one another.
219
- // We need to clear the timing entries at the end of gathering.
220
- // Set artifacts.Timing again to ensure lh:runner:gather is included.
221
- artifacts.Timing = log.takeTimeEntries();
222
-
223
- // -G means save these to disk (e.g. ./latest-run).
224
- if (settings.gatherMode) {
225
- const path = this._getDataSavePath(settings);
226
- await assetSaver.saveArtifacts(artifacts, path);
227
- }
205
+ return assetSaver.loadArtifacts(path);
206
+ }
207
+
208
+ const runnerStatus = {msg: 'Gather phase', id: 'lh:runner:gather'};
209
+ log.time(runnerStatus, 'verbose');
210
+
211
+ const artifacts = await gatherFn({resolvedConfig: options.resolvedConfig});
212
+ log.timeEnd(runnerStatus);
213
+
214
+ // If `gather` is run multiple times before `audit`, the timing entries for each `gather` can pollute one another.
215
+ // We need to clear the timing entries at the end of gathering.
216
+ // Set artifacts.Timing again to ensure lh:runner:gather is included.
217
+ artifacts.Timing = log.takeTimeEntries();
218
+
219
+ // -G means save these to disk (e.g. ./latest-run).
220
+ if (settings.gatherMode) {
221
+ const path = this._getDataSavePath(settings);
222
+ await assetSaver.saveArtifacts(artifacts, path);
228
223
  }
229
224
 
230
225
  return artifacts;