[ve] Instrument and test performance panel
Bug: 308381366, 348173254
Change-Id: Ie1e2d4a757adaea70ede3ab5298183ceb238384c
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5741263
Reviewed-by: Jack Franklin <jacktfranklin@chromium.org>
Auto-Submit: Danil Somsikov <dsv@chromium.org>
Commit-Queue: Danil Somsikov <dsv@chromium.org>
diff --git a/front_end/panels/mobile_throttling/ThrottlingManager.ts b/front_end/panels/mobile_throttling/ThrottlingManager.ts
index cf87b0b..acd99ca 100644
--- a/front_end/panels/mobile_throttling/ThrottlingManager.ts
+++ b/front_end/panels/mobile_throttling/ThrottlingManager.ts
@@ -299,7 +299,7 @@
createCPUThrottlingSelector(): UI.Toolbar.ToolbarComboBox {
const control = new UI.Toolbar.ToolbarComboBox(
event => this.setCPUThrottlingRate(this.cpuThrottlingRates[(event.target as HTMLSelectElement).selectedIndex]),
- i18nString(UIStrings.cpuThrottling), '', 'cpu-throttling-selector');
+ i18nString(UIStrings.cpuThrottling), '', 'cpu-throttling');
this.cpuThrottlingControls.add(control);
const currentRate = this.cpuThrottlingManager.cpuThrottlingRate();
@@ -322,8 +322,8 @@
warning: UI.Toolbar.ToolbarItem,
toggle: UI.Toolbar.ToolbarItem,
} {
- const input = new UI.Toolbar.ToolbarItem(
- UI.UIUtils.createInput('devtools-text-input', 'number', 'hardware-concurrency-selector'));
+ const input =
+ new UI.Toolbar.ToolbarItem(UI.UIUtils.createInput('devtools-text-input', 'number', 'hardware-concurrency'));
input.setTitle(i18nString(UIStrings.hardwareConcurrencySettingTooltip));
const inputElement = input.element as HTMLInputElement;
inputElement.min = '1';
@@ -331,7 +331,7 @@
const toggle = new UI.Toolbar.ToolbarCheckbox(
i18nString(UIStrings.hardwareConcurrency), i18nString(UIStrings.hardwareConcurrencySettingTooltip), undefined,
- 'hardware-concurrency-toggle');
+ 'hardware-concurrency');
const reset = new UI.Toolbar.ToolbarButton('Reset concurrency', 'undo', undefined, 'hardware-concurrency-reset');
reset.setTitle(i18nString(UIStrings.resetConcurrency));
const icon = new IconButton.Icon.Icon();
diff --git a/front_end/panels/timeline/EventsTimelineTreeView.ts b/front_end/panels/timeline/EventsTimelineTreeView.ts
index 9b7a949..b8fc103 100644
--- a/front_end/panels/timeline/EventsTimelineTreeView.ts
+++ b/front_end/panels/timeline/EventsTimelineTreeView.ts
@@ -8,6 +8,7 @@
import * as TraceEngine from '../../models/trace/trace.js';
import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
import * as UI from '../../ui/legacy/legacy.js';
+import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
import {type EventCategory, getCategoryStyles} from './EventUICategory.js';
import {Category, IsLong} from './TimelineFilters.js';
@@ -43,6 +44,7 @@
private currentTree!: TimelineModel.TimelineProfileTree.Node;
constructor(delegate: TimelineModeViewDelegate) {
super();
+ this.element.setAttribute('jslog', `${VisualLogging.pane('event-log').track({resize: true})}`);
this.filtersControl = new Filters();
this.filtersControl.addEventListener(Events.FilterChanged, this.onFilterChanged, this);
this.init();
@@ -166,8 +168,8 @@
}
populateToolbar(toolbar: UI.Toolbar.Toolbar): void {
- const durationFilterUI =
- new UI.Toolbar.ToolbarComboBox(durationFilterChanged.bind(this), i18nString(UIStrings.durationFilter));
+ const durationFilterUI = new UI.Toolbar.ToolbarComboBox(
+ durationFilterChanged.bind(this), i18nString(UIStrings.durationFilter), undefined, 'duration');
for (const durationMs of Filters.durationFilterPresetsMs) {
durationFilterUI.addOption(durationFilterUI.createOption(
durationMs ? `≥ ${i18nString(UIStrings.Dms, {PH1: durationMs})}` : i18nString(UIStrings.all),
@@ -183,7 +185,7 @@
continue;
}
const checkbox = new UI.Toolbar.ToolbarCheckbox(
- category.title, undefined, categoriesFilterChanged.bind(this, categoryName as EventCategory));
+ category.title, undefined, categoriesFilterChanged.bind(this, categoryName as EventCategory), categoryName);
checkbox.setChecked(true);
checkbox.inputElement.style.backgroundColor = category.color;
categoryFiltersUI.set(category.name, checkbox);
diff --git a/front_end/panels/timeline/TimelineDetailsView.ts b/front_end/panels/timeline/TimelineDetailsView.ts
index 60e404c..7b6142c 100644
--- a/front_end/panels/timeline/TimelineDetailsView.ts
+++ b/front_end/panels/timeline/TimelineDetailsView.ts
@@ -10,6 +10,7 @@
import * as TraceBounds from '../../services/trace_bounds/trace_bounds.js';
import * as Components from '../../ui/legacy/components/utils/utils.js';
import * as UI from '../../ui/legacy/legacy.js';
+import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
import * as TimelineComponents from './components/components.js';
import {EventsTimelineTreeView} from './EventsTimelineTreeView.js';
@@ -86,9 +87,13 @@
this.tabbedPane = new UI.TabbedPane.TabbedPane();
this.tabbedPane.show(this.element);
+ this.tabbedPane.headerElement().setAttribute(
+ 'jslog',
+ `${VisualLogging.toolbar('sidebar').track({keydown: 'ArrowUp|ArrowLeft|ArrowDown|ArrowRight|Enter|Space'})}`);
this.defaultDetailsWidget = new UI.Widget.VBox();
this.defaultDetailsWidget.element.classList.add('timeline-details-view');
+ this.defaultDetailsWidget.element.setAttribute('jslog', `${VisualLogging.pane('details').track({resize: true})}`);
this.defaultDetailsContentElement =
this.defaultDetailsWidget.element.createChild('div', 'timeline-details-view-body vbox');
this.appendTab(Tab.Details, i18nString(UIStrings.summary), this.defaultDetailsWidget);
diff --git a/front_end/panels/timeline/TimelineHistoryManager.ts b/front_end/panels/timeline/TimelineHistoryManager.ts
index 900d99c..7c03424 100644
--- a/front_end/panels/timeline/TimelineHistoryManager.ts
+++ b/front_end/panels/timeline/TimelineHistoryManager.ts
@@ -671,6 +671,7 @@
constructor(action: UI.ActionRegistration.Action) {
const element = document.createElement('button');
element.classList.add('history-dropdown-button');
+ element.setAttribute('jslog', `${VisualLogging.dropDown('history')}`);
super(element);
this.contentElement = this.element.createChild('span', 'content');
this.element.addEventListener('click', () => void action.execute(), false);
diff --git a/front_end/panels/timeline/TimelineLandingPage.ts b/front_end/panels/timeline/TimelineLandingPage.ts
index ef61de4..e46460e 100644
--- a/front_end/panels/timeline/TimelineLandingPage.ts
+++ b/front_end/panels/timeline/TimelineLandingPage.ts
@@ -90,7 +90,8 @@
this.contentElement.classList.add('legacy');
const centered = this.contentElement.createChild('div');
- const recordButton = UI.UIUtils.createInlineButton(UI.Toolbar.Toolbar.createActionButton(this.toggleRecordAction));
+ const recordButton = UI.UIUtils.createInlineButton(
+ UI.Toolbar.Toolbar.createActionButton(this.toggleRecordAction, {showLabel: false, ignoreToggleable: true}));
const reloadButton =
UI.UIUtils.createInlineButton(UI.Toolbar.Toolbar.createActionButtonForId('timeline.record-reload'));
diff --git a/front_end/panels/timeline/TimelinePanel.ts b/front_end/panels/timeline/TimelinePanel.ts
index 606e454..e74a5c7 100644
--- a/front_end/panels/timeline/TimelinePanel.ts
+++ b/front_end/panels/timeline/TimelinePanel.ts
@@ -838,7 +838,7 @@
// Record
this.panelToolbar.appendToolbarItem(UI.Toolbar.Toolbar.createActionButton(this.toggleRecordAction));
this.panelToolbar.appendToolbarItem(UI.Toolbar.Toolbar.createActionButton(this.recordReloadAction));
- this.clearButton = new UI.Toolbar.ToolbarButton(i18nString(UIStrings.clear), 'clear');
+ this.clearButton = new UI.Toolbar.ToolbarButton(i18nString(UIStrings.clear), 'clear', undefined, 'timeline.clear');
this.clearButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => this.onClearButton());
this.panelToolbar.appendToolbarItem(this.clearButton);
@@ -2119,6 +2119,7 @@
super(true);
this.contentElement.classList.add('timeline-status-dialog');
+ this.contentElement.setAttribute('jslog', `${VisualLogging.dialog('timeline-status').track({resize: true})}`);
const statusLine = this.contentElement.createChild('div', 'status-dialog-line status');
statusLine.createChild('div', 'label').textContent = i18nString(UIStrings.status);
diff --git a/front_end/panels/timeline/TimelineSelectorStatsView.ts b/front_end/panels/timeline/TimelineSelectorStatsView.ts
index bc362f7..c43e478 100644
--- a/front_end/panels/timeline/TimelineSelectorStatsView.ts
+++ b/front_end/panels/timeline/TimelineSelectorStatsView.ts
@@ -11,6 +11,7 @@
import * as Linkifier from '../../ui/components/linkifier/linkifier.js';
import * as UI from '../../ui/legacy/legacy.js';
import * as LitHtml from '../../ui/lit-html/lit-html.js';
+import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
const UIStrings = {
/**
@@ -107,6 +108,7 @@
super();
this.#datagrid = new DataGrid.DataGridController.DataGridController();
+ this.element.setAttribute('jslog', `${VisualLogging.pane('selector-stats').track({resize: true})}`);
this.#selectorLocations = new Map<string, Protocol.CSS.SourceRange[]>();
this.#traceParsedData = traceParsedData;
diff --git a/front_end/panels/timeline/TimelineTreeView.ts b/front_end/panels/timeline/TimelineTreeView.ts
index a1d5e4e..09470de 100644
--- a/front_end/panels/timeline/TimelineTreeView.ts
+++ b/front_end/panels/timeline/TimelineTreeView.ts
@@ -11,6 +11,7 @@
import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
import * as Components from '../../ui/legacy/components/utils/utils.js';
import * as UI from '../../ui/legacy/legacy.js';
+import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
import {ActiveFilters} from './ActiveFilters.js';
import {getCategoryStyles, stringIsEventCategory} from './EventUICategory.js';
@@ -219,6 +220,7 @@
this.splitWidget = new UI.SplitWidget.SplitWidget(true, true, 'timeline-tree-view-details-split-widget');
const mainView = new UI.Widget.VBox();
const toolbar = new UI.Toolbar.Toolbar('', mainView.element);
+ toolbar.element.setAttribute('jslog', `${VisualLogging.toolbar()}`);
toolbar.makeWrappable(true);
this.populateToolbar(toolbar);
@@ -278,19 +280,22 @@
}
populateToolbar(toolbar: UI.Toolbar.Toolbar): void {
- this.caseSensitiveButton = new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.matchCase), 'match-case');
+ this.caseSensitiveButton =
+ new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.matchCase), 'match-case', undefined, 'match-case');
this.caseSensitiveButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => {
this.#filterChanged();
}, this);
toolbar.appendToolbarItem(this.caseSensitiveButton);
- this.regexButton = new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.useRegularExpression), 'regular-expression');
+ this.regexButton = new UI.Toolbar.ToolbarToggle(
+ i18nString(UIStrings.useRegularExpression), 'regular-expression', undefined, 'regular-expression');
this.regexButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => {
this.#filterChanged();
}, this);
toolbar.appendToolbarItem(this.regexButton);
- this.matchWholeWord = new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.matchWholeWord), 'match-whole-word');
+ this.matchWholeWord = new UI.Toolbar.ToolbarToggle(
+ i18nString(UIStrings.matchWholeWord), 'match-whole-word', undefined, 'match-whole-word');
this.matchWholeWord.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => {
this.#filterChanged();
}, this);
@@ -973,6 +978,7 @@
export class CallTreeTimelineTreeView extends AggregatedTimelineTreeView {
constructor() {
super();
+ this.element.setAttribute('jslog', `${VisualLogging.pane('call-tree').track({resize: true})}`);
this.dataGrid.markColumnAsSortedBy('total', DataGrid.DataGrid.Order.Descending);
}
@@ -985,6 +991,7 @@
export class BottomUpTimelineTreeView extends AggregatedTimelineTreeView {
constructor() {
super();
+ this.element.setAttribute('jslog', `${VisualLogging.pane('bottom-up').track({resize: true})}`);
this.dataGrid.markColumnAsSortedBy('self', DataGrid.DataGrid.Order.Descending);
}
diff --git a/front_end/panels/timeline/components/BreadcrumbsUI.ts b/front_end/panels/timeline/components/BreadcrumbsUI.ts
index 92302d0..05f49d4 100644
--- a/front_end/panels/timeline/components/BreadcrumbsUI.ts
+++ b/front_end/panels/timeline/components/BreadcrumbsUI.ts
@@ -74,7 +74,7 @@
// clang-format off
return html`
<div class="breadcrumb" @click=${() => this.#removeBreadcrumb(breadcrumb)}
- jslog=${VisualLogging.action('timeline.breadcrumb-select').track({click: true})}>
+ jslog=${VisualLogging.item('timeline.breadcrumb-select').track({click: true})}>
<span class="${(index !== 0 && breadcrumb.child === null) ? 'last-breadcrumb' : ''} range">
${(index === 0) ?
`Full range (${i18n.TimeUtilities.preciseMillisToString(breadcrumbRange, 2)})` :
@@ -97,7 +97,7 @@
#render(): void {
// clang-format off
const output = html`
- ${this.#breadcrumb === null ? html`` : html`<div class="breadcrumbs">
+ ${this.#breadcrumb === null ? html`` : html`<div class="breadcrumbs" jslog=${VisualLogging.section('breadcrumbs')}>
${flattenBreadcrumbs(this.#breadcrumb).map((breadcrumb, index) => this.#renderElement(breadcrumb, index))}
</div>`}
`;
diff --git a/front_end/panels/timeline/components/CPUThrottlingSelector.ts b/front_end/panels/timeline/components/CPUThrottlingSelector.ts
index e69bff2..22a729c 100644
--- a/front_end/panels/timeline/components/CPUThrottlingSelector.ts
+++ b/front_end/panels/timeline/components/CPUThrottlingSelector.ts
@@ -80,6 +80,7 @@
.sideButton=${false}
.showSelectedItem=${true}
.showConnector=${false}
+ .jslogContext=${'cpu-throttling'}
.buttonTitle=${i18nString(UIStrings.cpu, {PH1: selectionTitle})}
aria-label=${i18nString(UIStrings.cpuThrottling, {PH1: selectionTitle})}
>
diff --git a/front_end/panels/timeline/components/FieldSettingsDialog.ts b/front_end/panels/timeline/components/FieldSettingsDialog.ts
index dd66c3f..ea1c423 100644
--- a/front_end/panels/timeline/components/FieldSettingsDialog.ts
+++ b/front_end/panels/timeline/components/FieldSettingsDialog.ts
@@ -252,8 +252,8 @@
.data=${{
variant: Buttons.Button.Variant.OUTLINED,
title: i18nString(UIStrings.configure),
+ jslogContext: 'field-data-configure',
} as Buttons.Button.ButtonData}
- jslogContext=${'field-data-configure'}
>${i18nString(UIStrings.configure)}</${Buttons.Button.Button.litTagName}>
`;
// clang-format on
diff --git a/front_end/ui/legacy/Toolbar.ts b/front_end/ui/legacy/Toolbar.ts
index 74697f9..6dad617 100644
--- a/front_end/ui/legacy/Toolbar.ts
+++ b/front_end/ui/legacy/Toolbar.ts
@@ -216,7 +216,7 @@
static createActionButton(action: Action, options: ToolbarButtonOptions|undefined = TOOLBAR_BUTTON_DEFAULT_OPTIONS):
ToolbarButton {
- const button = action.toggleable() ? makeToggle() : makeButton();
+ const button = (action.toggleable() && !options?.ignoreToggleable) ? makeToggle() : makeButton();
if (options.showLabel) {
button.setText(options.label?.() || action.title());
@@ -441,6 +441,7 @@
label?: () => Platform.UIString.LocalizedString;
showLabel: boolean;
userActionCode?: Host.UserMetrics.Action;
+ ignoreToggleable?: boolean;
}
const TOOLBAR_BUTTON_DEFAULT_OPTIONS: ToolbarButtonOptions = {
@@ -1189,7 +1190,7 @@
private readonly setting: Common.Settings.Setting<string>;
private muteSettingListener?: boolean;
constructor(options: Option[], setting: Common.Settings.Setting<string>, accessibleName: string) {
- super(null, accessibleName);
+ super(null, accessibleName, undefined, setting.name);
this.optionsInternal = options;
this.setting = setting;
this.selectElementInternal.addEventListener('change', this.valueChanged.bind(this), false);
diff --git a/front_end/ui/visual_logging/KnownContextValues.ts b/front_end/ui/visual_logging/KnownContextValues.ts
index 81860a8..c4930d6 100644
--- a/front_end/ui/visual_logging/KnownContextValues.ts
+++ b/front_end/ui/visual_logging/KnownContextValues.ts
@@ -409,6 +409,7 @@
'br',
'brand-name',
'brand-version',
+ 'breadcrumbs',
'break-after',
'break-before',
'break-inside',
@@ -700,6 +701,7 @@
'cpu-throttled-20',
'cpu-throttled-4',
'cpu-throttled-6',
+ 'cpu-throttling',
'cpu-throttling-selector',
'create-new-snippet',
'create-recording',
@@ -1080,6 +1082,7 @@
'fetch-and-xhr',
'fi',
'field-data',
+ 'field-data-configure',
'field-data-settings',
'field-sizing',
'field-url-override-enabled',
@@ -1234,6 +1237,7 @@
'gu',
'gutter',
'gzip',
+ 'hardware-concurrency',
'hardware-concurrency-reset',
'hardware-concurrency-selector',
'hardware-concurrency-toggle',
@@ -1283,6 +1287,7 @@
'hide-repeating-children',
'highlight-errors-elements-panel',
'highlight-node-on-hover-in-overlay',
+ 'history',
'historyRedo',
'historyUndo',
'hover',
@@ -1660,6 +1665,7 @@
'mask-size',
'mask-type',
'match-case',
+ 'match-whole-word',
'match_attempts',
'match_count',
'matched-address-item',
@@ -1684,6 +1690,7 @@
'messageURLFilters',
'messageerror',
'messages',
+ 'messaging',
'metadata',
'metadata-allowed-sites-details',
'method',
@@ -1914,6 +1921,7 @@
'page',
'page-orientation',
'paint-order',
+ 'painting',
'palatino',
'palette-panel',
'palette-switcher',
@@ -2232,6 +2240,7 @@
'script-snippets-last-identifier',
'script-source-url',
'script-text-node',
+ 'scripting',
'scroll',
'scroll-behavior',
'scroll-into-view',
@@ -2667,12 +2676,14 @@
'timeline-show-postmessage-events',
'timeline-show-screenshots',
'timeline-show-settings-toolbar',
+ 'timeline-status',
'timeline-tree-current-thread',
'timeline-tree-group-by',
'timeline-v8-runtime-call-stats',
'timeline.animations',
'timeline.annotations-tab',
'timeline.breadcrumb-select',
+ 'timeline.clear',
'timeline.create-breadcrumb',
'timeline.download-after-error',
'timeline.extension',
@@ -2769,6 +2780,7 @@
'uk',
'unavailable',
'unblock',
+ 'undefined',
'undo',
'unicode-bidi',
'unit',
diff --git a/test/e2e/cross_tool_integration/workflow_test.ts b/test/e2e/cross_tool_integration/workflow_test.ts
index 1d76df8..2335c7c 100644
--- a/test/e2e/cross_tool_integration/workflow_test.ts
+++ b/test/e2e/cross_tool_integration/workflow_test.ts
@@ -17,7 +17,7 @@
import {LAYERS_TAB_SELECTOR} from '../helpers/layers-helpers.js';
import {MEMORY_TAB_ID, navigateToMemoryTab} from '../helpers/memory-helpers.js';
import {
- navigateToPerformanceSidebarTab,
+ navigateToBottomUpTab,
navigateToPerformanceTab,
startRecording,
stopRecording,
@@ -75,7 +75,7 @@
await stopRecording();
- await navigateToPerformanceSidebarTab('Bottom-Up');
+ await navigateToBottomUpTab();
await click('.devtools-link[title*="default.html"]');
await waitFor('.panel[aria-label="sources"]');
diff --git a/test/e2e/helpers/cross-tool-helper.ts b/test/e2e/helpers/cross-tool-helper.ts
index acd41b3..53b4ed3 100644
--- a/test/e2e/helpers/cross-tool-helper.ts
+++ b/test/e2e/helpers/cross-tool-helper.ts
@@ -82,6 +82,7 @@
await waitFor(`.panel.${selectedPanel}`);
const expectClosedPanels = options?.expectClosedPanels;
const newFilterBar = enableExperiments.includes('network-panel-filter-bar-redesign');
+ const timelineObservationLandingPage = enableExperiments.includes('timeline-observations');
const dockable = options?.canDock;
const panelImpression = selectedPanel === 'elements' ? veImpressionForElementsPanel({dockable}) :
selectedPanel === 'animations' ? veImpressionForAnimationsPanel() :
@@ -89,12 +90,12 @@
selectedPanel === 'layers' ? veImpressionForLayersPanel() :
selectedPanel === 'network' ? veImpressionForNetworkPanel({newFilterBar}) :
selectedPanel === 'console' ? veImpressionForConsolePanel() :
- selectedPanel === 'timeline' ? veImpressionForPerformancePanel() :
- selectedPanel === 'sources' ? veImpressionForSourcesPanel() :
- selectedPanel === 'animations' ? veImpressionForSourcesPanel() :
- selectedPanel === 'changes' ? veImpressionForChangesPanel() :
- selectedPanel === 'resources' ? veImpressionForApplicationPanel() :
- veImpression('Panel', selectedPanel);
+ selectedPanel === 'timeline' ? veImpressionForPerformancePanel({timelineObservationLandingPage}) :
+ selectedPanel === 'sources' ? veImpressionForSourcesPanel() :
+ selectedPanel === 'animations' ? veImpressionForSourcesPanel() :
+ selectedPanel === 'changes' ? veImpressionForChangesPanel() :
+ selectedPanel === 'resources' ? veImpressionForApplicationPanel() :
+ veImpression('Panel', selectedPanel);
const expectedVeEvents = [veImpressionForMainToolbar({selectedPanel, expectClosedPanels, dockable}), panelImpression];
if (options?.drawerShown) {
expectedVeEvents.push(veImpression('Drawer', undefined, [
diff --git a/test/e2e/helpers/performance-helpers.ts b/test/e2e/helpers/performance-helpers.ts
index eb1973d..ca3d666 100644
--- a/test/e2e/helpers/performance-helpers.ts
+++ b/test/e2e/helpers/performance-helpers.ts
@@ -9,7 +9,7 @@
$,
click,
goToResource,
- platform,
+ summonSearchBox,
waitFor,
waitForAria,
waitForElementWithTextContent,
@@ -17,7 +17,15 @@
waitForMany,
} from '../../shared/helper.js';
-import {veImpression} from './visual-logging-helpers.js';
+import {
+ expectVeEvents,
+ veChange,
+ veClick,
+ veImpression,
+ veImpressionsUnder,
+ veKeyDown,
+ veResize,
+} from './visual-logging-helpers.js';
export const FILTER_TEXTBOX_SELECTOR = '[aria-label="Filter"]';
export const RECORD_BUTTON_SELECTOR = '[aria-label="Record"]';
@@ -44,52 +52,144 @@
// Make sure the landing page is shown.
await waitFor('.timeline-landing-page');
+ await expectVeEvents([veClick('Toolbar: main > PanelTabHeader: timeline'), veImpressionForPerformancePanel()]);
}
export async function openCaptureSettings(sectionClassName: string) {
const captureSettingsButton = await waitForAria('Capture settings');
await captureSettingsButton.click();
- return await waitFor(sectionClassName);
+ await waitFor(sectionClassName);
+ await expectVeEvents(
+ [
+ veClick('Toolbar > Toggle: timeline-settings-toggle'),
+ veImpression(
+ 'Pane', 'timeline-settings-pane',
+ [
+ veImpression('Toggle', 'timeline-capture-layers-and-pictures'),
+ veImpression('Toggle', 'timeline-capture-selector-stats'),
+ veImpression('Toggle', 'timeline-disable-js-sampling'),
+ veImpression('DropDown', 'cpu-throttling'),
+ veImpression('DropDown', 'preferred-network-condition'),
+ veImpression('Toggle', 'hardware-concurrency'),
+ veImpression('TextField', 'hardware-concurrency'),
+ veImpression('Action', 'hardware-concurrency-reset'),
+ veImpression('Toggle', 'timeline-show-extension-data'),
+ ]),
+ ],
+ 'Panel: timeline');
}
export async function searchForComponent(frontend: puppeteer.Page, searchEntry: string) {
- const modifierKey = platform === 'mac' ? 'Meta' : 'Control';
- await frontend.keyboard.down(modifierKey);
- await frontend.keyboard.press('KeyF');
- await frontend.keyboard.up(modifierKey);
+ await waitFor('.timeline-details-chip-body');
+ await summonSearchBox();
+ await waitFor('.search-bar');
await frontend.keyboard.type(searchEntry);
-}
-
-export async function navigateToSummaryTab() {
- await click(SUMMARY_TAB_SELECTOR);
+ await frontend.keyboard.press('Tab');
+ await expectVeEvents([
+ veKeyDown(''),
+ veImpressionsUnder('Panel: timeline', [veImpression(
+ 'Toolbar', 'search',
+ [
+ veImpression('TextField', 'search'),
+ veImpression('Action', 'regular-expression'),
+ veImpression('Action', 'match-case'),
+ veImpression('Action', 'select-previous'),
+ veImpression('Action', 'select-next'),
+ veImpression('Action', 'close-search'),
+ ])]),
+ veChange('Panel: timeline > Toolbar: search > TextField: search'),
+ ]);
}
export async function navigateToBottomUpTab() {
await click(BOTTOM_UP_SELECTOR);
+ await expectVeEvents(
+ [
+ veClick('Toolbar: sidebar > PanelTabHeader: bottom-up'),
+ veImpression(
+ 'Pane', 'bottom-up',
+ [
+ veImpression(
+ 'Toolbar', undefined,
+ [
+ veImpression('Toggle', 'match-case'),
+ veImpression('Toggle', 'regular-expression'),
+ veImpression('Toggle', 'match-whole-word'),
+ veImpression('TextField', 'filter'),
+ veImpression('DropDown', 'timeline-tree-group-by'),
+ ]),
+ veImpression('TableHeader', 'self'),
+ veImpression('TableHeader', 'total'),
+ veImpression('TableHeader', 'activity'),
+ veImpression(
+ 'TableRow', undefined,
+ [
+ veImpression('TableCell', 'self'),
+ veImpression('TableCell', 'total'),
+ veImpression('TableCell', 'activity', [veImpression('Link', 'url')]),
+ ]),
+ ]),
+
+ ],
+ 'Panel: timeline');
}
export async function navigateToCallTreeTab() {
await click(CALL_TREE_SELECTOR);
+ await expectVeEvents(
+ [
+ veClick('Toolbar: sidebar > PanelTabHeader: call-tree'),
+ veImpression(
+ 'Pane', 'call-tree',
+ [
+ veImpression(
+ 'Toolbar', undefined,
+ [
+ veImpression('Toggle', 'match-case'),
+ veImpression('Toggle', 'regular-expression'),
+ veImpression('Toggle', 'match-whole-word'),
+ veImpression('TextField', 'filter'),
+ veImpression('DropDown', 'timeline-tree-group-by'),
+ ]),
+ veImpression('TableHeader: self'),
+ veImpression('TableHeader: total'),
+ veImpression('TableHeader: activity'),
+ veImpression(
+ 'TableRow', undefined,
+ [
+ veImpression('TableCell: self'),
+ veImpression('TableCell: total'),
+ veImpression('TableCell: activity'),
+ ]),
+ ]),
+ ],
+ 'Panel: timeline');
}
export async function setFilter(filter: string) {
const filterBoxElement = await click(FILTER_TEXTBOX_SELECTOR);
await filterBoxElement.type(filter);
+ await expectVeEvents(
+ [veChange(''), veImpression('Action', 'clear')],
+ 'Panel: timeline > Pane: bottom-up > Toolbar > TextField: filter');
}
export async function toggleCaseSensitive() {
const matchCaseButton = await waitForAria('Match Case');
await matchCaseButton.click();
+ await expectVeEvents([veClick('Panel: timeline > Pane: bottom-up > Toolbar > Toggle: match-case')]);
}
export async function toggleRegExButtonBottomUp() {
const regexButton = await waitFor('[aria-label="Use Regular Expression"]');
await regexButton.click();
+ await expectVeEvents([veClick('Panel: timeline > Pane: bottom-up > Toolbar > Toggle: regular-expression')]);
}
export async function toggleMatchWholeWordButtonBottomUp() {
const wholeWordButton = await waitForAria('Match whole word');
await wholeWordButton.click();
+ await expectVeEvents([veClick('Panel: timeline > Pane: bottom-up > Toolbar > Toggle: match-whole-word')]);
}
export async function startRecording() {
@@ -97,6 +197,8 @@
// Wait for the button to turn to its stop state.
await waitFor(STOP_BUTTON_SELECTOR);
+ await expectVeEvents(
+ [veClick('Toolbar > Toggle: timeline.toggle-recording'), veImpressionForStatusDialog()], 'Panel: timeline');
}
export async function reloadAndRecord() {
@@ -105,6 +207,8 @@
// that a recording is actually displayed as some of the other elements in
// the timeline remain in the DOM even after the recording has been cleared.
await waitFor('.timeline-details-chip-body');
+ await expectVeEvents(
+ [veClick('Toolbar > Action: timeline.record-reload'), veImpressionForStatusDialog()], 'Panel: timeline');
}
export async function stopRecording() {
@@ -114,6 +218,12 @@
// that a recording is actually displayed as some of the other elements in
// the timeline remain in the DOM even after the recording has been cleared.
await waitFor('.timeline-details-chip-body');
+ await expectVeEvents(
+ [
+ veClick('Toolbar > Toggle: timeline.toggle-recording'),
+ veResize('Dialog: timeline-status'),
+ ],
+ 'Panel: timeline');
}
export async function getTotalTimeFromSummary(): Promise<number> {
@@ -143,16 +253,24 @@
return tree;
}
-export async function navigateToPerformanceSidebarTab(tabName: string) {
- await click(`[aria-label="${tabName}"]`);
-}
-
-export async function clickOnFunctionLink() {
- await click('.timeline-details.devtools-link');
-}
-
export async function navigateToSelectorStatsTab() {
await click(SELECTOR_STATS_SELECTOR);
+ await expectVeEvents(
+ [
+ veClick('Toolbar: sidebar > PanelTabHeader: selector-stats'),
+ veImpression(
+ 'Pane', 'selector-stats',
+ [
+ veImpression('TableHeader', 'elapsed(us)'),
+ veImpression('TableHeader', 'match_attempts'),
+ veImpression('TableHeader', 'match_count'),
+ veImpression('TableHeader', 'reject_percentage'),
+ veImpression('TableHeader', 'selector'),
+ veImpression('TableHeader', 'style_sheet_id'),
+ veImpression('TableRow', undefined, [veImpression('TableCell')]),
+ ]),
+ ],
+ 'Panel: timeline');
}
export async function selectRecalculateStylesEvent() {
@@ -187,6 +305,8 @@
}
return true;
}));
+ await expectVeEvents(
+ [veChange('Panel: timeline > Pane: timeline-settings-pane > Toggle: timeline-capture-selector-stats')]);
}
export async function disableCSSSelectorStats() {
@@ -207,24 +327,35 @@
}
return true;
}));
+ await expectVeEvents(
+ [veChange('Panel: timeline > Pane: timeline-settings-pane > Toggle: timeline-capture-selector-stats')]);
}
-export function veImpressionForPerformancePanel() {
+export function veImpressionForPerformancePanel(options?: {timelineObservationLandingPage?: boolean}) {
return veImpression('Panel', 'timeline', [
veImpression(
'Toolbar', undefined,
[
veImpression('Toggle', 'timeline.toggle-recording'),
veImpression('Action', 'timeline.record-reload'),
+ veImpression('Action', 'timeline.clear'),
veImpression('Action', 'timeline.load-from-file'),
veImpression('Action', 'timeline.save-to-file'),
- veImpression('Action', 'components.collect-garbage'),
+ veImpression('DropDown', 'history'),
veImpression('Toggle', 'timeline-show-screenshots'),
veImpression('Toggle', 'timeline-show-memory'),
+ veImpression('Action', 'components.collect-garbage'),
]),
- // veImpression('Pane', 'timeline-settings-pane', {optional: true}),
- veImpression('Link', 'learn-more'),
- veImpression('Toggle', 'timeline.toggle-recording'),
+ veImpression('Action', 'timeline.toggle-recording'),
veImpression('Action', 'timeline.record-reload'),
+ ...(options?.timelineObservationLandingPage ?
+ [veImpression('DropDown', 'cpu-throttling'), veImpression('DropDown', 'network-conditions')] :
+ [veImpression('Link', 'learn-more')]),
]);
}
+
+function veImpressionForStatusDialog() {
+ return veImpression(
+ 'Dialog', 'timeline-status',
+ [veImpression('Action', 'timeline.download-after-error'), veImpression('Action', 'timeline.stop-recording')]);
+}
diff --git a/test/e2e/performance/landing-page_test.ts b/test/e2e/performance/landing-page_test.ts
index fcc5a48..fda4467 100644
--- a/test/e2e/performance/landing-page_test.ts
+++ b/test/e2e/performance/landing-page_test.ts
@@ -7,7 +7,6 @@
import {
$$,
- enableExperiment,
getBrowserAndPages,
getResourcesPath,
goTo,
@@ -19,9 +18,7 @@
waitForVisible,
} from '../../shared/helper.js';
import {describe, it} from '../../shared/mocha-extensions.js';
-import {
- navigateToPerformanceTab,
-} from '../helpers/performance-helpers.js';
+import {reloadDevTools} from '../helpers/cross-tool-helper.js';
const READY_LOCAL_METRIC_SELECTOR = '#local-value .metric-value:not(.waiting)';
const READY_FIELD_METRIC_SELECTOR = '#field-value .metric-value:not(.waiting)';
@@ -61,14 +58,12 @@
describe('The Performance panel landing page', () => {
beforeEach(async () => {
- await enableExperiment('timeline-observations');
+ await reloadDevTools({selectedPanel: {name: 'timeline'}, enableExperiments: ['timeline-observations']});
});
it('displays live metrics', async () => {
const {target, frontend} = await getBrowserAndPages();
- await navigateToPerformanceTab();
-
await target.bringToFront();
const targetSession = await target.createCDPSession();
@@ -129,7 +124,6 @@
await executionContextPromise;
await frontend.bringToFront();
- await navigateToPerformanceTab();
const [lcpValueElem, clsValueElem, inpValueElem] = await waitForMany(READY_LOCAL_METRIC_SELECTOR, 3);
const interactions = await $$<HTMLElement>(INTERACTION_SELECTOR);
@@ -156,8 +150,6 @@
it('treats bfcache restoration like a regular navigation', async () => {
const {target, frontend} = await getBrowserAndPages();
- await navigateToPerformanceTab();
-
await target.bringToFront();
const targetSession = await target.createCDPSession();
@@ -215,8 +207,6 @@
});
it('gets field data automatically', async () => {
- await navigateToPerformanceTab();
-
await setCruxRawResponse('performance/crux-none.rawresponse');
await goToResource('performance/fake-website.html');
@@ -271,8 +261,6 @@
});
it('uses URL override for field data', async () => {
- await navigateToPerformanceTab();
-
await setCruxRawResponse('performance/crux-valid.rawresponse');
await goToResource('performance/fake-website.html');