[go: nahoru, domu]

blob: 079ef1498d6072836a0b293296189d0f353545f0 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {click, goToResource, waitFor, waitForElementWithTextContent, waitForFunction} from '../../shared/helper.js';
import {waitForQuotaUsage} from './application-helpers.js';
import {type ElementHandle} from 'puppeteer';
export async function navigateToLighthouseTab(path?: string): Promise<ElementHandle<Element>> {
await click('#tab-lighthouse');
await waitFor('.view-container > .lighthouse');
if (path) {
await goToResource(path);
}
return waitFor('.lighthouse-start-view-fr');
}
// Instead of watching the worker or controller/panel internals, we wait for the Lighthouse renderer
// to create the new report DOM. And we pull the LHR and artifacts off the lh-root node.
export async function waitForResult() {
return await waitForFunction(async () => {
const reportEl = await waitFor('.lh-root');
const result = await reportEl.evaluate(elem => {
// @ts-expect-error we installed this obj on a DOM element
const lhr = elem._lighthouseResultForTesting;
// @ts-expect-error we installed this obj on a DOM element
const artifacts = elem._lighthouseArtifactsForTesting;
// Delete so any subsequent runs don't accidentally reuse this.
// @ts-expect-error
delete elem._lighthouseResultForTesting;
// @ts-expect-error
delete elem._lighthouseArtifactsForTesting;
return {lhr, artifacts};
});
return {...result, reportEl};
});
}
// Can't reference ToolbarSettingCheckbox inside e2e
type CheckboxLabel = Element&{checkboxElement: HTMLInputElement};
/**
* Set the category checkboxes
* @param selectedCategoryIds One of 'performance'|'accessibility'|'best-practices'|'seo'|'pwa'|'lighthouse-plugin-publisher-ads'
*/
export async function selectCategories(selectedCategoryIds: string[]) {
const startViewHandle = await waitFor('.lighthouse-start-view-fr');
const checkboxHandles = await startViewHandle.$$('[is=dt-checkbox]');
for (const checkboxHandle of checkboxHandles) {
await checkboxHandle.evaluate((dtCheckboxElem, selectedCategoryIds: string[]) => {
const elem = dtCheckboxElem as CheckboxLabel;
const categoryId = elem.getAttribute('data-lh-category') || '';
elem.checkboxElement.checked = selectedCategoryIds.includes(categoryId);
elem.checkboxElement.dispatchEvent(new Event('change')); // Need change event to update the backing setting.
}, selectedCategoryIds);
}
}
export async function selectMode(device: 'mobile'|'desktop') {
const startViewHandle = await waitFor('.lighthouse-start-view-fr');
await startViewHandle.$eval(`input[value="${device}"][name="lighthouse.device_type"]`, radioElem => {
(radioElem as HTMLInputElement).checked = true;
(radioElem as HTMLInputElement)
.dispatchEvent(new Event('change')); // Need change event to update the backing setting.
});
}
export async function setToolbarCheckboxWithText(enabled: boolean, textContext: string) {
const toolbarHandle = await waitFor('.lighthouse-settings-pane .toolbar');
const label = await waitForElementWithTextContent(textContext, toolbarHandle);
await label.evaluate((label, enabled: boolean) => {
const rootNode = label.getRootNode() as ShadowRoot;
const checkboxId = label.getAttribute('for') as string;
const checkboxElem = rootNode.getElementById(checkboxId) as HTMLInputElement;
checkboxElem.checked = enabled;
checkboxElem.dispatchEvent(new Event('change')); // Need change event to update the backing setting.
}, enabled);
}
export async function setLegacyNavigation(enabled: boolean) {
return setToolbarCheckboxWithText(enabled, 'Legacy navigation');
}
export async function setThrottlingMethod(throttlingMethod: 'simulate'|'devtools') {
const toolbarHandle = await waitFor('.lighthouse-settings-pane .toolbar');
await toolbarHandle.evaluate((toolbar, throttlingMethod) => {
const selectElem = toolbar.shadowRoot?.querySelector('select') as HTMLSelectElement;
const optionElem = selectElem.querySelector(`option[value="${throttlingMethod}"]`) as HTMLOptionElement;
optionElem.selected = true;
selectElem.dispatchEvent(new Event('change')); // Need change event to update the backing setting.
}, throttlingMethod);
}
export async function clickStartButton() {
const panel = await waitFor('.lighthouse-start-view-fr');
const button = await waitFor('button', panel);
await button.click();
}
export async function isGenerateReportButtonDisabled() {
const button = await waitFor('.lighthouse-start-view-fr .primary-button');
return button.evaluate(element => (element as HTMLButtonElement).disabled);
}
export async function openStorageView() {
await click('#tab-resources');
const STORAGE_SELECTOR = '[aria-label="Storage"]';
await waitFor('.storage-group-list-item');
await waitFor(STORAGE_SELECTOR);
await click(STORAGE_SELECTOR);
}
export async function clearSiteData() {
await goToResource('empty.html');
await openStorageView();
await click('#storage-view-clear-button');
await waitForQuotaUsage(quota => quota === 0);
}
export async function waitForStorageUsage(p: (quota: number) => boolean) {
await openStorageView();
await waitForQuotaUsage(p);
await click('#tab-lighthouse');
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getAuditsBreakdown(lhr: any, flakyAudits: string[] = []) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const auditResults = Object.values(lhr.audits) as any[];
const irrelevantDisplayModes = new Set(['notApplicable', 'manual']);
const applicableAudits = auditResults.filter(
audit => !irrelevantDisplayModes.has(audit.scoreDisplayMode),
);
const informativeAudits = applicableAudits.filter(
audit => audit.scoreDisplayMode === 'informative',
);
const erroredAudits = applicableAudits.filter(
audit => audit.score === null && audit && !informativeAudits.includes(audit),
);
// 0.5 is the minimum score before we consider an audit "failed"
// https://github.com/GoogleChrome/lighthouse/blob/d956ec929d2b67028279f5e40d7e9a515a0b7404/report/renderer/util.js#L27
const failedAudits = applicableAudits.filter(
audit => audit.score !== null && audit.score < 0.5 && !flakyAudits.includes(audit.id),
);
return {auditResults, erroredAudits, failedAudits};
}