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
|
@@ -71,7 +71,7 @@ class GatherRunner {
|
|
|
71
71
|
log.time(status);
|
|
72
72
|
try {
|
|
73
73
|
const requestedUrl = passContext.url;
|
|
74
|
-
const {
|
|
74
|
+
const {finalUrl, warnings} = await navigation.gotoURL(driver, requestedUrl, {
|
|
75
75
|
waitUntil: passContext.passConfig.recordTrace ?
|
|
76
76
|
['load', 'fcp'] : ['load'],
|
|
77
77
|
debugNavigation: passContext.settings.debugNavigation,
|
|
@@ -79,12 +79,7 @@ class GatherRunner {
|
|
|
79
79
|
maxWaitForLoad: passContext.settings.maxWaitForLoad,
|
|
80
80
|
...passContext.passConfig,
|
|
81
81
|
});
|
|
82
|
-
passContext.url =
|
|
83
|
-
const {URL} = passContext.baseArtifacts;
|
|
84
|
-
if (!URL.finalUrl || !URL.mainDocumentUrl) {
|
|
85
|
-
URL.finalUrl = mainDocumentUrl;
|
|
86
|
-
URL.mainDocumentUrl = mainDocumentUrl;
|
|
87
|
-
}
|
|
82
|
+
passContext.url = finalUrl;
|
|
88
83
|
if (passContext.passConfig.loadFailureMode === 'fatal') {
|
|
89
84
|
passContext.LighthouseRunWarnings.push(...warnings);
|
|
90
85
|
}
|
|
@@ -183,6 +178,11 @@ class GatherRunner {
|
|
|
183
178
|
const resetStorage = !options.settings.disableStorageReset;
|
|
184
179
|
if (resetStorage) await storage.clearDataForOrigin(session, options.requestedUrl);
|
|
185
180
|
|
|
181
|
+
// Disable fetcher, in case a gatherer enabled it.
|
|
182
|
+
// This cleanup should be removed once the only usage of
|
|
183
|
+
// fetcher (fetching arbitrary URLs) is replaced by new protocol support.
|
|
184
|
+
await driver.fetcher.disable();
|
|
185
|
+
|
|
186
186
|
await driver.disconnect();
|
|
187
187
|
} catch (err) {
|
|
188
188
|
// Ignore disconnecting error if browser was already closed.
|
|
@@ -407,12 +407,7 @@ class GatherRunner {
|
|
|
407
407
|
devtoolsLogs: {},
|
|
408
408
|
settings: options.settings,
|
|
409
409
|
GatherContext: {gatherMode: 'navigation'},
|
|
410
|
-
URL: {
|
|
411
|
-
initialUrl: await options.driver.url(),
|
|
412
|
-
requestedUrl: options.requestedUrl,
|
|
413
|
-
mainDocumentUrl: '',
|
|
414
|
-
finalUrl: '',
|
|
415
|
-
},
|
|
410
|
+
URL: {requestedUrl: options.requestedUrl, finalUrl: options.requestedUrl},
|
|
416
411
|
Timing: [],
|
|
417
412
|
PageLoadError: null,
|
|
418
413
|
};
|
|
@@ -430,6 +425,9 @@ class GatherRunner {
|
|
|
430
425
|
|
|
431
426
|
const baseArtifacts = passContext.baseArtifacts;
|
|
432
427
|
|
|
428
|
+
// Copy redirected URL to artifact.
|
|
429
|
+
baseArtifacts.URL.finalUrl = passContext.url;
|
|
430
|
+
|
|
433
431
|
// Fetch the manifest, if it exists.
|
|
434
432
|
try {
|
|
435
433
|
baseArtifacts.WebAppManifest = await WebAppManifest.getWebAppManifest(
|
|
@@ -519,6 +517,12 @@ class GatherRunner {
|
|
|
519
517
|
await GatherRunner.populateBaseArtifacts(passContext);
|
|
520
518
|
isFirstPass = false;
|
|
521
519
|
}
|
|
520
|
+
|
|
521
|
+
// Disable fetcher for every pass, in case a gatherer enabled it.
|
|
522
|
+
// Noop if fetcher was never enabled.
|
|
523
|
+
// This cleanup should be removed once the only usage of
|
|
524
|
+
// fetcher (fetching arbitrary URLs) is replaced by new protocol support.
|
|
525
|
+
await driver.fetcher.disable();
|
|
522
526
|
}
|
|
523
527
|
|
|
524
528
|
await GatherRunner.disposeDriver(driver, options);
|
|
@@ -12,6 +12,9 @@ const axeLibSource = require('../../lib/axe.js').source;
|
|
|
12
12
|
const pageFunctions = require('../../lib/page-functions.js');
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
+
* This is run in the page, not Lighthouse itself.
|
|
16
|
+
* axe.run returns a promise which fulfills with a results object
|
|
17
|
+
* containing any violations.
|
|
15
18
|
* @return {Promise<LH.Artifacts.Accessibility>}
|
|
16
19
|
*/
|
|
17
20
|
/* c8 ignore start */
|
|
@@ -35,11 +38,8 @@ async function runA11yChecks() {
|
|
|
35
38
|
'wcag2aa',
|
|
36
39
|
],
|
|
37
40
|
},
|
|
38
|
-
// resultTypes doesn't limit the output of the axeResults object. Instead, if it's defined,
|
|
39
|
-
// some expensive element identification is done only for the respective types. https://github.com/dequelabs/axe-core/blob/f62f0cf18f7b69b247b0b6362cf1ae71ffbf3a1b/lib/core/reporters/helpers/process-aggregate.js#L61-L97
|
|
40
41
|
resultTypes: ['violations', 'inapplicable'],
|
|
41
42
|
rules: {
|
|
42
|
-
// Consider http://go/prcpg for expert review of the aXe rules.
|
|
43
43
|
'tabindex': {enabled: true},
|
|
44
44
|
'accesskeys': {enabled: true},
|
|
45
45
|
'heading-order': {enabled: true},
|
|
@@ -60,12 +60,6 @@ async function runA11yChecks() {
|
|
|
60
60
|
// https://github.com/dequelabs/axe-core/issues/2958
|
|
61
61
|
'nested-interactive': {enabled: false},
|
|
62
62
|
'frame-focusable-content': {enabled: false},
|
|
63
|
-
'aria-roledescription': {enabled: false},
|
|
64
|
-
'scrollable-region-focusable': {enabled: false},
|
|
65
|
-
// TODO(paulirish): create audits and enable these 3.
|
|
66
|
-
'input-button-name': {enabled: false},
|
|
67
|
-
'role-img-alt': {enabled: false},
|
|
68
|
-
'select-name': {enabled: false},
|
|
69
63
|
},
|
|
70
64
|
});
|
|
71
65
|
|
|
@@ -76,8 +70,7 @@ async function runA11yChecks() {
|
|
|
76
70
|
return {
|
|
77
71
|
violations: axeResults.violations.map(createAxeRuleResultArtifact),
|
|
78
72
|
incomplete: axeResults.incomplete.map(createAxeRuleResultArtifact),
|
|
79
|
-
notApplicable: axeResults.inapplicable.map(result => ({id: result.id})),
|
|
80
|
-
passes: axeResults.passes.map(result => ({id: result.id})),
|
|
73
|
+
notApplicable: axeResults.inapplicable.map(result => ({id: result.id})),
|
|
81
74
|
version: axeResults.testEngine.version,
|
|
82
75
|
};
|
|
83
76
|
}
|
|
@@ -157,11 +150,6 @@ class Accessibility extends FRGatherer {
|
|
|
157
150
|
supportedModes: ['snapshot', 'navigation'],
|
|
158
151
|
};
|
|
159
152
|
|
|
160
|
-
static pageFns = {
|
|
161
|
-
runA11yChecks,
|
|
162
|
-
createAxeRuleResultArtifact,
|
|
163
|
-
};
|
|
164
|
-
|
|
165
153
|
/**
|
|
166
154
|
* @param {LH.Gatherer.FRTransitionalContext} passContext
|
|
167
155
|
* @return {Promise<LH.Artifacts.Accessibility>}
|
|
@@ -101,7 +101,6 @@ class ConsoleMessages extends FRGatherer {
|
|
|
101
101
|
stackTrace: event.exceptionDetails.stackTrace,
|
|
102
102
|
timestamp: event.timestamp,
|
|
103
103
|
url: event.exceptionDetails.url,
|
|
104
|
-
scriptId: event.exceptionDetails.scriptId,
|
|
105
104
|
lineNumber: event.exceptionDetails.lineNumber,
|
|
106
105
|
columnNumber: event.exceptionDetails.columnNumber,
|
|
107
106
|
};
|
|
@@ -118,7 +117,7 @@ class ConsoleMessages extends FRGatherer {
|
|
|
118
117
|
|
|
119
118
|
// JS events have a stack trace, which we use to get the column.
|
|
120
119
|
// CSS/HTML events only expose a line number.
|
|
121
|
-
const
|
|
120
|
+
const {columnNumber} = event.entry.stackTrace?.callFrames[0] || {};
|
|
122
121
|
|
|
123
122
|
this._logEntries.push({
|
|
124
123
|
eventType: 'protocolLog',
|
|
@@ -128,9 +127,8 @@ class ConsoleMessages extends FRGatherer {
|
|
|
128
127
|
stackTrace,
|
|
129
128
|
timestamp,
|
|
130
129
|
url,
|
|
131
|
-
scriptId: firstStackFrame?.scriptId,
|
|
132
130
|
lineNumber,
|
|
133
|
-
columnNumber
|
|
131
|
+
columnNumber,
|
|
134
132
|
});
|
|
135
133
|
}
|
|
136
134
|
|
|
@@ -12,8 +12,7 @@ const FRGatherer = require('../../../fraggle-rock/gather/base-gatherer.js');
|
|
|
12
12
|
/**
|
|
13
13
|
* Get and return `name`, `publicId`, `systemId` from
|
|
14
14
|
* `document.doctype`
|
|
15
|
-
*
|
|
16
|
-
* @return {{name: string, publicId: string, systemId: string, documentCompatMode: string} | null}
|
|
15
|
+
* @return {{name: string, publicId: string, systemId: string} | null}
|
|
17
16
|
*/
|
|
18
17
|
function getDoctype() {
|
|
19
18
|
// An example of this is warnerbros.com/archive/spacejam/movie/jam.htm
|
|
@@ -21,9 +20,8 @@ function getDoctype() {
|
|
|
21
20
|
return null;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
const documentCompatMode = document.compatMode;
|
|
25
23
|
const {name, publicId, systemId} = document.doctype;
|
|
26
|
-
return {name, publicId, systemId
|
|
24
|
+
return {name, publicId, systemId};
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
class Doctype extends FRGatherer {
|
|
@@ -15,7 +15,6 @@ const {waitForNetworkIdle} = require('../driver/wait-for-condition.js');
|
|
|
15
15
|
|
|
16
16
|
// JPEG quality setting
|
|
17
17
|
// Exploration and examples of reports using different quality settings: https://docs.google.com/document/d/1ZSffucIca9XDW2eEwfoevrk-OTl7WQFeMf0CgeJAA8M/edit#
|
|
18
|
-
// Note: this analysis was done for JPEG, but now we use WEBP.
|
|
19
18
|
const FULL_PAGE_SCREENSHOT_QUALITY = 30;
|
|
20
19
|
|
|
21
20
|
/**
|
|
@@ -119,10 +118,10 @@ class FullPageScreenshot extends FRGatherer {
|
|
|
119
118
|
await context.driver.executionContext.evaluate(waitForDoubleRaf, {args: []});
|
|
120
119
|
|
|
121
120
|
const result = await session.sendCommand('Page.captureScreenshot', {
|
|
122
|
-
format: '
|
|
121
|
+
format: 'jpeg',
|
|
123
122
|
quality: FULL_PAGE_SCREENSHOT_QUALITY,
|
|
124
123
|
});
|
|
125
|
-
const data = 'data:image/
|
|
124
|
+
const data = 'data:image/jpeg;base64,' + result.data;
|
|
126
125
|
|
|
127
126
|
return {
|
|
128
127
|
data,
|
|
@@ -17,13 +17,10 @@ const pageFunctions = require('../../lib/page-functions.js');
|
|
|
17
17
|
*/
|
|
18
18
|
/* c8 ignore start */
|
|
19
19
|
function collectIFrameElements() {
|
|
20
|
-
const realBoundingClientRect = window.__HTMLElementBoundingClientRect ||
|
|
21
|
-
window.HTMLElement.prototype.getBoundingClientRect;
|
|
22
|
-
|
|
23
20
|
// @ts-expect-error - put into scope via stringification
|
|
24
21
|
const iFrameElements = getElementsInDocument('iframe'); // eslint-disable-line no-undef
|
|
25
22
|
return iFrameElements.map(/** @param {HTMLIFrameElement} node */ (node) => {
|
|
26
|
-
const clientRect =
|
|
23
|
+
const clientRect = node.getBoundingClientRect();
|
|
27
24
|
const {top, bottom, left, right, width, height} = clientRect;
|
|
28
25
|
return {
|
|
29
26
|
id: node.id,
|
|
@@ -258,7 +258,6 @@ class ImageElements extends FRGatherer {
|
|
|
258
258
|
driver.defaultSession.setNextProtocolTimeout(250);
|
|
259
259
|
size = await driver.executionContext.evaluate(determineNaturalSize, {
|
|
260
260
|
args: [url],
|
|
261
|
-
useIsolation: true,
|
|
262
261
|
});
|
|
263
262
|
this._naturalSizeCache.set(url, size);
|
|
264
263
|
} catch (_) {
|
|
@@ -341,7 +340,6 @@ class ImageElements extends FRGatherer {
|
|
|
341
340
|
|
|
342
341
|
const elements = await executionContext.evaluate(collectImageElementInfo, {
|
|
343
342
|
args: [],
|
|
344
|
-
useIsolation: true,
|
|
345
343
|
deps: [
|
|
346
344
|
pageFunctions.getElementsInDocumentString,
|
|
347
345
|
pageFunctions.getBoundingClientRectString,
|
|
@@ -18,8 +18,20 @@ class JsUsage extends FRGatherer {
|
|
|
18
18
|
|
|
19
19
|
constructor() {
|
|
20
20
|
super();
|
|
21
|
+
/** @type {LH.Crdp.Debugger.ScriptParsedEvent[]} */
|
|
22
|
+
this._scriptParsedEvents = [];
|
|
21
23
|
/** @type {LH.Crdp.Profiler.ScriptCoverage[]} */
|
|
22
24
|
this._scriptUsages = [];
|
|
25
|
+
this.onScriptParsed = this.onScriptParsed.bind(this);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {LH.Crdp.Debugger.ScriptParsedEvent} event
|
|
30
|
+
*/
|
|
31
|
+
onScriptParsed(event) {
|
|
32
|
+
if (event.embedderName) {
|
|
33
|
+
this._scriptParsedEvents.push(event);
|
|
34
|
+
}
|
|
23
35
|
}
|
|
24
36
|
|
|
25
37
|
/**
|
|
@@ -43,27 +55,90 @@ class JsUsage extends FRGatherer {
|
|
|
43
55
|
}
|
|
44
56
|
|
|
45
57
|
/**
|
|
58
|
+
* @param {LH.Gatherer.FRTransitionalContext} context
|
|
59
|
+
*/
|
|
60
|
+
async startSensitiveInstrumentation(context) {
|
|
61
|
+
const session = context.driver.defaultSession;
|
|
62
|
+
session.on('Debugger.scriptParsed', this.onScriptParsed);
|
|
63
|
+
await session.sendCommand('Debugger.enable');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {LH.Gatherer.FRTransitionalContext} context
|
|
68
|
+
*/
|
|
69
|
+
async stopSensitiveInstrumentation(context) {
|
|
70
|
+
const session = context.driver.defaultSession;
|
|
71
|
+
await session.sendCommand('Debugger.disable');
|
|
72
|
+
session.off('Debugger.scriptParsed', this.onScriptParsed);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Usages alone do not always generate an exhaustive list of scripts in timespan and snapshot.
|
|
77
|
+
* For audits which use this for url/scriptId mappings, we can include an empty usage object.
|
|
78
|
+
*
|
|
79
|
+
* @param {Record<string, Array<LH.Crdp.Profiler.ScriptCoverage>>} usageByUrl
|
|
80
|
+
*/
|
|
81
|
+
_addMissingScriptIds(usageByUrl) {
|
|
82
|
+
for (const scriptParsedEvent of this._scriptParsedEvents) {
|
|
83
|
+
const url = scriptParsedEvent.embedderName;
|
|
84
|
+
if (!url) continue;
|
|
85
|
+
|
|
86
|
+
const scripts = usageByUrl[url] || [];
|
|
87
|
+
if (!scripts.find(s => s.scriptId === scriptParsedEvent.scriptId)) {
|
|
88
|
+
scripts.push({
|
|
89
|
+
url,
|
|
90
|
+
scriptId: scriptParsedEvent.scriptId,
|
|
91
|
+
functions: [],
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
usageByUrl[url] = scripts;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @param {LH.Gatherer.FRTransitionalContext} context
|
|
46
100
|
* @return {Promise<LH.Artifacts['JsUsage']>}
|
|
47
101
|
*/
|
|
48
|
-
async getArtifact() {
|
|
49
|
-
/** @type {Record<string, LH.Crdp.Profiler.ScriptCoverage
|
|
50
|
-
const
|
|
102
|
+
async getArtifact(context) {
|
|
103
|
+
/** @type {Record<string, Array<LH.Crdp.Profiler.ScriptCoverage>>} */
|
|
104
|
+
const usageByUrl = {};
|
|
105
|
+
|
|
106
|
+
// Force `Debugger.scriptParsed` events for url to scriptId mappings in snapshot mode.
|
|
107
|
+
if (context.gatherMode === 'snapshot') {
|
|
108
|
+
await this.startSensitiveInstrumentation(context);
|
|
109
|
+
await this.stopSensitiveInstrumentation(context);
|
|
110
|
+
}
|
|
51
111
|
|
|
52
112
|
for (const scriptUsage of this._scriptUsages) {
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
113
|
+
// `ScriptCoverage.url` can be overridden by a magic sourceURL comment.
|
|
114
|
+
// Get the associated ScriptParsedEvent and use embedderName, which is the original url.
|
|
115
|
+
// See https://chromium-review.googlesource.com/c/v8/v8/+/2317310
|
|
116
|
+
let url = scriptUsage.url;
|
|
117
|
+
const scriptParsedEvent =
|
|
118
|
+
this._scriptParsedEvents.find(e => e.scriptId === scriptUsage.scriptId);
|
|
119
|
+
if (scriptParsedEvent?.embedderName) {
|
|
120
|
+
url = scriptParsedEvent.embedderName;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// If `url` is blank, that means the script was anonymous (eval, new Function, onload, ...).
|
|
124
|
+
// Or, it's because it was code Lighthouse over the protocol via `Runtime.evaluate`.
|
|
125
|
+
// We currently don't consider coverage of anonymous scripts, and we definitely don't want
|
|
126
|
+
// coverage of code Lighthouse ran to inspect the page, so we ignore this ScriptCoverage if
|
|
127
|
+
// url is blank.
|
|
128
|
+
if (scriptUsage.url === '' || (scriptParsedEvent && scriptParsedEvent.embedderName === '')) {
|
|
60
129
|
continue;
|
|
61
130
|
}
|
|
62
131
|
|
|
63
|
-
|
|
132
|
+
const scripts = usageByUrl[url] || [];
|
|
133
|
+
scripts.push(scriptUsage);
|
|
134
|
+
usageByUrl[url] = scripts;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (context.gatherMode !== 'navigation') {
|
|
138
|
+
this._addMissingScriptIds(usageByUrl);
|
|
64
139
|
}
|
|
65
140
|
|
|
66
|
-
return
|
|
141
|
+
return usageByUrl;
|
|
67
142
|
}
|
|
68
143
|
}
|
|
69
144
|
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
const LinkHeader = require('http-link-header');
|
|
9
9
|
const FRGatherer = require('../../fraggle-rock/gather/base-gatherer.js');
|
|
10
10
|
const {URL} = require('../../lib/url-shim.js');
|
|
11
|
+
const NetworkRecords = require('../../computed/network-records.js');
|
|
12
|
+
const NetworkAnalyzer = require('../../lib/dependency-graph/simulator/network-analyzer.js');
|
|
11
13
|
const pageFunctions = require('../../lib/page-functions.js');
|
|
12
14
|
const DevtoolsLog = require('./devtools-log.js');
|
|
13
|
-
const MainResource = require('../../computed/main-resource.js');
|
|
14
15
|
|
|
15
16
|
/* globals HTMLLinkElement getNodeDetails */
|
|
16
17
|
|
|
@@ -113,12 +114,12 @@ class LinkElements extends FRGatherer {
|
|
|
113
114
|
|
|
114
115
|
/**
|
|
115
116
|
* @param {LH.Gatherer.FRTransitionalContext} context
|
|
116
|
-
* @param {LH.Artifacts[
|
|
117
|
-
* @return {
|
|
117
|
+
* @param {LH.Artifacts.NetworkRequest[]} networkRecords
|
|
118
|
+
* @return {LH.Artifacts['LinkElements']}
|
|
118
119
|
*/
|
|
119
|
-
static
|
|
120
|
-
const
|
|
121
|
-
|
|
120
|
+
static getLinkElementsInHeaders(context, networkRecords) {
|
|
121
|
+
const finalUrl = context.url;
|
|
122
|
+
const mainDocument = NetworkAnalyzer.findMainDocument(networkRecords, finalUrl);
|
|
122
123
|
|
|
123
124
|
/** @type {LH.Artifacts['LinkElements']} */
|
|
124
125
|
const linkElements = [];
|
|
@@ -129,7 +130,7 @@ class LinkElements extends FRGatherer {
|
|
|
129
130
|
for (const link of LinkHeader.parse(header.value).refs) {
|
|
130
131
|
linkElements.push({
|
|
131
132
|
rel: link.rel || '',
|
|
132
|
-
href: normalizeUrlOrNull(link.uri,
|
|
133
|
+
href: normalizeUrlOrNull(link.uri, finalUrl),
|
|
133
134
|
hrefRaw: link.uri || '',
|
|
134
135
|
hreflang: link.hreflang || '',
|
|
135
136
|
as: link.as || '',
|
|
@@ -145,12 +146,12 @@ class LinkElements extends FRGatherer {
|
|
|
145
146
|
|
|
146
147
|
/**
|
|
147
148
|
* @param {LH.Gatherer.FRTransitionalContext} context
|
|
148
|
-
* @param {LH.Artifacts[
|
|
149
|
+
* @param {LH.Artifacts.NetworkRequest[]} networkRecords
|
|
149
150
|
* @return {Promise<LH.Artifacts['LinkElements']>}
|
|
150
151
|
*/
|
|
151
|
-
async _getArtifact(context,
|
|
152
|
+
async _getArtifact(context, networkRecords) {
|
|
152
153
|
const fromDOM = await LinkElements.getLinkElementsInDOM(context);
|
|
153
|
-
const fromHeaders =
|
|
154
|
+
const fromHeaders = LinkElements.getLinkElementsInHeaders(context, networkRecords);
|
|
154
155
|
const linkElements = fromDOM.concat(fromHeaders);
|
|
155
156
|
|
|
156
157
|
for (const link of linkElements) {
|
|
@@ -167,7 +168,7 @@ class LinkElements extends FRGatherer {
|
|
|
167
168
|
* @return {Promise<LH.Artifacts['LinkElements']>}
|
|
168
169
|
*/
|
|
169
170
|
async afterPass(context, loadData) {
|
|
170
|
-
return this._getArtifact({...context, dependencies: {}}, loadData.
|
|
171
|
+
return this._getArtifact({...context, dependencies: {}}, loadData.networkRecords);
|
|
171
172
|
}
|
|
172
173
|
|
|
173
174
|
/**
|
|
@@ -175,7 +176,8 @@ class LinkElements extends FRGatherer {
|
|
|
175
176
|
* @return {Promise<LH.Artifacts['LinkElements']>}
|
|
176
177
|
*/
|
|
177
178
|
async getArtifact(context) {
|
|
178
|
-
|
|
179
|
+
const records = await NetworkRecords.request(context.dependencies.DevtoolsLog, context);
|
|
180
|
+
return this._getArtifact(context, records);
|
|
179
181
|
}
|
|
180
182
|
}
|
|
181
183
|
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
8
|
const FRGatherer = require('../../fraggle-rock/gather/base-gatherer.js');
|
|
9
|
+
const NetworkAnalyzer = require('../../lib/dependency-graph/simulator/network-analyzer.js');
|
|
10
|
+
const NetworkRecords = require('../../computed/network-records.js');
|
|
9
11
|
const DevtoolsLog = require('./devtools-log.js');
|
|
10
12
|
const {fetchResponseBodyFromCache} = require('../driver/network.js');
|
|
11
|
-
const MainResource = require('../../computed/main-resource.js');
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Collects the content of the main html document.
|
|
@@ -23,16 +24,14 @@ class MainDocumentContent extends FRGatherer {
|
|
|
23
24
|
/**
|
|
24
25
|
*
|
|
25
26
|
* @param {LH.Gatherer.FRTransitionalContext} context
|
|
26
|
-
* @param {LH.Artifacts[
|
|
27
|
+
* @param {LH.Artifacts.NetworkRequest[]} networkRecords
|
|
27
28
|
* @return {Promise<LH.Artifacts['MainDocumentContent']>}
|
|
28
29
|
*/
|
|
29
|
-
async _getArtifact(context,
|
|
30
|
-
const mainResource =
|
|
31
|
-
await MainResource.request({devtoolsLog, URL: context.baseArtifacts.URL}, context);
|
|
30
|
+
async _getArtifact(context, networkRecords) {
|
|
31
|
+
const mainResource = NetworkAnalyzer.findMainDocument(networkRecords, context.url);
|
|
32
32
|
const session = context.driver.defaultSession;
|
|
33
33
|
return fetchResponseBodyFromCache(session, mainResource.requestId);
|
|
34
34
|
}
|
|
35
|
-
|
|
36
35
|
/**
|
|
37
36
|
*
|
|
38
37
|
* @param {LH.Gatherer.FRTransitionalContext<'DevtoolsLog'>} context
|
|
@@ -40,7 +39,8 @@ class MainDocumentContent extends FRGatherer {
|
|
|
40
39
|
*/
|
|
41
40
|
async getArtifact(context) {
|
|
42
41
|
const devtoolsLog = context.dependencies.DevtoolsLog;
|
|
43
|
-
|
|
42
|
+
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
|
|
43
|
+
return this._getArtifact(context, networkRecords);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -49,7 +49,7 @@ class MainDocumentContent extends FRGatherer {
|
|
|
49
49
|
* @return {Promise<LH.Artifacts['MainDocumentContent']>}
|
|
50
50
|
*/
|
|
51
51
|
async afterPass(passContext, loadData) {
|
|
52
|
-
return this._getArtifact({...passContext, dependencies: {}}, loadData.
|
|
52
|
+
return this._getArtifact({...passContext, dependencies: {}}, loadData.networkRecords);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
const FRGatherer = require('../../fraggle-rock/gather/base-gatherer.js');
|
|
9
9
|
const NetworkRecords = require('../../computed/network-records.js');
|
|
10
|
+
const NetworkAnalyzer = require('../../lib/dependency-graph/simulator/network-analyzer.js');
|
|
10
11
|
const NetworkRequest = require('../../lib/network-request.js');
|
|
11
12
|
const pageFunctions = require('../../lib/page-functions.js');
|
|
13
|
+
const {fetchResponseBodyFromCache} = require('../driver/network.js');
|
|
12
14
|
const DevtoolsLog = require('./devtools-log.js');
|
|
13
15
|
|
|
14
16
|
/* global getNodeDetails */
|
|
@@ -30,6 +32,8 @@ function collectAllScriptElements() {
|
|
|
30
32
|
async: script.async,
|
|
31
33
|
defer: script.defer,
|
|
32
34
|
source: script.closest('head') ? 'head' : 'body',
|
|
35
|
+
content: script.src ? null : script.text,
|
|
36
|
+
requestId: null,
|
|
33
37
|
// @ts-expect-error - getNodeDetails put into scope via stringification
|
|
34
38
|
node: getNodeDetails(script),
|
|
35
39
|
};
|
|
@@ -37,6 +41,27 @@ function collectAllScriptElements() {
|
|
|
37
41
|
}
|
|
38
42
|
/* c8 ignore stop */
|
|
39
43
|
|
|
44
|
+
/**
|
|
45
|
+
* @template T, U
|
|
46
|
+
* @param {Array<T>} values
|
|
47
|
+
* @param {(value: T) => Promise<U>} promiseMapper
|
|
48
|
+
* @param {boolean} runInSeries
|
|
49
|
+
* @return {Promise<Array<U>>}
|
|
50
|
+
*/
|
|
51
|
+
async function runInSeriesOrParallel(values, promiseMapper, runInSeries) {
|
|
52
|
+
if (runInSeries) {
|
|
53
|
+
const results = [];
|
|
54
|
+
for (const value of values) {
|
|
55
|
+
const result = await promiseMapper(value);
|
|
56
|
+
results.push(result);
|
|
57
|
+
}
|
|
58
|
+
return results;
|
|
59
|
+
} else {
|
|
60
|
+
const promises = values.map(promiseMapper);
|
|
61
|
+
return await Promise.all(promises);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
40
65
|
/**
|
|
41
66
|
* @fileoverview Gets JavaScript file contents.
|
|
42
67
|
*/
|
|
@@ -50,10 +75,13 @@ class ScriptElements extends FRGatherer {
|
|
|
50
75
|
/**
|
|
51
76
|
* @param {LH.Gatherer.FRTransitionalContext} context
|
|
52
77
|
* @param {LH.Artifacts.NetworkRequest[]} networkRecords
|
|
78
|
+
* @param {LH.Artifacts['HostFormFactor']} formFactor
|
|
53
79
|
* @return {Promise<LH.Artifacts['ScriptElements']>}
|
|
54
80
|
*/
|
|
55
|
-
async _getArtifact(context, networkRecords) {
|
|
81
|
+
async _getArtifact(context, networkRecords, formFactor) {
|
|
82
|
+
const session = context.driver.defaultSession;
|
|
56
83
|
const executionContext = context.driver.executionContext;
|
|
84
|
+
const mainResource = NetworkAnalyzer.findOptionalMainDocument(networkRecords, context.url);
|
|
57
85
|
|
|
58
86
|
const scripts = await executionContext.evaluate(collectAllScriptElements, {
|
|
59
87
|
args: [],
|
|
@@ -64,16 +92,34 @@ class ScriptElements extends FRGatherer {
|
|
|
64
92
|
],
|
|
65
93
|
});
|
|
66
94
|
|
|
95
|
+
for (const script of scripts) {
|
|
96
|
+
if (mainResource && script.content) script.requestId = mainResource.requestId;
|
|
97
|
+
}
|
|
98
|
+
|
|
67
99
|
const scriptRecords = networkRecords
|
|
68
|
-
.filter(record => record.resourceType === NetworkRequest.TYPES.Script)
|
|
69
100
|
// Ignore records from OOPIFs
|
|
70
|
-
.filter(record => !record.sessionId)
|
|
101
|
+
.filter(record => !record.sessionId)
|
|
102
|
+
// Only get the content of script requests
|
|
103
|
+
.filter(record => record.resourceType === NetworkRequest.TYPES.Script);
|
|
104
|
+
|
|
105
|
+
// If run on a mobile device, be sensitive to memory limitations and only request one
|
|
106
|
+
// record at a time.
|
|
107
|
+
const scriptRecordContents = await runInSeriesOrParallel(
|
|
108
|
+
scriptRecords,
|
|
109
|
+
record => fetchResponseBodyFromCache(session, record.requestId).catch(() => ''),
|
|
110
|
+
formFactor === 'mobile' /* runInSeries */
|
|
111
|
+
);
|
|
71
112
|
|
|
72
113
|
for (let i = 0; i < scriptRecords.length; i++) {
|
|
73
114
|
const record = scriptRecords[i];
|
|
115
|
+
const content = scriptRecordContents[i];
|
|
116
|
+
if (!content) continue;
|
|
74
117
|
|
|
75
118
|
const matchedScriptElement = scripts.find(script => script.src === record.url);
|
|
76
|
-
if (
|
|
119
|
+
if (matchedScriptElement) {
|
|
120
|
+
matchedScriptElement.requestId = record.requestId;
|
|
121
|
+
matchedScriptElement.content = content;
|
|
122
|
+
} else {
|
|
77
123
|
scripts.push({
|
|
78
124
|
type: null,
|
|
79
125
|
src: record.url,
|
|
@@ -81,11 +127,12 @@ class ScriptElements extends FRGatherer {
|
|
|
81
127
|
async: false,
|
|
82
128
|
defer: false,
|
|
83
129
|
source: 'network',
|
|
130
|
+
requestId: record.requestId,
|
|
131
|
+
content,
|
|
84
132
|
node: null,
|
|
85
133
|
});
|
|
86
134
|
}
|
|
87
135
|
}
|
|
88
|
-
|
|
89
136
|
return scripts;
|
|
90
137
|
}
|
|
91
138
|
|
|
@@ -94,8 +141,9 @@ class ScriptElements extends FRGatherer {
|
|
|
94
141
|
*/
|
|
95
142
|
async getArtifact(context) {
|
|
96
143
|
const devtoolsLog = context.dependencies.DevtoolsLog;
|
|
144
|
+
const formFactor = context.baseArtifacts.HostFormFactor;
|
|
97
145
|
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
|
|
98
|
-
return this._getArtifact(context, networkRecords);
|
|
146
|
+
return this._getArtifact(context, networkRecords, formFactor);
|
|
99
147
|
}
|
|
100
148
|
|
|
101
149
|
/**
|
|
@@ -104,7 +152,8 @@ class ScriptElements extends FRGatherer {
|
|
|
104
152
|
*/
|
|
105
153
|
async afterPass(passContext, loadData) {
|
|
106
154
|
const networkRecords = loadData.networkRecords;
|
|
107
|
-
|
|
155
|
+
const formFactor = passContext.baseArtifacts.HostFormFactor;
|
|
156
|
+
return this._getArtifact({...passContext, dependencies: {}}, networkRecords, formFactor);
|
|
108
157
|
}
|
|
109
158
|
}
|
|
110
159
|
|
|
@@ -7,6 +7,25 @@
|
|
|
7
7
|
|
|
8
8
|
const FRGatherer = require('../../../fraggle-rock/gather/base-gatherer.js');
|
|
9
9
|
|
|
10
|
+
/* global fetch, location */
|
|
11
|
+
|
|
12
|
+
/** @return {Promise<LH.Artifacts['RobotsTxt']>} */
|
|
13
|
+
/* c8 ignore start */
|
|
14
|
+
async function getRobotsTxtContent() {
|
|
15
|
+
try {
|
|
16
|
+
const response = await fetch(new URL('/robots.txt', location.href).href);
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
return {status: response.status, content: null};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const content = await response.text();
|
|
22
|
+
return {status: response.status, content};
|
|
23
|
+
} catch (err) {
|
|
24
|
+
return {status: null, content: null, errorMessage: err.message};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/* c8 ignore stop */
|
|
28
|
+
|
|
10
29
|
class RobotsTxt extends FRGatherer {
|
|
11
30
|
/** @type {LH.Gatherer.GathererMeta} */
|
|
12
31
|
meta = {
|
|
@@ -18,8 +37,17 @@ class RobotsTxt extends FRGatherer {
|
|
|
18
37
|
* @return {Promise<LH.Artifacts['RobotsTxt']>}
|
|
19
38
|
*/
|
|
20
39
|
async getArtifact(passContext) {
|
|
21
|
-
|
|
22
|
-
|
|
40
|
+
// Iframe fetcher still has issues with CSPs.
|
|
41
|
+
// Only use the fetcher if we are fetching over the protocol.
|
|
42
|
+
if (await passContext.driver.fetcher.shouldUseLegacyFetcher()) {
|
|
43
|
+
return passContext.driver.executionContext.evaluate(getRobotsTxtContent, {
|
|
44
|
+
args: [],
|
|
45
|
+
useIsolation: true,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const robotsUrl = new URL('/robots.txt', passContext.url).href;
|
|
50
|
+
await passContext.driver.fetcher.enable();
|
|
23
51
|
return passContext.driver.fetcher.fetchResource(robotsUrl)
|
|
24
52
|
.catch(err => ({status: null, content: null, errorMessage: err.message}));
|
|
25
53
|
}
|