lighthouse 11.6.0-dev.20240225 → 11.6.0-dev.20240226

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.
@@ -53,9 +53,10 @@ export class ExecutionContext {
53
53
  * page without isolation.
54
54
  * @param {string} expression
55
55
  * @param {number|undefined} contextId
56
+ * @param {number} timeout
56
57
  * @return {Promise<*>}
57
58
  */
58
- _evaluateInContext(expression: string, contextId: number | undefined): Promise<any>;
59
+ _evaluateInContext(expression: string, contextId: number | undefined, timeout: number): Promise<any>;
59
60
  /**
60
61
  * Note: Prefer `evaluate` instead.
61
62
  * Evaluate an expression in the context of the current page. If useIsolation is true, the expression
@@ -80,15 +80,10 @@ class ExecutionContext {
80
80
  * page without isolation.
81
81
  * @param {string} expression
82
82
  * @param {number|undefined} contextId
83
+ * @param {number} timeout
83
84
  * @return {Promise<*>}
84
85
  */
85
- async _evaluateInContext(expression, contextId) {
86
- // Use a higher than default timeout if the user hasn't specified a specific timeout.
87
- // Otherwise, use whatever was requested.
88
- const timeout = this._session.hasNextProtocolTimeout() ?
89
- this._session.getNextProtocolTimeout() :
90
- 60000;
91
-
86
+ async _evaluateInContext(expression, contextId, timeout) {
92
87
  // `__lighthouseExecutionContextUniqueIdentifier` is only used by the FullPageScreenshot gatherer.
93
88
  // See `getNodeDetails` in page-functions.
94
89
  const uniqueExecutionContextIdentifier = contextId === undefined ?
@@ -166,17 +161,22 @@ class ExecutionContext {
166
161
  * @return {Promise<*>}
167
162
  */
168
163
  async evaluateAsync(expression, options = {}) {
164
+ // Use a higher than default timeout if the user hasn't specified a specific timeout.
165
+ // Otherwise, use whatever was requested.
166
+ const timeout = this._session.hasNextProtocolTimeout() ?
167
+ this._session.getNextProtocolTimeout() :
168
+ 60000;
169
169
  const contextId = options.useIsolation ? await this._getOrCreateIsolatedContextId() : undefined;
170
170
 
171
171
  try {
172
172
  // `await` is not redundant here because we want to `catch` the async errors
173
- return await this._evaluateInContext(expression, contextId);
173
+ return await this._evaluateInContext(expression, contextId, timeout);
174
174
  } catch (err) {
175
175
  // If we were using isolation and the context disappeared on us, retry one more time.
176
176
  if (contextId && err.message.includes('Cannot find context')) {
177
177
  this.clearContextId();
178
178
  const freshContextId = await this._getOrCreateIsolatedContextId();
179
- return this._evaluateInContext(expression, freshContextId);
179
+ return this._evaluateInContext(expression, freshContextId, timeout);
180
180
  }
181
181
 
182
182
  throw err;
@@ -497,8 +497,10 @@ async function waitForFullyLoaded(session, networkMonitor, options) {
497
497
  log.warn('waitFor', 'Timed out waiting for page load. Checking if page is hung...');
498
498
  if (await isPageHung(session)) {
499
499
  log.warn('waitFor', 'Page appears to be hung, killing JavaScript...');
500
- await session.sendCommand('Emulation.setScriptExecutionDisabled', {value: true});
501
- await session.sendCommand('Runtime.terminateExecution');
500
+ // We don't await these, as we want to exit with PAGE_HUNG
501
+ void session.sendCommand('Emulation.setScriptExecutionDisabled', {value: true})
502
+ .catch(_ => {});
503
+ void session.sendCommand('Runtime.terminateExecution').catch(_ => {});
502
504
  throw new LighthouseError(LighthouseError.errors.PAGE_HUNG);
503
505
  }
504
506
 
@@ -265,44 +265,43 @@ async function navigationGather(page, requestor, options = {}) {
265
265
  const isCallback = typeof requestor === 'function';
266
266
 
267
267
  const runnerOptions = {resolvedConfig, computedCache};
268
- const artifacts = await Runner.gather(
269
- async () => {
270
- const normalizedRequestor = isCallback ? requestor : UrlUtils.normalizeUrl(requestor);
271
-
272
- /** @type {LH.Puppeteer.Browser|undefined} */
273
- let lhBrowser = undefined;
274
- /** @type {LH.Puppeteer.Page|undefined} */
275
- let lhPage = undefined;
276
-
277
- // For navigation mode, we shouldn't connect to a browser in audit mode,
278
- // therefore we connect to the browser in the gatherFn callback.
279
- if (!page) {
280
- const {hostname = DEFAULT_HOSTNAME, port = DEFAULT_PORT} = flags;
281
- lhBrowser = await puppeteer.connect({browserURL: `http://${hostname}:${port}`, defaultViewport: null});
282
- lhPage = await lhBrowser.newPage();
283
- page = lhPage;
284
- }
285
-
286
- const driver = new Driver(page);
287
- const context = {
288
- driver,
289
- lhBrowser,
290
- lhPage,
291
- page,
292
- resolvedConfig,
293
- requestor: normalizedRequestor,
294
- computedCache,
295
- };
296
- const {baseArtifacts} = await _setup(context);
297
-
298
- const artifacts = await _navigation({...context, baseArtifacts});
299
-
300
- await _cleanup(context);
301
-
302
- return finalizeArtifacts(baseArtifacts, artifacts);
303
- },
304
- runnerOptions
305
- );
268
+
269
+ const gatherFn = async () => {
270
+ const normalizedRequestor = isCallback ? requestor : UrlUtils.normalizeUrl(requestor);
271
+
272
+ /** @type {LH.Puppeteer.Browser|undefined} */
273
+ let lhBrowser = undefined;
274
+ /** @type {LH.Puppeteer.Page|undefined} */
275
+ let lhPage = undefined;
276
+
277
+ // For navigation mode, we shouldn't connect to a browser in audit mode,
278
+ // therefore we connect to the browser in the gatherFn callback.
279
+ if (!page) {
280
+ const {hostname = DEFAULT_HOSTNAME, port = DEFAULT_PORT} = flags;
281
+ lhBrowser = await puppeteer.connect({browserURL: `http://${hostname}:${port}`, defaultViewport: null});
282
+ lhPage = await lhBrowser.newPage();
283
+ page = lhPage;
284
+ }
285
+
286
+ const driver = new Driver(page);
287
+ const context = {
288
+ driver,
289
+ lhBrowser,
290
+ lhPage,
291
+ page,
292
+ resolvedConfig,
293
+ requestor: normalizedRequestor,
294
+ computedCache,
295
+ };
296
+ const {baseArtifacts} = await _setup(context);
297
+
298
+ const artifacts = await _navigation({...context, baseArtifacts});
299
+
300
+ await _cleanup(context);
301
+
302
+ return finalizeArtifacts(baseArtifacts, artifacts);
303
+ };
304
+ const artifacts = await Runner.gather(gatherFn, runnerOptions);
306
305
  return {artifacts, runnerOptions};
307
306
  }
308
307
 
@@ -30,35 +30,35 @@ async function snapshotGather(page, options = {}) {
30
30
  const url = await driver.url();
31
31
 
32
32
  const runnerOptions = {resolvedConfig, computedCache};
33
- const artifacts = await Runner.gather(
34
- async () => {
35
- const baseArtifacts =
33
+
34
+ const gatherFn = async () => {
35
+ const baseArtifacts =
36
36
  await getBaseArtifacts(resolvedConfig, driver, {gatherMode: 'snapshot'});
37
- baseArtifacts.URL = {
38
- finalDisplayedUrl: url,
39
- };
37
+ baseArtifacts.URL = {
38
+ finalDisplayedUrl: url,
39
+ };
40
+
41
+ const artifactDefinitions = resolvedConfig.artifacts || [];
42
+ const artifactState = getEmptyArtifactState();
43
+ await collectPhaseArtifacts({
44
+ phase: 'getArtifact',
45
+ gatherMode: 'snapshot',
46
+ driver,
47
+ page,
48
+ baseArtifacts,
49
+ artifactDefinitions,
50
+ artifactState,
51
+ computedCache,
52
+ settings: resolvedConfig.settings,
53
+ });
40
54
 
41
- const artifactDefinitions = resolvedConfig.artifacts || [];
42
- const artifactState = getEmptyArtifactState();
43
- await collectPhaseArtifacts({
44
- phase: 'getArtifact',
45
- gatherMode: 'snapshot',
46
- driver,
47
- page,
48
- baseArtifacts,
49
- artifactDefinitions,
50
- artifactState,
51
- computedCache,
52
- settings: resolvedConfig.settings,
53
- });
55
+ await driver.disconnect();
54
56
 
55
- await driver.disconnect();
57
+ const artifacts = await awaitArtifacts(artifactState);
58
+ return finalizeArtifacts(baseArtifacts, artifacts);
59
+ };
56
60
 
57
- const artifacts = await awaitArtifacts(artifactState);
58
- return finalizeArtifacts(baseArtifacts, artifacts);
59
- },
60
- runnerOptions
61
- );
61
+ const artifacts = await Runner.gather(gatherFn, runnerOptions);
62
62
  return {artifacts, runnerOptions};
63
63
  }
64
64
 
@@ -72,31 +72,30 @@ async function startTimespanGather(page, options = {}) {
72
72
  const finalDisplayedUrl = await driver.url();
73
73
 
74
74
  const runnerOptions = {resolvedConfig, computedCache};
75
- const artifacts = await Runner.gather(
76
- async () => {
77
- baseArtifacts.URL = {finalDisplayedUrl};
78
-
79
- await collectPhaseArtifacts({phase: 'stopSensitiveInstrumentation', ...phaseOptions});
80
- await collectPhaseArtifacts({phase: 'stopInstrumentation', ...phaseOptions});
81
-
82
- // bf-cache-failures can emit `Page.frameNavigated` at the end of the run.
83
- // This can cause us to issue protocol commands after the target closes.
84
- // We should disable our `Page.frameNavigated` handlers before that.
85
- await disableAsyncStacks();
86
-
87
- driver.defaultSession.off('Page.frameNavigated', onFrameNavigated);
88
- if (pageNavigationDetected) {
89
- baseArtifacts.LighthouseRunWarnings.push(str_(UIStrings.warningNavigationDetected));
90
- }
91
-
92
- await collectPhaseArtifacts({phase: 'getArtifact', ...phaseOptions});
93
- await driver.disconnect();
94
-
95
- const artifacts = await awaitArtifacts(artifactState);
96
- return finalizeArtifacts(baseArtifacts, artifacts);
97
- },
98
- runnerOptions
99
- );
75
+ const gatherFn = async () => {
76
+ baseArtifacts.URL = {finalDisplayedUrl};
77
+
78
+ await collectPhaseArtifacts({phase: 'stopSensitiveInstrumentation', ...phaseOptions});
79
+ await collectPhaseArtifacts({phase: 'stopInstrumentation', ...phaseOptions});
80
+
81
+ // bf-cache-failures can emit `Page.frameNavigated` at the end of the run.
82
+ // This can cause us to issue protocol commands after the target closes.
83
+ // We should disable our `Page.frameNavigated` handlers before that.
84
+ await disableAsyncStacks();
85
+
86
+ driver.defaultSession.off('Page.frameNavigated', onFrameNavigated);
87
+ if (pageNavigationDetected) {
88
+ baseArtifacts.LighthouseRunWarnings.push(str_(UIStrings.warningNavigationDetected));
89
+ }
90
+
91
+ await collectPhaseArtifacts({phase: 'getArtifact', ...phaseOptions});
92
+ await driver.disconnect();
93
+
94
+ const artifacts = await awaitArtifacts(artifactState);
95
+ return finalizeArtifacts(baseArtifacts, artifacts);
96
+ };
97
+
98
+ const artifacts = await Runner.gather(gatherFn, runnerOptions);
100
99
  return {artifacts, runnerOptions};
101
100
  },
102
101
  };
@@ -257,7 +257,7 @@ class NetworkRecorder extends RequestEventEmitter {
257
257
  let candidates = recordsByURL.get(initiatorURL) || [];
258
258
  // The (valid) initiator must come before the initiated request.
259
259
  candidates = candidates.filter(c => {
260
- return c.responseHeadersEndTime <= record.networkRequestTime &&
260
+ return c.responseHeadersEndTime <= record.rendererStartTime &&
261
261
  c.finished && !c.failed;
262
262
  });
263
263
  if (candidates.length > 1) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lighthouse",
3
3
  "type": "module",
4
- "version": "11.6.0-dev.20240225",
4
+ "version": "11.6.0-dev.20240226",
5
5
  "description": "Automated auditing, performance metrics, and best practices for the web.",
6
6
  "main": "./core/index.js",
7
7
  "bin": {