Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 43 additions & 33 deletions packages/trace-viewer/src/ui/workbench.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const PartitionedWorkbench: React.FunctionComponent<WorkbenchProps & { partition
const [selectedNavigatorTab, setSelectedNavigatorTab] = useSetting<string>('navigatorTab', 'actions');
const [selectedPropertiesTab, setSelectedPropertiesTab] = useSetting<string>('propertiesTab', showSourcesFirst ? 'source' : 'call');
const [sidebarLocation, setSidebarLocation] = useSetting<'bottom' | 'right'>('propertiesSidebarLocation', 'bottom');
const [browserPanelHidden, setBrowserPanelHidden] = useSetting<boolean>('browserPanelHidden', false);
const [actionsFilter] = useSetting<ActionGroup[]>('actionsFilter', []);

// Per-model settings, should be primitive non-retaining types.
Expand Down Expand Up @@ -360,6 +361,44 @@ const PartitionedWorkbench: React.FunctionComponent<WorkbenchProps & { partition
};

const actionsFilterWithCount = selectedNavigatorTab === 'actions' && <ActionsFilterButton counters={model?.actionCounters} hiddenActionsCount={hiddenActionsCount} />;
const propertiesPaneToolbar = [
browserPanelHidden ?
<ToolbarButton key='browser-panel' title='Show browser panel' icon='eye' onClick={() => setBrowserPanelHidden(false)} /> :
<ToolbarButton key='browser-panel' title='Hide browser panel' icon='eye-closed' onClick={() => setBrowserPanelHidden(true)} />,
];
if (!browserPanelHidden) {
propertiesPaneToolbar.push(sidebarLocation === 'bottom' ?
<ToolbarButton key='dock-properties' title='Dock to right' icon='layout-sidebar-right-off' onClick={() => {
setSidebarLocation('right');
}} /> :
<ToolbarButton key='dock-properties' title='Dock to bottom' icon='layout-panel-off' onClick={() => {
setSidebarLocation('bottom');
}} />
);
}
const navigatorPane = <TabbedPane
tabs={[actionsTab, metadataTab]}
rightToolbar={[actionsFilterWithCount]}
selectedTab={selectedNavigatorTab}
setSelectedTab={setSelectedNavigatorTab}
/>;
const propertiesPane = <TabbedPane
tabs={tabs}
selectedTab={selectedPropertiesTab}
setSelectedTab={selectPropertiesTab}
rightToolbar={propertiesPaneToolbar}
mode={sidebarLocation === 'bottom' && !browserPanelHidden ? 'default' : 'select'}
/>;
const browserPane = <SnapshotTabsView
action={activeAction}
model={model}
sdkLanguage={sdkLanguage}
testIdAttributeName={model?.testIdAttributeName || 'data-testid'}
isInspecting={isInspecting}
setIsInspecting={setIsInspecting}
highlightedElement={highlightedElement}
setHighlightedElement={elementPicked}
playback={playback} />;

return <div className='vbox workbench' {...(inert ? { inert: true } : {})}>
{!hideTimeline && <Timeline
Expand All @@ -380,40 +419,11 @@ const PartitionedWorkbench: React.FunctionComponent<WorkbenchProps & { partition
orientation='horizontal'
sidebarIsFirst
settingName='actionListSidebar'
main={<SnapshotTabsView
action={activeAction}
model={model}
sdkLanguage={sdkLanguage}
testIdAttributeName={model?.testIdAttributeName || 'data-testid'}
isInspecting={isInspecting}
setIsInspecting={setIsInspecting}
highlightedElement={highlightedElement}
setHighlightedElement={elementPicked}
playback={playback} />}
sidebar={
<TabbedPane
tabs={[actionsTab, metadataTab]}
rightToolbar={[actionsFilterWithCount]}
selectedTab={selectedNavigatorTab}
setSelectedTab={setSelectedNavigatorTab}
/>
}
/>}
sidebar={<TabbedPane
tabs={tabs}
selectedTab={selectedPropertiesTab}
setSelectedTab={selectPropertiesTab}
rightToolbar={[
sidebarLocation === 'bottom' ?
<ToolbarButton title='Dock to right' icon='layout-sidebar-right-off' onClick={() => {
setSidebarLocation('right');
}} /> :
<ToolbarButton title='Dock to bottom' icon='layout-panel-off' onClick={() => {
setSidebarLocation('bottom');
}} />
]}
mode={sidebarLocation === 'bottom' ? 'default' : 'select'}
main={browserPanelHidden ? propertiesPane : browserPane}
sidebar={navigatorPane}
/>}
sidebarHidden={browserPanelHidden}
sidebar={propertiesPane}
/>
</div>;
};
Expand Down
30 changes: 30 additions & 0 deletions tests/library/trace-viewer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,36 @@ test('should have network requests', async ({ showTraceViewer }) => {
await expect(traceViewer.networkRequests.filter({ hasText: '404GET404text' })).toHaveCSS('background-color', 'rgb(242, 222, 222)');
});

test('should expand network details when browser panel is hidden', async ({ showTraceViewer }) => {
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/41062' });
const traceViewer = await showTraceViewer(traceFile);
await traceViewer.selectAction('Navigate');
await traceViewer.showNetworkTab();
const networkTab = traceViewer.networkTab;
const initialBox = await networkTab.boundingBox();

await expect(traceViewer.snapshotContainer).toBeVisible();
await expect(traceViewer.page.getByRole('button', { name: 'Dock to right' })).toBeVisible();
await traceViewer.page.getByRole('button', { name: 'Hide browser panel' }).click();
await expect(traceViewer.snapshotContainer).toBeHidden();
await expect(traceViewer.page.getByRole('button', { name: 'Show browser panel' })).toBeVisible();
await expect(traceViewer.page.getByRole('button', { name: 'Dock to right' })).toBeHidden();
await expect(traceViewer.actionsTree).toBeVisible();
await traceViewer.selectAction('Click');
await expect(traceViewer.actionsTree.getByRole('treeitem', { selected: true })).toHaveText(/Click/);
await traceViewer.selectAction('Navigate');
const expandedBox = await networkTab.boundingBox();

expect(initialBox).toBeTruthy();
expect(expandedBox).toBeTruthy();
expect(expandedBox!.height).toBeGreaterThan(initialBox!.height);
await expect(traceViewer.networkRequests).toContainText([/frame.htmlGET200text\/html/]);

await traceViewer.page.getByRole('button', { name: 'Show browser panel' }).click();
await expect(traceViewer.snapshotContainer).toBeVisible();
await expect(traceViewer.page.getByRole('button', { name: 'Dock to right' })).toBeVisible();
});

test('should highlight network request on timeline on hover', async ({ showTraceViewer }) => {
const traceViewer = await showTraceViewer(traceFile);
await traceViewer.selectAction('Navigate');
Expand Down