lighthouse 9.5.0-dev.20230112 → 9.5.0-dev.20230113

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 (36) hide show
  1. package/cli/cli-flags.js +5 -1
  2. package/cli/test/smokehouse/core-tests.js +2 -0
  3. package/cli/test/smokehouse/report-assert.js +11 -7
  4. package/core/config/constants.js +1 -0
  5. package/core/config/default-config.js +0 -1
  6. package/core/config/filters.js +8 -4
  7. package/core/gather/gatherers/accessibility.js +15 -1
  8. package/core/gather/gatherers/full-page-screenshot.js +51 -40
  9. package/core/gather/gatherers/seo/tap-targets.js +39 -19
  10. package/core/legacy/config/config.js +8 -10
  11. package/core/legacy/gather/driver.js +0 -17
  12. package/core/legacy/gather/gather-runner.js +0 -6
  13. package/core/runner.js +2 -0
  14. package/core/util.cjs +30 -0
  15. package/dist/report/bundle.esm.js +40 -19
  16. package/dist/report/flow.js +5 -5
  17. package/dist/report/standalone.js +4 -4
  18. package/flow-report/src/common.tsx +3 -3
  19. package/flow-report/src/util.ts +0 -11
  20. package/flow-report/test/common-test.tsx +4 -7
  21. package/flow-report/test/summary/summary-test.tsx +1 -1
  22. package/package.json +1 -1
  23. package/readme.md +1 -0
  24. package/report/renderer/details-renderer.js +1 -2
  25. package/report/renderer/element-screenshot-renderer.js +4 -4
  26. package/report/renderer/report-renderer.js +3 -7
  27. package/report/renderer/report-ui-features.js +3 -7
  28. package/report/renderer/util.js +30 -0
  29. package/report/test/renderer/util-test.js +20 -0
  30. package/report/test-assets/faux-psi.js +3 -3
  31. package/types/artifacts.d.ts +1 -11
  32. package/types/lhr/audit-details.d.ts +0 -17
  33. package/types/lhr/lhr.d.ts +13 -0
  34. package/types/lhr/settings.d.ts +2 -0
  35. package/types/smokehouse.d.ts +2 -1
  36. package/core/audits/full-page-screenshot.js +0 -42
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lighthouse",
3
3
  "type": "module",
4
- "version": "9.5.0-dev.20230112",
4
+ "version": "9.5.0-dev.20230113",
5
5
  "description": "Automated auditing, performance metrics, and best practices for the web.",
6
6
  "main": "./core/index.js",
7
7
  "bin": {
package/readme.md CHANGED
@@ -105,6 +105,7 @@ Configuration:
105
105
  --only-categories Only run the specified categories. Available categories: accessibility, best-practices, performance, pwa, seo [array]
106
106
  --skip-audits Run everything except these audits [array]
107
107
  --budget-path The path to the budget.json file for LightWallet. [string]
108
+ --disable-full-page-screenshot Disables collection of the full page screenshot, which can be quite large [boolean]
108
109
 
109
110
  Output:
110
111
  --output Reporter for the results, supports multiple values. choices: "json", "html", "csv" [array] [default: ["html"]]
@@ -34,7 +34,7 @@ const URL_PREFIXES = ['http://', 'https://', 'data:'];
34
34
  export class DetailsRenderer {
35
35
  /**
36
36
  * @param {DOM} dom
37
- * @param {{fullPageScreenshot?: LH.Audit.Details.FullPageScreenshot}} [options]
37
+ * @param {{fullPageScreenshot?: LH.Result.FullPageScreenshot}} [options]
38
38
  */
39
39
  constructor(dom, options = {}) {
40
40
  this._dom = dom;
@@ -60,7 +60,6 @@ export class DetailsRenderer {
60
60
  // Internal-only details, not for rendering.
61
61
  case 'screenshot':
62
62
  case 'debugdata':
63
- case 'full-page-screenshot':
64
63
  case 'treemap-data':
65
64
  return null;
66
65
 
@@ -19,13 +19,13 @@
19
19
  * @property {DOM} dom
20
20
  * @property {Element} rootEl
21
21
  * @property {Element} overlayContainerEl
22
- * @property {LH.Audit.Details.FullPageScreenshot} fullPageScreenshot
22
+ * @property {LH.Result.FullPageScreenshot} fullPageScreenshot
23
23
  */
24
24
 
25
25
  import {Util} from './util.js';
26
26
 
27
27
  /**
28
- * @param {LH.Audit.Details.FullPageScreenshot['screenshot']} screenshot
28
+ * @param {LH.Result.FullPageScreenshot['screenshot']} screenshot
29
29
  * @param {LH.Audit.Details.Rect} rect
30
30
  * @return {boolean}
31
31
  */
@@ -131,7 +131,7 @@ export class ElementScreenshotRenderer {
131
131
  * Allows for multiple Lighthouse reports to be rendered on the page, each with their
132
132
  * own full page screenshot.
133
133
  * @param {HTMLElement} el
134
- * @param {LH.Audit.Details.FullPageScreenshot['screenshot']} screenshot
134
+ * @param {LH.Result.FullPageScreenshot['screenshot']} screenshot
135
135
  */
136
136
  static installFullPageScreenshot(el, screenshot) {
137
137
  el.style.setProperty('--element-screenshot-url', `url('${screenshot.data}')`);
@@ -213,7 +213,7 @@ export class ElementScreenshotRenderer {
213
213
  * Used to render both the thumbnail preview in details tables and the full-page screenshot in the lightbox.
214
214
  * Returns null if element rect is outside screenshot bounds.
215
215
  * @param {DOM} dom
216
- * @param {LH.Audit.Details.FullPageScreenshot['screenshot']} screenshot
216
+ * @param {LH.Result.FullPageScreenshot['screenshot']} screenshot
217
217
  * @param {Rect} elementRectSC Region of screenshot to highlight.
218
218
  * @param {Size} maxRenderSizeDC e.g. maxThumbnailSize or maxLightboxSize.
219
219
  * @return {Element|null}
@@ -268,12 +268,8 @@ export class ReportRenderer {
268
268
  Util.i18n = i18n;
269
269
  Util.reportJson = report;
270
270
 
271
- const fullPageScreenshot =
272
- report.audits['full-page-screenshot']?.details &&
273
- report.audits['full-page-screenshot'].details.type === 'full-page-screenshot' ?
274
- report.audits['full-page-screenshot'].details : undefined;
275
271
  const detailsRenderer = new DetailsRenderer(this._dom, {
276
- fullPageScreenshot,
272
+ fullPageScreenshot: report.fullPageScreenshot ?? undefined,
277
273
  });
278
274
 
279
275
  const categoryRenderer = new CategoryRenderer(this._dom, detailsRenderer);
@@ -344,9 +340,9 @@ export class ReportRenderer {
344
340
  reportSection.append(this._renderReportFooter(report));
345
341
  reportContainer.append(headerContainer, reportSection);
346
342
 
347
- if (fullPageScreenshot) {
343
+ if (report.fullPageScreenshot) {
348
344
  ElementScreenshotRenderer.installFullPageScreenshot(
349
- this._dom.rootEl, fullPageScreenshot.screenshot);
345
+ this._dom.rootEl, report.fullPageScreenshot.screenshot);
350
346
  }
351
347
 
352
348
  return reportFragment;
@@ -60,6 +60,7 @@ export class ReportUIFeatures {
60
60
  */
61
61
  initFeatures(lhr) {
62
62
  this.json = lhr;
63
+ this._fullPageScreenshot = Util.getFullPageScreenshot(lhr);
63
64
 
64
65
  if (this._topbar) {
65
66
  this._topbar.enable(lhr);
@@ -299,18 +300,13 @@ export class ReportUIFeatures {
299
300
  * @param {Element} rootEl
300
301
  */
301
302
  _setupElementScreenshotOverlay(rootEl) {
302
- const fullPageScreenshot =
303
- this.json.audits['full-page-screenshot'] &&
304
- this.json.audits['full-page-screenshot'].details &&
305
- this.json.audits['full-page-screenshot'].details.type === 'full-page-screenshot' &&
306
- this.json.audits['full-page-screenshot'].details;
307
- if (!fullPageScreenshot) return;
303
+ if (!this._fullPageScreenshot) return;
308
304
 
309
305
  ElementScreenshotRenderer.installOverlayFeature({
310
306
  dom: this._dom,
311
307
  rootEl: rootEl,
312
308
  overlayContainerEl: rootEl,
313
- fullPageScreenshot,
309
+ fullPageScreenshot: this._fullPageScreenshot,
314
310
  });
315
311
  }
316
312
 
@@ -212,9 +212,39 @@ class Util {
212
212
  });
213
213
  }
214
214
 
215
+ // In 10.0, full-page-screenshot became a top-level property on the LHR.
216
+ if (clone.audits['full-page-screenshot']) {
217
+ const details = /** @type {LH.Result.FullPageScreenshot=} */ (
218
+ clone.audits['full-page-screenshot'].details);
219
+ if (details) {
220
+ clone.fullPageScreenshot = {
221
+ screenshot: details.screenshot,
222
+ nodes: details.nodes,
223
+ };
224
+ } else {
225
+ clone.fullPageScreenshot = null;
226
+ }
227
+ delete clone.audits['full-page-screenshot'];
228
+ }
229
+
215
230
  return clone;
216
231
  }
217
232
 
233
+ /**
234
+ * @param {LH.Result} lhr
235
+ * @return {LH.Result.FullPageScreenshot=}
236
+ */
237
+ static getFullPageScreenshot(lhr) {
238
+ if (lhr.fullPageScreenshot) {
239
+ return lhr.fullPageScreenshot;
240
+ }
241
+
242
+ // Prior to 10.0.
243
+ const details = /** @type {LH.Result.FullPageScreenshot=} */ (
244
+ lhr.audits['full-page-screenshot']?.details);
245
+ return details;
246
+ }
247
+
218
248
  /**
219
249
  * Used to determine if the "passed" for the purposes of showing up in the "failed" or "passed"
220
250
  * sections of the report.
@@ -168,6 +168,26 @@ describe('util helpers', () => {
168
168
  assert.deepStrictEqual(preparedResult.audits, sampleResult.audits);
169
169
  });
170
170
 
171
+ it('moves full-page-screenshot audit', () => {
172
+ const clonedSampleResult = JSON.parse(JSON.stringify(sampleResult));
173
+
174
+ clonedSampleResult.audits['full-page-screenshot'] = {
175
+ details: {
176
+ type: 'full-page-screenshot',
177
+ ...sampleResult.fullPageScreenshot,
178
+ },
179
+ };
180
+ delete clonedSampleResult.fullPageScreenshot;
181
+
182
+ assert.ok(clonedSampleResult.audits['full-page-screenshot'].details.nodes); // Make sure something's being tested.
183
+ assert.notDeepStrictEqual(clonedSampleResult.audits, sampleResult.audits);
184
+
185
+ // Original audit results should be restored.
186
+ const preparedResult = Util.prepareReportResult(clonedSampleResult);
187
+ assert.deepStrictEqual(preparedResult.audits, sampleResult.audits);
188
+ assert.deepStrictEqual(preparedResult.fullPageScreenshot, sampleResult.fullPageScreenshot);
189
+ });
190
+
171
191
  it('corrects performance category without hidden group', () => {
172
192
  const clonedSampleResult = JSON.parse(JSON.stringify(sampleResult));
173
193
 
@@ -134,9 +134,9 @@ async function distinguishLHR(lhr, tabId) {
134
134
  finalSSDetails.data = await decorateScreenshot(finalSSDetails.data, tabId);
135
135
  }
136
136
 
137
- const fpSSDetails = lhr.audits['full-page-screenshot']?.details;
138
- if (fpSSDetails && fpSSDetails.type === 'full-page-screenshot') {
139
- fpSSDetails.screenshot.data = await decorateScreenshot(fpSSDetails.screenshot.data, tabId);
137
+ if (lhr.fullPageScreenshot) {
138
+ lhr.fullPageScreenshot.screenshot.data =
139
+ await decorateScreenshot(lhr.fullPageScreenshot.screenshot.data, tabId);
140
140
  }
141
141
  }
142
142
 
@@ -146,7 +146,7 @@ export interface GathererArtifacts extends PublicGathererArtifacts,LegacyBaseArt
146
146
  /** All the input elements, including associated form and label elements. */
147
147
  Inputs: {inputs: Artifacts.InputElement[]; forms: Artifacts.FormElement[]; labels: Artifacts.LabelElement[]};
148
148
  /** Screenshot of the entire page (rather than just the above the fold content). */
149
- FullPageScreenshot: Artifacts.FullPageScreenshot | null;
149
+ FullPageScreenshot: LHResult.FullPageScreenshot | null;
150
150
  /** Information about event listeners registered on the global object. */
151
151
  GlobalListeners: Array<Artifacts.GlobalListener>;
152
152
  /** The issues surfaced in the devtools Issues panel */
@@ -770,16 +770,6 @@ declare module Artifacts {
770
770
  npm?: string;
771
771
  }
772
772
 
773
- interface FullPageScreenshot {
774
- screenshot: {
775
- /** Base64 image data URL. */
776
- data: string;
777
- width: number;
778
- height: number;
779
- };
780
- nodes: Record<string, Rect>;
781
- }
782
-
783
773
  interface TimingSummary {
784
774
  firstContentfulPaint: number | undefined;
785
775
  firstContentfulPaintTs: number | undefined;
@@ -15,7 +15,6 @@ type Details =
15
15
  Details.List |
16
16
  Details.Opportunity |
17
17
  Details.Screenshot |
18
- Details.FullPageScreenshot |
19
18
  Details.Table;
20
19
 
21
20
  // Details namespace.
@@ -79,22 +78,6 @@ declare module Details {
79
78
  data: string;
80
79
  }
81
80
 
82
- /**
83
- * A screenshot of the entire page, including width and height information,
84
- * and the locations of interesting nodes.
85
- * Used by element screenshots renderer.
86
- */
87
- interface FullPageScreenshot {
88
- type: 'full-page-screenshot';
89
- screenshot: {
90
- /** Base64 image data URL. */
91
- data: string;
92
- width: number;
93
- height: number;
94
- };
95
- nodes: Record<string, Rect>;
96
- }
97
-
98
81
  interface Rect {
99
82
  width: number;
100
83
  height: number;
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import {Result as AuditResult} from './audit-result';
8
+ import AuditDetails from './audit-details.js';
8
9
  import {ConfigSettings} from './settings';
9
10
 
10
11
  /**
@@ -55,6 +56,8 @@ interface Result {
55
56
  };
56
57
  /** An array containing the result of all stack packs. */
57
58
  stackPacks?: Result.StackPack[];
59
+ /** Screenshot taken of the full page, with node rects referencing audit results. If there was an error with collection, this is null. If disabled via the disableFullPageScreenshot setting, this is undefined. */
60
+ fullPageScreenshot?: Result.FullPageScreenshot | null;
58
61
  }
59
62
 
60
63
  // Result namespace
@@ -138,6 +141,16 @@ declare module Result {
138
141
  descriptions: Record<string, string>;
139
142
  }
140
143
 
144
+ interface FullPageScreenshot {
145
+ screenshot: {
146
+ /** Base64 image data URL. */
147
+ data: string;
148
+ width: number;
149
+ height: number;
150
+ };
151
+ nodes: Record<string, AuditDetails.Rect>;
152
+ }
153
+
141
154
  /**
142
155
  * Info about an `LH.IcuMessage` value that was localized to a string when
143
156
  * included in the LHR. Value is either a
@@ -112,6 +112,8 @@ export type ScreenEmulationSettings = {
112
112
  cpuQuietThresholdMs?: number;
113
113
  /** The URL to use for the "blank" neutral page in between navigations. Defaults to `about:blank`. */
114
114
  blankPage?: string;
115
+ /** Disables collection of the full page screenshot, which can be rather large and possibly leave the page in an undesirable state. */
116
+ disableFullPageScreenshot?: boolean;
115
117
  }
116
118
 
117
119
  export interface ConfigSettings extends Required<SharedFlagsSettings> {
@@ -22,7 +22,8 @@ declare global {
22
22
  };
23
23
  timing?: {
24
24
  entries?: any
25
- }
25
+ };
26
+ fullPageScreenshot?: any;
26
27
  }
27
28
 
28
29
  export type ExpectedRunnerResult = {
@@ -1,42 +0,0 @@
1
- /**
2
- * @license Copyright 2020 Google Inc. 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
-
9
- class FullPageScreenshot extends Audit {
10
- /**
11
- * @return {LH.Audit.Meta}
12
- */
13
- static get meta() {
14
- return {
15
- id: 'full-page-screenshot',
16
- scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,
17
- title: 'Full-page screenshot',
18
- description: 'A full-height screenshot of the final rendered page',
19
- requiredArtifacts: ['FullPageScreenshot'],
20
- };
21
- }
22
-
23
- /**
24
- * @param {LH.Artifacts} artifacts
25
- * @return {Promise<LH.Audit.Product>}
26
- */
27
- static async audit(artifacts) {
28
- if (!artifacts.FullPageScreenshot) {
29
- return {score: 0, notApplicable: true};
30
- }
31
-
32
- return {
33
- score: 1,
34
- details: {
35
- type: 'full-page-screenshot',
36
- ...artifacts.FullPageScreenshot,
37
- },
38
- };
39
- }
40
- }
41
-
42
- export default FullPageScreenshot;