lighthouse 10.4.0 → 11.0.0

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 (288) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/cli/cli-flags.d.ts +1 -6
  3. package/cli/cli-flags.js +0 -5
  4. package/cli/run.js +3 -10
  5. package/cli/sentry-prompt.js +4 -2
  6. package/cli/test/smokehouse/core-tests.js +0 -2
  7. package/cli/test/smokehouse/frontends/smokehouse-bin.js +24 -14
  8. package/cli/test/smokehouse/lighthouse-runners/bundle.d.ts +1 -2
  9. package/cli/test/smokehouse/lighthouse-runners/bundle.js +12 -21
  10. package/cli/test/smokehouse/lighthouse-runners/cli.d.ts +1 -3
  11. package/cli/test/smokehouse/lighthouse-runners/cli.js +3 -7
  12. package/cli/test/smokehouse/lighthouse-runners/devtools.d.ts +1 -5
  13. package/cli/test/smokehouse/lighthouse-runners/devtools.js +1 -12
  14. package/cli/test/smokehouse/readme.md +0 -2
  15. package/cli/test/smokehouse/report-assert.d.ts +1 -3
  16. package/cli/test/smokehouse/report-assert.js +2 -19
  17. package/cli/test/smokehouse/smokehouse.js +3 -32
  18. package/core/audits/accessibility/aria-allowed-role.d.ts +10 -0
  19. package/core/audits/accessibility/aria-allowed-role.js +46 -0
  20. package/core/audits/accessibility/image-redundant-alt.d.ts +10 -0
  21. package/core/audits/accessibility/image-redundant-alt.js +45 -0
  22. package/core/audits/accessibility/label-content-name-mismatch.d.ts +10 -0
  23. package/core/audits/accessibility/label-content-name-mismatch.js +44 -0
  24. package/core/audits/accessibility/skip-link.d.ts +10 -0
  25. package/core/audits/accessibility/skip-link.js +43 -0
  26. package/core/audits/accessibility/table-duplicate-name.d.ts +10 -0
  27. package/core/audits/accessibility/table-duplicate-name.js +44 -0
  28. package/core/audits/accessibility/target-size.js +1 -1
  29. package/core/audits/byte-efficiency/duplicated-javascript.js +2 -2
  30. package/core/audits/byte-efficiency/render-blocking-resources.js +1 -0
  31. package/core/audits/dobetterweb/uses-http2.d.ts +18 -1
  32. package/core/audits/dobetterweb/uses-http2.js +62 -16
  33. package/core/audits/installable-manifest.d.ts +1 -5
  34. package/core/audits/installable-manifest.js +2 -7
  35. package/core/audits/largest-contentful-paint-element.d.ts +0 -6
  36. package/core/audits/largest-contentful-paint-element.js +13 -15
  37. package/core/audits/metrics/{experimental-interaction-to-next-paint.d.ts → interaction-to-next-paint.d.ts} +3 -3
  38. package/core/audits/metrics/{experimental-interaction-to-next-paint.js → interaction-to-next-paint.js} +3 -3
  39. package/core/audits/uses-rel-preconnect.js +23 -8
  40. package/core/audits/work-during-interaction.js +2 -2
  41. package/core/computed/processed-navigation.d.ts +1 -1
  42. package/core/config/config-helpers.d.ts +3 -3
  43. package/core/config/config-helpers.js +5 -12
  44. package/core/config/config.js +1 -7
  45. package/core/config/constants.d.ts +0 -2
  46. package/core/config/constants.js +2 -18
  47. package/core/config/default-config.js +59 -53
  48. package/core/config/filters.js +1 -1
  49. package/core/config/validation.d.ts +7 -12
  50. package/core/config/validation.js +16 -26
  51. package/core/gather/base-artifacts.d.ts +4 -4
  52. package/core/gather/base-artifacts.js +2 -6
  53. package/core/gather/base-gatherer.d.ts +12 -37
  54. package/core/gather/base-gatherer.js +7 -54
  55. package/core/gather/driver/dom.d.ts +4 -4
  56. package/core/gather/driver/dom.js +2 -2
  57. package/core/gather/driver/environment.d.ts +4 -4
  58. package/core/gather/driver/environment.js +2 -2
  59. package/core/gather/driver/execution-context.d.ts +12 -3
  60. package/core/gather/driver/execution-context.js +34 -3
  61. package/core/gather/driver/navigation.d.ts +2 -2
  62. package/core/gather/driver/navigation.js +2 -5
  63. package/core/gather/driver/network-monitor.d.ts +7 -6
  64. package/core/gather/driver/network-monitor.js +4 -4
  65. package/core/gather/driver/network.d.ts +2 -2
  66. package/core/gather/driver/network.js +1 -1
  67. package/core/gather/driver/prepare.d.ts +10 -10
  68. package/core/gather/driver/prepare.js +10 -10
  69. package/core/gather/driver/service-workers.d.ts +4 -4
  70. package/core/gather/driver/service-workers.js +2 -2
  71. package/core/gather/driver/storage.d.ts +6 -6
  72. package/core/gather/driver/storage.js +3 -3
  73. package/core/gather/driver/target-manager.d.ts +6 -5
  74. package/core/gather/driver/target-manager.js +3 -3
  75. package/core/gather/driver/wait-for-condition.d.ts +14 -14
  76. package/core/gather/driver/wait-for-condition.js +8 -8
  77. package/core/gather/driver.d.ts +9 -6
  78. package/core/gather/driver.js +14 -4
  79. package/core/gather/fetcher.d.ts +3 -3
  80. package/core/gather/fetcher.js +1 -1
  81. package/core/gather/gatherers/accessibility.d.ts +4 -4
  82. package/core/gather/gatherers/accessibility.js +8 -3
  83. package/core/gather/gatherers/anchor-elements.d.ts +4 -4
  84. package/core/gather/gatherers/anchor-elements.js +4 -4
  85. package/core/gather/gatherers/bf-cache-failures.d.ts +8 -14
  86. package/core/gather/gatherers/bf-cache-failures.js +5 -14
  87. package/core/gather/gatherers/cache-contents.d.ts +4 -4
  88. package/core/gather/gatherers/cache-contents.js +3 -3
  89. package/core/gather/gatherers/console-messages.d.ts +6 -6
  90. package/core/gather/gatherers/console-messages.js +4 -4
  91. package/core/gather/gatherers/css-usage.d.ts +14 -14
  92. package/core/gather/gatherers/css-usage.js +9 -9
  93. package/core/gather/gatherers/devtools-log-compat.d.ts +5 -5
  94. package/core/gather/gatherers/devtools-log-compat.js +4 -4
  95. package/core/gather/gatherers/devtools-log.d.ts +6 -6
  96. package/core/gather/gatherers/devtools-log.js +4 -4
  97. package/core/gather/gatherers/dobetterweb/doctype.d.ts +4 -4
  98. package/core/gather/gatherers/dobetterweb/doctype.js +3 -3
  99. package/core/gather/gatherers/dobetterweb/domstats.d.ts +4 -4
  100. package/core/gather/gatherers/dobetterweb/domstats.js +3 -3
  101. package/core/gather/gatherers/dobetterweb/optimized-images.d.ts +10 -22
  102. package/core/gather/gatherers/dobetterweb/optimized-images.js +10 -27
  103. package/core/gather/gatherers/dobetterweb/response-compression.d.ts +6 -12
  104. package/core/gather/gatherers/dobetterweb/response-compression.js +14 -21
  105. package/core/gather/gatherers/dobetterweb/tags-blocking-first-paint.d.ts +8 -14
  106. package/core/gather/gatherers/dobetterweb/tags-blocking-first-paint.js +5 -14
  107. package/core/gather/gatherers/full-page-screenshot.d.ts +10 -10
  108. package/core/gather/gatherers/full-page-screenshot.js +7 -10
  109. package/core/gather/gatherers/global-listeners.d.ts +4 -4
  110. package/core/gather/gatherers/global-listeners.js +3 -3
  111. package/core/gather/gatherers/iframe-elements.d.ts +4 -4
  112. package/core/gather/gatherers/iframe-elements.js +3 -3
  113. package/core/gather/gatherers/image-elements.d.ts +10 -10
  114. package/core/gather/gatherers/image-elements.js +6 -6
  115. package/core/gather/gatherers/inputs.d.ts +4 -4
  116. package/core/gather/gatherers/inputs.js +3 -3
  117. package/core/gather/gatherers/inspector-issues.d.ts +8 -19
  118. package/core/gather/gatherers/inspector-issues.js +9 -26
  119. package/core/gather/gatherers/installability-errors.d.ts +6 -6
  120. package/core/gather/gatherers/installability-errors.js +4 -4
  121. package/core/gather/gatherers/js-usage.d.ts +6 -6
  122. package/core/gather/gatherers/js-usage.js +4 -4
  123. package/core/gather/gatherers/link-elements.d.ts +8 -20
  124. package/core/gather/gatherers/link-elements.js +7 -24
  125. package/core/gather/gatherers/main-document-content.d.ts +4 -16
  126. package/core/gather/gatherers/main-document-content.js +5 -23
  127. package/core/gather/gatherers/meta-elements.d.ts +4 -4
  128. package/core/gather/gatherers/meta-elements.js +3 -3
  129. package/core/gather/gatherers/network-user-agent.d.ts +5 -5
  130. package/core/gather/gatherers/network-user-agent.js +4 -4
  131. package/core/gather/gatherers/script-elements.d.ts +6 -11
  132. package/core/gather/gatherers/script-elements.js +4 -13
  133. package/core/gather/gatherers/scripts.d.ts +7 -6
  134. package/core/gather/gatherers/scripts.js +7 -9
  135. package/core/gather/gatherers/seo/embedded-content.d.ts +4 -4
  136. package/core/gather/gatherers/seo/embedded-content.js +3 -3
  137. package/core/gather/gatherers/seo/font-size.d.ts +6 -6
  138. package/core/gather/gatherers/seo/font-size.js +5 -5
  139. package/core/gather/gatherers/seo/robots-txt.d.ts +4 -4
  140. package/core/gather/gatherers/seo/robots-txt.js +3 -3
  141. package/core/gather/gatherers/seo/tap-targets.d.ts +8 -8
  142. package/core/gather/gatherers/seo/tap-targets.js +5 -5
  143. package/core/gather/gatherers/service-worker.d.ts +4 -10
  144. package/core/gather/gatherers/service-worker.js +3 -15
  145. package/core/gather/gatherers/source-maps.d.ts +11 -23
  146. package/core/gather/gatherers/source-maps.js +22 -53
  147. package/core/gather/gatherers/stacks.d.ts +7 -7
  148. package/core/gather/gatherers/stacks.js +6 -6
  149. package/core/gather/gatherers/trace-compat.d.ts +5 -5
  150. package/core/gather/gatherers/trace-compat.js +4 -4
  151. package/core/gather/gatherers/trace-elements.d.ts +13 -25
  152. package/core/gather/gatherers/trace-elements.js +19 -32
  153. package/core/gather/gatherers/trace.d.ts +8 -8
  154. package/core/gather/gatherers/trace.js +5 -5
  155. package/core/gather/gatherers/viewport-dimensions.d.ts +4 -4
  156. package/core/gather/gatherers/viewport-dimensions.js +3 -3
  157. package/core/gather/gatherers/web-app-manifest.d.ts +8 -8
  158. package/core/gather/gatherers/web-app-manifest.js +5 -5
  159. package/core/gather/navigation-runner.d.ts +9 -9
  160. package/core/gather/navigation-runner.js +14 -8
  161. package/core/gather/runner-helpers.d.ts +3 -3
  162. package/core/gather/runner-helpers.js +12 -4
  163. package/core/gather/session.d.ts +2 -2
  164. package/core/gather/session.js +1 -1
  165. package/core/gather/snapshot-runner.d.ts +2 -2
  166. package/core/gather/snapshot-runner.js +1 -1
  167. package/core/gather/timespan-runner.d.ts +2 -2
  168. package/core/gather/timespan-runner.js +1 -1
  169. package/core/index.cjs +0 -7
  170. package/core/index.d.ts +0 -15
  171. package/core/index.js +2 -40
  172. package/core/lib/asset-saver.js +14 -4
  173. package/core/lib/axe.js +1 -1
  174. package/core/lib/dependency-graph/simulator/network-analyzer.d.ts +28 -12
  175. package/core/lib/dependency-graph/simulator/network-analyzer.js +128 -100
  176. package/core/lib/emulation.d.ts +14 -14
  177. package/core/lib/emulation.js +7 -7
  178. package/core/lib/navigation-error.js +5 -0
  179. package/core/lib/network-recorder.d.ts +2 -1
  180. package/core/lib/network-recorder.js +1 -0
  181. package/core/lib/network-request.js +12 -3
  182. package/core/lib/page-functions.d.ts +10 -2
  183. package/core/lib/page-functions.js +85 -8
  184. package/core/lib/sentry.js +9 -2
  185. package/core/lib/stack-packs.js +4 -0
  186. package/core/runner.d.ts +8 -30
  187. package/core/runner.js +8 -39
  188. package/core/user-flow.d.ts +4 -4
  189. package/core/user-flow.js +2 -2
  190. package/dist/report/bundle.esm.js +2221 -5832
  191. package/dist/report/flow.js +2631 -235
  192. package/dist/report/standalone.js +2586 -234
  193. package/flow-report/src/i18n/i18n.d.ts +2 -2
  194. package/package.json +17 -24
  195. package/readme.md +3 -1
  196. package/report/assets/templates.html +3 -1
  197. package/report/renderer/category-renderer.d.ts +3 -2
  198. package/report/renderer/category-renderer.js +8 -4
  199. package/report/renderer/components.js +11 -5
  200. package/report/renderer/pwa-category-renderer.js +1 -1
  201. package/report/renderer/report-ui-features.js +9 -6
  202. package/report/renderer/report-utils.d.ts +1 -1
  203. package/report/renderer/report-utils.js +2 -2
  204. package/report/renderer/topbar-features.js +3 -0
  205. package/shared/localization/locales/ar-XB.json +185 -44
  206. package/shared/localization/locales/ar.json +185 -44
  207. package/shared/localization/locales/bg.json +185 -44
  208. package/shared/localization/locales/ca.json +190 -49
  209. package/shared/localization/locales/cs.json +185 -44
  210. package/shared/localization/locales/da.json +185 -44
  211. package/shared/localization/locales/de.json +185 -44
  212. package/shared/localization/locales/el.json +185 -44
  213. package/shared/localization/locales/en-GB.json +185 -44
  214. package/shared/localization/locales/en-US.json +99 -45
  215. package/shared/localization/locales/en-XA.json +185 -44
  216. package/shared/localization/locales/en-XL.json +99 -45
  217. package/shared/localization/locales/es-419.json +185 -44
  218. package/shared/localization/locales/es.json +185 -44
  219. package/shared/localization/locales/fi.json +185 -44
  220. package/shared/localization/locales/fil.json +185 -44
  221. package/shared/localization/locales/fr.json +185 -44
  222. package/shared/localization/locales/he.json +186 -45
  223. package/shared/localization/locales/hi.json +185 -44
  224. package/shared/localization/locales/hr.json +185 -44
  225. package/shared/localization/locales/hu.json +185 -44
  226. package/shared/localization/locales/id.json +185 -44
  227. package/shared/localization/locales/it.json +185 -44
  228. package/shared/localization/locales/ja.json +185 -44
  229. package/shared/localization/locales/ko.json +185 -44
  230. package/shared/localization/locales/lt.json +185 -44
  231. package/shared/localization/locales/lv.json +185 -44
  232. package/shared/localization/locales/nl.json +185 -44
  233. package/shared/localization/locales/no.json +185 -44
  234. package/shared/localization/locales/pl.json +185 -44
  235. package/shared/localization/locales/pt-PT.json +185 -44
  236. package/shared/localization/locales/pt.json +190 -49
  237. package/shared/localization/locales/ro.json +185 -44
  238. package/shared/localization/locales/ru.json +185 -44
  239. package/shared/localization/locales/sk.json +185 -44
  240. package/shared/localization/locales/sl.json +185 -44
  241. package/shared/localization/locales/sr-Latn.json +185 -44
  242. package/shared/localization/locales/sr.json +185 -44
  243. package/shared/localization/locales/sv.json +185 -44
  244. package/shared/localization/locales/ta.json +185 -44
  245. package/shared/localization/locales/te.json +185 -44
  246. package/shared/localization/locales/th.json +185 -44
  247. package/shared/localization/locales/tr.json +185 -44
  248. package/shared/localization/locales/uk.json +185 -44
  249. package/shared/localization/locales/vi.json +185 -44
  250. package/shared/localization/locales/zh-HK.json +185 -44
  251. package/shared/localization/locales/zh-TW.json +185 -44
  252. package/shared/localization/locales/zh.json +185 -44
  253. package/third-party/esbuild-plugins-polyfills/LICENSE +3 -0
  254. package/third-party/esbuild-plugins-polyfills/README.md +7 -0
  255. package/third-party/esbuild-plugins-polyfills/esbuild-polyfills.d.ts +9 -0
  256. package/third-party/esbuild-plugins-polyfills/esbuild-polyfills.js +129 -0
  257. package/tsconfig.json +2 -1
  258. package/types/artifacts.d.ts +16 -45
  259. package/types/config.d.ts +10 -52
  260. package/types/externs.d.ts +0 -2
  261. package/types/gatherer.d.ts +24 -47
  262. package/types/internal/rxjs.d.ts +26 -0
  263. package/types/internal/smokehouse.d.ts +1 -3
  264. package/types/lh.d.ts +0 -2
  265. package/types/lhr/settings.d.ts +1 -1
  266. package/core/audits/metrics/first-contentful-paint-3g.d.ts +0 -15
  267. package/core/audits/metrics/first-contentful-paint-3g.js +0 -69
  268. package/core/audits/resource-summary.d.ts +0 -16
  269. package/core/audits/resource-summary.js +0 -104
  270. package/core/audits/service-worker.d.ts +0 -46
  271. package/core/audits/service-worker.js +0 -182
  272. package/core/gather/gatherers/gatherer.d.ts +0 -46
  273. package/core/gather/gatherers/gatherer.js +0 -58
  274. package/core/legacy/config/config.d.ts +0 -107
  275. package/core/legacy/config/config.js +0 -566
  276. package/core/legacy/config/legacy-default-config.d.ts +0 -4
  277. package/core/legacy/config/legacy-default-config.js +0 -87
  278. package/core/legacy/gather/connections/connection.d.ts +0 -77
  279. package/core/legacy/gather/connections/connection.js +0 -196
  280. package/core/legacy/gather/connections/cri.d.ts +0 -27
  281. package/core/legacy/gather/connections/cri.js +0 -162
  282. package/core/legacy/gather/connections/raw.d.ts +0 -20
  283. package/core/legacy/gather/connections/raw.js +0 -57
  284. package/core/legacy/gather/driver.d.ts +0 -216
  285. package/core/legacy/gather/driver.js +0 -480
  286. package/core/legacy/gather/gather-runner.d.ts +0 -166
  287. package/core/legacy/gather/gather-runner.js +0 -590
  288. package/types/internal/lighthouse-logger.d.ts +0 -34
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @license Copyright 2023 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
+ /**
8
+ * @fileoverview Ensures <img> elements have alternative text that is not repeated text.
9
+ * See base class in axe-audit.js for audit() implementation.
10
+ */
11
+
12
+ import AxeAudit from './axe-audit.js';
13
+ import * as i18n from '../../lib/i18n/i18n.js';
14
+
15
+ const UIStrings = {
16
+ /** Title of an accesibility audit that evaluates if all image elements have the alt HTML attribute that is not redundant. This title is descriptive of the successful state and is shown to users when no user action is required. */
17
+ title: 'Image elements do not have `[alt]` attributes that are redundant text.',
18
+ /** Title of an accesibility audit that evaluates if all image elements have the alt HTML attribute that is not redundant. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
+ failureTitle: 'Image elements have `[alt]` attributes that are redundant text.',
20
+ /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
+ description: 'Informative elements should aim for short, descriptive alternative text. ' +
22
+ 'Alternative text that is exactly the same as the text adjacent to the link or image is ' +
23
+ 'potentially confusing for screen reader users, because the text will be read twice. ' +
24
+ '[Learn more about the `alt` attribute](https://dequeuniversity.com/rules/axe/4.7/image-redundant-alt).',
25
+ };
26
+
27
+ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
28
+
29
+ class ImageRedundantAlt extends AxeAudit {
30
+ /**
31
+ * @return {LH.Audit.Meta}
32
+ */
33
+ static get meta() {
34
+ return {
35
+ id: 'image-redundant-alt',
36
+ title: str_(UIStrings.title),
37
+ failureTitle: str_(UIStrings.failureTitle),
38
+ description: str_(UIStrings.description),
39
+ requiredArtifacts: ['Accessibility'],
40
+ };
41
+ }
42
+ }
43
+
44
+ export default ImageRedundantAlt;
45
+ export {UIStrings};
@@ -0,0 +1,10 @@
1
+ export default LabelContentNameMismatch;
2
+ declare class LabelContentNameMismatch extends AxeAudit {
3
+ }
4
+ export namespace UIStrings {
5
+ const title: string;
6
+ const failureTitle: string;
7
+ const description: string;
8
+ }
9
+ import AxeAudit from './axe-audit.js';
10
+ //# sourceMappingURL=label-content-name-mismatch.d.ts.map
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @license Copyright 2023 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
+ /**
8
+ * @fileoverview Ensure that interactive elements labeled with their content have their visible label as part of their accessible name.
9
+ * See base class in axe-audit.js for audit() implementation.
10
+ */
11
+
12
+ import AxeAudit from './axe-audit.js';
13
+ import * as i18n from '../../lib/i18n/i18n.js';
14
+
15
+ const UIStrings = {
16
+ /** Title of an accesibility audit that evaluates if elements labeled through their content have their visible text as part of their accessible name. This title is descriptive of the successful state and is shown to users when no user action is required. */
17
+ title: 'Elements with visible text labels have matching accessible names.',
18
+ /** Title of an accesibility audit that evaluates if elements labeled through their content have their visible text as part of their accessible name. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
+ failureTitle: 'Elements with visible text labels do not have matching accessible names.',
20
+ /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
+ description: 'Visible text labels that do not match the accessible name can result in a ' +
22
+ 'confusing experience for screen reader users. ' +
23
+ '[Learn more about accessible names](https://dequeuniversity.com/rules/axe/4.7/label-content-name-mismatch).',
24
+ };
25
+
26
+ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
27
+
28
+ class LabelContentNameMismatch extends AxeAudit {
29
+ /**
30
+ * @return {LH.Audit.Meta}
31
+ */
32
+ static get meta() {
33
+ return {
34
+ id: 'label-content-name-mismatch',
35
+ title: str_(UIStrings.title),
36
+ failureTitle: str_(UIStrings.failureTitle),
37
+ description: str_(UIStrings.description),
38
+ requiredArtifacts: ['Accessibility'],
39
+ };
40
+ }
41
+ }
42
+
43
+ export default LabelContentNameMismatch;
44
+ export {UIStrings};
@@ -0,0 +1,10 @@
1
+ export default SkipLink;
2
+ declare class SkipLink extends AxeAudit {
3
+ }
4
+ export namespace UIStrings {
5
+ const title: string;
6
+ const failureTitle: string;
7
+ const description: string;
8
+ }
9
+ import AxeAudit from './axe-audit.js';
10
+ //# sourceMappingURL=skip-link.d.ts.map
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @license Copyright 2023 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
+ /**
8
+ * @fileoverview Ensures that the skip-link target is focusable.
9
+ * See base class in axe-audit.js for audit() implementation.
10
+ */
11
+
12
+ import AxeAudit from './axe-audit.js';
13
+ import * as i18n from '../../lib/i18n/i18n.js';
14
+
15
+ const UIStrings = {
16
+ /** Title of an accesibility audit that evaluates if the skip link is focusable. This title is descriptive of the successful state and is shown to users when no user action is required. */
17
+ title: 'Skip links are focusable.',
18
+ /** Title of an accesibility audit that evaluates if the skip link is focusable. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
+ failureTitle: 'Skip links are not focusable.',
20
+ /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
+ description: 'Including a skip link can help users skip to the main content to save time. ' +
22
+ '[Learn more about skip links](https://dequeuniversity.com/rules/axe/4.7/skip-link).',
23
+ };
24
+
25
+ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
26
+
27
+ class SkipLink extends AxeAudit {
28
+ /**
29
+ * @return {LH.Audit.Meta}
30
+ */
31
+ static get meta() {
32
+ return {
33
+ id: 'skip-link',
34
+ title: str_(UIStrings.title),
35
+ failureTitle: str_(UIStrings.failureTitle),
36
+ description: str_(UIStrings.description),
37
+ requiredArtifacts: ['Accessibility'],
38
+ };
39
+ }
40
+ }
41
+
42
+ export default SkipLink;
43
+ export {UIStrings};
@@ -0,0 +1,10 @@
1
+ export default TableDuplicateName;
2
+ declare class TableDuplicateName extends AxeAudit {
3
+ }
4
+ export namespace UIStrings {
5
+ const title: string;
6
+ const failureTitle: string;
7
+ const description: string;
8
+ }
9
+ import AxeAudit from './axe-audit.js';
10
+ //# sourceMappingURL=table-duplicate-name.d.ts.map
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @license Copyright 2023 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
+ /**
8
+ * @fileoverview Ensure that table summary and caption have different content.
9
+ * See base class in axe-audit.js for audit() implementation.
10
+ */
11
+
12
+ import AxeAudit from './axe-audit.js';
13
+ import * as i18n from '../../lib/i18n/i18n.js';
14
+
15
+ const UIStrings = {
16
+ /** Title of an accesibility audit that evaluates if tables have different content in the summary attribute and caption element. This title is descriptive of the successful state and is shown to users when no user action is required. */
17
+ title: 'Tables have different content in the summary attribute and `<caption>`.',
18
+ /** Title of an accesibility audit that evaluates if tables have different content in the summary attribute and caption element. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
+ failureTitle: 'Tables have the same content in the summary attribute and `<caption>.`',
20
+ /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
+ description: 'The summary attribute should describe the table structure, while `<caption>` ' +
22
+ 'should have the onscreen title. Accurate table mark-up helps users of screen readers. ' +
23
+ '[Learn more about summary and caption](https://dequeuniversity.com/rules/axe/4.7/table-duplicate-name).',
24
+ };
25
+
26
+ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
27
+
28
+ class TableDuplicateName extends AxeAudit {
29
+ /**
30
+ * @return {LH.Audit.Meta}
31
+ */
32
+ static get meta() {
33
+ return {
34
+ id: 'table-duplicate-name',
35
+ title: str_(UIStrings.title),
36
+ failureTitle: str_(UIStrings.failureTitle),
37
+ description: str_(UIStrings.description),
38
+ requiredArtifacts: ['Accessibility'],
39
+ };
40
+ }
41
+ }
42
+
43
+ export default TableDuplicateName;
44
+ export {UIStrings};
@@ -19,7 +19,7 @@ const UIStrings = {
19
19
  failureTitle: 'Touch targets do not have sufficient size or spacing.',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Touch targets with sufficient size and spacing help users who may have ' +
22
- 'difficulty targeting small controls activate the targets. ' +
22
+ 'difficulty targeting small controls to activate the targets. ' +
23
23
  '[Learn more about touch targets](https://dequeuniversity.com/rules/axe/4.7/target-size).',
24
24
  };
25
25
 
@@ -229,8 +229,8 @@ class DuplicatedJavascript extends ByteEfficiencyAudit {
229
229
  const headings = [
230
230
  /* eslint-disable max-len */
231
231
  {key: 'source', valueType: 'code', subItemsHeading: {key: 'url', valueType: 'url'}, label: str_(i18n.UIStrings.columnSource)},
232
- {key: null, valueType: 'bytes', subItemsHeading: {key: 'sourceTransferBytes'}, granularity: 0.05, label: str_(i18n.UIStrings.columnTransferSize)},
233
- {key: 'wastedBytes', valueType: 'bytes', granularity: 0.05, label: str_(i18n.UIStrings.columnWastedBytes)},
232
+ {key: null, valueType: 'bytes', subItemsHeading: {key: 'sourceTransferBytes'}, granularity: 10, label: str_(i18n.UIStrings.columnTransferSize)},
233
+ {key: 'wastedBytes', valueType: 'bytes', granularity: 10, label: str_(i18n.UIStrings.columnWastedBytes)},
234
234
  /* eslint-enable max-len */
235
235
  ];
236
236
 
@@ -299,6 +299,7 @@ class RenderBlockingResources extends Audit {
299
299
  numericValue: wastedMs,
300
300
  numericUnit: 'millisecond',
301
301
  details,
302
+ metricSavings: {FCP: wastedMs, LCP: wastedMs},
302
303
  };
303
304
  }
304
305
  }
@@ -2,12 +2,29 @@ export default UsesHTTP2Audit;
2
2
  export type Simulator = import('../../lib/dependency-graph/simulator/simulator').Simulator;
3
3
  export type Node = import('../../lib/dependency-graph/base-node.js').Node;
4
4
  declare class UsesHTTP2Audit extends Audit {
5
+ /**
6
+ * Computes the estimated effect of all results being converted to http/2 on the provided graph.
7
+ *
8
+ * @param {Array<{url: string}>} results
9
+ * @param {Node} graph
10
+ * @param {Simulator} simulator
11
+ * @param {{label?: string}=} options
12
+ * @return {{savings: number, simulationBefore: LH.Gatherer.Simulation.Result, simulationAfter: LH.Gatherer.Simulation.Result}}
13
+ */
14
+ static computeWasteWithGraph(results: Array<{
15
+ url: string;
16
+ }>, graph: Node, simulator: Simulator, options?: {
17
+ label?: string;
18
+ } | undefined): {
19
+ savings: number;
20
+ simulationBefore: LH.Gatherer.Simulation.Result;
21
+ simulationAfter: LH.Gatherer.Simulation.Result;
22
+ };
5
23
  /**
6
24
  * Computes the estimated effect all results being converted to use http/2, the max of:
7
25
  *
8
26
  * - end time of the last long task in the provided graph
9
27
  * - end time of the last node in the graph
10
- *
11
28
  * @param {Array<{url: string}>} results
12
29
  * @param {Node} graph
13
30
  * @param {Simulator} simulator
@@ -21,6 +21,8 @@ import {NetworkRequest} from '../../lib/network-request.js';
21
21
  import {NetworkRecords} from '../../computed/network-records.js';
22
22
  import {LoadSimulator} from '../../computed/load-simulator.js';
23
23
  import {PageDependencyGraph} from '../../computed/page-dependency-graph.js';
24
+ import {LanternLargestContentfulPaint} from '../../computed/metrics/lantern-largest-contentful-paint.js';
25
+ import {LanternFirstContentfulPaint} from '../../computed/metrics/lantern-first-contentful-paint.js';
24
26
  import * as i18n from '../../lib/i18n/i18n.js';
25
27
 
26
28
  const UIStrings = {
@@ -66,23 +68,23 @@ class UsesHTTP2Audit extends Audit {
66
68
  }
67
69
 
68
70
  /**
69
- * Computes the estimated effect all results being converted to use http/2, the max of:
70
- *
71
- * - end time of the last long task in the provided graph
72
- * - end time of the last node in the graph
71
+ * Computes the estimated effect of all results being converted to http/2 on the provided graph.
73
72
  *
74
73
  * @param {Array<{url: string}>} results
75
74
  * @param {Node} graph
76
75
  * @param {Simulator} simulator
77
- * @return {number}
76
+ * @param {{label?: string}=} options
77
+ * @return {{savings: number, simulationBefore: LH.Gatherer.Simulation.Result, simulationAfter: LH.Gatherer.Simulation.Result}}
78
78
  */
79
- static computeWasteWithTTIGraph(results, graph, simulator) {
80
- const beforeLabel = `uses-http2-before`;
81
- const afterLabel = `uses-http2-after`;
79
+ static computeWasteWithGraph(results, graph, simulator, options) {
80
+ options = Object.assign({label: ''}, options);
81
+ const beforeLabel = `${this.meta.id}-${options.label}-before`;
82
+ const afterLabel = `${this.meta.id}-${options.label}-after`;
82
83
  const flexibleOrdering = true;
83
84
 
84
85
  const urlsToChange = new Set(results.map(result => result.url));
85
- const simulationBefore = simulator.simulate(graph, {label: beforeLabel, flexibleOrdering});
86
+ const simulationBefore =
87
+ simulator.simulate(graph, {label: beforeLabel, flexibleOrdering});
86
88
 
87
89
  // Update all the protocols to reflect implementing our recommendations
88
90
  /** @type {Map<string, string>} */
@@ -105,9 +107,36 @@ class UsesHTTP2Audit extends Audit {
105
107
  node.record.protocol = originalProtocol;
106
108
  });
107
109
 
108
- const savingsOnOverallLoad = simulationBefore.timeInMs - simulationAfter.timeInMs;
109
- const savingsOnTTI = LanternInteractive.getLastLongTaskEndTime(simulationBefore.nodeTimings) -
110
+ const savings = simulationBefore.timeInMs - simulationAfter.timeInMs;
111
+
112
+ return {
113
+ // Round waste to nearest 10ms
114
+ savings: Math.round(Math.max(savings, 0) / 10) * 10,
115
+ simulationBefore,
116
+ simulationAfter,
117
+ };
118
+ }
119
+
120
+ /**
121
+ * Computes the estimated effect all results being converted to use http/2, the max of:
122
+ *
123
+ * - end time of the last long task in the provided graph
124
+ * - end time of the last node in the graph
125
+ * @param {Array<{url: string}>} results
126
+ * @param {Node} graph
127
+ * @param {Simulator} simulator
128
+ * @return {number}
129
+ */
130
+ static computeWasteWithTTIGraph(results, graph, simulator) {
131
+ const {savings: savingsOnOverallLoad, simulationBefore, simulationAfter} =
132
+ this.computeWasteWithGraph(results, graph, simulator, {
133
+ label: 'tti',
134
+ });
135
+
136
+ const savingsOnTTI =
137
+ LanternInteractive.getLastLongTaskEndTime(simulationBefore.nodeTimings) -
110
138
  LanternInteractive.getLastLongTaskEndTime(simulationAfter.nodeTimings);
139
+
111
140
  const savings = Math.max(savingsOnTTI, savingsOnOverallLoad);
112
141
 
113
142
  // Round waste to nearest 10ms
@@ -237,9 +266,25 @@ class UsesHTTP2Audit extends Audit {
237
266
  devtoolsLog,
238
267
  settings,
239
268
  };
240
- const graph = await PageDependencyGraph.request({trace, devtoolsLog, URL}, context);
269
+ const pageGraph = await PageDependencyGraph.request({trace, devtoolsLog, URL}, context);
241
270
  const simulator = await LoadSimulator.request(simulatorOptions, context);
242
- const wastedMs = UsesHTTP2Audit.computeWasteWithTTIGraph(resources, graph, simulator);
271
+ const metricComputationInput = Audit.makeMetricComputationDataInput(artifacts, context);
272
+
273
+ const {
274
+ pessimisticGraph: fcpGraph,
275
+ } = await LanternFirstContentfulPaint.request(metricComputationInput, context);
276
+ const {
277
+ pessimisticGraph: lcpGraph,
278
+ } = await LanternLargestContentfulPaint.request(metricComputationInput, context);
279
+
280
+ const wastedMsTti = UsesHTTP2Audit.computeWasteWithTTIGraph(
281
+ resources, pageGraph, simulator);
282
+ const wasteFcp =
283
+ UsesHTTP2Audit.computeWasteWithGraph(resources,
284
+ fcpGraph, simulator, {label: 'fcp'});
285
+ const wasteLcp =
286
+ UsesHTTP2Audit.computeWasteWithGraph(resources,
287
+ lcpGraph, simulator, {label: 'lcp'});
243
288
 
244
289
  /** @type {LH.Audit.Details.Opportunity['headings']} */
245
290
  const headings = [
@@ -248,14 +293,15 @@ class UsesHTTP2Audit extends Audit {
248
293
  ];
249
294
 
250
295
  const details = Audit.makeOpportunityDetails(headings, resources,
251
- {overallSavingsMs: wastedMs});
296
+ {overallSavingsMs: wastedMsTti});
252
297
 
253
298
  return {
254
299
  displayValue,
255
- numericValue: wastedMs,
300
+ numericValue: wastedMsTti,
256
301
  numericUnit: 'millisecond',
257
- score: ByteEfficiencyAudit.scoreForWastedMs(wastedMs),
302
+ score: ByteEfficiencyAudit.scoreForWastedMs(wastedMsTti),
258
303
  details,
304
+ metricSavings: {LCP: wasteLcp.savings, FCP: wasteFcp.savings},
259
305
  };
260
306
  }
261
307
  }
@@ -59,10 +59,6 @@ export const UIStrings: {
59
59
  'manifest-display-not-supported': string;
60
60
  /** Error message explaining that the manifest could not be fetched, might be empty, or could not be parsed. */
61
61
  'manifest-empty': string;
62
- /** Error message explaining that no matching service worker was detected,
63
- * and provides a suggestion to reload the page or check whether the scope of the service worker
64
- * for the current page encloses the scope and start URL from the manifest. */
65
- 'no-matching-service-worker': string;
66
62
  /**
67
63
  * @description Error message explaining that the manifest does not contain a suitable icon.
68
64
  * @example {192} value0
@@ -104,7 +100,7 @@ export const UIStrings: {
104
100
  'manifest-location-changed': string;
105
101
  /** Warning message explaining that the page does not work offline. */
106
102
  'warn-not-offline-capable': string;
107
- /** Error message explaining that Lighthouse failed while detecting a service worker, and directing the user to try again in a new Chrome. */
103
+ /** Error message explaining that Lighthouse failed while checking if the page is installable, and directing the user to try again in a new Chrome. */
108
104
  'protocol-timeout': string;
109
105
  /** Message logged when the web app has been uninstalled o desktop, signalling that the install banner state is being reset. */
110
106
  'pipeline-restarted': string;
@@ -44,11 +44,6 @@ const UIStrings = {
44
44
  'manifest-display-not-supported': `Manifest 'display' property must be one of 'standalone', 'fullscreen', or 'minimal-ui'`,
45
45
  /** Error message explaining that the manifest could not be fetched, might be empty, or could not be parsed. */
46
46
  'manifest-empty': `Manifest could not be fetched, is empty, or could not be parsed`,
47
- // TODO: This error was removed in M114, we can remove this message when it hits stable.
48
- /** Error message explaining that no matching service worker was detected,
49
- * and provides a suggestion to reload the page or check whether the scope of the service worker
50
- * for the current page encloses the scope and start URL from the manifest. */
51
- 'no-matching-service-worker': `No matching service worker detected. You may need to reload the page, or check that the scope of the service worker for the current page encloses the scope and start URL from the manifest.`,
52
47
  /**
53
48
  * @description Error message explaining that the manifest does not contain a suitable icon.
54
49
  * @example {192} value0
@@ -93,8 +88,8 @@ const UIStrings = {
93
88
  'manifest-location-changed': `Manifest URL changed while the manifest was being fetched.`,
94
89
  /** Warning message explaining that the page does not work offline. */
95
90
  'warn-not-offline-capable': `Page does not work offline. The page will not be regarded as installable after Chrome 93, stable release August 2021.`,
96
- /** Error message explaining that Lighthouse failed while detecting a service worker, and directing the user to try again in a new Chrome. */
97
- 'protocol-timeout': `Lighthouse could not determine if there was a service worker. Please try with a newer version of Chrome.`,
91
+ /** Error message explaining that Lighthouse failed while checking if the page is installable, and directing the user to try again in a new Chrome. */
92
+ 'protocol-timeout': `Lighthouse could not determine if the page is installable. Please try with a newer version of Chrome.`,
98
93
  /** Message logged when the web app has been uninstalled o desktop, signalling that the install banner state is being reset. */
99
94
  'pipeline-restarted': 'PWA has been uninstalled and installability checks resetting.',
100
95
  /**
@@ -1,11 +1,5 @@
1
1
  export default LargestContentfulPaintElement;
2
2
  declare class LargestContentfulPaintElement extends Audit {
3
- /**
4
- * @param {LH.Artifacts.MetricComputationDataInput} metricComputationData
5
- * @param {LH.Audit.Context} context
6
- * @return {Promise<number|undefined>}
7
- */
8
- static getOptionalLCPMetric(metricComputationData: LH.Artifacts.MetricComputationDataInput, context: LH.Audit.Context): Promise<number | undefined>;
9
3
  /**
10
4
  * @param {LH.Artifacts} artifacts
11
5
  * @return {LH.Audit.Details.Table|undefined}
@@ -4,10 +4,13 @@
4
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
5
  */
6
6
 
7
+ import log from 'lighthouse-logger';
8
+
7
9
  import {Audit} from './audit.js';
8
10
  import * as i18n from '../lib/i18n/i18n.js';
9
11
  import {LargestContentfulPaint} from '../computed/metrics/largest-contentful-paint.js';
10
12
  import {LCPBreakdown} from '../computed/metrics/lcp-breakdown.js';
13
+ import {Sentry} from '../lib/sentry.js';
11
14
 
12
15
  const UIStrings = {
13
16
  /** Descriptive title of a diagnostic audit that provides the element that was determined to be the Largest Contentful Paint. */
@@ -49,19 +52,6 @@ class LargestContentfulPaintElement extends Audit {
49
52
  };
50
53
  }
51
54
 
52
- /**
53
- * @param {LH.Artifacts.MetricComputationDataInput} metricComputationData
54
- * @param {LH.Audit.Context} context
55
- * @return {Promise<number|undefined>}
56
- */
57
- static async getOptionalLCPMetric(metricComputationData, context) {
58
- try {
59
- const {timing: metricLcp} =
60
- await LargestContentfulPaint.request(metricComputationData, context);
61
- return metricLcp;
62
- } catch {}
63
- }
64
-
65
55
  /**
66
56
  * @param {LH.Artifacts} artifacts
67
57
  * @return {LH.Audit.Details.Table|undefined}
@@ -139,11 +129,19 @@ class LargestContentfulPaintElement extends Audit {
139
129
  const items = [elementTable];
140
130
  let displayValue;
141
131
 
142
- const metricLcp = await this.getOptionalLCPMetric(metricComputationData, context);
143
- if (metricLcp) {
132
+ try {
133
+ const {timing: metricLcp} =
134
+ await LargestContentfulPaint.request(metricComputationData, context);
144
135
  displayValue = str_(i18n.UIStrings.ms, {timeInMs: metricLcp});
136
+
145
137
  const phaseTable = await this.makePhaseTable(metricLcp, metricComputationData, context);
146
138
  items.push(phaseTable);
139
+ } catch (err) {
140
+ Sentry.captureException(err, {
141
+ tags: {audit: this.meta.id},
142
+ level: 'error',
143
+ });
144
+ log.error(this.meta.id, err.message);
147
145
  }
148
146
 
149
147
  const details = Audit.makeListDetails(items);
@@ -1,8 +1,8 @@
1
- export default ExperimentalInteractionToNextPaint;
1
+ export default InteractionToNextPaint;
2
2
  /**
3
3
  * @fileoverview This metric gives a high-percentile measure of responsiveness to input.
4
4
  */
5
- declare class ExperimentalInteractionToNextPaint extends Audit {
5
+ declare class InteractionToNextPaint extends Audit {
6
6
  /**
7
7
  * @return {LH.Audit.ScoreOptions}
8
8
  */
@@ -18,4 +18,4 @@ export namespace UIStrings {
18
18
  const description: string;
19
19
  }
20
20
  import { Audit } from '../audit.js';
21
- //# sourceMappingURL=experimental-interaction-to-next-paint.d.ts.map
21
+ //# sourceMappingURL=interaction-to-next-paint.d.ts.map
@@ -20,13 +20,13 @@ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
20
20
  /**
21
21
  * @fileoverview This metric gives a high-percentile measure of responsiveness to input.
22
22
  */
23
- class ExperimentalInteractionToNextPaint extends Audit {
23
+ class InteractionToNextPaint extends Audit {
24
24
  /**
25
25
  * @return {LH.Audit.Meta}
26
26
  */
27
27
  static get meta() {
28
28
  return {
29
- id: 'experimental-interaction-to-next-paint',
29
+ id: 'interaction-to-next-paint',
30
30
  title: str_(i18n.UIStrings.interactionToNextPaint),
31
31
  description: str_(UIStrings.description),
32
32
  scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
@@ -84,5 +84,5 @@ class ExperimentalInteractionToNextPaint extends Audit {
84
84
  }
85
85
  }
86
86
 
87
- export default ExperimentalInteractionToNextPaint;
87
+ export default InteractionToNextPaint;
88
88
  export {UIStrings};
@@ -14,6 +14,7 @@ import {LoadSimulator} from '../computed/load-simulator.js';
14
14
  import {ProcessedNavigation} from '../computed/processed-navigation.js';
15
15
  import {PageDependencyGraph} from '../computed/page-dependency-graph.js';
16
16
  import {LanternLargestContentfulPaint} from '../computed/metrics/lantern-largest-contentful-paint.js';
17
+ import {LanternFirstContentfulPaint} from '../computed/metrics/lantern-first-contentful-paint.js';
17
18
 
18
19
  // Preconnect establishes a "clean" socket. Chrome's socket manager will keep an unused socket
19
20
  // around for 10s. Meaning, the time delta between processing preconnect a request should be <10s,
@@ -125,7 +126,8 @@ class UsesRelPreconnectAudit extends Audit {
125
126
  const devtoolsLog = artifacts.devtoolsLogs[UsesRelPreconnectAudit.DEFAULT_PASS];
126
127
  const settings = context.settings;
127
128
 
128
- let maxWasted = 0;
129
+ let maxWastedLcp = 0;
130
+ let maxWastedFcp = 0;
129
131
  /** @type {Array<LH.IcuMessage>} */
130
132
  const warnings = [];
131
133
 
@@ -144,7 +146,14 @@ class UsesRelPreconnectAudit extends Audit {
144
146
  /** @type {Set<string>} */
145
147
  const lcpGraphURLs = new Set();
146
148
  lcpGraph.traverse(node => {
147
- if (node.type === 'network' ) lcpGraphURLs.add(node.record.url);
149
+ if (node.type === 'network') lcpGraphURLs.add(node.record.url);
150
+ });
151
+
152
+ const fcpGraph =
153
+ await LanternFirstContentfulPaint.getPessimisticGraph(pageGraph, processedNavigation);
154
+ const fcpGraphURLs = new Set();
155
+ fcpGraph.traverse(node => {
156
+ if (node.type === 'network') fcpGraphURLs.add(node.record.url);
148
157
  });
149
158
 
150
159
  /** @type {Map<string, LH.Artifacts.NetworkRequest[]>} */
@@ -216,7 +225,11 @@ class UsesRelPreconnectAudit extends Audit {
216
225
  return;
217
226
  }
218
227
 
219
- maxWasted = Math.max(wastedMs, maxWasted);
228
+ maxWastedLcp = Math.max(wastedMs, maxWastedLcp);
229
+
230
+ if (fcpGraphURLs.has(firstRecordOfOrigin.url)) {
231
+ maxWastedFcp = Math.max(wastedMs, maxWastedLcp);
232
+ }
220
233
  results.push({
221
234
  url: securityOrigin,
222
235
  wastedMs: wastedMs,
@@ -240,6 +253,7 @@ class UsesRelPreconnectAudit extends Audit {
240
253
  score: 1,
241
254
  warnings: preconnectLinks.length >= 3 ?
242
255
  [...warnings, str_(UIStrings.tooManyPreconnectLinksWarning)] : warnings,
256
+ metricSavings: {LCP: maxWastedLcp, FCP: maxWastedFcp},
243
257
  };
244
258
  }
245
259
 
@@ -250,17 +264,18 @@ class UsesRelPreconnectAudit extends Audit {
250
264
  ];
251
265
 
252
266
  const details = Audit.makeOpportunityDetails(headings, results,
253
- {overallSavingsMs: maxWasted, sortedBy: ['wastedMs']});
267
+ {overallSavingsMs: maxWastedLcp, sortedBy: ['wastedMs']});
254
268
 
255
269
  return {
256
- score: ByteEfficiencyAudit.scoreForWastedMs(maxWasted),
257
- numericValue: maxWasted,
270
+ score: ByteEfficiencyAudit.scoreForWastedMs(maxWastedLcp),
271
+ numericValue: maxWastedLcp,
258
272
  numericUnit: 'millisecond',
259
- displayValue: maxWasted ?
260
- str_(i18n.UIStrings.displayValueMsSavings, {wastedMs: maxWasted}) :
273
+ displayValue: maxWastedLcp ?
274
+ str_(i18n.UIStrings.displayValueMsSavings, {wastedMs: maxWastedLcp}) :
261
275
  '',
262
276
  warnings,
263
277
  details,
278
+ metricSavings: {LCP: maxWastedLcp, FCP: maxWastedFcp},
264
279
  };
265
280
  }
266
281
  }