import type { Page } from '@stablyai/playwright-test' import { test, expect } from './helpers/orca-app' import { waitForActiveWorktree, waitForSessionReady } from './helpers/store' import { worktreeRow } from './worktree-row-locators' function worktreeOption(page: Page, worktreeId: string) { return worktreeRow(page, worktreeId) } async function prepareSidebarForScrollTest(page: Page): Promise { await page.evaluate(() => { const store = window.__store if (!store) { throw new Error('window.__store is not available') } const state = store.getState() state.setActiveView('terminal') state.setSidebarOpen(true) state.setGroupBy('none') state.setSortBy('recent') state.setShowActiveOnly(false) state.setShowSleepingWorkspaces(true) state.setHideDefaultBranchWorkspace(false) state.setFilterRepoIds([]) }) } async function forceCurrentWorkspaceClipped(page: Page, targetId: string): Promise { await page.locator('[data-worktree-sidebar]').evaluate((element, targetId) => { const scroller = element as HTMLElement const target = [...document.querySelectorAll('[data-worktree-id]')].find( (candidate) => candidate.dataset.worktreeId === targetId ) if (!target) { throw new Error('Target workspace row is not mounted') } // Why: the reveal assertion checks full visibility; keep the synthetic // viewport taller than the real row while still forcing a clipped start. const clippedViewportHeight = Math.max( 72, Math.ceil(target.getBoundingClientRect().height) + 16 ) scroller.style.height = `${clippedViewportHeight}px` scroller.style.maxHeight = `${clippedViewportHeight}px` scroller.style.overflowY = 'auto' const scrollerBounds = scroller.getBoundingClientRect() const targetBounds = target.getBoundingClientRect() const desiredTargetTop = scrollerBounds.bottom - 24 scroller.scrollTop += targetBounds.top - desiredTargetTop scroller.dispatchEvent(new Event('scroll', { bubbles: true })) window.dispatchEvent(new Event('resize')) }, targetId) await expect .poll( () => page.evaluate((targetId) => { const scroller = document.querySelector('[data-worktree-sidebar]') const target = [...document.querySelectorAll('[data-worktree-id]')].find( (candidate) => candidate.dataset.worktreeId === targetId ) if (!scroller || !target) { return false } const scrollerBounds = scroller.getBoundingClientRect() const targetBounds = target.getBoundingClientRect() return ( targetBounds.top < scrollerBounds.bottom && targetBounds.bottom > scrollerBounds.bottom ) }, targetId), { timeout: 10_000, message: 'Target workspace should be clipped before using the reveal button' } ) .toBe(true) } async function expectNoRevealHighlightDuring( page: Page, targetId: string, durationMs: number ): Promise { const deadline = Date.now() + durationMs while (Date.now() < deadline) { const isHighlighted = await page.evaluate((targetId) => { const target = [...document.querySelectorAll('[data-worktree-id]')].find( (candidate) => candidate.dataset.worktreeId === targetId ) return target?.getAttribute('data-scroll-reveal-highlight') === 'true' }, targetId) expect(isHighlighted).toBe(false) await page.waitForTimeout(50) } } test.describe('Reveal active workspace button', () => { test.beforeEach(async ({ orcaPage }) => { await waitForSessionReady(orcaPage) await waitForActiveWorktree(orcaPage) }) test('reveals the current workspace when it is clipped in the production sidebar', async ({ orcaPage }) => { await prepareSidebarForScrollTest(orcaPage) const renderedOptions = orcaPage.locator('[data-worktree-sidebar] [role="option"]') await expect(renderedOptions).toHaveCount(2) const targetId = await renderedOptions.last().getAttribute('data-worktree-id') if (!targetId) { throw new Error('Bottom workspace row did not expose a data-worktree-id') } const targetRow = worktreeOption(orcaPage, targetId) const revealButton = orcaPage.getByRole('button', { name: 'Reveal active workspace' }) await renderedOptions.last().click() await expect(targetRow).toHaveAttribute('aria-current', 'page') await expectNoRevealHighlightDuring(orcaPage, targetId, 400) await expect(revealButton).toBeVisible() await expect(revealButton).toBeEnabled() await forceCurrentWorkspaceClipped(orcaPage, targetId) await expect(revealButton).toBeVisible() await expect(revealButton).toBeEnabled() await revealButton.click() await expect(targetRow).toHaveAttribute('data-scroll-reveal-highlight', 'true') await expect .poll( () => orcaPage.evaluate((targetId) => { const scroller = document.querySelector('[data-worktree-sidebar]') const target = [...document.querySelectorAll('[data-worktree-id]')].find( (candidate) => candidate.dataset.worktreeId === targetId ) if (!scroller || !target) { return false } const scrollerBounds = scroller.getBoundingClientRect() const targetBounds = target.getBoundingClientRect() return ( targetBounds.top >= scrollerBounds.top - 1 && targetBounds.bottom <= scrollerBounds.bottom + 1 ) }, targetId), { timeout: 10_000, message: 'Reveal button did not scroll the current workspace fully into view' } ) .toBe(true) await expect(revealButton).toBeVisible() await expect(revealButton).toBeEnabled() }) test('clears sidebar filters before revealing a hidden current workspace', async ({ orcaPage }) => { await prepareSidebarForScrollTest(orcaPage) const renderedOptions = orcaPage.locator('[data-worktree-sidebar] [role="option"]') await expect(renderedOptions).toHaveCount(2) const targetId = await renderedOptions.last().getAttribute('data-worktree-id') if (!targetId) { throw new Error('Bottom workspace row did not expose a data-worktree-id') } const targetRow = worktreeOption(orcaPage, targetId) const revealButton = orcaPage.getByRole('button', { name: 'Reveal active workspace' }) await renderedOptions.last().click() await expect(targetRow).toHaveAttribute('aria-current', 'page') await orcaPage.evaluate(() => { const store = window.__store if (!store) { throw new Error('window.__store is not available') } store.getState().setFilterRepoIds(['__filtered_repo__']) }) await expect(renderedOptions).toHaveCount(0) await expect(orcaPage.getByText('No workspaces found')).toBeVisible() await revealButton.click() await expect(targetRow).toBeVisible() await expect(targetRow).toHaveAttribute('data-scroll-reveal-highlight', 'true') await expect .poll( () => orcaPage.evaluate(() => { const store = window.__store if (!store) { throw new Error('window.__store is not available') } return store.getState().filterRepoIds }), { timeout: 10_000, message: 'Reveal button should clear repo filters that hide the current workspace' } ) .toEqual([]) }) })