diff --git a/packages/trace-viewer/src/ui/actionList.tsx b/packages/trace-viewer/src/ui/actionList.tsx index 8f4e6ccaa321b..07d1d12297bda 100644 --- a/packages/trace-viewer/src/ui/actionList.tsx +++ b/packages/trace-viewer/src/ui/actionList.tsx @@ -102,8 +102,14 @@ export const ActionList: React.FC = ({ onHighlighted?.(item?.action); }, [onHighlighted]); + const [showAllCounter, setShowAllCounter] = React.useState(); + const onShowAll = React.useCallback(() => { + setSelectedTime(undefined); + setShowAllCounter(n => (n ?? 0) + 1); + }, [setSelectedTime]); + return
- {selectedTime &&
setSelectedTime(undefined)}>Show all
} + {selectedTime &&
Show all
} = ({ isVisible={isVisible} render={render} autoExpandDepth={actionFilterText?.trim() ? 5 : 0} + revealSelectedKey={showAllCounter} />
; }; diff --git a/packages/web/src/components/treeView.tsx b/packages/web/src/components/treeView.tsx index 2f406180bbda1..a2d584bb86415 100644 --- a/packages/web/src/components/treeView.tsx +++ b/packages/web/src/components/treeView.tsx @@ -45,6 +45,7 @@ export type TreeViewProps = { treeState: TreeState, setTreeState: (treeState: TreeState) => void, autoExpandDepth?: number, + revealSelectedKey?: number, }; const scrollPositions = new Map(); @@ -66,6 +67,7 @@ export function TreeView({ noItemsMessage, dataTestId, autoExpandDepth, + revealSelectedKey, }: TreeViewProps) { const treeItems = React.useMemo(() => { return indexTree(rootItem, selectedItem, treeState.expandedItems, autoExpandDepth || 0, isVisible); @@ -94,6 +96,14 @@ export function TreeView({ itemListRef.current.scrollTop = scrollPositions.get(name) || 0; }, [name]); + React.useEffect(() => { + if (revealSelectedKey === undefined) + return; + const selectedEl = itemListRef.current?.querySelector('[aria-selected="true"]'); + if (selectedEl) + scrollIntoViewIfNeeded(selectedEl); + }, [revealSelectedKey]); + const toggleExpanded = React.useCallback((item: T) => { const { expanded } = treeItems.get(item)!; if (expanded) { diff --git a/tests/library/trace-viewer.spec.ts b/tests/library/trace-viewer.spec.ts index 237dd89130d55..c23da1fc49c60 100644 --- a/tests/library/trace-viewer.spec.ts +++ b/tests/library/trace-viewer.spec.ts @@ -206,6 +206,29 @@ test('should filter actions by text', async ({ showTraceViewer }) => { await expect(traceViewer.actionTitles).toHaveCount(fullCount); }); +test('should keep selected action in view after Show all', async ({ runAndTrace, page }) => { + test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/40808' }); + const traceViewer = await runAndTrace(async () => { + await page.setContent('
hello
'); + for (let i = 0; i < 50; i++) + await page.evaluate(x => x, i); + }); + + const treeItems = traceViewer.actionsTree.getByRole('treeitem'); + const deepAction = treeItems.filter({ hasText: 'Evaluate' }).nth(40); + await deepAction.scrollIntoViewIfNeeded(); + await deepAction.dblclick(); + + const showAll = traceViewer.page.locator('.action-list-show-all'); + await expect(showAll).toBeVisible(); + await showAll.click(); + await expect(showAll).toBeHidden(); + + const selected = traceViewer.actionsTree.locator('[role="treeitem"][aria-selected="true"]'); + await expect(selected).toHaveCount(1); + await expect(selected).toBeInViewport(); +}); + test('should open uncompressed trace directory', async ({ showTraceViewer }) => { const traceDir = test.info().outputPath('unzipped-trace'); await extractZip(traceFile, { dir: traceDir });