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.
- package/cli/cli-flags.d.ts +5 -1
- package/cli/cli-flags.js +5 -1
- package/cli/test/smokehouse/__snapshots__/report-assert-test.js.snap +2 -2
- package/cli/test/smokehouse/frontends/smokehouse-bin.js +18 -7
- package/cli/test/smokehouse/lighthouse-runners/bundle.d.ts +2 -4
- package/cli/test/smokehouse/lighthouse-runners/bundle.js +8 -4
- package/cli/test/smokehouse/lighthouse-runners/cli.d.ts +2 -4
- package/cli/test/smokehouse/lighthouse-runners/cli.js +5 -3
- package/cli/test/smokehouse/lighthouse-runners/devtools.d.ts +2 -1
- package/cli/test/smokehouse/lighthouse-runners/devtools.js +3 -1
- package/cli/test/smokehouse/smokehouse.d.ts +4 -2
- package/cli/test/smokehouse/smokehouse.js +10 -7
- package/core/audits/byte-efficiency/legacy-javascript.js +2 -2
- package/core/audits/image-size-responsive.js +1 -1
- package/core/audits/layout-shift-elements.js +1 -1
- package/core/audits/lcp-lazy-loaded.js +2 -2
- package/core/audits/long-tasks.js +1 -1
- package/core/audits/metrics/cumulative-layout-shift.js +2 -2
- package/core/audits/metrics/interaction-to-next-paint.js +2 -2
- package/core/audits/metrics/largest-contentful-paint.js +1 -1
- package/core/audits/no-unload-listeners.js +1 -1
- package/core/audits/preload-fonts.js +1 -1
- package/core/audits/prioritize-lcp-image.js +1 -1
- package/core/audits/unsized-images.js +1 -1
- package/core/audits/work-during-interaction.js +1 -1
- package/core/config/config.d.ts +1 -2
- package/core/config/config.js +18 -62
- package/core/config/constants.d.ts +1 -3
- package/core/config/constants.js +4 -18
- package/core/config/default-config.js +8 -8
- package/core/config/filters.d.ts +0 -8
- package/core/config/filters.js +0 -28
- package/core/config/validation.d.ts +4 -15
- package/core/config/validation.js +18 -63
- package/core/gather/base-artifacts.d.ts +2 -2
- package/core/gather/base-artifacts.js +5 -5
- package/core/gather/driver/navigation.d.ts +1 -1
- package/core/gather/driver/navigation.js +1 -1
- package/core/gather/driver/prepare.d.ts +3 -18
- package/core/gather/driver/prepare.js +21 -43
- package/core/gather/driver/storage.d.ts +2 -1
- package/core/gather/driver/storage.js +3 -12
- package/core/gather/gatherers/inspector-issues.js +1 -0
- package/core/gather/navigation-runner.d.ts +3 -31
- package/core/gather/navigation-runner.js +46 -113
- package/core/lib/navigation-error.d.ts +8 -3
- package/core/lib/navigation-error.js +19 -11
- package/dist/report/bundle.esm.js +4 -4
- package/dist/report/flow.js +7 -7
- package/dist/report/standalone.js +5 -5
- package/package.json +8 -8
- package/report/renderer/performance-category-renderer.js +2 -1
- package/shared/localization/locales/ar-XB.json +78 -75
- package/shared/localization/locales/ar.json +78 -75
- package/shared/localization/locales/bg.json +78 -75
- package/shared/localization/locales/ca.json +78 -75
- package/shared/localization/locales/cs.json +78 -75
- package/shared/localization/locales/da.json +78 -75
- package/shared/localization/locales/de.json +81 -78
- package/shared/localization/locales/el.json +84 -81
- package/shared/localization/locales/en-GB.json +78 -75
- package/shared/localization/locales/en-US.json +26 -23
- package/shared/localization/locales/en-XA.json +78 -75
- package/shared/localization/locales/en-XL.json +26 -23
- package/shared/localization/locales/es-419.json +78 -75
- package/shared/localization/locales/es.json +78 -75
- package/shared/localization/locales/fi.json +79 -76
- package/shared/localization/locales/fil.json +78 -75
- package/shared/localization/locales/fr.json +78 -75
- package/shared/localization/locales/he.json +78 -75
- package/shared/localization/locales/hi.json +78 -75
- package/shared/localization/locales/hr.json +78 -75
- package/shared/localization/locales/hu.json +78 -75
- package/shared/localization/locales/id.json +78 -75
- package/shared/localization/locales/it.json +79 -76
- package/shared/localization/locales/ja.json +78 -75
- package/shared/localization/locales/ko.json +78 -75
- package/shared/localization/locales/lt.json +78 -75
- package/shared/localization/locales/lv.json +78 -75
- package/shared/localization/locales/nl.json +78 -75
- package/shared/localization/locales/no.json +78 -75
- package/shared/localization/locales/pl.json +78 -75
- package/shared/localization/locales/pt-PT.json +78 -75
- package/shared/localization/locales/pt.json +79 -76
- package/shared/localization/locales/ro.json +78 -75
- package/shared/localization/locales/ru.json +78 -75
- package/shared/localization/locales/sk.json +78 -75
- package/shared/localization/locales/sl.json +78 -75
- package/shared/localization/locales/sr-Latn.json +78 -75
- package/shared/localization/locales/sr.json +78 -75
- package/shared/localization/locales/sv.json +78 -75
- package/shared/localization/locales/ta.json +78 -75
- package/shared/localization/locales/te.json +78 -75
- package/shared/localization/locales/th.json +78 -75
- package/shared/localization/locales/tr.json +78 -75
- package/shared/localization/locales/uk.json +78 -75
- package/shared/localization/locales/vi.json +78 -75
- package/shared/localization/locales/zh-HK.json +78 -75
- package/shared/localization/locales/zh-TW.json +79 -76
- package/shared/localization/locales/zh.json +78 -75
- package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +1 -0
- package/types/artifacts.d.ts +1 -0
- package/types/config.d.ts +0 -38
- package/types/internal/rxjs.d.ts +4 -0
- package/types/internal/smokehouse.d.ts +10 -5
- package/types/lhr/settings.d.ts +13 -0
|
@@ -89,21 +89,22 @@ async function dismissJavaScriptDialogs(session) {
|
|
|
89
89
|
* Reset the storage and warn if any stored data could be affecting the scores.
|
|
90
90
|
* @param {LH.Gatherer.ProtocolSession} session
|
|
91
91
|
* @param {string} url
|
|
92
|
+
* @param {LH.Config.Settings['clearStorageTypes']} clearStorageTypes
|
|
92
93
|
* @return {Promise<{warnings: Array<LH.IcuMessage>}>}
|
|
93
94
|
*/
|
|
94
|
-
async function resetStorageForUrl(session, url) {
|
|
95
|
+
async function resetStorageForUrl(session, url, clearStorageTypes) {
|
|
95
96
|
/** @type {Array<LH.IcuMessage>} */
|
|
96
97
|
const warnings = [];
|
|
97
98
|
|
|
98
|
-
const
|
|
99
|
-
if (importantStorageWarning) warnings.push(importantStorageWarning);
|
|
100
|
-
|
|
101
|
-
const clearDataWarnings = await storage.clearDataForOrigin(session, url);
|
|
99
|
+
const clearDataWarnings = await storage.clearDataForOrigin(session, url, clearStorageTypes);
|
|
102
100
|
warnings.push(...clearDataWarnings);
|
|
103
101
|
|
|
104
102
|
const clearCacheWarnings = await storage.clearBrowserCaches(session);
|
|
105
103
|
warnings.push(...clearCacheWarnings);
|
|
106
104
|
|
|
105
|
+
const importantStorageWarning = await storage.getImportantStorageWarning(session, url);
|
|
106
|
+
if (importantStorageWarning) warnings.push(importantStorageWarning);
|
|
107
|
+
|
|
107
108
|
return {warnings};
|
|
108
109
|
}
|
|
109
110
|
|
|
@@ -114,21 +115,17 @@ async function resetStorageForUrl(session, url) {
|
|
|
114
115
|
*
|
|
115
116
|
* @param {LH.Gatherer.ProtocolSession} session
|
|
116
117
|
* @param {LH.Config.Settings} settings
|
|
117
|
-
* @param {{disableThrottling: boolean, blockedUrlPatterns?: string[]}} options
|
|
118
118
|
*/
|
|
119
|
-
async function prepareThrottlingAndNetwork(session, settings
|
|
119
|
+
async function prepareThrottlingAndNetwork(session, settings) {
|
|
120
120
|
const status = {msg: 'Preparing network conditions', id: `lh:gather:prepareThrottlingAndNetwork`};
|
|
121
121
|
log.time(status);
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
else await emulation.throttle(session, settings);
|
|
123
|
+
await emulation.throttle(session, settings);
|
|
125
124
|
|
|
126
125
|
// Set request blocking before any network activity.
|
|
127
126
|
// No "clearing" is done at the end of the recording since Network.setBlockedURLs([]) will unset all if
|
|
128
127
|
// neccessary at the beginning of the next section.
|
|
129
|
-
const blockedUrls =
|
|
130
|
-
settings.blockedUrlPatterns || []
|
|
131
|
-
);
|
|
128
|
+
const blockedUrls = settings.blockedUrlPatterns || [];
|
|
132
129
|
await session.sendCommand('Network.setBlockedURLs', {urls: blockedUrls});
|
|
133
130
|
|
|
134
131
|
const headers = settings.extraHeaders;
|
|
@@ -163,10 +160,7 @@ async function prepareTargetForTimespanMode(driver, settings) {
|
|
|
163
160
|
log.time(status);
|
|
164
161
|
|
|
165
162
|
await prepareDeviceEmulation(driver, settings);
|
|
166
|
-
await prepareThrottlingAndNetwork(driver.defaultSession, settings
|
|
167
|
-
disableThrottling: false,
|
|
168
|
-
blockedUrlPatterns: undefined,
|
|
169
|
-
});
|
|
163
|
+
await prepareThrottlingAndNetwork(driver.defaultSession, settings);
|
|
170
164
|
await warmUpIntlSegmenter(driver);
|
|
171
165
|
|
|
172
166
|
log.timeEnd(status);
|
|
@@ -192,11 +186,16 @@ async function warmUpIntlSegmenter(driver) {
|
|
|
192
186
|
*
|
|
193
187
|
* @param {LH.Gatherer.Driver} driver
|
|
194
188
|
* @param {LH.Config.Settings} settings
|
|
189
|
+
* @param {LH.NavigationRequestor} requestor
|
|
190
|
+
* @return {Promise<{warnings: Array<LH.IcuMessage>}>}
|
|
195
191
|
*/
|
|
196
|
-
async function prepareTargetForNavigationMode(driver, settings) {
|
|
192
|
+
async function prepareTargetForNavigationMode(driver, settings, requestor) {
|
|
197
193
|
const status = {msg: 'Preparing target for navigation mode', id: 'lh:prepare:navigationMode'};
|
|
198
194
|
log.time(status);
|
|
199
195
|
|
|
196
|
+
/** @type {Array<LH.IcuMessage>} */
|
|
197
|
+
const warnings = [];
|
|
198
|
+
|
|
200
199
|
await prepareDeviceEmulation(driver, settings);
|
|
201
200
|
|
|
202
201
|
// Automatically handle any JavaScript dialogs to prevent a hung renderer.
|
|
@@ -212,41 +211,21 @@ async function prepareTargetForNavigationMode(driver, settings) {
|
|
|
212
211
|
|
|
213
212
|
await warmUpIntlSegmenter(driver);
|
|
214
213
|
|
|
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
214
|
const shouldResetStorage =
|
|
237
215
|
!settings.disableStorageReset &&
|
|
238
|
-
!navigation.disableStorageReset &&
|
|
239
216
|
// Without prior knowledge of the destination, we cannot know which URL to clear storage for.
|
|
240
217
|
typeof requestor === 'string';
|
|
241
218
|
if (shouldResetStorage) {
|
|
242
|
-
const
|
|
243
|
-
|
|
219
|
+
const {warnings: storageWarnings} = await resetStorageForUrl(driver.defaultSession,
|
|
220
|
+
requestor,
|
|
221
|
+
settings.clearStorageTypes);
|
|
244
222
|
warnings.push(...storageWarnings);
|
|
245
223
|
}
|
|
246
224
|
|
|
247
|
-
await prepareThrottlingAndNetwork(
|
|
225
|
+
await prepareThrottlingAndNetwork(driver.defaultSession, settings);
|
|
248
226
|
|
|
249
227
|
log.timeEnd(status);
|
|
228
|
+
|
|
250
229
|
return {warnings};
|
|
251
230
|
}
|
|
252
231
|
|
|
@@ -254,6 +233,5 @@ export {
|
|
|
254
233
|
prepareThrottlingAndNetwork,
|
|
255
234
|
prepareTargetForTimespanMode,
|
|
256
235
|
prepareTargetForNavigationMode,
|
|
257
|
-
prepareTargetForIndividualNavigation,
|
|
258
236
|
enableAsyncStacks,
|
|
259
237
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @param {LH.Gatherer.ProtocolSession} session
|
|
3
3
|
* @param {string} url
|
|
4
|
+
* @param {LH.Config.Settings['clearStorageTypes']} clearStorageTypes
|
|
4
5
|
* @return {Promise<LH.IcuMessage[]>}
|
|
5
6
|
*/
|
|
6
|
-
export function clearDataForOrigin(session: LH.Gatherer.ProtocolSession, url: string): Promise<LH.IcuMessage[]>;
|
|
7
|
+
export function clearDataForOrigin(session: LH.Gatherer.ProtocolSession, url: string, clearStorageTypes: LH.Config.Settings['clearStorageTypes']): Promise<LH.IcuMessage[]>;
|
|
7
8
|
/**
|
|
8
9
|
* Clear the network cache on disk and in memory.
|
|
9
10
|
* @param {LH.Gatherer.ProtocolSession} session
|
|
@@ -36,9 +36,10 @@ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
|
36
36
|
/**
|
|
37
37
|
* @param {LH.Gatherer.ProtocolSession} session
|
|
38
38
|
* @param {string} url
|
|
39
|
+
* @param {LH.Config.Settings['clearStorageTypes']} clearStorageTypes
|
|
39
40
|
* @return {Promise<LH.IcuMessage[]>}
|
|
40
41
|
*/
|
|
41
|
-
async function clearDataForOrigin(session, url) {
|
|
42
|
+
async function clearDataForOrigin(session, url, clearStorageTypes) {
|
|
42
43
|
const status = {msg: 'Cleaning origin data', id: 'lh:storage:clearDataForOrigin'};
|
|
43
44
|
log.time(status);
|
|
44
45
|
|
|
@@ -46,17 +47,7 @@ async function clearDataForOrigin(session, url) {
|
|
|
46
47
|
|
|
47
48
|
const origin = new URL(url).origin;
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
// Cookies are not cleared, so the user isn't logged out.
|
|
51
|
-
// indexeddb, websql, and localstorage are not cleared to prevent loss of potentially important data.
|
|
52
|
-
// https://chromedevtools.github.io/debugger-protocol-viewer/tot/Storage/#type-StorageType
|
|
53
|
-
const typesToClear = [
|
|
54
|
-
// 'cookies',
|
|
55
|
-
'file_systems',
|
|
56
|
-
'shader_cache',
|
|
57
|
-
'service_workers',
|
|
58
|
-
'cache_storage',
|
|
59
|
-
].join(',');
|
|
50
|
+
const typesToClear = clearStorageTypes.join(',');
|
|
60
51
|
|
|
61
52
|
// `Storage.clearDataForOrigin` is one of our PROTOCOL_TIMEOUT culprits and this command is also
|
|
62
53
|
// run in the context of PAGE_HUNG to cleanup. We'll keep the timeout low and just warn if it fails.
|
|
@@ -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<{
|
|
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<
|
|
62
|
+
* @return {Promise<Partial<LH.GathererArtifacts>>}
|
|
87
63
|
*/
|
|
88
|
-
declare function _computeNavigationResult(navigationContext: NavigationContext, phaseState: PhaseState,
|
|
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
|
-
|
|
54
|
-
|
|
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();
|
|
55
54
|
|
|
56
|
-
|
|
55
|
+
await gotoURL(driver, resolvedConfig.settings.blankPage, {waitUntil: ['navigated']});
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
await driver._networkMonitor?.enable();
|
|
58
|
+
}
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
}
|
|
60
|
+
const baseArtifacts = await getBaseArtifacts(resolvedConfig, driver, {gatherMode: 'navigation'});
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
}
|
|
62
|
+
const {warnings} =
|
|
63
|
+
await prepare.prepareTargetForNavigationMode(driver, resolvedConfig.settings, requestor);
|
|
72
64
|
|
|
73
|
-
|
|
74
|
-
driver.defaultSession,
|
|
75
|
-
resolvedConfig.settings,
|
|
76
|
-
{
|
|
77
|
-
...navigation,
|
|
78
|
-
requestor,
|
|
79
|
-
}
|
|
80
|
-
);
|
|
65
|
+
baseArtifacts.LighthouseRunWarnings.push(...warnings);
|
|
81
66
|
|
|
82
|
-
return {
|
|
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
|
|
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
|
-
...
|
|
102
|
-
|
|
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
|
-
|
|
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,33 @@ 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<
|
|
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
|
-
|
|
158
|
+
ignoreStatusCode: navigationContext.resolvedConfig.settings.ignoreStatusCode,
|
|
178
159
|
networkRecords: debugData.records,
|
|
179
|
-
warnings,
|
|
160
|
+
warnings: navigationContext.baseArtifacts.LighthouseRunWarnings,
|
|
180
161
|
})
|
|
181
162
|
: navigationError;
|
|
182
163
|
|
|
183
164
|
if (pageLoadError) {
|
|
184
165
|
const locale = navigationContext.resolvedConfig.settings.locale;
|
|
185
166
|
const localizedMessage = format.getFormatted(pageLoadError.friendlyMessage, locale);
|
|
186
|
-
log.error('NavigationRunner', localizedMessage,
|
|
167
|
+
log.error('NavigationRunner', localizedMessage, requestedUrl);
|
|
187
168
|
|
|
188
169
|
/** @type {Partial<LH.GathererArtifacts>} */
|
|
189
170
|
const artifacts = {};
|
|
190
|
-
const pageLoadErrorId =
|
|
171
|
+
const pageLoadErrorId = 'pageLoadError-defaultPass';
|
|
191
172
|
if (debugData.devtoolsLog) {
|
|
192
173
|
artifacts.DevtoolsLogError = debugData.devtoolsLog;
|
|
193
174
|
artifacts.devtoolsLogs = {[pageLoadErrorId]: debugData.devtoolsLog};
|
|
@@ -197,20 +178,14 @@ async function _computeNavigationResult(
|
|
|
197
178
|
artifacts.traces = {[pageLoadErrorId]: debugData.trace};
|
|
198
179
|
}
|
|
199
180
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
};
|
|
181
|
+
navigationContext.baseArtifacts.LighthouseRunWarnings.push(pageLoadError.friendlyMessage);
|
|
182
|
+
navigationContext.baseArtifacts.PageLoadError = pageLoadError;
|
|
183
|
+
|
|
184
|
+
return artifacts;
|
|
205
185
|
} else {
|
|
206
186
|
await collectPhaseArtifacts({phase: 'getArtifact', ...phaseState});
|
|
207
187
|
|
|
208
|
-
|
|
209
|
-
return {
|
|
210
|
-
artifacts,
|
|
211
|
-
warnings,
|
|
212
|
-
pageLoadError: undefined,
|
|
213
|
-
};
|
|
188
|
+
return await awaitArtifacts(phaseState.artifactState);
|
|
214
189
|
}
|
|
215
190
|
}
|
|
216
191
|
|
|
@@ -219,6 +194,10 @@ async function _computeNavigationResult(
|
|
|
219
194
|
* @return {ReturnType<typeof _computeNavigationResult>}
|
|
220
195
|
*/
|
|
221
196
|
async function _navigation(navigationContext) {
|
|
197
|
+
if (!navigationContext.resolvedConfig.artifacts) {
|
|
198
|
+
throw new Error('No artifacts were defined on the config');
|
|
199
|
+
}
|
|
200
|
+
|
|
222
201
|
const artifactState = getEmptyArtifactState();
|
|
223
202
|
const phaseState = {
|
|
224
203
|
url: await navigationContext.driver.url(),
|
|
@@ -226,14 +205,12 @@ async function _navigation(navigationContext) {
|
|
|
226
205
|
driver: navigationContext.driver,
|
|
227
206
|
page: navigationContext.page,
|
|
228
207
|
computedCache: navigationContext.computedCache,
|
|
229
|
-
artifactDefinitions: navigationContext.
|
|
208
|
+
artifactDefinitions: navigationContext.resolvedConfig.artifacts,
|
|
230
209
|
artifactState,
|
|
231
210
|
baseArtifacts: navigationContext.baseArtifacts,
|
|
232
211
|
settings: navigationContext.resolvedConfig.settings,
|
|
233
212
|
};
|
|
234
213
|
|
|
235
|
-
const setupResult = await _setupNavigation(navigationContext);
|
|
236
|
-
|
|
237
214
|
const disableAsyncStacks =
|
|
238
215
|
await prepare.enableAsyncStacks(navigationContext.driver.defaultSession);
|
|
239
216
|
|
|
@@ -262,58 +239,7 @@ async function _navigation(navigationContext) {
|
|
|
262
239
|
|
|
263
240
|
await _cleanupNavigation(navigationContext);
|
|
264
241
|
|
|
265
|
-
return _computeNavigationResult(navigationContext, phaseState,
|
|
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}};
|
|
242
|
+
return _computeNavigationResult(navigationContext, phaseState, navigateResult);
|
|
317
243
|
}
|
|
318
244
|
|
|
319
245
|
/**
|
|
@@ -321,7 +247,12 @@ async function _navigations(args) {
|
|
|
321
247
|
*/
|
|
322
248
|
async function _cleanup({requestedUrl, driver, resolvedConfig, lhBrowser, lhPage}) {
|
|
323
249
|
const didResetStorage = !resolvedConfig.settings.disableStorageReset && requestedUrl;
|
|
324
|
-
if (didResetStorage)
|
|
250
|
+
if (didResetStorage) {
|
|
251
|
+
await storage.clearDataForOrigin(driver.defaultSession,
|
|
252
|
+
requestedUrl,
|
|
253
|
+
resolvedConfig.settings.clearStorageTypes
|
|
254
|
+
);
|
|
255
|
+
}
|
|
325
256
|
|
|
326
257
|
await driver.disconnect();
|
|
327
258
|
|
|
@@ -369,11 +300,15 @@ async function navigationGather(page, requestor, options = {}) {
|
|
|
369
300
|
driver,
|
|
370
301
|
lhBrowser,
|
|
371
302
|
lhPage,
|
|
303
|
+
page,
|
|
372
304
|
resolvedConfig,
|
|
373
305
|
requestor: normalizedRequestor,
|
|
306
|
+
computedCache: new Map(),
|
|
374
307
|
};
|
|
375
308
|
const {baseArtifacts} = await _setup(context);
|
|
376
|
-
|
|
309
|
+
|
|
310
|
+
const artifacts = await _navigation({...context, baseArtifacts});
|
|
311
|
+
|
|
377
312
|
await _cleanup(context);
|
|
378
313
|
|
|
379
314
|
return finalizeArtifacts(baseArtifacts, artifacts);
|
|
@@ -386,9 +321,7 @@ async function navigationGather(page, requestor, options = {}) {
|
|
|
386
321
|
export {
|
|
387
322
|
navigationGather,
|
|
388
323
|
_setup,
|
|
389
|
-
_setupNavigation,
|
|
390
324
|
_navigate,
|
|
391
325
|
_navigation,
|
|
392
|
-
_navigations,
|
|
393
326
|
_cleanup,
|
|
394
327
|
};
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Returns an error if the original network request failed or wasn't found.
|
|
3
3
|
* @param {LH.Artifacts.NetworkRequest|undefined} mainRecord
|
|
4
|
+
* @param {{warnings: Array<string | LH.IcuMessage>, ignoreStatusCode?: LH.Config.Settings['ignoreStatusCode']}} context
|
|
4
5
|
* @return {LH.LighthouseError|undefined}
|
|
5
6
|
*/
|
|
6
|
-
export function getNetworkError(mainRecord: LH.Artifacts.NetworkRequest | undefined
|
|
7
|
+
export function getNetworkError(mainRecord: LH.Artifacts.NetworkRequest | undefined, context: {
|
|
8
|
+
warnings: Array<string | LH.IcuMessage>;
|
|
9
|
+
ignoreStatusCode?: LH.Config.Settings['ignoreStatusCode'];
|
|
10
|
+
}): LH.LighthouseError | undefined;
|
|
7
11
|
/**
|
|
8
12
|
* Returns an error if we ended up on the `chrome-error` page and all other requests failed.
|
|
9
13
|
* @param {LH.Artifacts.NetworkRequest|undefined} mainRecord
|
|
@@ -15,12 +19,12 @@ export function getInterstitialError(mainRecord: LH.Artifacts.NetworkRequest | u
|
|
|
15
19
|
* Returns an error if the page load should be considered failed, e.g. from a
|
|
16
20
|
* main document request failure, a security issue, etc.
|
|
17
21
|
* @param {LH.LighthouseError|undefined} navigationError
|
|
18
|
-
* @param {{url: string,
|
|
22
|
+
* @param {{url: string, ignoreStatusCode?: LH.Config.Settings['ignoreStatusCode'], networkRecords: Array<LH.Artifacts.NetworkRequest>, warnings: Array<string | LH.IcuMessage>}} context
|
|
19
23
|
* @return {LH.LighthouseError|undefined}
|
|
20
24
|
*/
|
|
21
25
|
export function getPageLoadError(navigationError: LH.LighthouseError | undefined, context: {
|
|
22
26
|
url: string;
|
|
23
|
-
|
|
27
|
+
ignoreStatusCode?: boolean | undefined;
|
|
24
28
|
networkRecords: Array<LH.Artifacts.NetworkRequest>;
|
|
25
29
|
warnings: Array<string | LH.IcuMessage>;
|
|
26
30
|
}): LH.LighthouseError | undefined;
|
|
@@ -33,6 +37,7 @@ export function getPageLoadError(navigationError: LH.LighthouseError | undefined
|
|
|
33
37
|
export function getNonHtmlError(finalRecord: LH.Artifacts.NetworkRequest | undefined): LH.LighthouseError | undefined;
|
|
34
38
|
export namespace UIStrings {
|
|
35
39
|
const warningXhtml: string;
|
|
40
|
+
const warningStatusCode: string;
|
|
36
41
|
}
|
|
37
42
|
import { NetworkRequest } from './network-request.js';
|
|
38
43
|
import { LighthouseError } from './lh-error.js';
|
|
@@ -16,6 +16,13 @@ const UIStrings = {
|
|
|
16
16
|
*/
|
|
17
17
|
warningXhtml:
|
|
18
18
|
'The page MIME type is XHTML: Lighthouse does not explicitly support this document type',
|
|
19
|
+
/**
|
|
20
|
+
* @description Warning shown in report when the page under test returns an error code, which Lighthouse is not able to reliably load so we display a warning.
|
|
21
|
+
* @example {404} errorCode
|
|
22
|
+
*/
|
|
23
|
+
warningStatusCode: 'Lighthouse was unable to reliably load the page you requested. Make sure' +
|
|
24
|
+
' you are testing the correct URL and that the server is properly responding' +
|
|
25
|
+
' to all requests. (Status code: {errorCode})',
|
|
19
26
|
};
|
|
20
27
|
|
|
21
28
|
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
@@ -27,9 +34,10 @@ const XHTML_MIME_TYPE = 'application/xhtml+xml';
|
|
|
27
34
|
/**
|
|
28
35
|
* Returns an error if the original network request failed or wasn't found.
|
|
29
36
|
* @param {LH.Artifacts.NetworkRequest|undefined} mainRecord
|
|
37
|
+
* @param {{warnings: Array<string | LH.IcuMessage>, ignoreStatusCode?: LH.Config.Settings['ignoreStatusCode']}} context
|
|
30
38
|
* @return {LH.LighthouseError|undefined}
|
|
31
39
|
*/
|
|
32
|
-
function getNetworkError(mainRecord) {
|
|
40
|
+
function getNetworkError(mainRecord, context) {
|
|
33
41
|
if (!mainRecord) {
|
|
34
42
|
return new LighthouseError(LighthouseError.errors.NO_DOCUMENT_REQUEST);
|
|
35
43
|
} else if (mainRecord.failed) {
|
|
@@ -47,9 +55,13 @@ function getNetworkError(mainRecord) {
|
|
|
47
55
|
LighthouseError.errors.FAILED_DOCUMENT_REQUEST, {errorDetails: netErr});
|
|
48
56
|
}
|
|
49
57
|
} else if (mainRecord.hasErrorStatusCode()) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
58
|
+
if (context.ignoreStatusCode) {
|
|
59
|
+
context.warnings.push(str_(UIStrings.warningStatusCode, {errorCode: mainRecord.statusCode}));
|
|
60
|
+
} else {
|
|
61
|
+
return new LighthouseError(LighthouseError.errors.ERRORED_DOCUMENT_REQUEST, {
|
|
62
|
+
statusCode: `${mainRecord.statusCode}`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
53
65
|
}
|
|
54
66
|
}
|
|
55
67
|
|
|
@@ -113,11 +125,11 @@ function getNonHtmlError(finalRecord) {
|
|
|
113
125
|
* Returns an error if the page load should be considered failed, e.g. from a
|
|
114
126
|
* main document request failure, a security issue, etc.
|
|
115
127
|
* @param {LH.LighthouseError|undefined} navigationError
|
|
116
|
-
* @param {{url: string,
|
|
128
|
+
* @param {{url: string, ignoreStatusCode?: LH.Config.Settings['ignoreStatusCode'], networkRecords: Array<LH.Artifacts.NetworkRequest>, warnings: Array<string | LH.IcuMessage>}} context
|
|
117
129
|
* @return {LH.LighthouseError|undefined}
|
|
118
130
|
*/
|
|
119
131
|
function getPageLoadError(navigationError, context) {
|
|
120
|
-
const {url,
|
|
132
|
+
const {url, networkRecords} = context;
|
|
121
133
|
/** @type {LH.Artifacts.NetworkRequest|undefined} */
|
|
122
134
|
let mainRecord = NetworkAnalyzer.findResourceForUrl(networkRecords, url);
|
|
123
135
|
|
|
@@ -144,14 +156,10 @@ function getPageLoadError(navigationError, context) {
|
|
|
144
156
|
context.warnings.push(str_(UIStrings.warningXhtml));
|
|
145
157
|
}
|
|
146
158
|
|
|
147
|
-
const networkError = getNetworkError(mainRecord);
|
|
159
|
+
const networkError = getNetworkError(mainRecord, context);
|
|
148
160
|
const interstitialError = getInterstitialError(mainRecord, networkRecords);
|
|
149
161
|
const nonHtmlError = getNonHtmlError(finalRecord);
|
|
150
162
|
|
|
151
|
-
// Check to see if we need to ignore the page load failure.
|
|
152
|
-
// e.g. When the driver is offline, the load will fail without page offline support.
|
|
153
|
-
if (loadFailureMode === 'ignore') return;
|
|
154
|
-
|
|
155
163
|
// We want to special-case the interstitial beyond FAILED_DOCUMENT_REQUEST. See https://github.com/GoogleChrome/lighthouse/pull/8865#issuecomment-497507618
|
|
156
164
|
if (interstitialError) return interstitialError;
|
|
157
165
|
|