lighthouse 11.2.0-dev.20231016 → 11.2.0-dev.20231018

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 (31) hide show
  1. package/cli/test/smokehouse/frontends/smokehouse-bin.js +18 -7
  2. package/cli/test/smokehouse/lighthouse-runners/bundle.d.ts +2 -4
  3. package/cli/test/smokehouse/lighthouse-runners/bundle.js +8 -4
  4. package/cli/test/smokehouse/lighthouse-runners/cli.d.ts +2 -4
  5. package/cli/test/smokehouse/lighthouse-runners/cli.js +5 -3
  6. package/cli/test/smokehouse/lighthouse-runners/devtools.d.ts +2 -1
  7. package/cli/test/smokehouse/lighthouse-runners/devtools.js +3 -1
  8. package/cli/test/smokehouse/smokehouse.d.ts +4 -2
  9. package/cli/test/smokehouse/smokehouse.js +10 -7
  10. package/core/config/config.d.ts +1 -2
  11. package/core/config/config.js +18 -62
  12. package/core/config/constants.d.ts +1 -3
  13. package/core/config/constants.js +2 -18
  14. package/core/config/default-config.js +3 -3
  15. package/core/config/filters.d.ts +0 -8
  16. package/core/config/filters.js +0 -28
  17. package/core/config/validation.d.ts +4 -15
  18. package/core/config/validation.js +18 -63
  19. package/core/gather/base-artifacts.d.ts +2 -2
  20. package/core/gather/base-artifacts.js +5 -5
  21. package/core/gather/driver/navigation.d.ts +1 -1
  22. package/core/gather/driver/navigation.js +1 -1
  23. package/core/gather/driver/prepare.d.ts +3 -18
  24. package/core/gather/driver/prepare.js +14 -38
  25. package/core/gather/navigation-runner.d.ts +3 -31
  26. package/core/gather/navigation-runner.js +39 -112
  27. package/core/lib/navigation-error.d.ts +1 -2
  28. package/core/lib/navigation-error.js +2 -6
  29. package/package.json +1 -1
  30. package/types/config.d.ts +0 -38
  31. package/types/internal/smokehouse.d.ts +10 -5
@@ -68,43 +68,6 @@ function assertValidArtifact(artifactDefn) {
68
68
  }
69
69
  }
70
70
 
71
- /**
72
- * Throws an error if the provided object does not implement the required navigations interface.
73
- * @param {LH.Config.ResolvedConfig['navigations']} navigationsDefn
74
- * @return {{warnings: string[]}}
75
- */
76
- function assertValidNavigations(navigationsDefn) {
77
- if (!navigationsDefn || !navigationsDefn.length) return {warnings: []};
78
-
79
- /** @type {string[]} */
80
- const warnings = [];
81
-
82
- // Assert that the first navigation has loadFailureMode fatal.
83
- const firstNavigation = navigationsDefn[0];
84
- if (firstNavigation.loadFailureMode !== 'fatal') {
85
- const currentMode = firstNavigation.loadFailureMode;
86
- const warning = [
87
- `"${firstNavigation.id}" is the first navigation but had a failure mode of ${currentMode}.`,
88
- `The first navigation will always be treated as loadFailureMode=fatal.`,
89
- ].join(' ');
90
-
91
- warnings.push(warning);
92
- firstNavigation.loadFailureMode = 'fatal';
93
- }
94
-
95
- // Assert that navigations have unique IDs.
96
- const navigationIds = navigationsDefn.map(navigation => navigation.id);
97
- const duplicateId = navigationIds.find(
98
- (id, i) => navigationIds.slice(i + 1).some(other => id === other)
99
- );
100
-
101
- if (duplicateId) {
102
- throw new Error(`Navigation must have unique identifiers, but "${duplicateId}" was repeated.`);
103
- }
104
-
105
- return {warnings};
106
- }
107
-
108
71
  /**
109
72
  * Throws an error if the provided object does not implement the required properties of an audit
110
73
  * definition.
@@ -223,42 +186,36 @@ function assertValidSettings(settings) {
223
186
  }
224
187
 
225
188
  /**
226
- * Asserts that artifacts are in a valid dependency order that can be computed.
189
+ * Asserts that artifacts are unique, valid and are in a dependency order that can be computed.
227
190
  *
228
- * @param {Array<LH.Config.NavigationDefn>} navigations
191
+ * @param {Array<LH.Config.AnyArtifactDefn>} artifactDefns
229
192
  */
230
- function assertArtifactTopologicalOrder(navigations) {
193
+ function assertValidArtifacts(artifactDefns) {
194
+ /** @type {Set<string>} */
231
195
  const availableArtifacts = new Set();
232
196
 
233
- for (const navigation of navigations) {
234
- for (const artifact of navigation.artifacts) {
235
- availableArtifacts.add(artifact.id);
236
- if (!artifact.dependencies) continue;
197
+ for (const artifact of artifactDefns) {
198
+ assertValidArtifact(artifact);
237
199
 
238
- for (const [dependencyKey, {id: dependencyId}] of Object.entries(artifact.dependencies)) {
239
- if (availableArtifacts.has(dependencyId)) continue;
240
- throwInvalidDependencyOrder(artifact.id, dependencyKey);
241
- }
200
+ if (availableArtifacts.has(artifact.id)) {
201
+ throw new Error(`Config defined multiple artifacts with id '${artifact.id}'`);
202
+ }
203
+
204
+ availableArtifacts.add(artifact.id);
205
+ if (!artifact.dependencies) continue;
206
+
207
+ for (const [dependencyKey, {id: dependencyId}] of Object.entries(artifact.dependencies)) {
208
+ if (availableArtifacts.has(dependencyId)) continue;
209
+ throwInvalidDependencyOrder(artifact.id, dependencyKey);
242
210
  }
243
211
  }
244
212
  }
245
213
 
246
214
  /**
247
215
  * @param {LH.Config.ResolvedConfig} resolvedConfig
248
- * @return {{warnings: string[]}}
249
216
  */
250
217
  function assertValidConfig(resolvedConfig) {
251
- const {warnings} = assertValidNavigations(resolvedConfig.navigations);
252
-
253
- /** @type {Set<string>} */
254
- const artifactIds = new Set();
255
- for (const artifactDefn of resolvedConfig.artifacts || []) {
256
- if (artifactIds.has(artifactDefn.id)) {
257
- throw new Error(`Config defined multiple artifacts with id '${artifactDefn.id}'`);
258
- }
259
- artifactIds.add(artifactDefn.id);
260
- assertValidArtifact(artifactDefn);
261
- }
218
+ assertValidArtifacts(resolvedConfig.artifacts || []);
262
219
 
263
220
  for (const auditDefn of resolvedConfig.audits || []) {
264
221
  assertValidAudit(auditDefn);
@@ -266,7 +223,6 @@ function assertValidConfig(resolvedConfig) {
266
223
 
267
224
  assertValidCategories(resolvedConfig.categories, resolvedConfig.audits, resolvedConfig.groups);
268
225
  assertValidSettings(resolvedConfig.settings);
269
- return {warnings};
270
226
  }
271
227
 
272
228
  /**
@@ -303,11 +259,10 @@ export {
303
259
  isValidArtifactDependency,
304
260
  assertValidPluginName,
305
261
  assertValidArtifact,
306
- assertValidNavigations,
307
262
  assertValidAudit,
308
263
  assertValidCategories,
309
264
  assertValidSettings,
310
- assertArtifactTopologicalOrder,
265
+ assertValidArtifacts,
311
266
  assertValidConfig,
312
267
  throwInvalidDependencyOrder,
313
268
  throwInvalidArtifactDependency,
@@ -9,8 +9,8 @@ export function getBaseArtifacts(resolvedConfig: LH.Config.ResolvedConfig, drive
9
9
  }): Promise<LH.BaseArtifacts>;
10
10
  /**
11
11
  * @param {LH.BaseArtifacts} baseArtifacts
12
- * @param {Partial<LH.Artifacts>} gathererArtifacts
12
+ * @param {Partial<LH.GathererArtifacts>} gathererArtifacts
13
13
  * @return {LH.Artifacts}
14
14
  */
15
- export function finalizeArtifacts(baseArtifacts: LH.BaseArtifacts, gathererArtifacts: Partial<LH.Artifacts>): LH.Artifacts;
15
+ export function finalizeArtifacts(baseArtifacts: LH.BaseArtifacts, gathererArtifacts: Partial<LH.GathererArtifacts>): LH.Artifacts;
16
16
  //# sourceMappingURL=base-artifacts.d.ts.map
@@ -60,20 +60,20 @@ function deduplicateWarnings(warnings) {
60
60
 
61
61
  /**
62
62
  * @param {LH.BaseArtifacts} baseArtifacts
63
- * @param {Partial<LH.Artifacts>} gathererArtifacts
63
+ * @param {Partial<LH.GathererArtifacts>} gathererArtifacts
64
64
  * @return {LH.Artifacts}
65
65
  */
66
66
  function finalizeArtifacts(baseArtifacts, gathererArtifacts) {
67
- const warnings = baseArtifacts.LighthouseRunWarnings
68
- .concat(gathererArtifacts.LighthouseRunWarnings || [])
69
- .concat(getEnvironmentWarnings({settings: baseArtifacts.settings, baseArtifacts}));
67
+ baseArtifacts.LighthouseRunWarnings.push(
68
+ ...getEnvironmentWarnings({settings: baseArtifacts.settings, baseArtifacts})
69
+ );
70
70
 
71
71
  // Cast to remove the partial from gathererArtifacts.
72
72
  const artifacts = /** @type {LH.Artifacts} */ ({...baseArtifacts, ...gathererArtifacts});
73
73
 
74
74
  // Set the post-run meta artifacts.
75
75
  artifacts.Timing = log.getTimeEntries();
76
- artifacts.LighthouseRunWarnings = deduplicateWarnings(warnings);
76
+ artifacts.LighthouseRunWarnings = deduplicateWarnings(baseArtifacts.LighthouseRunWarnings);
77
77
 
78
78
  if (artifacts.PageLoadError && !artifacts.URL.finalDisplayedUrl) {
79
79
  artifacts.URL.finalDisplayedUrl = artifacts.URL.requestedUrl || '';
@@ -1,6 +1,6 @@
1
1
  export type NavigationOptions = {
2
2
  waitUntil: Array<'fcp' | 'load' | 'navigated'>;
3
- } & LH.Config.SharedPassNavigationJson & Partial<Pick<LH.Config.Settings, 'maxWaitForFcp' | 'maxWaitForLoad' | 'debugNavigation'>>;
3
+ } & Partial<LH.Config.Settings>;
4
4
  /**
5
5
  * Navigates to the given URL, assuming that the page is not already on this URL.
6
6
  * Resolves on the url of the loaded page, taking into account any redirects.
@@ -39,7 +39,7 @@ const DEFAULT_NETWORK_QUIET_THRESHOLD = 5000;
39
39
  // Controls how long to wait between longtasks before determining the CPU is idle, off by default
40
40
  const DEFAULT_CPU_QUIET_THRESHOLD = 0;
41
41
 
42
- /** @typedef {{waitUntil: Array<'fcp'|'load'|'navigated'>} & LH.Config.SharedPassNavigationJson & Partial<Pick<LH.Config.Settings, 'maxWaitForFcp'|'maxWaitForLoad'|'debugNavigation'>>} NavigationOptions */
42
+ /** @typedef {{waitUntil: Array<'fcp'|'load'|'navigated'>} & Partial<LH.Config.Settings>} NavigationOptions */
43
43
 
44
44
  /** @param {NavigationOptions} options */
45
45
  function resolveWaitForFullyLoadedOptions(options) {
@@ -5,12 +5,8 @@
5
5
  *
6
6
  * @param {LH.Gatherer.ProtocolSession} session
7
7
  * @param {LH.Config.Settings} settings
8
- * @param {{disableThrottling: boolean, blockedUrlPatterns?: string[]}} options
9
8
  */
10
- export function prepareThrottlingAndNetwork(session: LH.Gatherer.ProtocolSession, settings: LH.Config.Settings, options: {
11
- disableThrottling: boolean;
12
- blockedUrlPatterns?: string[];
13
- }): Promise<void>;
9
+ export function prepareThrottlingAndNetwork(session: LH.Gatherer.ProtocolSession, settings: LH.Config.Settings): Promise<void>;
14
10
  /**
15
11
  * Prepares a target to be analyzed in timespan mode by enabling protocol domains, emulation, and throttling.
16
12
  *
@@ -26,21 +22,10 @@ export function prepareTargetForTimespanMode(driver: LH.Gatherer.Driver, setting
26
22
  *
27
23
  * @param {LH.Gatherer.Driver} driver
28
24
  * @param {LH.Config.Settings} settings
29
- */
30
- export function prepareTargetForNavigationMode(driver: LH.Gatherer.Driver, settings: LH.Config.Settings): Promise<void>;
31
- /**
32
- * Prepares a target for a particular navigation by resetting storage and setting network.
33
- *
34
- * This method assumes `prepareTargetForNavigationMode` has already been invoked.
35
- *
36
- * @param {LH.Gatherer.ProtocolSession} session
37
- * @param {LH.Config.Settings} settings
38
- * @param {Pick<LH.Config.NavigationDefn, 'disableThrottling'|'disableStorageReset'|'blockedUrlPatterns'> & {requestor: LH.NavigationRequestor}} navigation
25
+ * @param {LH.NavigationRequestor} requestor
39
26
  * @return {Promise<{warnings: Array<LH.IcuMessage>}>}
40
27
  */
41
- export function prepareTargetForIndividualNavigation(session: LH.Gatherer.ProtocolSession, settings: LH.Config.Settings, navigation: Pick<import("../../../types/config.js").default.NavigationDefn, "blockedUrlPatterns" | "disableStorageReset" | "disableThrottling"> & {
42
- requestor: LH.NavigationRequestor;
43
- }): Promise<{
28
+ export function prepareTargetForNavigationMode(driver: LH.Gatherer.Driver, settings: LH.Config.Settings, requestor: LH.NavigationRequestor): Promise<{
44
29
  warnings: Array<LH.IcuMessage>;
45
30
  }>;
46
31
  /**
@@ -114,21 +114,17 @@ async function resetStorageForUrl(session, url) {
114
114
  *
115
115
  * @param {LH.Gatherer.ProtocolSession} session
116
116
  * @param {LH.Config.Settings} settings
117
- * @param {{disableThrottling: boolean, blockedUrlPatterns?: string[]}} options
118
117
  */
119
- async function prepareThrottlingAndNetwork(session, settings, options) {
118
+ async function prepareThrottlingAndNetwork(session, settings) {
120
119
  const status = {msg: 'Preparing network conditions', id: `lh:gather:prepareThrottlingAndNetwork`};
121
120
  log.time(status);
122
121
 
123
- if (options.disableThrottling) await emulation.clearThrottling(session);
124
- else await emulation.throttle(session, settings);
122
+ await emulation.throttle(session, settings);
125
123
 
126
124
  // Set request blocking before any network activity.
127
125
  // No "clearing" is done at the end of the recording since Network.setBlockedURLs([]) will unset all if
128
126
  // neccessary at the beginning of the next section.
129
- const blockedUrls = (options.blockedUrlPatterns || []).concat(
130
- settings.blockedUrlPatterns || []
131
- );
127
+ const blockedUrls = settings.blockedUrlPatterns || [];
132
128
  await session.sendCommand('Network.setBlockedURLs', {urls: blockedUrls});
133
129
 
134
130
  const headers = settings.extraHeaders;
@@ -163,10 +159,7 @@ async function prepareTargetForTimespanMode(driver, settings) {
163
159
  log.time(status);
164
160
 
165
161
  await prepareDeviceEmulation(driver, settings);
166
- await prepareThrottlingAndNetwork(driver.defaultSession, settings, {
167
- disableThrottling: false,
168
- blockedUrlPatterns: undefined,
169
- });
162
+ await prepareThrottlingAndNetwork(driver.defaultSession, settings);
170
163
  await warmUpIntlSegmenter(driver);
171
164
 
172
165
  log.timeEnd(status);
@@ -192,11 +185,16 @@ async function warmUpIntlSegmenter(driver) {
192
185
  *
193
186
  * @param {LH.Gatherer.Driver} driver
194
187
  * @param {LH.Config.Settings} settings
188
+ * @param {LH.NavigationRequestor} requestor
189
+ * @return {Promise<{warnings: Array<LH.IcuMessage>}>}
195
190
  */
196
- async function prepareTargetForNavigationMode(driver, settings) {
191
+ async function prepareTargetForNavigationMode(driver, settings, requestor) {
197
192
  const status = {msg: 'Preparing target for navigation mode', id: 'lh:prepare:navigationMode'};
198
193
  log.time(status);
199
194
 
195
+ /** @type {Array<LH.IcuMessage>} */
196
+ const warnings = [];
197
+
200
198
  await prepareDeviceEmulation(driver, settings);
201
199
 
202
200
  // Automatically handle any JavaScript dialogs to prevent a hung renderer.
@@ -212,41 +210,20 @@ async function prepareTargetForNavigationMode(driver, settings) {
212
210
 
213
211
  await warmUpIntlSegmenter(driver);
214
212
 
215
- log.timeEnd(status);
216
- }
217
-
218
- /**
219
- * Prepares a target for a particular navigation by resetting storage and setting network.
220
- *
221
- * This method assumes `prepareTargetForNavigationMode` has already been invoked.
222
- *
223
- * @param {LH.Gatherer.ProtocolSession} session
224
- * @param {LH.Config.Settings} settings
225
- * @param {Pick<LH.Config.NavigationDefn, 'disableThrottling'|'disableStorageReset'|'blockedUrlPatterns'> & {requestor: LH.NavigationRequestor}} navigation
226
- * @return {Promise<{warnings: Array<LH.IcuMessage>}>}
227
- */
228
- async function prepareTargetForIndividualNavigation(session, settings, navigation) {
229
- const status = {msg: 'Preparing target for navigation', id: 'lh:prepare:navigation'};
230
- log.time(status);
231
-
232
- /** @type {Array<LH.IcuMessage>} */
233
- const warnings = [];
234
-
235
- const {requestor} = navigation;
236
213
  const shouldResetStorage =
237
214
  !settings.disableStorageReset &&
238
- !navigation.disableStorageReset &&
239
215
  // Without prior knowledge of the destination, we cannot know which URL to clear storage for.
240
216
  typeof requestor === 'string';
241
217
  if (shouldResetStorage) {
242
- const requestedUrl = requestor;
243
- const {warnings: storageWarnings} = await resetStorageForUrl(session, requestedUrl);
218
+ const {warnings: storageWarnings} =
219
+ await resetStorageForUrl(driver.defaultSession, requestor);
244
220
  warnings.push(...storageWarnings);
245
221
  }
246
222
 
247
- await prepareThrottlingAndNetwork(session, settings, navigation);
223
+ await prepareThrottlingAndNetwork(driver.defaultSession, settings);
248
224
 
249
225
  log.timeEnd(status);
226
+
250
227
  return {warnings};
251
228
  }
252
229
 
@@ -254,6 +231,5 @@ export {
254
231
  prepareThrottlingAndNetwork,
255
232
  prepareTargetForTimespanMode,
256
233
  prepareTargetForNavigationMode,
257
- prepareTargetForIndividualNavigation,
258
234
  enableAsyncStacks,
259
235
  };
@@ -2,7 +2,6 @@ export type NavigationContext = {
2
2
  driver: Driver;
3
3
  page: LH.Puppeteer.Page;
4
4
  resolvedConfig: LH.Config.ResolvedConfig;
5
- navigation: LH.Config.NavigationDefn;
6
5
  requestor: LH.NavigationRequestor;
7
6
  baseArtifacts: LH.BaseArtifacts;
8
7
  computedCache: Map<string, LH.ArbitraryEqualityMap>;
@@ -31,40 +30,18 @@ export function _setup({ driver, resolvedConfig, requestor }: {
31
30
  }>;
32
31
  /**
33
32
  * @param {NavigationContext} navigationContext
34
- * @return {Promise<{warnings: Array<LH.IcuMessage>}>}
35
- */
36
- export function _setupNavigation({ requestor, driver, navigation, resolvedConfig }: NavigationContext): Promise<{
37
- warnings: Array<LH.IcuMessage>;
38
- }>;
39
- /**
40
- * @param {NavigationContext} navigationContext
41
- * @return {Promise<{requestedUrl: string, mainDocumentUrl: string, navigationError: LH.LighthouseError | undefined, warnings: Array<LH.IcuMessage>}>}
33
+ * @return {Promise<{requestedUrl: string, mainDocumentUrl: string, navigationError: LH.LighthouseError | undefined}>}
42
34
  */
43
35
  export function _navigate(navigationContext: NavigationContext): Promise<{
44
36
  requestedUrl: string;
45
37
  mainDocumentUrl: string;
46
38
  navigationError: LH.LighthouseError | undefined;
47
- warnings: Array<LH.IcuMessage>;
48
39
  }>;
49
40
  /**
50
41
  * @param {NavigationContext} navigationContext
51
42
  * @return {ReturnType<typeof _computeNavigationResult>}
52
43
  */
53
44
  export function _navigation(navigationContext: NavigationContext): ReturnType<typeof _computeNavigationResult>;
54
- /**
55
- * @param {{driver: Driver, page: LH.Puppeteer.Page, resolvedConfig: LH.Config.ResolvedConfig, requestor: LH.NavigationRequestor; baseArtifacts: LH.BaseArtifacts, computedCache: NavigationContext['computedCache']}} args
56
- * @return {Promise<{artifacts: Partial<LH.Artifacts & LH.BaseArtifacts>}>}
57
- */
58
- export function _navigations(args: {
59
- driver: Driver;
60
- page: LH.Puppeteer.Page;
61
- resolvedConfig: LH.Config.ResolvedConfig;
62
- requestor: LH.NavigationRequestor;
63
- baseArtifacts: LH.BaseArtifacts;
64
- computedCache: NavigationContext['computedCache'];
65
- }): Promise<{
66
- artifacts: Partial<LH.Artifacts & LH.BaseArtifacts>;
67
- }>;
68
45
  /**
69
46
  * @param {{requestedUrl?: string, driver: Driver, resolvedConfig: LH.Config.ResolvedConfig, lhBrowser?: LH.Puppeteer.Browser, lhPage?: LH.Puppeteer.Page}} args
70
47
  */
@@ -81,14 +58,9 @@ import { LighthouseError } from '../lib/lh-error.js';
81
58
  /**
82
59
  * @param {NavigationContext} navigationContext
83
60
  * @param {PhaseState} phaseState
84
- * @param {Awaited<ReturnType<typeof _setupNavigation>>} setupResult
85
61
  * @param {Awaited<ReturnType<typeof _navigate>>} navigateResult
86
- * @return {Promise<{artifacts: Partial<LH.GathererArtifacts>, warnings: Array<LH.IcuMessage>, pageLoadError: LH.LighthouseError | undefined}>}
62
+ * @return {Promise<Partial<LH.GathererArtifacts>>}
87
63
  */
88
- declare function _computeNavigationResult(navigationContext: NavigationContext, phaseState: PhaseState, setupResult: Awaited<ReturnType<typeof _setupNavigation>>, navigateResult: Awaited<ReturnType<typeof _navigate>>): Promise<{
89
- artifacts: Partial<LH.GathererArtifacts>;
90
- warnings: Array<LH.IcuMessage>;
91
- pageLoadError: LH.LighthouseError | undefined;
92
- }>;
64
+ declare function _computeNavigationResult(navigationContext: NavigationContext, phaseState: PhaseState, navigateResult: Awaited<ReturnType<typeof _navigate>>): Promise<Partial<LH.GathererArtifacts>>;
93
65
  export {};
94
66
  //# sourceMappingURL=navigation-runner.d.ts.map
@@ -14,7 +14,6 @@ import * as prepare from './driver/prepare.js';
14
14
  import {gotoURL} from './driver/navigation.js';
15
15
  import * as storage from './driver/storage.js';
16
16
  import * as emulation from '../lib/emulation.js';
17
- import {defaultNavigationConfig} from '../config/constants.js';
18
17
  import {initializeConfig} from '../config/config.js';
19
18
  import {getBaseArtifacts, finalizeArtifacts} from './base-artifacts.js';
20
19
  import * as format from '../../shared/localization/format.js';
@@ -30,7 +29,6 @@ import {NetworkRecords} from '../computed/network-records.js';
30
29
  * @property {Driver} driver
31
30
  * @property {LH.Puppeteer.Page} page
32
31
  * @property {LH.Config.ResolvedConfig} resolvedConfig
33
- * @property {LH.Config.NavigationDefn} navigation
34
32
  * @property {LH.NavigationRequestor} requestor
35
33
  * @property {LH.BaseArtifacts} baseArtifacts
36
34
  * @property {Map<string, LH.ArbitraryEqualityMap>} computedCache
@@ -50,36 +48,23 @@ async function _setup({driver, resolvedConfig, requestor}) {
50
48
 
51
49
  // We can't trigger the navigation through user interaction if we reset the page before starting.
52
50
  if (typeof requestor === 'string' && !resolvedConfig.settings.skipAboutBlank) {
53
- await gotoURL(driver, defaultNavigationConfig.blankPage, {waitUntil: ['navigated']});
51
+ // Disable network monitor on the blank page to prevent it from picking up network requests and
52
+ // frame navigated events before the run starts.
53
+ await driver._networkMonitor?.disable();
54
+
55
+ await gotoURL(driver, resolvedConfig.settings.blankPage, {waitUntil: ['navigated']});
56
+
57
+ await driver._networkMonitor?.enable();
54
58
  }
55
59
 
56
60
  const baseArtifacts = await getBaseArtifacts(resolvedConfig, driver, {gatherMode: 'navigation'});
57
61
 
58
- await prepare.prepareTargetForNavigationMode(driver, resolvedConfig.settings);
59
-
60
- return {baseArtifacts};
61
- }
62
+ const {warnings} =
63
+ await prepare.prepareTargetForNavigationMode(driver, resolvedConfig.settings, requestor);
62
64
 
63
- /**
64
- * @param {NavigationContext} navigationContext
65
- * @return {Promise<{warnings: Array<LH.IcuMessage>}>}
66
- */
67
- async function _setupNavigation({requestor, driver, navigation, resolvedConfig}) {
68
- // We can't trigger the navigation through user interaction if we reset the page before starting.
69
- if (typeof requestor === 'string' && !resolvedConfig.settings.skipAboutBlank) {
70
- await gotoURL(driver, navigation.blankPage, {...navigation, waitUntil: ['navigated']});
71
- }
65
+ baseArtifacts.LighthouseRunWarnings.push(...warnings);
72
66
 
73
- const {warnings} = await prepare.prepareTargetForIndividualNavigation(
74
- driver.defaultSession,
75
- resolvedConfig.settings,
76
- {
77
- ...navigation,
78
- requestor,
79
- }
80
- );
81
-
82
- return {warnings};
67
+ return {baseArtifacts};
83
68
  }
84
69
 
85
70
  /**
@@ -91,20 +76,20 @@ async function _cleanupNavigation({driver}) {
91
76
 
92
77
  /**
93
78
  * @param {NavigationContext} navigationContext
94
- * @return {Promise<{requestedUrl: string, mainDocumentUrl: string, navigationError: LH.LighthouseError | undefined, warnings: Array<LH.IcuMessage>}>}
79
+ * @return {Promise<{requestedUrl: string, mainDocumentUrl: string, navigationError: LH.LighthouseError | undefined}>}
95
80
  */
96
81
  async function _navigate(navigationContext) {
97
82
  const {driver, resolvedConfig, requestor} = navigationContext;
98
83
 
99
84
  try {
100
85
  const {requestedUrl, mainDocumentUrl, warnings} = await gotoURL(driver, requestor, {
101
- ...navigationContext.navigation,
102
- debugNavigation: resolvedConfig.settings.debugNavigation,
103
- maxWaitForFcp: resolvedConfig.settings.maxWaitForFcp,
104
- maxWaitForLoad: resolvedConfig.settings.maxWaitForLoad,
105
- waitUntil: navigationContext.navigation.pauseAfterFcpMs ? ['fcp', 'load'] : ['load'],
86
+ ...resolvedConfig.settings,
87
+ waitUntil: resolvedConfig.settings.pauseAfterFcpMs ? ['fcp', 'load'] : ['load'],
106
88
  });
107
- return {requestedUrl, mainDocumentUrl, navigationError: undefined, warnings};
89
+
90
+ navigationContext.baseArtifacts.LighthouseRunWarnings.push(...warnings);
91
+
92
+ return {requestedUrl, mainDocumentUrl, navigationError: undefined};
108
93
  } catch (err) {
109
94
  if (!(err instanceof LighthouseError)) throw err;
110
95
  if (err.code !== 'NO_FCP' && err.code !== 'PAGE_HUNG') throw err;
@@ -115,7 +100,6 @@ async function _navigate(navigationContext) {
115
100
  requestedUrl: requestor,
116
101
  mainDocumentUrl: requestor,
117
102
  navigationError: err,
118
- warnings: [],
119
103
  };
120
104
  }
121
105
  }
@@ -158,36 +142,32 @@ async function _collectDebugData(navigationContext, phaseState) {
158
142
  /**
159
143
  * @param {NavigationContext} navigationContext
160
144
  * @param {PhaseState} phaseState
161
- * @param {Awaited<ReturnType<typeof _setupNavigation>>} setupResult
162
145
  * @param {Awaited<ReturnType<typeof _navigate>>} navigateResult
163
- * @return {Promise<{artifacts: Partial<LH.GathererArtifacts>, warnings: Array<LH.IcuMessage>, pageLoadError: LH.LighthouseError | undefined}>}
146
+ * @return {Promise<Partial<LH.GathererArtifacts>>}
164
147
  */
165
148
  async function _computeNavigationResult(
166
149
  navigationContext,
167
150
  phaseState,
168
- setupResult,
169
151
  navigateResult
170
152
  ) {
171
- const {navigationError, mainDocumentUrl} = navigateResult;
172
- const warnings = [...setupResult.warnings, ...navigateResult.warnings];
153
+ const {navigationError, requestedUrl, mainDocumentUrl} = navigateResult;
173
154
  const debugData = await _collectDebugData(navigationContext, phaseState);
174
155
  const pageLoadError = debugData.records
175
156
  ? getPageLoadError(navigationError, {
176
157
  url: mainDocumentUrl,
177
- loadFailureMode: navigationContext.navigation.loadFailureMode,
178
158
  networkRecords: debugData.records,
179
- warnings,
159
+ warnings: navigationContext.baseArtifacts.LighthouseRunWarnings,
180
160
  })
181
161
  : navigationError;
182
162
 
183
163
  if (pageLoadError) {
184
164
  const locale = navigationContext.resolvedConfig.settings.locale;
185
165
  const localizedMessage = format.getFormatted(pageLoadError.friendlyMessage, locale);
186
- log.error('NavigationRunner', localizedMessage, navigateResult.requestedUrl);
166
+ log.error('NavigationRunner', localizedMessage, requestedUrl);
187
167
 
188
168
  /** @type {Partial<LH.GathererArtifacts>} */
189
169
  const artifacts = {};
190
- const pageLoadErrorId = `pageLoadError-${navigationContext.navigation.id}`;
170
+ const pageLoadErrorId = 'pageLoadError-defaultPass';
191
171
  if (debugData.devtoolsLog) {
192
172
  artifacts.DevtoolsLogError = debugData.devtoolsLog;
193
173
  artifacts.devtoolsLogs = {[pageLoadErrorId]: debugData.devtoolsLog};
@@ -197,20 +177,14 @@ async function _computeNavigationResult(
197
177
  artifacts.traces = {[pageLoadErrorId]: debugData.trace};
198
178
  }
199
179
 
200
- return {
201
- pageLoadError,
202
- artifacts,
203
- warnings: [...warnings, pageLoadError.friendlyMessage],
204
- };
180
+ navigationContext.baseArtifacts.LighthouseRunWarnings.push(pageLoadError.friendlyMessage);
181
+ navigationContext.baseArtifacts.PageLoadError = pageLoadError;
182
+
183
+ return artifacts;
205
184
  } else {
206
185
  await collectPhaseArtifacts({phase: 'getArtifact', ...phaseState});
207
186
 
208
- const artifacts = await awaitArtifacts(phaseState.artifactState);
209
- return {
210
- artifacts,
211
- warnings,
212
- pageLoadError: undefined,
213
- };
187
+ return await awaitArtifacts(phaseState.artifactState);
214
188
  }
215
189
  }
216
190
 
@@ -219,6 +193,10 @@ async function _computeNavigationResult(
219
193
  * @return {ReturnType<typeof _computeNavigationResult>}
220
194
  */
221
195
  async function _navigation(navigationContext) {
196
+ if (!navigationContext.resolvedConfig.artifacts) {
197
+ throw new Error('No artifacts were defined on the config');
198
+ }
199
+
222
200
  const artifactState = getEmptyArtifactState();
223
201
  const phaseState = {
224
202
  url: await navigationContext.driver.url(),
@@ -226,14 +204,12 @@ async function _navigation(navigationContext) {
226
204
  driver: navigationContext.driver,
227
205
  page: navigationContext.page,
228
206
  computedCache: navigationContext.computedCache,
229
- artifactDefinitions: navigationContext.navigation.artifacts,
207
+ artifactDefinitions: navigationContext.resolvedConfig.artifacts,
230
208
  artifactState,
231
209
  baseArtifacts: navigationContext.baseArtifacts,
232
210
  settings: navigationContext.resolvedConfig.settings,
233
211
  };
234
212
 
235
- const setupResult = await _setupNavigation(navigationContext);
236
-
237
213
  const disableAsyncStacks =
238
214
  await prepare.enableAsyncStacks(navigationContext.driver.defaultSession);
239
215
 
@@ -262,58 +238,7 @@ async function _navigation(navigationContext) {
262
238
 
263
239
  await _cleanupNavigation(navigationContext);
264
240
 
265
- return _computeNavigationResult(navigationContext, phaseState, setupResult, navigateResult);
266
- }
267
-
268
- /**
269
- * @param {{driver: Driver, page: LH.Puppeteer.Page, resolvedConfig: LH.Config.ResolvedConfig, requestor: LH.NavigationRequestor; baseArtifacts: LH.BaseArtifacts, computedCache: NavigationContext['computedCache']}} args
270
- * @return {Promise<{artifacts: Partial<LH.Artifacts & LH.BaseArtifacts>}>}
271
- */
272
- async function _navigations(args) {
273
- const {
274
- driver,
275
- page,
276
- resolvedConfig,
277
- requestor,
278
- baseArtifacts,
279
- computedCache,
280
- } = args;
281
-
282
- if (!resolvedConfig.artifacts || !resolvedConfig.navigations) {
283
- throw new Error('No artifacts were defined on the config');
284
- }
285
-
286
- /** @type {Partial<LH.Artifacts & LH.BaseArtifacts>} */
287
- const artifacts = {};
288
- /** @type {Array<LH.IcuMessage>} */
289
- const LighthouseRunWarnings = [];
290
-
291
- for (const navigation of resolvedConfig.navigations) {
292
- const navigationContext = {
293
- driver,
294
- page,
295
- navigation,
296
- requestor,
297
- resolvedConfig,
298
- baseArtifacts,
299
- computedCache,
300
- };
301
-
302
- let shouldHaltNavigations = false;
303
- const navigationResult = await _navigation(navigationContext);
304
- if (navigation.loadFailureMode === 'fatal') {
305
- if (navigationResult.pageLoadError) {
306
- artifacts.PageLoadError = navigationResult.pageLoadError;
307
- shouldHaltNavigations = true;
308
- }
309
- }
310
-
311
- LighthouseRunWarnings.push(...navigationResult.warnings);
312
- Object.assign(artifacts, navigationResult.artifacts);
313
- if (shouldHaltNavigations) break;
314
- }
315
-
316
- return {artifacts: {...artifacts, LighthouseRunWarnings}};
241
+ return _computeNavigationResult(navigationContext, phaseState, navigateResult);
317
242
  }
318
243
 
319
244
  /**
@@ -369,11 +294,15 @@ async function navigationGather(page, requestor, options = {}) {
369
294
  driver,
370
295
  lhBrowser,
371
296
  lhPage,
297
+ page,
372
298
  resolvedConfig,
373
299
  requestor: normalizedRequestor,
300
+ computedCache: new Map(),
374
301
  };
375
302
  const {baseArtifacts} = await _setup(context);
376
- const {artifacts} = await _navigations({...context, page, baseArtifacts, computedCache});
303
+
304
+ const artifacts = await _navigation({...context, baseArtifacts});
305
+
377
306
  await _cleanup(context);
378
307
 
379
308
  return finalizeArtifacts(baseArtifacts, artifacts);
@@ -386,9 +315,7 @@ async function navigationGather(page, requestor, options = {}) {
386
315
  export {
387
316
  navigationGather,
388
317
  _setup,
389
- _setupNavigation,
390
318
  _navigate,
391
319
  _navigation,
392
- _navigations,
393
320
  _cleanup,
394
321
  };