lighthouse 9.5.0-dev.20230201 → 9.5.0-dev.20230202

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.
@@ -43,4 +43,10 @@ export function prepareTargetForIndividualNavigation(session: LH.Gatherer.FRProt
43
43
  }): Promise<{
44
44
  warnings: Array<LH.IcuMessage>;
45
45
  }>;
46
+ /**
47
+ * Enables `Debugger` domain to receive async stacktrace information on network request initiators.
48
+ * This is critical for tracking attribution of tasks and performance simulation accuracy.
49
+ * @param {LH.Gatherer.FRProtocolSession} session
50
+ */
51
+ export function enableAsyncStacks(session: LH.Gatherer.FRProtocolSession): Promise<() => Promise<void>>;
46
52
  //# sourceMappingURL=prepare.d.ts.map
@@ -22,17 +22,33 @@ async function enableAsyncStacks(session) {
22
22
  await session.sendCommand('Debugger.setAsyncCallStackDepth', {maxDepth: 8});
23
23
  };
24
24
 
25
- // Resume any pauses that make it through `setSkipAllPauses`
26
- session.on('Debugger.paused', () => session.sendCommand('Debugger.resume'));
25
+ /**
26
+ * Resume any pauses that make it through `setSkipAllPauses`
27
+ */
28
+ function onDebuggerPaused() {
29
+ session.sendCommand('Debugger.resume');
30
+ }
27
31
 
28
- // `Debugger.setSkipAllPauses` is reset after every navigation, so retrigger it on main frame navigations.
29
- // See https://bugs.chromium.org/p/chromium/issues/detail?id=990945&q=setSkipAllPauses&can=2
30
- session.on('Page.frameNavigated', event => {
32
+ /**
33
+ * `Debugger.setSkipAllPauses` is reset after every navigation, so retrigger it on main frame navigations.
34
+ * See https://bugs.chromium.org/p/chromium/issues/detail?id=990945&q=setSkipAllPauses&can=2
35
+ * @param {LH.Crdp.Page.FrameNavigatedEvent} event
36
+ */
37
+ function onFrameNavigated(event) {
31
38
  if (event.frame.parentId) return;
32
39
  enable().catch(err => log.error('Driver', err));
33
- });
40
+ }
41
+
42
+ session.on('Debugger.paused', onDebuggerPaused);
43
+ session.on('Page.frameNavigated', onFrameNavigated);
34
44
 
35
45
  await enable();
46
+
47
+ return async () => {
48
+ await session.sendCommand('Debugger.disable');
49
+ session.off('Debugger.paused', onDebuggerPaused);
50
+ session.off('Page.frameNavigated', onFrameNavigated);
51
+ };
36
52
  }
37
53
 
38
54
  /**
@@ -128,15 +144,12 @@ async function prepareThrottlingAndNetwork(session, settings, options) {
128
144
  * @param {LH.Gatherer.FRTransitionalDriver} driver
129
145
  * @param {LH.Config.Settings} settings
130
146
  */
131
- async function prepareDeviceEmulationAndAsyncStacks(driver, settings) {
147
+ async function prepareDeviceEmulation(driver, settings) {
132
148
  // Enable network domain here so future calls to `emulate()` don't clear cache (https://github.com/GoogleChrome/lighthouse/issues/12631)
133
149
  await driver.defaultSession.sendCommand('Network.enable');
134
150
 
135
151
  // Emulate our target device screen and user agent.
136
152
  await emulation.emulate(driver.defaultSession, settings);
137
-
138
- // Enable better stacks on network requests.
139
- await enableAsyncStacks(driver.defaultSession);
140
153
  }
141
154
 
142
155
  /**
@@ -149,7 +162,7 @@ async function prepareTargetForTimespanMode(driver, settings) {
149
162
  const status = {msg: 'Preparing target for timespan mode', id: 'lh:prepare:timespanMode'};
150
163
  log.time(status);
151
164
 
152
- await prepareDeviceEmulationAndAsyncStacks(driver, settings);
165
+ await prepareDeviceEmulation(driver, settings);
153
166
  await prepareThrottlingAndNetwork(driver.defaultSession, settings, {
154
167
  disableThrottling: false,
155
168
  blockedUrlPatterns: undefined,
@@ -171,7 +184,7 @@ async function prepareTargetForNavigationMode(driver, settings) {
171
184
  const status = {msg: 'Preparing target for navigation mode', id: 'lh:prepare:navigationMode'};
172
185
  log.time(status);
173
186
 
174
- await prepareDeviceEmulationAndAsyncStacks(driver, settings);
187
+ await prepareDeviceEmulation(driver, settings);
175
188
 
176
189
  // Automatically handle any JavaScript dialogs to prevent a hung renderer.
177
190
  await dismissJavaScriptDialogs(driver.defaultSession);
@@ -227,4 +240,5 @@ export {
227
240
  prepareTargetForTimespanMode,
228
241
  prepareTargetForNavigationMode,
229
242
  prepareTargetForIndividualNavigation,
243
+ enableAsyncStacks,
230
244
  };
@@ -9,6 +9,7 @@ import {waitForFrameNavigated, waitForLoadEvent} from '../driver/wait-for-condit
9
9
  import DevtoolsLog from './devtools-log.js';
10
10
 
11
11
  const FAILURE_EVENT_TIMEOUT = 100;
12
+ const TEMP_PAGE_PAUSE_TIMEOUT = 100;
12
13
 
13
14
  class BFCacheFailures extends FRGatherer {
14
15
  /** @type {LH.Gatherer.GathererMeta<'DevtoolsLog'>} */
@@ -109,7 +110,9 @@ class BFCacheFailures extends FRGatherer {
109
110
  // https://github.com/GoogleChrome/lighthouse/issues/14665
110
111
  await Promise.all([
111
112
  session.sendCommand('Page.navigate', {url: 'chrome://terms'}),
112
- waitForLoadEvent(session, 0).promise,
113
+ // DevTools e2e tests can sometimes fail on the next command if we progress too fast.
114
+ // The only reliable way to prevent this is to wait for an arbitrary period of time after load.
115
+ waitForLoadEvent(session, TEMP_PAGE_PAUSE_TIMEOUT).promise,
113
116
  ]);
114
117
 
115
118
  const [, frameNavigatedEvent] = await Promise.all([
@@ -227,6 +227,10 @@ async function _navigation(navigationContext) {
227
227
  };
228
228
 
229
229
  const setupResult = await _setupNavigation(navigationContext);
230
+
231
+ const disableAsyncStacks =
232
+ await prepare.enableAsyncStacks(navigationContext.driver.defaultSession);
233
+
230
234
  await collectPhaseArtifacts({phase: 'startInstrumentation', ...phaseState});
231
235
  await collectPhaseArtifacts({phase: 'startSensitiveInstrumentation', ...phaseState});
232
236
  const navigateResult = await _navigate(navigationContext);
@@ -244,6 +248,12 @@ async function _navigation(navigationContext) {
244
248
 
245
249
  await collectPhaseArtifacts({phase: 'stopSensitiveInstrumentation', ...phaseState});
246
250
  await collectPhaseArtifacts({phase: 'stopInstrumentation', ...phaseState});
251
+
252
+ // bf-cache-failures can emit `Page.frameNavigated` at the end of the run.
253
+ // This can cause us to issue protocol commands after the target closes.
254
+ // We should disable our `Page.frameNavigated` handlers before that.
255
+ await disableAsyncStacks();
256
+
247
257
  await _cleanupNavigation(navigationContext);
248
258
 
249
259
  return _computeNavigationResult(navigationContext, phaseState, setupResult, navigateResult);
@@ -9,7 +9,7 @@ import log from 'lighthouse-logger';
9
9
  import {Driver} from './driver.js';
10
10
  import {Runner} from '../runner.js';
11
11
  import {getEmptyArtifactState, collectPhaseArtifacts, awaitArtifacts} from './runner-helpers.js';
12
- import {prepareTargetForTimespanMode} from './driver/prepare.js';
12
+ import {enableAsyncStacks, prepareTargetForTimespanMode} from './driver/prepare.js';
13
13
  import {initializeConfig} from '../config/config.js';
14
14
  import {getBaseArtifacts, finalizeArtifacts} from './base-artifacts.js';
15
15
 
@@ -44,6 +44,9 @@ async function startTimespanGather(page, options = {}) {
44
44
  };
45
45
 
46
46
  await prepareTargetForTimespanMode(driver, resolvedConfig.settings);
47
+
48
+ const disableAsyncStacks = await enableAsyncStacks(driver.defaultSession);
49
+
47
50
  await collectPhaseArtifacts({phase: 'startInstrumentation', ...phaseOptions});
48
51
  await collectPhaseArtifacts({phase: 'startSensitiveInstrumentation', ...phaseOptions});
49
52
 
@@ -58,6 +61,12 @@ async function startTimespanGather(page, options = {}) {
58
61
 
59
62
  await collectPhaseArtifacts({phase: 'stopSensitiveInstrumentation', ...phaseOptions});
60
63
  await collectPhaseArtifacts({phase: 'stopInstrumentation', ...phaseOptions});
64
+
65
+ // bf-cache-failures can emit `Page.frameNavigated` at the end of the run.
66
+ // This can cause us to issue protocol commands after the target closes.
67
+ // We should disable our `Page.frameNavigated` handlers before that.
68
+ await disableAsyncStacks();
69
+
61
70
  await collectPhaseArtifacts({phase: 'getArtifact', ...phaseOptions});
62
71
  await driver.disconnect();
63
72
 
@@ -200,12 +200,13 @@ export class Driver implements LH.Gatherer.FRTransitionalDriver {
200
200
  /**
201
201
  * Begin recording devtools protocol messages.
202
202
  */
203
- beginDevtoolsLog(): void;
203
+ beginDevtoolsLog(): Promise<void>;
204
+ _disableAsyncStacks: (() => Promise<void>) | undefined;
204
205
  /**
205
206
  * Stop recording to devtoolsLog and return log contents.
206
- * @return {LH.DevtoolsLog}
207
+ * @return {Promise<LH.DevtoolsLog>}
207
208
  */
208
- endDevtoolsLog(): LH.DevtoolsLog;
209
+ endDevtoolsLog(): Promise<LH.DevtoolsLog>;
209
210
  url(): Promise<string>;
210
211
  }
211
212
  import * as LH from "../../../types/lh.js";
@@ -16,6 +16,7 @@ import {fetchResponseBodyFromCache} from '../../gather/driver/network.js';
16
16
  import {DevtoolsMessageLog} from '../../gather/gatherers/devtools-log.js';
17
17
  import TraceGatherer from '../../gather/gatherers/trace.js';
18
18
  import {getBrowserVersion} from '../../gather/driver/environment.js';
19
+ import {enableAsyncStacks} from '../../gather/driver/prepare.js';
19
20
 
20
21
  // Controls how long to wait for a response after sending a DevTools protocol command.
21
22
  const DEFAULT_PROTOCOL_TIMEOUT = 30000;
@@ -443,17 +444,19 @@ class Driver {
443
444
  /**
444
445
  * Begin recording devtools protocol messages.
445
446
  */
446
- beginDevtoolsLog() {
447
+ async beginDevtoolsLog() {
448
+ this._disableAsyncStacks = await enableAsyncStacks(this);
447
449
  this._devtoolsLog.reset();
448
450
  this._devtoolsLog.beginRecording();
449
451
  }
450
452
 
451
453
  /**
452
454
  * Stop recording to devtoolsLog and return log contents.
453
- * @return {LH.DevtoolsLog}
455
+ * @return {Promise<LH.DevtoolsLog>}
454
456
  */
455
- endDevtoolsLog() {
457
+ async endDevtoolsLog() {
456
458
  this._devtoolsLog.endRecording();
459
+ await this._disableAsyncStacks?.();
457
460
  return this._devtoolsLog.messages;
458
461
  }
459
462
 
@@ -235,7 +235,7 @@ class GatherRunner {
235
235
  id: `lh:gather:getDevtoolsLog`,
236
236
  };
237
237
  log.time(status);
238
- const devtoolsLog = driver.endDevtoolsLog();
238
+ const devtoolsLog = await driver.endDevtoolsLog();
239
239
  const networkRecords = await NetworkRecords.request(devtoolsLog, passContext);
240
240
  log.timeEnd(status);
241
241
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lighthouse",
3
3
  "type": "module",
4
- "version": "9.5.0-dev.20230201",
4
+ "version": "9.5.0-dev.20230202",
5
5
  "description": "Automated auditing, performance metrics, and best practices for the web.",
6
6
  "main": "./core/index.js",
7
7
  "bin": {