lighthouse 9.5.0-dev.20220607 → 9.6.2
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/dist/report/bundle.esm.js +467 -520
- package/dist/report/flow.js +22 -22
- package/dist/report/standalone.js +19 -19
- package/flow-report/src/summary/category.tsx +1 -1
- package/flow-report/src/topbar.tsx +2 -10
- package/flow-report/src/util.ts +1 -1
- package/flow-report/test/topbar-test.tsx +8 -7
- package/jest.config.js +1 -1
- package/lighthouse-cli/.eslintrc.cjs +4 -3
- package/lighthouse-cli/bin.js +1 -0
- package/lighthouse-cli/cli-flags.js +4 -3
- package/lighthouse-cli/commands/commands.js +1 -0
- package/lighthouse-cli/commands/list-audits.js +1 -0
- package/lighthouse-cli/commands/list-locales.js +1 -0
- package/lighthouse-cli/commands/list-trace-categories.js +1 -0
- package/lighthouse-cli/index.js +1 -0
- package/lighthouse-cli/printer.js +1 -0
- package/lighthouse-cli/run.js +24 -9
- package/lighthouse-cli/sentry-prompt.js +1 -0
- package/lighthouse-cli/test/smokehouse/core-tests.js +1 -0
- package/lighthouse-cli/test/smokehouse/frontends/back-compat-util.js +1 -0
- package/lighthouse-cli/test/smokehouse/frontends/lib.js +1 -0
- package/lighthouse-cli/test/smokehouse/frontends/node.js +1 -0
- package/lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js +1 -0
- package/lighthouse-cli/test/smokehouse/lib/child-process-error.js +1 -0
- package/lighthouse-cli/test/smokehouse/lib/concurrent-mapper.js +1 -0
- package/lighthouse-cli/test/smokehouse/lib/local-console.js +1 -0
- package/lighthouse-cli/test/smokehouse/lighthouse-runners/bundle.js +23 -109
- package/lighthouse-cli/test/smokehouse/lighthouse-runners/cli.js +3 -2
- package/lighthouse-cli/test/smokehouse/lighthouse-runners/devtools.js +19 -28
- package/lighthouse-cli/test/smokehouse/report-assert.js +4 -3
- package/lighthouse-cli/test/smokehouse/smokehouse.js +1 -1
- package/lighthouse-cli/test/smokehouse/version-check-test.js +3 -0
- package/lighthouse-cli/test/smokehouse/version-check.js +1 -0
- package/lighthouse-core/audits/accessibility/accesskeys.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-allowed-attr.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-command-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-hidden-body.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-hidden-focus.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-input-field-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-meter-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-progressbar-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-required-attr.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-required-children.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-required-parent.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-roles.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-toggle-field-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-tooltip-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-treeitem-name.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-valid-attr-value.js +1 -1
- package/lighthouse-core/audits/accessibility/aria-valid-attr.js +1 -1
- package/lighthouse-core/audits/accessibility/button-name.js +1 -1
- package/lighthouse-core/audits/accessibility/bypass.js +1 -1
- package/lighthouse-core/audits/accessibility/color-contrast.js +1 -1
- package/lighthouse-core/audits/accessibility/definition-list.js +1 -1
- package/lighthouse-core/audits/accessibility/dlitem.js +1 -1
- package/lighthouse-core/audits/accessibility/document-title.js +1 -1
- package/lighthouse-core/audits/accessibility/duplicate-id-active.js +1 -1
- package/lighthouse-core/audits/accessibility/duplicate-id-aria.js +1 -1
- package/lighthouse-core/audits/accessibility/form-field-multiple-labels.js +1 -1
- package/lighthouse-core/audits/accessibility/frame-title.js +1 -1
- package/lighthouse-core/audits/accessibility/heading-order.js +1 -1
- package/lighthouse-core/audits/accessibility/html-has-lang.js +1 -1
- package/lighthouse-core/audits/accessibility/html-lang-valid.js +1 -1
- package/lighthouse-core/audits/accessibility/image-alt.js +1 -1
- package/lighthouse-core/audits/accessibility/input-image-alt.js +1 -1
- package/lighthouse-core/audits/accessibility/label.js +1 -1
- package/lighthouse-core/audits/accessibility/link-name.js +1 -1
- package/lighthouse-core/audits/accessibility/list.js +1 -1
- package/lighthouse-core/audits/accessibility/listitem.js +5 -5
- package/lighthouse-core/audits/accessibility/meta-refresh.js +1 -1
- package/lighthouse-core/audits/accessibility/meta-viewport.js +1 -1
- package/lighthouse-core/audits/accessibility/object-alt.js +1 -1
- package/lighthouse-core/audits/accessibility/tabindex.js +1 -1
- package/lighthouse-core/audits/accessibility/td-headers-attr.js +1 -1
- package/lighthouse-core/audits/accessibility/th-has-data-cells.js +1 -1
- package/lighthouse-core/audits/accessibility/valid-lang.js +1 -1
- package/lighthouse-core/audits/accessibility/video-caption.js +1 -1
- package/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +1 -2
- package/lighthouse-core/audits/byte-efficiency/duplicated-javascript.js +12 -11
- package/lighthouse-core/audits/byte-efficiency/efficient-animated-content.js +1 -1
- package/lighthouse-core/audits/byte-efficiency/legacy-javascript.js +24 -22
- package/lighthouse-core/audits/byte-efficiency/offscreen-images.js +2 -3
- package/lighthouse-core/audits/byte-efficiency/render-blocking-resources.js +3 -2
- package/lighthouse-core/audits/byte-efficiency/unminified-css.js +5 -3
- package/lighthouse-core/audits/byte-efficiency/unminified-javascript.js +11 -10
- package/lighthouse-core/audits/byte-efficiency/unused-css-rules.js +1 -0
- package/lighthouse-core/audits/byte-efficiency/unused-javascript.js +8 -11
- package/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +1 -1
- package/lighthouse-core/audits/byte-efficiency/uses-text-compression.js +1 -1
- package/lighthouse-core/audits/deprecations.js +598 -8
- package/lighthouse-core/audits/diagnostics.js +3 -4
- package/lighthouse-core/audits/dobetterweb/doctype.js +9 -20
- package/lighthouse-core/audits/dobetterweb/geolocation-on-start.js +1 -1
- package/lighthouse-core/audits/dobetterweb/no-document-write.js +1 -1
- package/lighthouse-core/audits/dobetterweb/notification-on-start.js +1 -1
- package/lighthouse-core/audits/dobetterweb/uses-http2.js +1 -2
- package/lighthouse-core/audits/dobetterweb/uses-passive-event-listeners.js +1 -1
- package/lighthouse-core/audits/errors-in-console.js +2 -2
- package/lighthouse-core/audits/long-tasks.js +2 -3
- package/lighthouse-core/audits/metrics/first-contentful-paint-3g.js +2 -2
- package/lighthouse-core/audits/metrics/first-contentful-paint.js +2 -3
- package/lighthouse-core/audits/metrics/first-meaningful-paint.js +2 -3
- package/lighthouse-core/audits/metrics/interactive.js +2 -3
- package/lighthouse-core/audits/metrics/largest-contentful-paint.js +2 -3
- package/lighthouse-core/audits/metrics/max-potential-fid.js +2 -3
- package/lighthouse-core/audits/metrics/speed-index.js +2 -3
- package/lighthouse-core/audits/metrics/total-blocking-time.js +2 -3
- package/lighthouse-core/audits/metrics.js +2 -3
- package/lighthouse-core/audits/no-unload-listeners.js +15 -7
- package/lighthouse-core/audits/predictive-perf.js +1 -2
- package/lighthouse-core/audits/preload-lcp-image.js +3 -3
- package/lighthouse-core/audits/redirects.js +1 -1
- package/lighthouse-core/audits/script-treemap-data.js +45 -45
- package/lighthouse-core/audits/seo/http-status-code.js +4 -2
- package/lighthouse-core/audits/seo/link-text.js +0 -2
- package/lighthouse-core/audits/server-response-time.js +17 -2
- package/lighthouse-core/audits/service-worker.js +2 -7
- package/lighthouse-core/audits/timing-budget.js +2 -3
- package/lighthouse-core/audits/uses-rel-preconnect.js +1 -1
- package/lighthouse-core/audits/uses-rel-preload.js +1 -1
- package/lighthouse-core/audits/valid-source-maps.js +14 -12
- package/lighthouse-core/audits/violation-audit.js +1 -1
- package/lighthouse-core/audits/work-during-interaction.js +2 -2
- package/lighthouse-core/computed/critical-request-chains.js +9 -5
- package/lighthouse-core/computed/js-bundles.js +11 -11
- package/lighthouse-core/computed/main-resource.js +2 -3
- package/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js +1 -1
- package/lighthouse-core/computed/metrics/first-contentful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/first-meaningful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/interactive.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-first-contentful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-first-meaningful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-interactive.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-largest-contentful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-max-potential-fid.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-metric.js +5 -3
- package/lighthouse-core/computed/metrics/lantern-speed-index.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-total-blocking-time.js +1 -1
- package/lighthouse-core/computed/metrics/largest-contentful-paint-all-frames.js +1 -1
- package/lighthouse-core/computed/metrics/largest-contentful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/max-potential-fid.js +1 -1
- package/lighthouse-core/computed/metrics/metric.js +0 -1
- package/lighthouse-core/computed/metrics/speed-index.js +1 -1
- package/lighthouse-core/computed/metrics/timing-summary.js +6 -13
- package/lighthouse-core/computed/metrics/total-blocking-time.js +1 -1
- package/lighthouse-core/computed/module-duplication.js +5 -6
- package/lighthouse-core/computed/page-dependency-graph.js +28 -55
- package/lighthouse-core/computed/resource-summary.js +5 -5
- package/lighthouse-core/computed/unused-css.js +7 -6
- package/lighthouse-core/computed/unused-javascript-summary.js +36 -16
- package/lighthouse-core/config/budget.js +2 -2
- package/lighthouse-core/config/default-config.js +1 -2
- package/lighthouse-core/fraggle-rock/api.js +1 -1
- package/lighthouse-core/fraggle-rock/config/default-config.js +0 -3
- package/lighthouse-core/fraggle-rock/gather/base-artifacts.js +3 -6
- package/lighthouse-core/fraggle-rock/gather/driver.js +2 -2
- package/lighthouse-core/fraggle-rock/gather/navigation-runner.js +26 -51
- package/lighthouse-core/fraggle-rock/gather/runner-helpers.js +3 -0
- package/lighthouse-core/fraggle-rock/gather/session.js +22 -23
- package/lighthouse-core/fraggle-rock/gather/snapshot-runner.js +4 -5
- package/lighthouse-core/fraggle-rock/gather/timespan-runner.js +6 -6
- package/lighthouse-core/gather/connections/cri.js +1 -5
- package/lighthouse-core/gather/driver/execution-context.js +2 -5
- package/lighthouse-core/gather/driver/navigation.js +10 -13
- package/lighthouse-core/gather/driver/network-monitor.js +3 -16
- package/lighthouse-core/gather/driver.js +1 -6
- package/lighthouse-core/gather/fetcher.js +210 -34
- package/lighthouse-core/gather/gather-runner.js +17 -13
- package/lighthouse-core/gather/gatherers/accessibility.js +4 -16
- package/lighthouse-core/gather/gatherers/console-messages.js +2 -4
- package/lighthouse-core/gather/gatherers/dobetterweb/doctype.js +2 -4
- package/lighthouse-core/gather/gatherers/full-page-screenshot.js +2 -3
- package/lighthouse-core/gather/gatherers/iframe-elements.js +1 -4
- package/lighthouse-core/gather/gatherers/image-elements.js +0 -2
- package/lighthouse-core/gather/gatherers/js-usage.js +87 -12
- package/lighthouse-core/gather/gatherers/link-elements.js +14 -12
- package/lighthouse-core/gather/gatherers/main-document-content.js +8 -8
- package/lighthouse-core/gather/gatherers/script-elements.js +56 -7
- package/lighthouse-core/gather/gatherers/seo/robots-txt.js +30 -2
- package/lighthouse-core/gather/gatherers/source-maps.js +1 -8
- package/lighthouse-core/gather/gatherers/web-app-manifest.js +2 -2
- package/lighthouse-core/index.js +2 -26
- package/lighthouse-core/lib/cdt/generated/SourceMap.js +1 -1
- package/lighthouse-core/lib/dependency-graph/simulator/network-analyzer.js +29 -8
- package/lighthouse-core/lib/navigation-error.js +4 -13
- package/lighthouse-core/lib/page-functions.js +1 -3
- package/lighthouse-core/lib/script-helpers.js +6 -11
- package/lighthouse-core/lib/url-shim.js +2 -2
- package/lighthouse-core/runner.js +5 -0
- package/lighthouse-core/scripts/manual-chrome-launcher.js +1 -0
- package/lighthouse-core/util-commonjs.js +6 -8
- package/package.json +13 -13
- package/readme.md +1 -1
- package/report/.eslintrc.cjs +1 -3
- package/report/assets/styles.css +5 -10
- package/report/assets/templates.html +9 -10
- package/report/clients/bundle.js +1 -0
- package/report/clients/standalone.js +1 -0
- package/report/generator/report-generator.js +21 -46
- package/report/renderer/api.js +2 -0
- package/report/renderer/category-renderer.js +24 -20
- package/report/renderer/components.js +304 -303
- package/report/renderer/crc-details-renderer.js +24 -21
- package/report/renderer/details-renderer.js +12 -12
- package/report/renderer/dom.js +7 -6
- package/report/renderer/drop-down-menu.js +1 -0
- package/report/renderer/element-screenshot-renderer.js +5 -1
- package/report/renderer/features-util.js +1 -0
- package/report/renderer/i18n.js +62 -118
- package/report/renderer/logger.js +1 -0
- package/report/renderer/open-tab.js +3 -1
- package/report/renderer/performance-category-renderer.js +11 -10
- package/report/renderer/pwa-category-renderer.js +4 -3
- package/report/renderer/report-renderer.js +17 -17
- package/report/renderer/report-ui-features.js +1 -0
- package/report/renderer/snippet-renderer.js +3 -2
- package/report/renderer/swap-locale-feature.js +1 -0
- package/report/renderer/text-encoding.js +1 -0
- package/report/renderer/topbar-features.js +1 -0
- package/report/renderer/util.js +6 -7
- package/report/test/clients/bundle-test.js +5 -0
- package/report/test/generator/file-namer-test.js +1 -0
- package/report/test/generator/report-generator-test.js +20 -25
- package/report/test/renderer/category-renderer-test.js +4 -3
- package/report/test/renderer/components-test.js +3 -0
- package/report/test/renderer/crc-details-renderer-test.js +3 -0
- package/report/test/renderer/details-renderer-test.js +3 -49
- package/report/test/renderer/dom-test.js +3 -0
- package/report/test/renderer/element-screenshot-renderer-test.js +6 -3
- package/report/test/renderer/i18n-test.js +25 -70
- package/report/test/renderer/performance-category-renderer-test.js +5 -14
- package/report/test/renderer/pwa-category-renderer-test.js +4 -3
- package/report/test/renderer/report-renderer-axe-test.js +4 -3
- package/report/test/renderer/report-renderer-test.js +4 -3
- package/report/test/renderer/report-ui-features-test.js +4 -3
- package/report/test/renderer/snippet-renderer-test.js +3 -0
- package/report/test/renderer/text-encoding-test.js +3 -0
- package/report/test/renderer/util-test.js +5 -4
- package/report/test-assets/faux-psi.js +1 -2
- package/shared/localization/format.js +3 -7
- package/shared/localization/locales/en-US.json +238 -55
- package/shared/localization/locales/en-XL.json +238 -55
- package/shared/test/localization/format-test.js +2 -8
- package/shared/test/localization/locales-test.js +2 -0
- package/shared/test/localization/swap-locale-test.js +2 -0
- package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +2 -0
- package/third-party/chromium-synchronization/installability-errors-test.js +2 -0
- package/tsconfig.json +0 -1
- package/types/artifacts.d.ts +8 -47
- package/types/config.d.ts +0 -2
- package/types/externs.d.ts +2 -3
- package/types/gatherer.d.ts +2 -1
- package/types/global-lh.d.ts +0 -3
- package/types/lhr/lhr.d.ts +2 -2
- package/types/lhr/treemap.d.ts +1 -0
- package/changelog.md +0 -5902
- package/lighthouse-core/audits/script-elements-test-audit.js +0 -30
- package/lighthouse-core/gather/gatherers/scripts.js +0 -154
- package/lighthouse-core/scripts/package.json +0 -4
- package/report/test/.eslintrc.cjs +0 -11
- package/shared/test/localization/.eslintrc.cjs +0 -11
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
8
|
const LHError = require('../../lib/lh-error.js');
|
|
9
|
+
const SessionEmitMonkeypatch = Symbol('monkeypatch');
|
|
9
10
|
|
|
10
11
|
// Controls how long to wait for a response after sending a DevTools protocol command.
|
|
11
12
|
const DEFAULT_PROTOCOL_TIMEOUT = 30000;
|
|
@@ -13,7 +14,7 @@ const DEFAULT_PROTOCOL_TIMEOUT = 30000;
|
|
|
13
14
|
/** @implements {LH.Gatherer.FRProtocolSession} */
|
|
14
15
|
class ProtocolSession {
|
|
15
16
|
/**
|
|
16
|
-
* @param {
|
|
17
|
+
* @param {import('puppeteer').CDPSession} session
|
|
17
18
|
*/
|
|
18
19
|
constructor(session) {
|
|
19
20
|
this._session = session;
|
|
@@ -23,12 +24,22 @@ class ProtocolSession {
|
|
|
23
24
|
this._nextProtocolTimeout = undefined;
|
|
24
25
|
/** @type {WeakMap<any, any>} */
|
|
25
26
|
this._callbackMap = new WeakMap();
|
|
26
|
-
}
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
// FIXME: Monkeypatch puppeteer to be able to listen to *all* protocol events.
|
|
29
|
+
// This patched method will now emit a copy of every event on `*`.
|
|
30
|
+
const originalEmit = session.emit;
|
|
31
|
+
// @ts-expect-error - Test for the monkeypatch.
|
|
32
|
+
if (originalEmit[SessionEmitMonkeypatch]) return;
|
|
33
|
+
session.emit = (method, ...args) => {
|
|
34
|
+
// OOPIF sessions need to emit their sessionId so downstream processors can recognize
|
|
35
|
+
// the target the event came from.
|
|
36
|
+
const sessionId = this._targetInfo && this._targetInfo.type === 'iframe' ?
|
|
37
|
+
this._targetInfo.targetId : undefined;
|
|
38
|
+
originalEmit.call(session, '*', {method, params: args[0], sessionId});
|
|
39
|
+
return originalEmit.call(session, method, ...args);
|
|
40
|
+
};
|
|
41
|
+
// @ts-expect-error - It's monkeypatching 🤷♂️.
|
|
42
|
+
session.emit[SessionEmitMonkeypatch] = true;
|
|
32
43
|
}
|
|
33
44
|
|
|
34
45
|
/** @param {LH.Crdp.Target.TargetInfo} targetInfo */
|
|
@@ -82,7 +93,7 @@ class ProtocolSession {
|
|
|
82
93
|
* @param {(session: ProtocolSession) => void} callback
|
|
83
94
|
*/
|
|
84
95
|
addSessionAttachedListener(callback) {
|
|
85
|
-
/** @param {
|
|
96
|
+
/** @param {import('puppeteer').CDPSession} session */
|
|
86
97
|
const listener = session => callback(new ProtocolSession(session));
|
|
87
98
|
this._callbackMap.set(callback, listener);
|
|
88
99
|
this._getConnection().on('sessionattached', listener);
|
|
@@ -99,31 +110,19 @@ class ProtocolSession {
|
|
|
99
110
|
}
|
|
100
111
|
|
|
101
112
|
/**
|
|
102
|
-
* Bind to
|
|
103
|
-
* and wrap it with data about the protocol message instead of just the event.
|
|
113
|
+
* Bind to our custom event that fires for *any* protocol event.
|
|
104
114
|
* @param {(payload: LH.Protocol.RawEventMessage) => void} callback
|
|
105
115
|
*/
|
|
106
116
|
addProtocolMessageListener(callback) {
|
|
107
|
-
/**
|
|
108
|
-
* @param {any} method
|
|
109
|
-
* @param {any} event
|
|
110
|
-
*/
|
|
111
|
-
const listener = (method, event) => callback({
|
|
112
|
-
method,
|
|
113
|
-
params: event,
|
|
114
|
-
sessionId: this.sessionId(),
|
|
115
|
-
});
|
|
116
|
-
this._callbackMap.set(callback, listener);
|
|
117
|
-
this._session.on('*', /** @type {*} */ (listener));
|
|
117
|
+
this._session.on('*', /** @type {*} */ (callback));
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
/**
|
|
121
|
+
* Unbind to our custom event that fires for *any* protocol event.
|
|
121
122
|
* @param {(payload: LH.Protocol.RawEventMessage) => void} callback
|
|
122
123
|
*/
|
|
123
124
|
removeProtocolMessageListener(callback) {
|
|
124
|
-
|
|
125
|
-
if (!listener) return;
|
|
126
|
-
this._session.off('*', /** @type {*} */ (listener));
|
|
125
|
+
this._session.off('*', /** @type {*} */ (callback));
|
|
127
126
|
}
|
|
128
127
|
|
|
129
128
|
/**
|
|
@@ -17,7 +17,7 @@ const {initializeConfig} = require('../config/config.js');
|
|
|
17
17
|
const {getBaseArtifacts, finalizeArtifacts} = require('./base-artifacts.js');
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* @param {{page:
|
|
20
|
+
* @param {{page: import('puppeteer').Page, config?: LH.Config.Json, configContext?: LH.Config.FRContext}} options
|
|
21
21
|
* @return {Promise<LH.Gatherer.FRGatherResult>}
|
|
22
22
|
*/
|
|
23
23
|
async function snapshotGather(options) {
|
|
@@ -36,14 +36,13 @@ async function snapshotGather(options) {
|
|
|
36
36
|
const artifacts = await Runner.gather(
|
|
37
37
|
async () => {
|
|
38
38
|
const baseArtifacts = await getBaseArtifacts(config, driver, {gatherMode: 'snapshot'});
|
|
39
|
-
baseArtifacts.URL =
|
|
40
|
-
|
|
41
|
-
finalUrl: url,
|
|
42
|
-
};
|
|
39
|
+
baseArtifacts.URL.requestedUrl = url;
|
|
40
|
+
baseArtifacts.URL.finalUrl = url;
|
|
43
41
|
|
|
44
42
|
const artifactDefinitions = config.artifacts || [];
|
|
45
43
|
const artifactState = getEmptyArtifactState();
|
|
46
44
|
await collectPhaseArtifacts({
|
|
45
|
+
url,
|
|
47
46
|
phase: 'getArtifact',
|
|
48
47
|
gatherMode: 'snapshot',
|
|
49
48
|
driver,
|
|
@@ -18,7 +18,7 @@ const {initializeConfig} = require('../config/config.js');
|
|
|
18
18
|
const {getBaseArtifacts, finalizeArtifacts} = require('./base-artifacts.js');
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* @param {{page:
|
|
21
|
+
* @param {{page: import('puppeteer').Page, config?: LH.Config.Json, configContext?: LH.Config.FRContext}} options
|
|
22
22
|
* @return {Promise<{endTimespanGather(): Promise<LH.Gatherer.FRGatherResult>}>}
|
|
23
23
|
*/
|
|
24
24
|
async function startTimespanGather(options) {
|
|
@@ -32,11 +32,12 @@ async function startTimespanGather(options) {
|
|
|
32
32
|
/** @type {Map<string, LH.ArbitraryEqualityMap>} */
|
|
33
33
|
const computedCache = new Map();
|
|
34
34
|
const artifactDefinitions = config.artifacts || [];
|
|
35
|
-
const
|
|
35
|
+
const requestedUrl = await driver.url();
|
|
36
36
|
const baseArtifacts = await getBaseArtifacts(config, driver, {gatherMode: 'timespan'});
|
|
37
37
|
const artifactState = getEmptyArtifactState();
|
|
38
38
|
/** @type {Omit<import('./runner-helpers.js').CollectPhaseArtifactOptions, 'phase'>} */
|
|
39
39
|
const phaseOptions = {
|
|
40
|
+
url: requestedUrl,
|
|
40
41
|
driver,
|
|
41
42
|
artifactDefinitions,
|
|
42
43
|
artifactState,
|
|
@@ -53,14 +54,13 @@ async function startTimespanGather(options) {
|
|
|
53
54
|
return {
|
|
54
55
|
async endTimespanGather() {
|
|
55
56
|
const finalUrl = await driver.url();
|
|
57
|
+
phaseOptions.url = finalUrl;
|
|
56
58
|
|
|
57
59
|
const runnerOptions = {config, computedCache};
|
|
58
60
|
const artifacts = await Runner.gather(
|
|
59
61
|
async () => {
|
|
60
|
-
baseArtifacts.URL =
|
|
61
|
-
|
|
62
|
-
finalUrl,
|
|
63
|
-
};
|
|
62
|
+
baseArtifacts.URL.requestedUrl = requestedUrl;
|
|
63
|
+
baseArtifacts.URL.finalUrl = finalUrl;
|
|
64
64
|
|
|
65
65
|
await collectPhaseArtifacts({phase: 'stopSensitiveInstrumentation', ...phaseOptions});
|
|
66
66
|
await collectPhaseArtifacts({phase: 'stopInstrumentation', ...phaseOptions});
|
|
@@ -82,14 +82,12 @@ class CriConnection extends Connection {
|
|
|
82
82
|
*/
|
|
83
83
|
_runJsonCommand(command) {
|
|
84
84
|
return new Promise((resolve, reject) => {
|
|
85
|
-
const request = http.
|
|
86
|
-
method: 'PUT', // GET and POST are deprecated: https://crrev.com/c/3595822
|
|
85
|
+
const request = http.get({
|
|
87
86
|
hostname: this.hostname,
|
|
88
87
|
port: this.port,
|
|
89
88
|
path: '/json/' + command,
|
|
90
89
|
}, response => {
|
|
91
90
|
let data = '';
|
|
92
|
-
response.setEncoding('utf8');
|
|
93
91
|
response.on('data', chunk => {
|
|
94
92
|
data += chunk;
|
|
95
93
|
});
|
|
@@ -110,8 +108,6 @@ class CriConnection extends Connection {
|
|
|
110
108
|
});
|
|
111
109
|
});
|
|
112
110
|
|
|
113
|
-
request.end();
|
|
114
|
-
|
|
115
111
|
// This error handler is critical to ensuring Lighthouse exits cleanly even when Chrome crashes.
|
|
116
112
|
// See https://github.com/GoogleChrome/lighthouse/pull/8583.
|
|
117
113
|
request.on('error', reject);
|
|
@@ -97,8 +97,7 @@ class ExecutionContext {
|
|
|
97
97
|
.catch(${pageFunctions.wrapRuntimeEvalErrorInBrowserString})
|
|
98
98
|
.then(resolve);
|
|
99
99
|
});
|
|
100
|
-
}())
|
|
101
|
-
//# sourceURL=_lighthouse-eval.js`,
|
|
100
|
+
}())`,
|
|
102
101
|
includeCommandLineAPI: true,
|
|
103
102
|
awaitPromise: true,
|
|
104
103
|
returnByValue: true,
|
|
@@ -196,8 +195,7 @@ class ExecutionContext {
|
|
|
196
195
|
${ExecutionContext._cachedNativesPreamble};
|
|
197
196
|
${depsSerialized};
|
|
198
197
|
(${mainFn})(${argsSerialized});
|
|
199
|
-
})()
|
|
200
|
-
//# sourceURL=_lighthouse-eval.js`;
|
|
198
|
+
})()`;
|
|
201
199
|
|
|
202
200
|
await this._session.sendCommand('Page.addScriptToEvaluateOnNewDocument', {source: expression});
|
|
203
201
|
}
|
|
@@ -215,7 +213,6 @@ class ExecutionContext {
|
|
|
215
213
|
window.__nativePerformance = window.performance;
|
|
216
214
|
window.__nativeFetch = window.fetch;
|
|
217
215
|
window.__ElementMatches = window.Element.prototype.matches;
|
|
218
|
-
window.__HTMLElementBoundingClientRect = window.HTMLElement.prototype.getBoundingClientRect;
|
|
219
216
|
// Ensure the native `performance.now` is not overwritable.
|
|
220
217
|
const performance = window.performance;
|
|
221
218
|
const performanceNow = window.performance.now;
|
|
@@ -80,7 +80,7 @@ function resolveWaitForFullyLoadedOptions(options) {
|
|
|
80
80
|
* @param {LH.Gatherer.FRTransitionalDriver} driver
|
|
81
81
|
* @param {LH.NavigationRequestor} requestor
|
|
82
82
|
* @param {NavigationOptions} options
|
|
83
|
-
* @return {Promise<{requestedUrl: string,
|
|
83
|
+
* @return {Promise<{requestedUrl: string, finalUrl: string, warnings: Array<LH.IcuMessage>}>}
|
|
84
84
|
*/
|
|
85
85
|
async function gotoURL(driver, requestor, options) {
|
|
86
86
|
const status = typeof requestor === 'string' ?
|
|
@@ -130,17 +130,14 @@ async function gotoURL(driver, requestor, options) {
|
|
|
130
130
|
|
|
131
131
|
let requestedUrl = navigationUrls.requestedUrl;
|
|
132
132
|
if (typeof requestor === 'string') {
|
|
133
|
-
if (
|
|
134
|
-
log.error(
|
|
135
|
-
'Navigation',
|
|
136
|
-
`Provided URL (${requestor}) did not match initial navigation URL (${requestedUrl})`
|
|
137
|
-
);
|
|
133
|
+
if (requestor !== requestedUrl) {
|
|
134
|
+
log.error('Navigation', 'Provided URL did not match initial navigation URL');
|
|
138
135
|
}
|
|
139
136
|
requestedUrl = requestor;
|
|
140
137
|
}
|
|
141
138
|
if (!requestedUrl) throw Error('No navigations detected when running user defined requestor.');
|
|
142
139
|
|
|
143
|
-
const
|
|
140
|
+
const finalUrl = navigationUrls.finalUrl || requestedUrl;
|
|
144
141
|
|
|
145
142
|
// Bring `Page.navigate` errors back into the promise chain. See https://github.com/GoogleChrome/lighthouse/pull/6739.
|
|
146
143
|
await waitForNavigationTriggered;
|
|
@@ -153,26 +150,26 @@ async function gotoURL(driver, requestor, options) {
|
|
|
153
150
|
log.timeEnd(status);
|
|
154
151
|
return {
|
|
155
152
|
requestedUrl,
|
|
156
|
-
|
|
157
|
-
warnings: getNavigationWarnings({timedOut,
|
|
153
|
+
finalUrl,
|
|
154
|
+
warnings: getNavigationWarnings({timedOut, finalUrl, requestedUrl}),
|
|
158
155
|
};
|
|
159
156
|
}
|
|
160
157
|
|
|
161
158
|
/**
|
|
162
|
-
* @param {{timedOut: boolean, requestedUrl: string,
|
|
159
|
+
* @param {{timedOut: boolean, requestedUrl: string, finalUrl: string; }} navigation
|
|
163
160
|
* @return {Array<LH.IcuMessage>}
|
|
164
161
|
*/
|
|
165
162
|
function getNavigationWarnings(navigation) {
|
|
166
|
-
const {requestedUrl,
|
|
163
|
+
const {requestedUrl, finalUrl} = navigation;
|
|
167
164
|
/** @type {Array<LH.IcuMessage>} */
|
|
168
165
|
const warnings = [];
|
|
169
166
|
|
|
170
167
|
if (navigation.timedOut) warnings.push(str_(UIStrings.warningTimeout));
|
|
171
168
|
|
|
172
|
-
if (!URL.equalWithExcludedFragments(requestedUrl,
|
|
169
|
+
if (!URL.equalWithExcludedFragments(requestedUrl, finalUrl)) {
|
|
173
170
|
warnings.push(str_(UIStrings.warningRedirected, {
|
|
174
171
|
requested: requestedUrl,
|
|
175
|
-
final:
|
|
172
|
+
final: finalUrl,
|
|
176
173
|
}));
|
|
177
174
|
}
|
|
178
175
|
|
|
@@ -133,7 +133,7 @@ class NetworkMonitor {
|
|
|
133
133
|
this._sessions = new Map();
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
/** @return {Promise<{requestedUrl?: string,
|
|
136
|
+
/** @return {Promise<{requestedUrl?: string, finalUrl?: string}>} */
|
|
137
137
|
async getNavigationUrls() {
|
|
138
138
|
const frameNavigations = this._frameNavigations;
|
|
139
139
|
if (!frameNavigations.length) return {};
|
|
@@ -143,22 +143,9 @@ class NetworkMonitor {
|
|
|
143
143
|
const mainFrameNavigations = frameNavigations.filter(frame => frame.id === mainFrameId);
|
|
144
144
|
if (!mainFrameNavigations.length) log.warn('NetworkMonitor', 'No detected navigations');
|
|
145
145
|
|
|
146
|
-
// The requested URL is the initiator request for the first frame navigation.
|
|
147
|
-
/** @type {string|undefined} */
|
|
148
|
-
let requestedUrl = mainFrameNavigations[0]?.url;
|
|
149
|
-
if (this._networkRecorder) {
|
|
150
|
-
const records = this._networkRecorder.getRawRecords();
|
|
151
|
-
|
|
152
|
-
let initialUrlRequest = records.find(record => record.url === requestedUrl);
|
|
153
|
-
while (initialUrlRequest?.redirectSource) {
|
|
154
|
-
initialUrlRequest = initialUrlRequest.redirectSource;
|
|
155
|
-
requestedUrl = initialUrlRequest.url;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
146
|
return {
|
|
160
|
-
requestedUrl,
|
|
161
|
-
|
|
147
|
+
requestedUrl: mainFrameNavigations[0]?.url,
|
|
148
|
+
finalUrl: mainFrameNavigations[mainFrameNavigations.length - 1]?.url,
|
|
162
149
|
};
|
|
163
150
|
}
|
|
164
151
|
|
|
@@ -64,7 +64,7 @@ class Driver {
|
|
|
64
64
|
defaultSession = this;
|
|
65
65
|
|
|
66
66
|
// eslint-disable-next-line no-invalid-this
|
|
67
|
-
fetcher = new Fetcher(this.defaultSession);
|
|
67
|
+
fetcher = new Fetcher(this.defaultSession, this.executionContext);
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* @param {Connection} connection
|
|
@@ -477,11 +477,6 @@ class Driver {
|
|
|
477
477
|
this._devtoolsLog.endRecording();
|
|
478
478
|
return this._devtoolsLog.messages;
|
|
479
479
|
}
|
|
480
|
-
|
|
481
|
-
async url() {
|
|
482
|
-
const {frameTree} = await this.sendCommand('Page.getFrameTree');
|
|
483
|
-
return `${frameTree.frame.url}${frameTree.frame.urlFragment || ''}`;
|
|
484
|
-
}
|
|
485
480
|
}
|
|
486
481
|
|
|
487
482
|
module.exports = Driver;
|
|
@@ -6,55 +6,124 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* @fileoverview Fetcher is a utility for making requests
|
|
10
|
-
*
|
|
9
|
+
* @fileoverview Fetcher is a utility for making requests within the context of the page.
|
|
10
|
+
* Requests can circumvent CORS, and so are good for fetching source maps that may be hosted
|
|
11
|
+
* on a different origin.
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
|
-
/* global
|
|
14
|
+
/* global document */
|
|
14
15
|
|
|
15
16
|
/** @typedef {{content: string|null, status: number|null}} FetchResponse */
|
|
16
17
|
|
|
18
|
+
const log = require('lighthouse-logger');
|
|
19
|
+
const {getBrowserVersion} = require('./driver/environment.js');
|
|
20
|
+
|
|
17
21
|
class Fetcher {
|
|
18
22
|
/**
|
|
19
23
|
* @param {LH.Gatherer.FRProtocolSession} session
|
|
24
|
+
* @param {import('./driver/execution-context.js')} executionContext
|
|
20
25
|
*/
|
|
21
|
-
constructor(session) {
|
|
26
|
+
constructor(session, executionContext) {
|
|
22
27
|
this.session = session;
|
|
28
|
+
this.executionContext = executionContext;
|
|
29
|
+
/** @type {Map<string, (event: LH.Crdp.Fetch.RequestPausedEvent) => void>} */
|
|
30
|
+
this._onRequestPausedHandlers = new Map();
|
|
31
|
+
this._onRequestPaused = this._onRequestPaused.bind(this);
|
|
32
|
+
this._enabled = false;
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
/**
|
|
26
|
-
*
|
|
36
|
+
* Chrome M92 and above:
|
|
37
|
+
* We use `Network.loadNetworkResource` to fetch each resource.
|
|
38
|
+
*
|
|
39
|
+
* Chrome <M92:
|
|
40
|
+
* The Fetch domain accepts patterns for controlling what requests are intercepted, but we
|
|
41
|
+
* enable the domain for all patterns and filter events at a lower level to support multiple
|
|
42
|
+
* concurrent usages. Reasons for this:
|
|
43
|
+
*
|
|
44
|
+
* 1) only one set of patterns may be applied for the entire domain.
|
|
45
|
+
* 2) every request that matches the patterns are paused and only resumes when certain Fetch
|
|
46
|
+
* commands are sent. So a listener of the `Fetch.requestPaused` event must either handle
|
|
47
|
+
* the requests it cares about, or explicitly allow them to continue.
|
|
48
|
+
* 3) if multiple commands to continue the same request are sent, protocol errors occur.
|
|
27
49
|
*
|
|
50
|
+
* So instead we have one global `Fetch.enable` / `Fetch.requestPaused` pair, and allow specific
|
|
51
|
+
* urls to be intercepted via `fetcher._setOnRequestPausedHandler`.
|
|
52
|
+
*/
|
|
53
|
+
async enable() {
|
|
54
|
+
if (this._enabled) return;
|
|
55
|
+
|
|
56
|
+
this._enabled = true;
|
|
57
|
+
await this.session.sendCommand('Fetch.enable', {
|
|
58
|
+
patterns: [{requestStage: 'Request'}, {requestStage: 'Response'}],
|
|
59
|
+
});
|
|
60
|
+
await this.session.on('Fetch.requestPaused', this._onRequestPaused);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async disable() {
|
|
64
|
+
if (!this._enabled) return;
|
|
65
|
+
|
|
66
|
+
this._enabled = false;
|
|
67
|
+
await this.session.off('Fetch.requestPaused', this._onRequestPaused);
|
|
68
|
+
await this.session.sendCommand('Fetch.disable');
|
|
69
|
+
this._onRequestPausedHandlers.clear();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
28
73
|
* @param {string} url
|
|
29
|
-
* @param {
|
|
30
|
-
* @return {Promise<FetchResponse>}
|
|
74
|
+
* @param {(event: LH.Crdp.Fetch.RequestPausedEvent) => void} handler
|
|
31
75
|
*/
|
|
32
|
-
async
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
76
|
+
async _setOnRequestPausedHandler(url, handler) {
|
|
77
|
+
this._onRequestPausedHandlers.set(url, handler);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {LH.Crdp.Fetch.RequestPausedEvent} event
|
|
82
|
+
*/
|
|
83
|
+
_onRequestPaused(event) {
|
|
84
|
+
const handler = this._onRequestPausedHandlers.get(event.request.url);
|
|
85
|
+
if (handler) {
|
|
86
|
+
handler(event);
|
|
87
|
+
} else {
|
|
88
|
+
// Nothing cares about this URL, so continue.
|
|
89
|
+
this.session.sendCommand('Fetch.continueRequest', {requestId: event.requestId}).catch(err => {
|
|
90
|
+
log.error('Fetcher', `Failed to continueRequest: ${err.message}`);
|
|
91
|
+
});
|
|
37
92
|
}
|
|
93
|
+
}
|
|
38
94
|
|
|
39
|
-
|
|
95
|
+
/**
|
|
96
|
+
* `Network.loadNetworkResource` was introduced in M88.
|
|
97
|
+
* The long timeout bug with `IO.read` was fixed in M92:
|
|
98
|
+
* https://bugs.chromium.org/p/chromium/issues/detail?id=1191757
|
|
99
|
+
* Lightrider has a bug forcing us to use the old version for now:
|
|
100
|
+
* https://docs.google.com/document/d/1V-DxgsOFMPxUuFrdGPQpyiCqSljvgNlOqXCtqDtd0b8/edit?usp=sharing&resourcekey=0-aIaIqcHFKG-0dX4MAudBEw
|
|
101
|
+
* @return {Promise<boolean>}
|
|
102
|
+
*/
|
|
103
|
+
async shouldUseLegacyFetcher() {
|
|
104
|
+
const {milestone} = await getBrowserVersion(this.session);
|
|
105
|
+
return milestone < 92 || Boolean(global.isLightrider);
|
|
40
106
|
}
|
|
41
107
|
|
|
42
108
|
/**
|
|
109
|
+
* Requires that `fetcher.enable` has been called.
|
|
110
|
+
*
|
|
111
|
+
* Fetches any resource in a way that circumvents CORS.
|
|
112
|
+
*
|
|
43
113
|
* @param {string} url
|
|
114
|
+
* @param {{timeout: number}=} options timeout is in ms
|
|
44
115
|
* @return {Promise<FetchResponse>}
|
|
45
116
|
*/
|
|
46
|
-
async
|
|
47
|
-
|
|
117
|
+
async fetchResource(url, options = {timeout: 2_000}) {
|
|
118
|
+
if (!this._enabled) {
|
|
119
|
+
throw new Error('Must call `enable` before using fetchResource');
|
|
120
|
+
}
|
|
48
121
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
} catch {}
|
|
122
|
+
if (await this.shouldUseLegacyFetcher()) {
|
|
123
|
+
return this._fetchResourceIframe(url, options);
|
|
124
|
+
}
|
|
53
125
|
|
|
54
|
-
return
|
|
55
|
-
content,
|
|
56
|
-
status: response.status,
|
|
57
|
-
};
|
|
126
|
+
return this._fetchResourceOverProtocol(url, options);
|
|
58
127
|
}
|
|
59
128
|
|
|
60
129
|
/**
|
|
@@ -103,6 +172,18 @@ class Fetcher {
|
|
|
103
172
|
};
|
|
104
173
|
}
|
|
105
174
|
|
|
175
|
+
/**
|
|
176
|
+
* @param {string} requestId
|
|
177
|
+
* @return {Promise<string>}
|
|
178
|
+
*/
|
|
179
|
+
async _resolveResponseBody(requestId) {
|
|
180
|
+
const responseBody = await this.session.sendCommand('Fetch.getResponseBody', {requestId});
|
|
181
|
+
if (responseBody.base64Encoded) {
|
|
182
|
+
return Buffer.from(responseBody.body, 'base64').toString();
|
|
183
|
+
}
|
|
184
|
+
return responseBody.body;
|
|
185
|
+
}
|
|
186
|
+
|
|
106
187
|
/**
|
|
107
188
|
* @param {string} url
|
|
108
189
|
* @param {{timeout: number}} options timeout is in ms
|
|
@@ -110,7 +191,18 @@ class Fetcher {
|
|
|
110
191
|
*/
|
|
111
192
|
async _fetchResourceOverProtocol(url, options) {
|
|
112
193
|
const startTime = Date.now();
|
|
113
|
-
|
|
194
|
+
|
|
195
|
+
/** @type {NodeJS.Timeout} */
|
|
196
|
+
let timeoutHandle;
|
|
197
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
198
|
+
timeoutHandle = setTimeout(reject, options.timeout, new Error('Timed out fetching resource'));
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const responsePromise = this._loadNetworkResource(url);
|
|
202
|
+
|
|
203
|
+
/** @type {{stream: LH.Crdp.IO.StreamHandle|null, status: number|null}} */
|
|
204
|
+
const response = await Promise.race([responsePromise, timeoutPromise])
|
|
205
|
+
.finally(() => clearTimeout(timeoutHandle));
|
|
114
206
|
|
|
115
207
|
const isOk = response.status && response.status >= 200 && response.status <= 299;
|
|
116
208
|
if (!response.stream || !isOk) return {status: response.status, content: null};
|
|
@@ -121,21 +213,105 @@ class Fetcher {
|
|
|
121
213
|
}
|
|
122
214
|
|
|
123
215
|
/**
|
|
124
|
-
*
|
|
125
|
-
* @param {
|
|
126
|
-
* @param {number} ms
|
|
216
|
+
* Fetches resource by injecting an iframe into the page.
|
|
217
|
+
* @param {string} url
|
|
218
|
+
* @param {{timeout: number}} options timeout is in ms
|
|
219
|
+
* @return {Promise<FetchResponse>}
|
|
127
220
|
*/
|
|
128
|
-
async
|
|
221
|
+
async _fetchResourceIframe(url, options) {
|
|
222
|
+
/** @type {Promise<FetchResponse>} */
|
|
223
|
+
const requestInterceptionPromise = new Promise((resolve, reject) => {
|
|
224
|
+
/** @param {LH.Crdp.Fetch.RequestPausedEvent} event */
|
|
225
|
+
const handlerAsync = async event => {
|
|
226
|
+
const {requestId, responseStatusCode} = event;
|
|
227
|
+
|
|
228
|
+
// The first requestPaused event is for the request stage. Continue it.
|
|
229
|
+
if (!responseStatusCode) {
|
|
230
|
+
// Remove cookies so we aren't buying stuff on Amazon.
|
|
231
|
+
const headers = Object.entries(event.request.headers)
|
|
232
|
+
.filter(([name]) => name !== 'Cookie')
|
|
233
|
+
.map(([name, value]) => {
|
|
234
|
+
return {name, value};
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
await this.session.sendCommand('Fetch.continueRequest', {
|
|
238
|
+
requestId,
|
|
239
|
+
headers,
|
|
240
|
+
});
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (responseStatusCode >= 200 && responseStatusCode <= 299) {
|
|
245
|
+
resolve({
|
|
246
|
+
status: responseStatusCode,
|
|
247
|
+
content: await this._resolveResponseBody(requestId),
|
|
248
|
+
});
|
|
249
|
+
} else {
|
|
250
|
+
resolve({status: responseStatusCode, content: null});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Fail the request (from the page's perspective) so that the iframe never loads.
|
|
254
|
+
await this.session.sendCommand('Fetch.failRequest', {requestId, errorReason: 'Aborted'});
|
|
255
|
+
};
|
|
256
|
+
this._setOnRequestPausedHandler(url, event => handlerAsync(event).catch(reject));
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* @param {string} src
|
|
261
|
+
*/
|
|
262
|
+
/* c8 ignore start */
|
|
263
|
+
function injectIframe(src) {
|
|
264
|
+
const iframe = document.createElement('iframe');
|
|
265
|
+
// Try really hard not to affect the page.
|
|
266
|
+
iframe.style.display = 'none';
|
|
267
|
+
iframe.style.visibility = 'hidden';
|
|
268
|
+
iframe.style.position = 'absolute';
|
|
269
|
+
iframe.style.top = '-1000px';
|
|
270
|
+
iframe.style.left = '-1000px';
|
|
271
|
+
iframe.style.width = '1px';
|
|
272
|
+
iframe.style.height = '1px';
|
|
273
|
+
iframe.src = src;
|
|
274
|
+
iframe.onload = iframe.onerror = () => {
|
|
275
|
+
iframe.remove();
|
|
276
|
+
iframe.onload = null;
|
|
277
|
+
iframe.onerror = null;
|
|
278
|
+
};
|
|
279
|
+
document.body.appendChild(iframe);
|
|
280
|
+
}
|
|
281
|
+
/* c8 ignore stop */
|
|
282
|
+
|
|
129
283
|
/** @type {NodeJS.Timeout} */
|
|
130
|
-
let
|
|
284
|
+
let asyncTimeout;
|
|
285
|
+
/** @type {Promise<never>} */
|
|
131
286
|
const timeoutPromise = new Promise((_, reject) => {
|
|
132
|
-
|
|
287
|
+
asyncTimeout = setTimeout(reject, options.timeout, new Error('Timed out fetching resource.'));
|
|
133
288
|
});
|
|
134
289
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
290
|
+
const racePromise = Promise.race([
|
|
291
|
+
timeoutPromise,
|
|
292
|
+
requestInterceptionPromise,
|
|
293
|
+
]).finally(() => clearTimeout(asyncTimeout));
|
|
294
|
+
|
|
295
|
+
// Temporarily disable auto-attaching for this iframe.
|
|
296
|
+
await this.session.sendCommand('Target.setAutoAttach', {
|
|
297
|
+
autoAttach: false,
|
|
298
|
+
waitForDebuggerOnStart: false,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const injectionPromise = this.executionContext.evaluate(injectIframe, {
|
|
302
|
+
args: [url],
|
|
303
|
+
useIsolation: true,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const [fetchResult] = await Promise.all([racePromise, injectionPromise]);
|
|
307
|
+
|
|
308
|
+
await this.session.sendCommand('Target.setAutoAttach', {
|
|
309
|
+
flatten: true,
|
|
310
|
+
autoAttach: true,
|
|
311
|
+
waitForDebuggerOnStart: true,
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
return fetchResult;
|
|
139
315
|
}
|
|
140
316
|
}
|
|
141
317
|
|