lighthouse 9.5.0-dev.20220627 → 9.5.0-dev.20220630

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 (81) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/dist/report/bundle.esm.js +7 -6
  3. package/dist/report/flow.js +24 -24
  4. package/dist/report/standalone.js +19 -19
  5. package/{eslint-local-rules.js → eslint-local-rules.cjs} +0 -0
  6. package/flow-report/test/common-test.tsx +5 -4
  7. package/flow-report/test/flow-report-pptr-test.ts +4 -7
  8. package/flow-report/test/run-flow-report-tests.sh +20 -0
  9. package/flow-report/test/setup/env-setup.ts +44 -24
  10. package/flow-report/test/sidebar/sidebar-test.tsx +0 -1
  11. package/flow-report/test/topbar-test.tsx +5 -5
  12. package/flow-report/test/util-test.tsx +3 -3
  13. package/flow-report/tsconfig.json +4 -1
  14. package/lighthouse-cli/cli-flags.js +313 -305
  15. package/lighthouse-cli/run.js +1 -1
  16. package/lighthouse-cli/test/smokehouse/report-assert-test.js +1 -1
  17. package/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +30 -5
  18. package/lighthouse-core/audits/final-screenshot.js +2 -2
  19. package/lighthouse-core/audits/screenshot-thumbnails.js +6 -6
  20. package/lighthouse-core/audits/work-during-interaction.js +3 -3
  21. package/lighthouse-core/computed/metrics/cumulative-layout-shift.js +3 -3
  22. package/lighthouse-core/computed/metrics/first-meaningful-paint.js +2 -2
  23. package/lighthouse-core/computed/metrics/interactive.js +5 -5
  24. package/lighthouse-core/computed/metrics/lantern-first-meaningful-paint.js +3 -3
  25. package/lighthouse-core/computed/metrics/lantern-largest-contentful-paint.js +3 -3
  26. package/lighthouse-core/computed/metrics/largest-contentful-paint-all-frames.js +2 -2
  27. package/lighthouse-core/computed/metrics/largest-contentful-paint.js +2 -2
  28. package/lighthouse-core/computed/speedline.js +4 -4
  29. package/lighthouse-core/config/config-plugin.js +26 -0
  30. package/lighthouse-core/fraggle-rock/gather/navigation-runner.js +1 -0
  31. package/lighthouse-core/fraggle-rock/gather/session.js +3 -2
  32. package/lighthouse-core/gather/connections/connection.js +2 -2
  33. package/lighthouse-core/gather/driver/wait-for-condition.js +3 -3
  34. package/lighthouse-core/gather/driver.js +3 -2
  35. package/lighthouse-core/gather/gather-runner.js +2 -1
  36. package/lighthouse-core/gather/gatherers/main-document-content.js +0 -2
  37. package/lighthouse-core/lib/asset-saver.js +6 -6
  38. package/lighthouse-core/lib/lh-env.js +1 -1
  39. package/lighthouse-core/lib/lh-error.js +5 -5
  40. package/lighthouse-core/lib/lh-trace-processor.js +6 -6
  41. package/lighthouse-core/lib/navigation-error.js +34 -14
  42. package/lighthouse-core/lib/sentry.js +3 -3
  43. package/lighthouse-core/lib/url-shim.js +2 -2
  44. package/lighthouse-core/runner.js +6 -4
  45. package/lighthouse-core/util-commonjs.js +7 -6
  46. package/package.json +24 -19
  47. package/report/renderer/util.js +7 -6
  48. package/report/test/clients/bundle-test.js +4 -4
  49. package/report/test/generator/report-generator-test.js +3 -1
  50. package/report/test/renderer/category-renderer-test.js +3 -3
  51. package/report/test/renderer/components-test.js +36 -34
  52. package/report/test/renderer/crc-details-renderer-test.js +2 -2
  53. package/report/test/renderer/details-renderer-test.js +2 -2
  54. package/report/test/renderer/dom-test.js +4 -4
  55. package/report/test/renderer/element-screenshot-renderer-test.js +3 -2
  56. package/report/test/renderer/performance-category-renderer-test.js +4 -4
  57. package/report/test/renderer/pwa-category-renderer-test.js +3 -3
  58. package/report/test/renderer/report-renderer-axe-test.js +6 -8
  59. package/report/test/renderer/report-renderer-test.js +5 -5
  60. package/report/test/renderer/report-ui-features-test.js +8 -8
  61. package/report/test/renderer/snippet-renderer-test.js +2 -2
  62. package/report/test/renderer/text-encoding-test.js +2 -2
  63. package/report/test/renderer/util-test.js +1 -1
  64. package/root.js +0 -18
  65. package/shared/localization/format.js +1 -1
  66. package/shared/localization/locales/en-US.json +3 -0
  67. package/shared/localization/locales/en-XL.json +3 -0
  68. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +1 -1
  69. package/third-party/chromium-synchronization/installability-errors-test.js +1 -3
  70. package/tsconfig.json +1 -1
  71. package/types/global-lh.d.ts +2 -2
  72. package/types/test.d.ts +53 -0
  73. package/flow-report/.eslintrc.cjs +0 -51
  74. package/flow-report/jest.config.js +0 -24
  75. package/flow-report/test/setup/global-setup.ts +0 -11
  76. package/jest.config.js +0 -30
  77. package/lighthouse-cli/.eslintrc.cjs +0 -28
  78. package/report/.eslintrc.cjs +0 -37
  79. package/report/test/.eslintrc.cjs +0 -11
  80. package/shared/test/localization/.eslintrc.cjs +0 -11
  81. package/types/jest.d.ts +0 -25
@@ -250,7 +250,7 @@ async function runLighthouse(url, flags, config) {
250
250
  if (runnerResult?.lhr.runtimeError) {
251
251
  const {runtimeError} = runnerResult.lhr;
252
252
  return printErrorAndExit({
253
- name: 'LHError',
253
+ name: 'LighthouseError',
254
254
  friendlyMessage: runtimeError.message,
255
255
  code: runtimeError.code,
256
256
  message: runtimeError.message,
@@ -6,8 +6,8 @@
6
6
 
7
7
  /* eslint-disable no-control-regex */
8
8
 
9
+ import {readJson} from '../../../lighthouse-core/test/test-utils.js';
9
10
  import {findDifferences, getAssertionReport} from './report-assert.js';
10
- import {readJson} from '../../../root.js';
11
11
 
12
12
  describe('findDiffersences', () => {
13
13
  const testCases = {
@@ -33,6 +33,9 @@ const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings);
33
33
 
34
34
  const IGNORE_THRESHOLD_IN_BYTES = 4096;
35
35
 
36
+ // Ignore up to 12KB of waste if an effort was made with breakpoints.
37
+ const IGNORE_THRESHOLD_IN_BYTES_BREAKPOINTS_PRESENT = 12288;
38
+
36
39
  class UsesResponsiveImages extends ByteEfficiencyAudit {
37
40
  /**
38
41
  * @return {LH.Audit.Meta}
@@ -112,6 +115,18 @@ class UsesResponsiveImages extends ByteEfficiencyAudit {
112
115
  };
113
116
  }
114
117
 
118
+
119
+ /**
120
+ * @param {LH.Artifacts.ImageElement} image
121
+ * @return {number};
122
+ */
123
+ static determineAllowableWaste(image) {
124
+ if (image.srcset || image.isPicture) {
125
+ return IGNORE_THRESHOLD_IN_BYTES_BREAKPOINTS_PRESENT;
126
+ }
127
+ return IGNORE_THRESHOLD_IN_BYTES;
128
+ }
129
+
115
130
  /**
116
131
  * @param {LH.Artifacts} artifacts
117
132
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
@@ -126,6 +141,8 @@ class UsesResponsiveImages extends ByteEfficiencyAudit {
126
141
  const ViewportDimensions = artifacts.ViewportDimensions;
127
142
  /** @type {Map<string, LH.Audit.ByteEfficiencyItem>} */
128
143
  const resultsMap = new Map();
144
+ /** @type {Array<string>} */
145
+ const passedImageList = [];
129
146
  for (const image of images) {
130
147
  // Give SVG a free pass because creating a "responsive" SVG is of questionable value.
131
148
  // Ignore CSS images because it's difficult to determine what is a spritesheet,
@@ -147,15 +164,23 @@ class UsesResponsiveImages extends ByteEfficiencyAudit {
147
164
  );
148
165
  if (!processed) continue;
149
166
 
150
- // Don't warn about an image that was later used appropriately
167
+ // Verify the image wastes more than the minimum.
168
+ const exceedsAllowableWaste = processed.wastedBytes > this.determineAllowableWaste(image);
169
+
151
170
  const existing = resultsMap.get(processed.url);
152
- if (!existing || existing.wastedBytes > processed.wastedBytes) {
153
- resultsMap.set(processed.url, processed);
171
+ // Don't warn about an image that was later used appropriately, or wastes a trivial amount of data.
172
+ if (exceedsAllowableWaste && !passedImageList.includes(processed.url)) {
173
+ if ((!existing || existing.wastedBytes > processed.wastedBytes)) {
174
+ resultsMap.set(processed.url, processed);
175
+ }
176
+ } else {
177
+ // Ensure this url passes for future tests.
178
+ resultsMap.delete(processed.url);
179
+ passedImageList.push(processed.url);
154
180
  }
155
181
  }
156
182
 
157
- const items = Array.from(resultsMap.values())
158
- .filter(item => item.wastedBytes > IGNORE_THRESHOLD_IN_BYTES);
183
+ const items = Array.from(resultsMap.values());
159
184
 
160
185
  /** @type {LH.Audit.Details.Opportunity['headings']} */
161
186
  const headings = [
@@ -6,7 +6,7 @@
6
6
  'use strict';
7
7
 
8
8
  const Audit = require('./audit.js');
9
- const LHError = require('../lib/lh-error.js');
9
+ const LighthouseError = require('../lib/lh-error.js');
10
10
  const ProcessedTrace = require('../computed/processed-trace.js');
11
11
  const Screenshots = require('../computed/screenshots.js');
12
12
 
@@ -41,7 +41,7 @@ class FinalScreenshot extends Audit {
41
41
  if (artifacts.GatherContext.gatherMode === 'timespan') return {notApplicable: true, score: 1};
42
42
 
43
43
  // If it was another mode, that's a fatal error.
44
- throw new LHError(LHError.errors.NO_SCREENSHOTS);
44
+ throw new LighthouseError(LighthouseError.errors.NO_SCREENSHOTS);
45
45
  }
46
46
 
47
47
  return {
@@ -6,7 +6,7 @@
6
6
  'use strict';
7
7
 
8
8
  const Audit = require('./audit.js');
9
- const LHError = require('../lib/lh-error.js');
9
+ const LighthouseError = require('../lib/lh-error.js');
10
10
  const jpeg = require('jpeg-js');
11
11
  const Speedline = require('../computed/speedline.js');
12
12
 
@@ -88,7 +88,7 @@ class ScreenshotThumbnails extends Audit {
88
88
  const timelineEnd = Math.max(maxFrameTime, minimumTimelineDuration);
89
89
 
90
90
  if (!analyzedFrames.length || !Number.isFinite(timelineEnd)) {
91
- throw new LHError(LHError.errors.INVALID_SPEEDLINE);
91
+ throw new LighthouseError(LighthouseError.errors.INVALID_SPEEDLINE);
92
92
  }
93
93
 
94
94
  for (let i = 1; i <= NUMBER_OF_THUMBNAILS; i++) {
@@ -144,10 +144,10 @@ class ScreenshotThumbnails extends Audit {
144
144
  return await this._audit(artifacts, context);
145
145
  } catch (err) {
146
146
  const noFramesErrors = new Set([
147
- LHError.errors.NO_SCREENSHOTS.code,
148
- LHError.errors.SPEEDINDEX_OF_ZERO.code,
149
- LHError.errors.NO_SPEEDLINE_FRAMES.code,
150
- LHError.errors.INVALID_SPEEDLINE.code,
147
+ LighthouseError.errors.NO_SCREENSHOTS.code,
148
+ LighthouseError.errors.SPEEDINDEX_OF_ZERO.code,
149
+ LighthouseError.errors.NO_SPEEDLINE_FRAMES.code,
150
+ LighthouseError.errors.INVALID_SPEEDLINE.code,
151
151
  ]);
152
152
 
153
153
  // If a timespan didn't happen to contain frames, that's fine. Just mark not applicable.
@@ -15,7 +15,7 @@ const {taskGroups} = require('../lib/tracehouse/task-groups.js');
15
15
  const TraceProcessor = require('../lib/tracehouse/trace-processor.js');
16
16
  const {getExecutionTimingsByURL} = require('../lib/tracehouse/task-summary.js');
17
17
  const inpThresholds = require('./metrics/experimental-interaction-to-next-paint.js').defaultOptions;
18
- const LHError = require('../lib/lh-error.js');
18
+ const LighthouseError = require('../lib/lh-error.js');
19
19
 
20
20
  /** @typedef {import('../computed/metrics/responsiveness.js').EventTimingEvent} EventTimingEvent */
21
21
  /** @typedef {import('../lib/tracehouse/main-thread-tasks.js').TaskNode} TaskNode */
@@ -237,8 +237,8 @@ class WorkDuringInteraction extends Audit {
237
237
  }
238
238
  // TODO: remove workaround once 103.0.5052.0 is sufficiently released.
239
239
  if (interactionEvent.name === 'FallbackTiming') {
240
- throw new LHError(
241
- LHError.errors.UNSUPPORTED_OLD_CHROME,
240
+ throw new LighthouseError(
241
+ LighthouseError.errors.UNSUPPORTED_OLD_CHROME,
242
242
  {featureName: 'detailed EventTiming trace events'}
243
243
  );
244
244
  }
@@ -7,7 +7,7 @@
7
7
 
8
8
  const makeComputedArtifact = require('../computed-artifact.js');
9
9
  const ProcessedTrace = require('../processed-trace.js');
10
- const LHError = require('../../lib/lh-error.js');
10
+ const LighthouseError = require('../../lib/lh-error.js');
11
11
 
12
12
  /** @typedef {{ts: number, isMainFrame: boolean, weightedScore: number}} LayoutShiftEvent */
13
13
 
@@ -40,8 +40,8 @@ class CumulativeLayoutShift {
40
40
  // For all-frames CLS calculation, we rely on `weighted_score_delta`, which
41
41
  // was added in Chrome 90: https://crbug.com/1173139
42
42
  if (event.args.data.weighted_score_delta === undefined) {
43
- throw new LHError(
44
- LHError.errors.UNSUPPORTED_OLD_CHROME,
43
+ throw new LighthouseError(
44
+ LighthouseError.errors.UNSUPPORTED_OLD_CHROME,
45
45
  {featureName: 'Cumulative Layout Shift'}
46
46
  );
47
47
  }
@@ -7,7 +7,7 @@
7
7
 
8
8
  const makeComputedArtifact = require('../computed-artifact.js');
9
9
  const NavigationMetric = require('./navigation-metric.js');
10
- const LHError = require('../../lib/lh-error.js');
10
+ const LighthouseError = require('../../lib/lh-error.js');
11
11
  const LanternFirstMeaningfulPaint = require('./lantern-first-meaningful-paint.js');
12
12
 
13
13
  class FirstMeaningfulPaint extends NavigationMetric {
@@ -28,7 +28,7 @@ class FirstMeaningfulPaint extends NavigationMetric {
28
28
  static async computeObservedMetric(data) {
29
29
  const {processedNavigation} = data;
30
30
  if (processedNavigation.timings.firstMeaningfulPaint === undefined) {
31
- throw new LHError(LHError.errors.NO_FMP);
31
+ throw new LighthouseError(LighthouseError.errors.NO_FMP);
32
32
  }
33
33
 
34
34
  return {
@@ -11,7 +11,7 @@ const LanternInteractive = require('./lantern-interactive.js');
11
11
 
12
12
  const NetworkMonitor = require('../../gather/driver/network-monitor.js');
13
13
  const TracingProcessor = require('../../lib/tracehouse/trace-processor.js');
14
- const LHError = require('../../lib/lh-error.js');
14
+ const LighthouseError = require('../../lib/lh-error.js');
15
15
 
16
16
  const REQUIRED_QUIET_WINDOW = 5000;
17
17
  const ALLOWED_CONCURRENT_REQUESTS = 2;
@@ -133,10 +133,10 @@ class Interactive extends NavigationMetric {
133
133
  }
134
134
  }
135
135
 
136
- throw new LHError(
136
+ throw new LighthouseError(
137
137
  cpuCandidate
138
- ? LHError.errors.NO_TTI_NETWORK_IDLE_PERIOD
139
- : LHError.errors.NO_TTI_CPU_IDLE_PERIOD
138
+ ? LighthouseError.errors.NO_TTI_NETWORK_IDLE_PERIOD
139
+ : LighthouseError.errors.NO_TTI_CPU_IDLE_PERIOD
140
140
  );
141
141
  }
142
142
 
@@ -158,7 +158,7 @@ class Interactive extends NavigationMetric {
158
158
  const {processedTrace, processedNavigation, networkRecords} = data;
159
159
 
160
160
  if (!processedNavigation.timestamps.domContentLoaded) {
161
- throw new LHError(LHError.errors.NO_DCL);
161
+ throw new LighthouseError(LighthouseError.errors.NO_DCL);
162
162
  }
163
163
 
164
164
  const longTasks = TracingProcessor.getMainThreadTopLevelEvents(processedTrace)
@@ -7,7 +7,7 @@
7
7
 
8
8
  const makeComputedArtifact = require('../computed-artifact.js');
9
9
  const LanternMetric = require('./lantern-metric.js');
10
- const LHError = require('../../lib/lh-error.js');
10
+ const LighthouseError = require('../../lib/lh-error.js');
11
11
  const LanternFirstContentfulPaint = require('./lantern-first-contentful-paint.js');
12
12
 
13
13
  /** @typedef {import('../../lib/dependency-graph/base-node.js').Node} Node */
@@ -32,7 +32,7 @@ class LanternFirstMeaningfulPaint extends LanternMetric {
32
32
  static getOptimisticGraph(dependencyGraph, processedNavigation) {
33
33
  const fmp = processedNavigation.timestamps.firstMeaningfulPaint;
34
34
  if (!fmp) {
35
- throw new LHError(LHError.errors.NO_FMP);
35
+ throw new LighthouseError(LighthouseError.errors.NO_FMP);
36
36
  }
37
37
 
38
38
  return LanternFirstContentfulPaint.getFirstPaintBasedGraph(
@@ -52,7 +52,7 @@ class LanternFirstMeaningfulPaint extends LanternMetric {
52
52
  static getPessimisticGraph(dependencyGraph, processedNavigation) {
53
53
  const fmp = processedNavigation.timestamps.firstMeaningfulPaint;
54
54
  if (!fmp) {
55
- throw new LHError(LHError.errors.NO_FMP);
55
+ throw new LighthouseError(LighthouseError.errors.NO_FMP);
56
56
  }
57
57
 
58
58
  return LanternFirstContentfulPaint.getFirstPaintBasedGraph(
@@ -7,7 +7,7 @@
7
7
 
8
8
  const makeComputedArtifact = require('../computed-artifact.js');
9
9
  const LanternMetric = require('./lantern-metric.js');
10
- const LHError = require('../../lib/lh-error.js');
10
+ const LighthouseError = require('../../lib/lh-error.js');
11
11
  const LanternFirstContentfulPaint = require('./lantern-first-contentful-paint.js');
12
12
 
13
13
  /** @typedef {import('../../lib/dependency-graph/base-node.js').Node} Node */
@@ -47,7 +47,7 @@ class LanternLargestContentfulPaint extends LanternMetric {
47
47
  static getOptimisticGraph(dependencyGraph, processedNavigation) {
48
48
  const lcp = processedNavigation.timestamps.largestContentfulPaint;
49
49
  if (!lcp) {
50
- throw new LHError(LHError.errors.NO_LCP);
50
+ throw new LighthouseError(LighthouseError.errors.NO_LCP);
51
51
  }
52
52
 
53
53
  return LanternFirstContentfulPaint.getFirstPaintBasedGraph(
@@ -65,7 +65,7 @@ class LanternLargestContentfulPaint extends LanternMetric {
65
65
  static getPessimisticGraph(dependencyGraph, processedNavigation) {
66
66
  const lcp = processedNavigation.timestamps.largestContentfulPaint;
67
67
  if (!lcp) {
68
- throw new LHError(LHError.errors.NO_LCP);
68
+ throw new LighthouseError(LighthouseError.errors.NO_LCP);
69
69
  }
70
70
 
71
71
  return LanternFirstContentfulPaint.getFirstPaintBasedGraph(
@@ -11,7 +11,7 @@
11
11
 
12
12
  const makeComputedArtifact = require('../computed-artifact.js');
13
13
  const NavigationMetric = require('./navigation-metric.js');
14
- const LHError = require('../../lib/lh-error.js');
14
+ const LighthouseError = require('../../lib/lh-error.js');
15
15
 
16
16
  class LargestContentfulPaintAllFrames extends NavigationMetric {
17
17
  /**
@@ -29,7 +29,7 @@ class LargestContentfulPaintAllFrames extends NavigationMetric {
29
29
  static async computeObservedMetric(data) {
30
30
  const {processedNavigation} = data;
31
31
  if (processedNavigation.timings.largestContentfulPaintAllFrames === undefined) {
32
- throw new LHError(LHError.errors.NO_LCP_ALL_FRAMES);
32
+ throw new LighthouseError(LighthouseError.errors.NO_LCP_ALL_FRAMES);
33
33
  }
34
34
 
35
35
  return {
@@ -15,7 +15,7 @@
15
15
 
16
16
  const makeComputedArtifact = require('../computed-artifact.js');
17
17
  const NavigationMetric = require('./navigation-metric.js');
18
- const LHError = require('../../lib/lh-error.js');
18
+ const LighthouseError = require('../../lib/lh-error.js');
19
19
  const LanternLargestContentfulPaint = require('./lantern-largest-contentful-paint.js');
20
20
 
21
21
  class LargestContentfulPaint extends NavigationMetric {
@@ -36,7 +36,7 @@ class LargestContentfulPaint extends NavigationMetric {
36
36
  static async computeObservedMetric(data) {
37
37
  const {processedNavigation} = data;
38
38
  if (processedNavigation.timings.largestContentfulPaint === undefined) {
39
- throw new LHError(LHError.errors.NO_LCP);
39
+ throw new LighthouseError(LighthouseError.errors.NO_LCP);
40
40
  }
41
41
 
42
42
  return {
@@ -7,7 +7,7 @@
7
7
 
8
8
  const makeComputedArtifact = require('./computed-artifact.js');
9
9
  const speedline = require('speedline-core');
10
- const LHError = require('../lib/lh-error.js');
10
+ const LighthouseError = require('../lib/lh-error.js');
11
11
  const ProcessedTrace = require('./processed-trace.js');
12
12
 
13
13
  class Speedline {
@@ -33,17 +33,17 @@ class Speedline {
33
33
  });
34
34
  }).catch(err => {
35
35
  if (/No screenshots found in trace/.test(err.message)) {
36
- throw new LHError(LHError.errors.NO_SCREENSHOTS);
36
+ throw new LighthouseError(LighthouseError.errors.NO_SCREENSHOTS);
37
37
  }
38
38
 
39
39
  throw err;
40
40
  }).then(speedline => {
41
41
  if (speedline.frames.length === 0) {
42
- throw new LHError(LHError.errors.NO_SPEEDLINE_FRAMES);
42
+ throw new LighthouseError(LighthouseError.errors.NO_SPEEDLINE_FRAMES);
43
43
  }
44
44
 
45
45
  if (speedline.speedIndex === 0) {
46
- throw new LHError(LHError.errors.SPEEDINDEX_OF_ZERO);
46
+ throw new LighthouseError(LighthouseError.errors.SPEEDINDEX_OF_ZERO);
47
47
  }
48
48
 
49
49
  return speedline;
@@ -23,6 +23,24 @@ function isObjectOfUnknownProperties(val) {
23
23
  return typeof val === 'object' && val !== null && !Array.isArray(val);
24
24
  }
25
25
 
26
+ /**
27
+ * @param {unknown} str
28
+ * @return {str is LH.Gatherer.GatherMode}
29
+ */
30
+ function objectIsGatherMode(str) {
31
+ if (typeof str !== 'string') return false;
32
+ return str === 'navigation' || str === 'timespan' || str === 'snapshot';
33
+ }
34
+
35
+ /**
36
+ * @param {unknown} arr
37
+ * @return {arr is Array<LH.Gatherer.GatherMode>}
38
+ */
39
+ function isArrayOfGatherModes(arr) {
40
+ if (!Array.isArray(arr)) return false;
41
+ return arr.every(objectIsGatherMode);
42
+ }
43
+
26
44
  /**
27
45
  * Asserts that obj has no own properties, throwing a nice error message if it does.
28
46
  * Plugin and object name are included for nicer logging.
@@ -124,6 +142,7 @@ class ConfigPlugin {
124
142
  description,
125
143
  manualDescription,
126
144
  auditRefs: auditRefsJson,
145
+ supportedModes,
127
146
  ...invalidRest
128
147
  } = categoryJson;
129
148
 
@@ -138,6 +157,12 @@ class ConfigPlugin {
138
157
  if (!i18n.isStringOrIcuMessage(manualDescription) && manualDescription !== undefined) {
139
158
  throw new Error(`${pluginName} has an invalid category manualDescription.`);
140
159
  }
160
+ if (!isArrayOfGatherModes(supportedModes) && supportedModes !== undefined) {
161
+ throw new Error(
162
+ `${pluginName} supportedModes must be an array, ` +
163
+ `valid array values are "navigation", "timespan", and "snapshot".`
164
+ );
165
+ }
141
166
  const auditRefs = ConfigPlugin._parseAuditRefsList(auditRefsJson, pluginName);
142
167
 
143
168
  return {
@@ -145,6 +170,7 @@ class ConfigPlugin {
145
170
  auditRefs,
146
171
  description: description,
147
172
  manualDescription: manualDescription,
173
+ supportedModes,
148
174
  };
149
175
  }
150
176
 
@@ -178,6 +178,7 @@ async function _computeNavigationResult(
178
178
  url: mainDocumentUrl,
179
179
  loadFailureMode: navigationContext.navigation.loadFailureMode,
180
180
  networkRecords: debugData.records,
181
+ warnings,
181
182
  })
182
183
  : navigationError;
183
184
 
@@ -6,7 +6,7 @@
6
6
  'use strict';
7
7
 
8
8
  const EventEmitter = require('events').EventEmitter;
9
- const LHError = require('../../lib/lh-error.js');
9
+ const LighthouseError = require('../../lib/lh-error.js');
10
10
 
11
11
  // Controls how long to wait for a response after sending a DevTools protocol command.
12
12
  const DEFAULT_PROTOCOL_TIMEOUT = 30000;
@@ -87,7 +87,8 @@ class ProtocolSession extends CrdpEventEmitter {
87
87
  const timeoutPromise = new Promise((resolve, reject) => {
88
88
  if (timeoutMs === Infinity) return;
89
89
 
90
- timeout = setTimeout(reject, timeoutMs, new LHError(LHError.errors.PROTOCOL_TIMEOUT, {
90
+ // eslint-disable-next-line max-len
91
+ timeout = setTimeout(reject, timeoutMs, new LighthouseError(LighthouseError.errors.PROTOCOL_TIMEOUT, {
91
92
  protocolMethod: method,
92
93
  }));
93
94
  });
@@ -7,7 +7,7 @@
7
7
 
8
8
  const EventEmitter = require('events').EventEmitter;
9
9
  const log = require('lighthouse-logger');
10
- const LHError = require('../../lib/lh-error.js');
10
+ const LighthouseError = require('../../lib/lh-error.js');
11
11
 
12
12
  // TODO(bckenny): CommandCallback properties should be tied by command type after
13
13
  // https://github.com/Microsoft/TypeScript/pull/22348. See driver.js TODO.
@@ -138,7 +138,7 @@ class Connection {
138
138
  callback.resolve(Promise.resolve().then(_ => {
139
139
  if (object.error) {
140
140
  log.formatProtocol('method <= browser ERR', {method: callback.method}, 'error');
141
- throw LHError.fromProtocolMessage(callback.method, object.error);
141
+ throw LighthouseError.fromProtocolMessage(callback.method, object.error);
142
142
  }
143
143
 
144
144
  log.formatProtocol('method <= browser OK',
@@ -8,7 +8,7 @@
8
8
  /* global window */
9
9
 
10
10
  const log = require('lighthouse-logger');
11
- const LHError = require('../../lib/lh-error.js');
11
+ const LighthouseError = require('../../lib/lh-error.js');
12
12
  const ExecutionContext = require('./execution-context.js');
13
13
 
14
14
  /** @typedef {import('./network-monitor.js')} NetworkMonitor */
@@ -75,7 +75,7 @@ function waitForFcp(session, pauseAfterFcpMs, maxWaitForFcpMs) {
75
75
  /** @type {Promise<void>} */
76
76
  const promise = new Promise((resolve, reject) => {
77
77
  const maxWaitTimeout = setTimeout(() => {
78
- reject(new LHError(LHError.errors.NO_FCP));
78
+ reject(new LighthouseError(LighthouseError.errors.NO_FCP));
79
79
  }, maxWaitForFcpMs);
80
80
  /** @type {NodeJS.Timeout|undefined} */
81
81
  let loadTimeout;
@@ -476,7 +476,7 @@ async function waitForFullyLoaded(session, networkMonitor, options) {
476
476
  log.warn('waitFor', 'Page appears to be hung, killing JavaScript...');
477
477
  await session.sendCommand('Emulation.setScriptExecutionDisabled', {value: true});
478
478
  await session.sendCommand('Runtime.terminateExecution');
479
- throw new LHError(LHError.errors.PAGE_HUNG);
479
+ throw new LighthouseError(LighthouseError.errors.PAGE_HUNG);
480
480
  }
481
481
 
482
482
  return {timedOut: true};
@@ -7,7 +7,7 @@
7
7
 
8
8
  const Fetcher = require('./fetcher.js');
9
9
  const ExecutionContext = require('./driver/execution-context.js');
10
- const LHError = require('../lib/lh-error.js');
10
+ const LighthouseError = require('../lib/lh-error.js');
11
11
  const {fetchResponseBodyFromCache} = require('../gather/driver/network.js');
12
12
  const EventEmitter = require('events').EventEmitter;
13
13
 
@@ -343,7 +343,8 @@ class Driver {
343
343
  let asyncTimeout;
344
344
  const timeoutPromise = new Promise((resolve, reject) => {
345
345
  if (timeout === Infinity) return;
346
- asyncTimeout = setTimeout(reject, timeout, new LHError(LHError.errors.PROTOCOL_TIMEOUT, {
346
+ // eslint-disable-next-line max-len
347
+ asyncTimeout = setTimeout(reject, timeout, new LighthouseError(LighthouseError.errors.PROTOCOL_TIMEOUT, {
347
348
  protocolMethod: method,
348
349
  }));
349
350
  });
@@ -90,7 +90,7 @@ class GatherRunner {
90
90
  passContext.LighthouseRunWarnings.push(...warnings);
91
91
  }
92
92
  } catch (err) {
93
- // If it's one of our loading-based LHErrors, we'll treat it as a page load error.
93
+ // If it's one of our loading-based LighthouseErrors, we'll treat it as a page load error.
94
94
  if (err.code === 'NO_FCP' || err.code === 'PAGE_HUNG') {
95
95
  return {navigationError: err};
96
96
  }
@@ -604,6 +604,7 @@ class GatherRunner {
604
604
  url: passContext.url,
605
605
  loadFailureMode: passConfig.loadFailureMode,
606
606
  networkRecords: loadData.networkRecords,
607
+ warnings: passContext.LighthouseRunWarnings,
607
608
  });
608
609
  if (pageLoadError) {
609
610
  const localizedMessage = format.getFormatted(pageLoadError.friendlyMessage,
@@ -21,7 +21,6 @@ class MainDocumentContent extends FRGatherer {
21
21
  };
22
22
 
23
23
  /**
24
- *
25
24
  * @param {LH.Gatherer.FRTransitionalContext} context
26
25
  * @param {LH.Artifacts['DevtoolsLog']} devtoolsLog
27
26
  * @return {Promise<LH.Artifacts['MainDocumentContent']>}
@@ -34,7 +33,6 @@ class MainDocumentContent extends FRGatherer {
34
33
  }
35
34
 
36
35
  /**
37
- *
38
36
  * @param {LH.Gatherer.FRTransitionalContext<'DevtoolsLog'>} context
39
37
  * @return {Promise<LH.Artifacts['MainDocumentContent']>}
40
38
  */
@@ -15,7 +15,7 @@ const lanternTraceSaver = require('./lantern-trace-saver.js');
15
15
  const Metrics = require('./traces/pwmetrics-events.js');
16
16
  const NetworkAnalysisComputed = require('../computed/network-analysis.js');
17
17
  const LoadSimulatorComputed = require('../computed/load-simulator.js');
18
- const LHError = require('../lib/lh-error.js');
18
+ const LighthouseError = require('../lib/lh-error.js');
19
19
  // TODO(esmodules): Rollup does not support `promisfy` or `stream.pipeline`. Bundled files
20
20
  // don't need anything in this file except for `stringifyReplacer`, so a check for
21
21
  // truthiness before using is enough.
@@ -48,10 +48,10 @@ function loadArtifacts(basePath) {
48
48
  throw new Error('No saved artifacts found at ' + basePath);
49
49
  }
50
50
 
51
- // load artifacts.json using a reviver to deserialize any LHErrors in artifacts.
51
+ // load artifacts.json using a reviver to deserialize any LighthouseErrors in artifacts.
52
52
  const artifactsStr = fs.readFileSync(path.join(basePath, artifactsFilename), 'utf8');
53
53
  /** @type {LH.Artifacts} */
54
- const artifacts = JSON.parse(artifactsStr, LHError.parseReviver);
54
+ const artifacts = JSON.parse(artifactsStr, LighthouseError.parseReviver);
55
55
 
56
56
  const filenames = fs.readdirSync(basePath);
57
57
 
@@ -87,9 +87,9 @@ function loadArtifacts(basePath) {
87
87
  * @param {any} value
88
88
  */
89
89
  function stringifyReplacer(key, value) {
90
- // Currently only handle LHError and other Error types.
90
+ // Currently only handle LighthouseError and other Error types.
91
91
  if (value instanceof Error) {
92
- return LHError.stringifyReplacer(value);
92
+ return LighthouseError.stringifyReplacer(value);
93
93
  }
94
94
 
95
95
  return value;
@@ -128,7 +128,7 @@ async function saveArtifacts(artifacts, basePath) {
128
128
  await saveDevtoolsLog(devtoolsLog, `${basePath}/${passName}${devtoolsLogSuffix}`);
129
129
  }
130
130
 
131
- // save everything else, using a replacer to serialize LHErrors in the artifacts.
131
+ // save everything else, using a replacer to serialize LighthouseErrors in the artifacts.
132
132
  const restArtifactsString = JSON.stringify(restArtifacts, stringifyReplacer, 2) + '\n';
133
133
  fs.writeFileSync(`${basePath}/${artifactsFilename}`, restArtifactsString, 'utf8');
134
134
  log.log('Artifacts saved to disk in folder:', basePath);
@@ -8,7 +8,7 @@
8
8
  const process = require('process');
9
9
 
10
10
  module.exports = {
11
- // NODE_ENV is set to test by jest and by smokehouse CLI runner
11
+ // NODE_ENV is set to test by mocha-setup.js and the smokehouse CLI runner
12
12
  // CI as a catchall for everything we do in GitHub Actions
13
13
  isUnderTest: !!process.env.CI || process.env.NODE_ENV === 'test',
14
14
  };
@@ -114,7 +114,7 @@ class LighthouseError extends Error {
114
114
  */
115
115
  constructor(errorDefinition, properties) {
116
116
  super(errorDefinition.code);
117
- this.name = 'LHError';
117
+ this.name = 'LighthouseError';
118
118
  this.code = errorDefinition.code;
119
119
  // Add additional properties to be ICU replacements in the error string.
120
120
  // `code` is always added as `errorCode` so callers don't need to specify the code multiple times.
@@ -148,7 +148,7 @@ class LighthouseError extends Error {
148
148
  }
149
149
 
150
150
  /**
151
- * A JSON.stringify replacer to serialize LHErrors and (as a fallback) Errors.
151
+ * A JSON.stringify replacer to serialize LighthouseErrors and (as a fallback) Errors.
152
152
  * Returns a simplified version of the error object that can be reconstituted
153
153
  * as a copy of the original error at parse time.
154
154
  * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter
@@ -169,7 +169,7 @@ class LighthouseError extends Error {
169
169
  };
170
170
  }
171
171
 
172
- // Unexpected errors won't be LHErrors, but we want them serialized as well.
172
+ // Unexpected errors won't be LighthouseErrors, but we want them serialized as well.
173
173
  if (err instanceof Error) {
174
174
  const {message, stack} = err;
175
175
  // @ts-expect-error - code can be helpful for e.g. node errors, so preserve it if it's present.
@@ -182,12 +182,12 @@ class LighthouseError extends Error {
182
182
  };
183
183
  }
184
184
 
185
- throw new Error('Invalid value for LHError stringification');
185
+ throw new Error('Invalid value for LighthouseError stringification');
186
186
  }
187
187
 
188
188
  /**
189
189
  * A JSON.parse reviver. If any value passed in is a serialized Error or
190
- * LHError, the error is recreated as the original object. Otherwise, the
190
+ * LighthouseError, the error is recreated as the original object. Otherwise, the
191
191
  * value is passed through unchanged.
192
192
  * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter
193
193
  * @param {string} key