lighthouse 11.2.0 → 11.3.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 (106) hide show
  1. package/cli/cli-flags.d.ts +5 -1
  2. package/cli/cli-flags.js +5 -1
  3. package/cli/test/smokehouse/__snapshots__/report-assert-test.js.snap +2 -2
  4. package/cli/test/smokehouse/frontends/smokehouse-bin.js +18 -7
  5. package/cli/test/smokehouse/lighthouse-runners/bundle.d.ts +2 -4
  6. package/cli/test/smokehouse/lighthouse-runners/bundle.js +8 -4
  7. package/cli/test/smokehouse/lighthouse-runners/cli.d.ts +2 -4
  8. package/cli/test/smokehouse/lighthouse-runners/cli.js +5 -3
  9. package/cli/test/smokehouse/lighthouse-runners/devtools.d.ts +2 -1
  10. package/cli/test/smokehouse/lighthouse-runners/devtools.js +3 -1
  11. package/cli/test/smokehouse/smokehouse.d.ts +4 -2
  12. package/cli/test/smokehouse/smokehouse.js +10 -7
  13. package/core/audits/byte-efficiency/legacy-javascript.js +2 -2
  14. package/core/audits/image-size-responsive.js +1 -1
  15. package/core/audits/layout-shift-elements.js +1 -1
  16. package/core/audits/lcp-lazy-loaded.js +2 -2
  17. package/core/audits/long-tasks.js +1 -1
  18. package/core/audits/metrics/cumulative-layout-shift.js +2 -2
  19. package/core/audits/metrics/interaction-to-next-paint.js +2 -2
  20. package/core/audits/metrics/largest-contentful-paint.js +1 -1
  21. package/core/audits/no-unload-listeners.js +1 -1
  22. package/core/audits/preload-fonts.js +1 -1
  23. package/core/audits/prioritize-lcp-image.js +1 -1
  24. package/core/audits/unsized-images.js +1 -1
  25. package/core/audits/work-during-interaction.js +1 -1
  26. package/core/config/config.d.ts +1 -2
  27. package/core/config/config.js +18 -62
  28. package/core/config/constants.d.ts +1 -3
  29. package/core/config/constants.js +4 -18
  30. package/core/config/default-config.js +8 -8
  31. package/core/config/filters.d.ts +0 -8
  32. package/core/config/filters.js +0 -28
  33. package/core/config/validation.d.ts +4 -15
  34. package/core/config/validation.js +18 -63
  35. package/core/gather/base-artifacts.d.ts +2 -2
  36. package/core/gather/base-artifacts.js +5 -5
  37. package/core/gather/driver/navigation.d.ts +1 -1
  38. package/core/gather/driver/navigation.js +1 -1
  39. package/core/gather/driver/prepare.d.ts +3 -18
  40. package/core/gather/driver/prepare.js +21 -43
  41. package/core/gather/driver/storage.d.ts +2 -1
  42. package/core/gather/driver/storage.js +3 -12
  43. package/core/gather/gatherers/inspector-issues.js +1 -0
  44. package/core/gather/navigation-runner.d.ts +3 -31
  45. package/core/gather/navigation-runner.js +46 -113
  46. package/core/lib/navigation-error.d.ts +8 -3
  47. package/core/lib/navigation-error.js +19 -11
  48. package/dist/report/bundle.esm.js +4 -4
  49. package/dist/report/flow.js +7 -7
  50. package/dist/report/standalone.js +5 -5
  51. package/package.json +8 -8
  52. package/report/renderer/performance-category-renderer.js +2 -1
  53. package/shared/localization/locales/ar-XB.json +78 -75
  54. package/shared/localization/locales/ar.json +78 -75
  55. package/shared/localization/locales/bg.json +78 -75
  56. package/shared/localization/locales/ca.json +78 -75
  57. package/shared/localization/locales/cs.json +78 -75
  58. package/shared/localization/locales/da.json +78 -75
  59. package/shared/localization/locales/de.json +81 -78
  60. package/shared/localization/locales/el.json +84 -81
  61. package/shared/localization/locales/en-GB.json +78 -75
  62. package/shared/localization/locales/en-US.json +26 -23
  63. package/shared/localization/locales/en-XA.json +78 -75
  64. package/shared/localization/locales/en-XL.json +26 -23
  65. package/shared/localization/locales/es-419.json +78 -75
  66. package/shared/localization/locales/es.json +78 -75
  67. package/shared/localization/locales/fi.json +79 -76
  68. package/shared/localization/locales/fil.json +78 -75
  69. package/shared/localization/locales/fr.json +78 -75
  70. package/shared/localization/locales/he.json +78 -75
  71. package/shared/localization/locales/hi.json +78 -75
  72. package/shared/localization/locales/hr.json +78 -75
  73. package/shared/localization/locales/hu.json +78 -75
  74. package/shared/localization/locales/id.json +78 -75
  75. package/shared/localization/locales/it.json +79 -76
  76. package/shared/localization/locales/ja.json +78 -75
  77. package/shared/localization/locales/ko.json +78 -75
  78. package/shared/localization/locales/lt.json +78 -75
  79. package/shared/localization/locales/lv.json +78 -75
  80. package/shared/localization/locales/nl.json +78 -75
  81. package/shared/localization/locales/no.json +78 -75
  82. package/shared/localization/locales/pl.json +78 -75
  83. package/shared/localization/locales/pt-PT.json +78 -75
  84. package/shared/localization/locales/pt.json +79 -76
  85. package/shared/localization/locales/ro.json +78 -75
  86. package/shared/localization/locales/ru.json +78 -75
  87. package/shared/localization/locales/sk.json +78 -75
  88. package/shared/localization/locales/sl.json +78 -75
  89. package/shared/localization/locales/sr-Latn.json +78 -75
  90. package/shared/localization/locales/sr.json +78 -75
  91. package/shared/localization/locales/sv.json +78 -75
  92. package/shared/localization/locales/ta.json +78 -75
  93. package/shared/localization/locales/te.json +78 -75
  94. package/shared/localization/locales/th.json +78 -75
  95. package/shared/localization/locales/tr.json +78 -75
  96. package/shared/localization/locales/uk.json +78 -75
  97. package/shared/localization/locales/vi.json +78 -75
  98. package/shared/localization/locales/zh-HK.json +78 -75
  99. package/shared/localization/locales/zh-TW.json +79 -76
  100. package/shared/localization/locales/zh.json +78 -75
  101. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +1 -0
  102. package/types/artifacts.d.ts +1 -0
  103. package/types/config.d.ts +0 -38
  104. package/types/internal/rxjs.d.ts +4 -0
  105. package/types/internal/smokehouse.d.ts +10 -5
  106. package/types/lhr/settings.d.ts +13 -0
@@ -24,7 +24,7 @@ export function getYargsParser(manualArgv?: string | undefined): yargs.Argv<yarg
24
24
  default: boolean;
25
25
  describe: string;
26
26
  };
27
- }>, "port" | "screenEmulation" | "emulatedUserAgent" | "hostname" | "preset" | "save-assets" | "list-all-audits" | "list-locales" | "list-trace-categories" | "debug-navigation" | "additional-trace-categories" | "config-path" | "chrome-flags" | "form-factor" | "max-wait-for-load" | "enable-error-reporting" | "gather-mode" | "audit-mode" | "only-audits" | "only-categories" | "skip-audits" | "budget-path" | "disable-full-page-screenshot"> & yargs.InferredOptionTypes<{
27
+ }>, "port" | "screenEmulation" | "emulatedUserAgent" | "hostname" | "preset" | "save-assets" | "list-all-audits" | "list-locales" | "list-trace-categories" | "debug-navigation" | "additional-trace-categories" | "config-path" | "chrome-flags" | "form-factor" | "max-wait-for-load" | "enable-error-reporting" | "gather-mode" | "audit-mode" | "only-audits" | "only-categories" | "skip-audits" | "budget-path" | "disable-full-page-screenshot" | "ignore-status-code"> & yargs.InferredOptionTypes<{
28
28
  'save-assets': {
29
29
  type: "boolean";
30
30
  default: boolean;
@@ -133,6 +133,10 @@ export function getYargsParser(manualArgv?: string | undefined): yargs.Argv<yarg
133
133
  type: "boolean";
134
134
  describe: string;
135
135
  };
136
+ 'ignore-status-code': {
137
+ type: "boolean";
138
+ describe: string;
139
+ };
136
140
  }>, "output" | "view" | "output-path"> & yargs.InferredOptionTypes<{
137
141
  output: {
138
142
  type: "array";
package/cli/cli-flags.js CHANGED
@@ -204,12 +204,16 @@ function getYargsParser(manualArgv) {
204
204
  type: 'boolean',
205
205
  describe: 'Disables collection of the full page screenshot, which can be quite large',
206
206
  },
207
+ 'ignore-status-code': {
208
+ type: 'boolean',
209
+ describe: 'Disables failing on all error status codes, and instead issues a warning.',
210
+ },
207
211
  })
208
212
  .group([
209
213
  'save-assets', 'list-all-audits', 'list-locales', 'list-trace-categories', 'additional-trace-categories',
210
214
  'config-path', 'preset', 'chrome-flags', 'port', 'hostname', 'form-factor', 'screenEmulation', 'emulatedUserAgent',
211
215
  'max-wait-for-load', 'enable-error-reporting', 'gather-mode', 'audit-mode',
212
- 'only-audits', 'only-categories', 'skip-audits', 'budget-path', 'disable-full-page-screenshot',
216
+ 'only-audits', 'only-categories', 'skip-audits', 'budget-path', 'disable-full-page-screenshot', 'ignore-status-code',
213
217
  ], 'Configuration:')
214
218
 
215
219
  // Output
@@ -14,7 +14,7 @@ exports[`getAssertionReport works (multiple failing) 1`] = `
14
14
  {
15
15
  \\"id\\": \\"cumulative-layout-shift\\",
16
16
  \\"title\\": \\"Cumulative Layout Shift\\",
17
- \\"description\\": \\"Cumulative Layout Shift measures the movement of visible elements within the viewport. [Learn more about the Cumulative Layout Shift metric](https://web.dev/cls/).\\",
17
+ \\"description\\": \\"Cumulative Layout Shift measures the movement of visible elements within the viewport. [Learn more about the Cumulative Layout Shift metric](https://web.dev/articles/cls).\\",
18
18
  \\"score\\": 0.8,
19
19
  \\"scoreDisplayMode\\": \\"numeric\\",
20
20
  \\"numericValue\\": 0.13570762803819444,
@@ -44,7 +44,7 @@ exports[`getAssertionReport works (trivial failing) 1`] = `
44
44
  {
45
45
  \\"id\\": \\"cumulative-layout-shift\\",
46
46
  \\"title\\": \\"Cumulative Layout Shift\\",
47
- \\"description\\": \\"Cumulative Layout Shift measures the movement of visible elements within the viewport. [Learn more about the Cumulative Layout Shift metric](https://web.dev/cls/).\\",
47
+ \\"description\\": \\"Cumulative Layout Shift measures the movement of visible elements within the viewport. [Learn more about the Cumulative Layout Shift metric](https://web.dev/articles/cls).\\",
48
48
  \\"score\\": 0.8,
49
49
  \\"scoreDisplayMode\\": \\"numeric\\",
50
50
  \\"numericValue\\": 0.13570762803819444,
@@ -21,7 +21,7 @@ import yargs from 'yargs';
21
21
  import * as yargsHelpers from 'yargs/helpers';
22
22
  import log from 'lighthouse-logger';
23
23
 
24
- import {runSmokehouse, getShardedDefinitions} from '../smokehouse.js';
24
+ import {runSmokehouse, getShardedDefinitions, DEFAULT_RETRIES, DEFAULT_CONCURRENT_RUNS} from '../smokehouse.js';
25
25
  import {updateTestDefnFormat} from './back-compat-util.js';
26
26
  import {LH_ROOT} from '../../../../shared/root.js';
27
27
  import exclusions from '../config/exclusions.js';
@@ -139,10 +139,12 @@ async function begin() {
139
139
  'jobs': {
140
140
  type: 'number',
141
141
  alias: 'j',
142
+ default: DEFAULT_CONCURRENT_RUNS,
142
143
  describe: 'Manually set the number of jobs to run at once. `1` runs all tests serially',
143
144
  },
144
145
  'retries': {
145
146
  type: 'number',
147
+ default: DEFAULT_RETRIES,
146
148
  describe: 'The number of times to retry failing tests before accepting. Defaults to 0',
147
149
  },
148
150
  'runner': {
@@ -164,6 +166,15 @@ async function begin() {
164
166
  default: false,
165
167
  describe: 'Ignore any smoke test exclusions set.',
166
168
  },
169
+ 'headless': {
170
+ type: 'boolean',
171
+ default: true,
172
+ hidden: true,
173
+ },
174
+ 'no-headless': {
175
+ type: 'boolean',
176
+ describe: 'Launch Chrome in typical desktop headful mode, rather than our default of `--headless=new` (https://developer.chrome.com/articles/new-headless/).', // eslint-disable-line max-len
177
+ },
167
178
  })
168
179
  .wrap(y.terminalWidth())
169
180
  .argv;
@@ -173,9 +184,6 @@ async function begin() {
173
184
  const argv =
174
185
  /** @type {Awaited<typeof rawArgv> & LH.Util.CamelCasify<Awaited<typeof rawArgv>>} */ (rawArgv);
175
186
 
176
- const jobs = Number.isFinite(argv.jobs) ? argv.jobs : undefined;
177
- const retries = Number.isFinite(argv.retries) ? argv.retries : undefined;
178
-
179
187
  const runnerPath = runnerPaths[/** @type {keyof typeof runnerPaths} */ (argv.runner)];
180
188
  if (argv.runner === 'bundle') {
181
189
  console.log('\n✨ Be sure to have recently run this: yarn build-all');
@@ -210,9 +218,12 @@ async function begin() {
210
218
 
211
219
  const prunedTestDefns = pruneExpectedNetworkRequests(testDefns, takeNetworkRequestUrls);
212
220
  const options = {
213
- jobs,
214
- retries,
215
- isDebug: argv.debug,
221
+ jobs: argv.jobs,
222
+ retries: argv.retries,
223
+ testRunnerOptions: {
224
+ isDebug: argv.debug,
225
+ headless: argv.headless,
226
+ },
216
227
  lighthouseRunner: runLighthouse,
217
228
  takeNetworkRequestUrls,
218
229
  setup,
@@ -2,12 +2,10 @@
2
2
  * Launch Chrome and do a full Lighthouse run via the Lighthouse DevTools bundle.
3
3
  * @param {string} url
4
4
  * @param {LH.Config=} config
5
- * @param {{isDebug?: boolean}=} testRunnerOptions
5
+ * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
6
6
  * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
7
7
  */
8
- export function runLighthouse(url: string, config?: LH.Config | undefined, testRunnerOptions?: {
9
- isDebug?: boolean;
10
- } | undefined): Promise<{
8
+ export function runLighthouse(url: string, config?: LH.Config | undefined, testRunnerOptions?: Smokehouse.SmokehouseOptions['testRunnerOptions'] | undefined): Promise<{
11
9
  lhr: LH.Result;
12
10
  artifacts: LH.Artifacts;
13
11
  log: string;
@@ -46,7 +46,7 @@ if (!isMainThread && parentPort) {
46
46
  /**
47
47
  * @param {string} url
48
48
  * @param {LH.Config|undefined} config
49
- * @param {{isDebug?: boolean}} testRunnerOptions
49
+ * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']} testRunnerOptions
50
50
  * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts}>}
51
51
  */
52
52
  async function runBundledLighthouse(url, config, testRunnerOptions) {
@@ -74,12 +74,16 @@ async function runBundledLighthouse(url, config, testRunnerOptions) {
74
74
  const lighthouse = global.runBundledLighthouse;
75
75
 
76
76
  // Launch and connect to Chrome.
77
- const launchedChrome = await ChromeLauncher.launch();
77
+ const launchedChrome = await ChromeLauncher.launch({
78
+ chromeFlags: [
79
+ testRunnerOptions?.headless ? '--headless=new' : '',
80
+ ],
81
+ });
78
82
  const port = launchedChrome.port;
79
83
 
80
84
  // Run Lighthouse.
81
85
  try {
82
- const logLevel = testRunnerOptions.isDebug ? 'verbose' : 'info';
86
+ const logLevel = testRunnerOptions?.isDebug ? 'verbose' : 'info';
83
87
 
84
88
  // Puppeteer is not included in the bundle, we must create the page here.
85
89
  const browser = await puppeteer.connect({browserURL: `http://127.0.0.1:${port}`});
@@ -101,7 +105,7 @@ async function runBundledLighthouse(url, config, testRunnerOptions) {
101
105
  * Launch Chrome and do a full Lighthouse run via the Lighthouse DevTools bundle.
102
106
  * @param {string} url
103
107
  * @param {LH.Config=} config
104
- * @param {{isDebug?: boolean}=} testRunnerOptions
108
+ * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
105
109
  * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
106
110
  */
107
111
  async function runLighthouse(url, config, testRunnerOptions = {}) {
@@ -2,12 +2,10 @@
2
2
  * Launch Chrome and do a full Lighthouse run via the Lighthouse CLI.
3
3
  * @param {string} url
4
4
  * @param {LH.Config=} config
5
- * @param {{isDebug?: boolean}=} testRunnerOptions
5
+ * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
6
6
  * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
7
7
  */
8
- export function runLighthouse(url: string, config?: LH.Config | undefined, testRunnerOptions?: {
9
- isDebug?: boolean | undefined;
10
- } | undefined): Promise<{
8
+ export function runLighthouse(url: string, config?: LH.Config | undefined, testRunnerOptions?: Smokehouse.SmokehouseOptions['testRunnerOptions'] | undefined): Promise<{
11
9
  lhr: LH.Result;
12
10
  artifacts: LH.Artifacts;
13
11
  log: string;
@@ -28,7 +28,7 @@ const execFileAsync = promisify(execFile);
28
28
  * Launch Chrome and do a full Lighthouse run via the Lighthouse CLI.
29
29
  * @param {string} url
30
30
  * @param {LH.Config=} config
31
- * @param {{isDebug?: boolean}=} testRunnerOptions
31
+ * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
32
32
  * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
33
33
  */
34
34
  async function runLighthouse(url, config, testRunnerOptions = {}) {
@@ -46,11 +46,11 @@ async function runLighthouse(url, config, testRunnerOptions = {}) {
46
46
  * @param {string} url
47
47
  * @param {string} tmpPath
48
48
  * @param {LH.Config=} config
49
- * @param {{isDebug?: boolean}=} options
49
+ * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} options
50
50
  * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
51
51
  */
52
52
  async function internalRun(url, tmpPath, config, options) {
53
- const {isDebug = false} = options || {};
53
+ const {isDebug, headless} = options || {};
54
54
  const localConsole = new LocalConsole();
55
55
 
56
56
  const outputPath = `${tmpPath}/smokehouse.report.json`;
@@ -67,6 +67,8 @@ async function internalRun(url, tmpPath, config, options) {
67
67
  '--quiet',
68
68
  ];
69
69
 
70
+ if (headless) args.push('--chrome-flags="--headless=new"');
71
+
70
72
  // Config can be optionally provided.
71
73
  if (config) {
72
74
  const configPath = `${tmpPath}/config.json`;
@@ -5,9 +5,10 @@
5
5
  * CHROME_PATH determines which Chrome is used–otherwise the default is puppeteer's chrome binary.
6
6
  * @param {string} url
7
7
  * @param {LH.Config=} config
8
+ * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
8
9
  * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
9
10
  */
10
- export function runLighthouse(url: string, config?: LH.Config | undefined): Promise<{
11
+ export function runLighthouse(url: string, config?: LH.Config | undefined, testRunnerOptions?: Smokehouse.SmokehouseOptions['testRunnerOptions'] | undefined): Promise<{
11
12
  lhr: LH.Result;
12
13
  artifacts: LH.Artifacts;
13
14
  log: string;
@@ -40,10 +40,12 @@ async function setup() {
40
40
  * CHROME_PATH determines which Chrome is used–otherwise the default is puppeteer's chrome binary.
41
41
  * @param {string} url
42
42
  * @param {LH.Config=} config
43
+ * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
43
44
  * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
44
45
  */
45
- async function runLighthouse(url, config) {
46
+ async function runLighthouse(url, config, testRunnerOptions) {
46
47
  const chromeFlags = [
48
+ testRunnerOptions?.headless ? '--headless=new' : '',
47
49
  `--custom-devtools-frontend=file://${devtoolsDir}/out/LighthouseIntegration/gen/front_end`,
48
50
  ];
49
51
  const {lhr, artifacts, logs} = await testUrlFromDevtools(url, {
@@ -14,10 +14,10 @@ export type SmokehouseResult = {
14
14
  /**
15
15
  * Runs the selected smoke tests. Returns whether all assertions pass.
16
16
  * @param {Array<Smokehouse.TestDfn>} smokeTestDefns
17
- * @param {Smokehouse.SmokehouseOptions} smokehouseOptions
17
+ * @param {Partial<Smokehouse.SmokehouseOptions>} smokehouseOptions
18
18
  * @return {Promise<{success: boolean, testResults: SmokehouseResult[]}>}
19
19
  */
20
- export function runSmokehouse(smokeTestDefns: Array<Smokehouse.TestDfn>, smokehouseOptions: Smokehouse.SmokehouseOptions): Promise<{
20
+ export function runSmokehouse(smokeTestDefns: Array<Smokehouse.TestDfn>, smokehouseOptions: Partial<Smokehouse.SmokehouseOptions>): Promise<{
21
21
  success: boolean;
22
22
  testResults: SmokehouseResult[];
23
23
  }>;
@@ -31,4 +31,6 @@ export function runSmokehouse(smokeTestDefns: Array<Smokehouse.TestDfn>, smokeho
31
31
  * @return {Array<Smokehouse.TestDfn>}
32
32
  */
33
33
  export function getShardedDefinitions(testDefns: Array<Smokehouse.TestDfn>, shardArg?: string | undefined): Array<Smokehouse.TestDfn>;
34
+ export const DEFAULT_RETRIES: 0;
35
+ export const DEFAULT_CONCURRENT_RUNS: 5;
34
36
  //# sourceMappingURL=smokehouse.d.ts.map
@@ -46,12 +46,12 @@ const DEFAULT_RETRIES = 0;
46
46
  /**
47
47
  * Runs the selected smoke tests. Returns whether all assertions pass.
48
48
  * @param {Array<Smokehouse.TestDfn>} smokeTestDefns
49
- * @param {Smokehouse.SmokehouseOptions} smokehouseOptions
49
+ * @param {Partial<Smokehouse.SmokehouseOptions>} smokehouseOptions
50
50
  * @return {Promise<{success: boolean, testResults: SmokehouseResult[]}>}
51
51
  */
52
52
  async function runSmokehouse(smokeTestDefns, smokehouseOptions) {
53
53
  const {
54
- isDebug,
54
+ testRunnerOptions,
55
55
  jobs = DEFAULT_CONCURRENT_RUNS,
56
56
  retries = DEFAULT_RETRIES,
57
57
  lighthouseRunner = Object.assign(cliLighthouseRunner, {runnerName: 'cli'}),
@@ -73,7 +73,8 @@ async function runSmokehouse(smokeTestDefns, smokehouseOptions) {
73
73
  const concurrentMapper = new ConcurrentMapper();
74
74
 
75
75
  const testOptions = {
76
- isDebug,
76
+ testRunnerOptions,
77
+ jobs,
77
78
  retries,
78
79
  lighthouseRunner,
79
80
  takeNetworkRequestUrls,
@@ -133,7 +134,7 @@ function purpleify(str) {
133
134
  /**
134
135
  * Run Lighthouse in the selected runner.
135
136
  * @param {Smokehouse.TestDfn} smokeTestDefn
136
- * @param {{isDebug?: boolean, retries: number, lighthouseRunner: Smokehouse.LighthouseRunner, takeNetworkRequestUrls?: () => string[]}} testOptions
137
+ * @param {Smokehouse.SmokehouseOptions} testOptions
137
138
  * @return {Promise<SmokehouseResult>}
138
139
  */
139
140
  async function runSmokeTest(smokeTestDefn, testOptions) {
@@ -141,7 +142,7 @@ async function runSmokeTest(smokeTestDefn, testOptions) {
141
142
  const {
142
143
  lighthouseRunner,
143
144
  retries,
144
- isDebug,
145
+ testRunnerOptions,
145
146
  takeNetworkRequestUrls,
146
147
  } = testOptions;
147
148
  const requestedUrl = expectations.lhr.requestedUrl;
@@ -163,7 +164,7 @@ async function runSmokeTest(smokeTestDefn, testOptions) {
163
164
  // Run Lighthouse.
164
165
  try {
165
166
  result = {
166
- ...await lighthouseRunner(requestedUrl, config, {isDebug}),
167
+ ...await lighthouseRunner(requestedUrl, config, testRunnerOptions),
167
168
  networkRequests: takeNetworkRequestUrls ? takeNetworkRequestUrls() : undefined,
168
169
  };
169
170
 
@@ -183,7 +184,7 @@ async function runSmokeTest(smokeTestDefn, testOptions) {
183
184
  // Assert result.
184
185
  report = getAssertionReport(result, expectations, {
185
186
  runner: lighthouseRunner.runnerName,
186
- isDebug,
187
+ ...testRunnerOptions,
187
188
  });
188
189
 
189
190
  runs.push({
@@ -310,4 +311,6 @@ function getShardedDefinitions(testDefns, shardArg) {
310
311
  export {
311
312
  runSmokehouse,
312
313
  getShardedDefinitions,
314
+ DEFAULT_RETRIES,
315
+ DEFAULT_CONCURRENT_RUNS,
313
316
  };
@@ -37,9 +37,9 @@ const UIStrings = {
37
37
  /** Title of a Lighthouse audit that tells the user about legacy polyfills and transforms used on the page. This is displayed in a list of audit titles that Lighthouse generates. */
38
38
  title: 'Avoid serving legacy JavaScript to modern browsers',
39
39
  // eslint-disable-next-line max-len
40
- // TODO: developer.chrome.com article. this codelab is good starting place: https://web.dev/codelab-serve-modern-code/
40
+ // TODO: developer.chrome.com article. this codelab is good starting place: https://web.dev/articles/codelab-serve-modern-code
41
41
  /** Description of a Lighthouse audit that tells the user about old JavaScript that is no longer needed. 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. */
42
- description: 'Polyfills and transforms enable legacy browsers to use new JavaScript features. However, many aren\'t necessary for modern browsers. For your bundled JavaScript, adopt a modern script deployment strategy using module/nomodule feature detection to reduce the amount of code shipped to modern browsers, while retaining support for legacy browsers. [Learn how to use modern JavaScript](https://web.dev/publish-modern-javascript/)',
42
+ description: 'Polyfills and transforms enable legacy browsers to use new JavaScript features. However, many aren\'t necessary for modern browsers. For your bundled JavaScript, adopt a modern script deployment strategy using module/nomodule feature detection to reduce the amount of code shipped to modern browsers, while retaining support for legacy browsers. [Learn how to use modern JavaScript](https://web.dev/articles/publish-modern-javascript)',
43
43
  };
44
44
 
45
45
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -24,7 +24,7 @@ const UIStrings = {
24
24
  /** Description of a Lighthouse audit that tells the user why they should maintain an appropriate size for all images. 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. */
25
25
  description: 'Image natural dimensions should be proportional to the display size and the ' +
26
26
  'pixel ratio to maximize image clarity. ' +
27
- '[Learn how to provide responsive images](https://web.dev/serve-responsive-images/).',
27
+ '[Learn how to provide responsive images](https://web.dev/articles/serve-responsive-images).',
28
28
  /** Label for a column in a data table; entries in the column will be a string representing the displayed size of the image. */
29
29
  columnDisplayed: 'Displayed size',
30
30
  /** Label for a column in a data table; entries in the column will be a string representing the actual size of the image. */
@@ -12,7 +12,7 @@ const UIStrings = {
12
12
  /** Descriptive title of a diagnostic audit that provides up to the top five elements contributing to Cumulative Layout Shift. */
13
13
  title: 'Avoid large layout shifts',
14
14
  /** Description of a diagnostic audit that provides up to the top five elements contributing to Cumulative Layout Shift. The last sentence starting with 'Learn' becomes link text to additional documentation. */
15
- description: 'These DOM elements contribute most to the CLS of the page. [Learn how to improve CLS](https://web.dev/optimize-cls/)',
15
+ description: 'These DOM elements contribute most to the CLS of the page. [Learn how to improve CLS](https://web.dev/articles/optimize-cls)',
16
16
  /** Label for a column in a data table; entries in this column will be the amount that the corresponding element contributes to the total CLS metric score. */
17
17
  columnContribution: 'CLS Contribution',
18
18
  };
@@ -15,7 +15,7 @@ const UIStrings = {
15
15
  /** Title of a Lighthouse audit that provides detail on whether the largest above-the-fold image was loaded with sufficient priority. This descriptive title is shown to users when the image was loaded inefficiently using the `loading=lazy` attribute. */
16
16
  failureTitle: 'Largest Contentful Paint image was lazily loaded',
17
17
  /** Description of a Lighthouse audit that tells the user why the advice is important. This is displayed after a user expands the section to see more. No character length limits. */
18
- description: 'Above-the-fold images that are lazily loaded render later in the page lifecycle, which can delay the largest contentful paint. [Learn more about optimal lazy loading](https://web.dev/lcp-lazy-loading/).',
18
+ description: 'Above-the-fold images that are lazily loaded render later in the page lifecycle, which can delay the largest contentful paint. [Learn more about optimal lazy loading](https://web.dev/articles/lcp-lazy-loading).',
19
19
  };
20
20
 
21
21
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -94,7 +94,7 @@ class LargestContentfulPaintLazyLoaded extends Audit {
94
94
  let lcpSavings = 0;
95
95
  if (wasLazyLoaded && lcpBreakdown.loadStart !== undefined) {
96
96
  // Estimate the LCP savings using a statistical percentage.
97
- // https://web.dev/lcp-lazy-loading/#causal-performance
97
+ // https://web.dev/articles/lcp-lazy-loading#causal_performance
98
98
  //
99
99
  // LCP savings will be at most the LCP load delay.
100
100
  const lcpLoadDelay = lcpBreakdown.loadStart - lcpBreakdown.ttfb;
@@ -23,7 +23,7 @@ const UIStrings = {
23
23
  /** Description of a diagnostic LH audit that shows the user the longest running tasks that occur when the page loads. */
24
24
  description: 'Lists the longest tasks on the main thread, ' +
25
25
  'useful for identifying worst contributors to input delay. ' +
26
- '[Learn how to avoid long main-thread tasks](https://web.dev/long-tasks-devtools/)',
26
+ '[Learn how to avoid long main-thread tasks](https://web.dev/articles/long-tasks-devtools)',
27
27
  /** [ICU Syntax] Label identifying the number of long-running CPU tasks that occurred while loading a web page. */
28
28
  displayValue: `{itemCount, plural,
29
29
  =1 {# long task found}
@@ -12,7 +12,7 @@ const UIStrings = {
12
12
  /** Description of the Cumulative Layout Shift metric that indicates how much the page changes its layout while it loads. If big segments of the page shift their location during load, the Cumulative Layout Shift will be higher. This description is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
13
13
  description: 'Cumulative Layout Shift measures the movement of visible ' +
14
14
  'elements within the viewport. ' +
15
- '[Learn more about the Cumulative Layout Shift metric](https://web.dev/cls/).',
15
+ '[Learn more about the Cumulative Layout Shift metric](https://web.dev/articles/cls).',
16
16
  };
17
17
 
18
18
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -39,7 +39,7 @@ class CumulativeLayoutShift extends Audit {
39
39
  */
40
40
  static get defaultOptions() {
41
41
  return {
42
- // https://web.dev/cls/#what-is-a-good-cls-score
42
+ // https://web.dev/articles/cls#what_is_a_good_cls_score
43
43
  // This 0.1 target score was determined through both manual evaluation and large-scale analysis.
44
44
  // see https://www.desmos.com/calculator/ksp7q91nop
45
45
  p10: 0.1,
@@ -12,7 +12,7 @@ const UIStrings = {
12
12
  /** Description of the Interaction to Next Paint metric. This description is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
13
13
  description: 'Interaction to Next Paint measures page responsiveness, how long it ' +
14
14
  'takes the page to visibly respond to user input. ' +
15
- '[Learn more about the Interaction to Next Paint metric](https://web.dev/inp/).',
15
+ '[Learn more about the Interaction to Next Paint metric](https://web.dev/articles/inp).',
16
16
  };
17
17
 
18
18
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -40,7 +40,7 @@ class InteractionToNextPaint extends Audit {
40
40
  */
41
41
  static get defaultOptions() {
42
42
  return {
43
- // https://web.dev/inp/
43
+ // https://web.dev/articles/inp
44
44
  // This is using the same threshold as field tools since only supported in
45
45
  // unsimulated user flows for now.
46
46
  // see https://www.desmos.com/calculator/4xtrhg51th
@@ -39,7 +39,7 @@ class LargestContentfulPaint extends Audit {
39
39
  mobile: {
40
40
  // 25th and 13th percentiles HTTPArchive -> median and p10 points.
41
41
  // https://bigquery.cloud.google.com/table/httparchive:lighthouse.2020_02_01_mobile?pli=1
42
- // https://web.dev/lcp/#what-is-a-good-lcp-score
42
+ // https://web.dev/articles/lcp#what_is_a_good_lcp_score
43
43
  // see https://www.desmos.com/calculator/1etesp32kt
44
44
  scoring: {
45
45
  p10: 2500,
@@ -14,7 +14,7 @@ const UIStrings = {
14
14
  /** Descriptive title of a Lighthouse audit that checks if a web page has 'unload' event listeners and finds that it is using them. */
15
15
  failureTitle: 'Registers an `unload` listener',
16
16
  /** Description of a Lighthouse audit that tells the user why pages should not use the 'unload' event. This is displayed after a user expands the section to see more. The last sentence starting with 'Learn' becomes link text to additional documentation. */
17
- description: 'The `unload` event does not fire reliably and listening for it can prevent browser optimizations like the Back-Forward Cache. Use `pagehide` or `visibilitychange` events instead. [Learn more about unload event listeners](https://web.dev/bfcache/#never-use-the-unload-event)',
17
+ description: 'The `unload` event does not fire reliably and listening for it can prevent browser optimizations like the Back-Forward Cache. Use `pagehide` or `visibilitychange` events instead. [Learn more about unload event listeners](https://web.dev/articles/bfcache#never_use_the_unload_event)',
18
18
  };
19
19
 
20
20
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -21,7 +21,7 @@ const UIStrings = {
21
21
  /** Title of a Lighthouse audit that provides detail on whether fonts that used `font-display: optional` were preloaded. This descriptive title is shown to users when one or more fonts used `font-display: optional` and were not preloaded. */
22
22
  failureTitle: 'Fonts with `font-display: optional` are not preloaded',
23
23
  /** Description of a Lighthouse audit that tells the user why they should preload fonts if they are using `font-display: optional`. 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. */
24
- description: 'Preload `optional` fonts so first-time visitors may use them. [Learn more about preloading fonts](https://web.dev/preload-optional-fonts/)',
24
+ description: 'Preload `optional` fonts so first-time visitors may use them. [Learn more about preloading fonts](https://web.dev/articles/preload-optional-fonts)',
25
25
  };
26
26
 
27
27
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -17,7 +17,7 @@ const UIStrings = {
17
17
  title: 'Preload Largest Contentful Paint image',
18
18
  /** Description of a lighthouse audit that tells a user to preload an image in order to improve their LCP time. */
19
19
  description: 'If the LCP element is dynamically added to the page, you should preload the ' +
20
- 'image in order to improve LCP. [Learn more about preloading LCP elements](https://web.dev/optimize-lcp/#optimize-when-the-resource-is-discovered).',
20
+ 'image in order to improve LCP. [Learn more about preloading LCP elements](https://web.dev/articles/optimize-lcp#optimize_when_the_resource_is_discovered).',
21
21
  };
22
22
 
23
23
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -19,7 +19,7 @@ const UIStrings = {
19
19
  /** Title of a Lighthouse audit that provides detail on whether all images have explicit width and height. This descriptive title is shown to users when one or more images does not have explicit width and height */
20
20
  failureTitle: 'Image elements do not have explicit `width` and `height`',
21
21
  /** Description of a Lighthouse audit that tells the user why they should include explicit width and height for all images. 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. */
22
- description: 'Set an explicit width and height on image elements to reduce layout shifts and improve CLS. [Learn how to set image dimensions](https://web.dev/optimize-cls/#images-without-dimensions)',
22
+ description: 'Set an explicit width and height on image elements to reduce layout shifts and improve CLS. [Learn how to set image dimensions](https://web.dev/articles/optimize-cls#images_without_dimensions)',
23
23
  };
24
24
 
25
25
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -27,7 +27,7 @@ const UIStrings = {
27
27
  /** Title of a diagnostic audit that provides detail on the main thread work the browser did during a key user interaction. This imperative title is shown to users when there is a significant amount of execution time that could be reduced. */
28
28
  failureTitle: 'Minimize work during key interaction',
29
29
  /** Description of the work-during-interaction metric. This description is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
30
- description: 'This is the thread-blocking work occurring during the Interaction to Next Paint measurement. [Learn more about the Interaction to Next Paint metric](https://web.dev/inp/).',
30
+ description: 'This is the thread-blocking work occurring during the Interaction to Next Paint measurement. [Learn more about the Interaction to Next Paint metric](https://web.dev/articles/inp).',
31
31
  /** Label for a column in a data table; entries will be information on the time that the browser is delayed before responding to user input. Ideally fits within a ~40 character limit. */
32
32
  inputDelay: 'Input delay',
33
33
  /** Label for a column in a data table; entries will be information on the time taken by code processing user input that delays a response to the user. Ideally fits within a ~40 character limit. */
@@ -14,11 +14,10 @@ export function resolveWorkingCopy(config: LH.Config | undefined, context: {
14
14
  * @param {LH.Gatherer.GatherMode} gatherMode
15
15
  * @param {LH.Config=} config
16
16
  * @param {LH.Flags=} flags
17
- * @return {Promise<{resolvedConfig: LH.Config.ResolvedConfig, warnings: string[]}>}
17
+ * @return {Promise<{resolvedConfig: LH.Config.ResolvedConfig}>}
18
18
  */
19
19
  export function initializeConfig(gatherMode: LH.Gatherer.GatherMode, config?: LH.Config | undefined, flags?: LH.Flags | undefined): Promise<{
20
20
  resolvedConfig: LH.Config.ResolvedConfig;
21
- warnings: string[];
22
21
  }>;
23
22
  /**
24
23
  * @param {LH.Config.ResolvedConfig} resolvedConfig