import { writeFileSync } from 'node:fs' import path from 'node:path' import { expect, test } from './helpers/orca-app' import { openFileExplorer } from './helpers/file-explorer' import { createRuntimeDesktopPairingOffer, launchPairedElectronClient, type PairedElectronClient } from './helpers/paired-electron-client' import { ensureTerminalVisible, waitForActiveWorktree, waitForSessionReady } from './helpers/store' const FIXTURE_NAME = 'paired-html-focus.html' test('keeps remote HTML preview placement and focuses it only after a click', async ({ orcaPage, testRepoPath }, testInfo) => { test.setTimeout(240_000) writeFileSync( path.join(testRepoPath, FIXTURE_NAME), '

paired html focus

\n' ) await waitForSessionReady(orcaPage) await waitForActiveWorktree(orcaPage) await ensureTerminalVisible(orcaPage) const offer = await createRuntimeDesktopPairingOffer(orcaPage) let client: PairedElectronClient | null = null try { client = await launchPairedElectronClient(offer, testInfo, 'Remote HTML focus') const page = client.page const worktreeId = await expect .poll( () => page.evaluate((repoPath) => { const state = window.__store?.getState() return state ? (state.allWorktrees().find((worktree) => worktree.path === repoPath)?.id ?? null) : null }, testRepoPath), { timeout: 60_000, message: 'paired client never received the host worktree' } ) .not.toBeNull() .then(() => page.evaluate((repoPath) => { const state = window.__store?.getState() return state?.allWorktrees().find((worktree) => worktree.path === repoPath)?.id ?? null }, testRepoPath) ) if (!worktreeId) { throw new Error('paired client worktree disappeared after discovery') } await page.evaluate( ({ environmentId, worktreeId }) => { window.__store?.getState().setActiveWorktree(worktreeId, `runtime:${environmentId}`) }, { environmentId: client.environmentId, worktreeId } ) await openFileExplorer(page) const fixtureRow = page.locator('[data-file-explorer-row]').filter({ hasText: FIXTURE_NAME }) await expect(fixtureRow).toBeVisible({ timeout: 30_000 }) await fixtureRow.click() const openPreviewToSide = page.getByRole('button', { name: 'Open Preview to the Side' }) await expect(openPreviewToSide).toBeVisible({ timeout: 30_000 }) const sourceEditor = await page.evaluate((targetWorktreeId) => { const state = window.__store?.getState() const groupId = state?.activeGroupIdByWorktree[targetWorktreeId] const group = (state?.groupsByWorktree[targetWorktreeId] ?? []).find( (candidate) => candidate.id === groupId ) const tab = (state?.unifiedTabsByWorktree[targetWorktreeId] ?? []).find( (candidate) => candidate.id === group?.activeTabId && candidate.contentType === 'editor' ) return groupId && tab ? { groupId, tabId: tab.id } : null }, worktreeId) if (!sourceEditor) { throw new Error('paired client editor had no source identity before side preview') } const sourceGroupId = sourceEditor.groupId const browserBaseline = await page.evaluate( async ({ environmentId, worktreeId }) => { const state = window.__store?.getState() const response = await window.api.runtimeEnvironments.call({ selector: environmentId, method: 'session.tabs.list', params: { worktree: `id:${worktreeId}` }, timeoutMs: 15_000 }) return { clientUnified: (state?.unifiedTabsByWorktree[worktreeId] ?? []).filter( (tab) => tab.contentType === 'browser' ).length, clientWorkspaces: (state?.browserTabsByWorktree[worktreeId] ?? []).length, host: response.ok ? response.result.tabs.filter((tab) => tab.type === 'browser').length : -1 } }, { environmentId: client.environmentId, worktreeId } ) await openPreviewToSide.click() await expect .poll( () => page.evaluate( async ({ environmentId, fixtureName, worktreeId }) => { const state = window.__store?.getState() if (!state) { return null } const browser = (state.browserTabsByWorktree[worktreeId] ?? []).find((tab) => tab.url.endsWith(`/${fixtureName}`) ) const browserPage = browser ? (state.browserPagesByWorkspace[browser.id] ?? [])[0] : null const handle = browserPage ? state.remoteBrowserPageHandlesByPageId[browserPage.id] : null const response = await window.api.runtimeEnvironments.call({ selector: environmentId, method: 'session.tabs.list', params: { worktree: `id:${worktreeId}` }, timeoutMs: 15_000 }) const hostHasHtml = response.ok && response.result.tabs.some( (tab) => tab.type === 'browser' && tab.url.endsWith(`/${fixtureName}`) ) return { browserRuntimeEnvironmentId: browserPage?.browserRuntimeEnvironmentId ?? null, handleEnvironmentId: handle?.environmentId ?? null, handleRemotePageId: handle?.remotePageId ?? null, hostHasHtml } }, { environmentId: client!.environmentId, fixtureName: FIXTURE_NAME, worktreeId } ), { timeout: 60_000, message: 'remote HTML browser ownership never converged' } ) .toMatchObject({ browserRuntimeEnvironmentId: client.environmentId, handleEnvironmentId: client.environmentId, hostHasHtml: true }) const htmlTabInventory = await page.evaluate( async ({ environmentId, fixtureName, worktreeId }) => { const state = window.__store?.getState() const response = await window.api.runtimeEnvironments.call({ selector: environmentId, method: 'session.tabs.list', params: { worktree: `id:${worktreeId}` }, timeoutMs: 15_000 }) const clientWorkspaceIds = (state?.browserTabsByWorktree[worktreeId] ?? []) .filter((tab) => tab.url.endsWith(`/${fixtureName}`)) .map((tab) => tab.id) return { clientWorkspaceIds, clientUnifiedTabs: (state?.unifiedTabsByWorktree[worktreeId] ?? []) .filter( (tab) => tab.contentType === 'browser' && clientWorkspaceIds.includes(tab.entityId) ) .map((tab) => ({ groupId: tab.groupId, id: tab.id })), hostTabIds: response.ok ? response.result.tabs .filter((tab) => tab.type === 'browser' && tab.url.endsWith(`/${fixtureName}`)) .map((tab) => tab.id) : [], hostTabGroups: response.ok ? (response.result.tabGroups ?? []) : [], totalClientUnified: (state?.unifiedTabsByWorktree[worktreeId] ?? []).filter( (tab) => tab.contentType === 'browser' ).length, totalClientWorkspaces: (state?.browserTabsByWorktree[worktreeId] ?? []).length, totalHost: response.ok ? response.result.tabs.filter((tab) => tab.type === 'browser').length : -1 } }, { environmentId: client.environmentId, fixtureName: FIXTURE_NAME, worktreeId } ) expect(htmlTabInventory.clientWorkspaceIds).toHaveLength(1) expect(htmlTabInventory.clientUnifiedTabs).toHaveLength(1) expect(htmlTabInventory.hostTabIds).toHaveLength(1) expect(htmlTabInventory.totalClientUnified).toBe(browserBaseline.clientUnified + 1) expect(htmlTabInventory.totalClientWorkspaces).toBe(browserBaseline.clientWorkspaces + 1) expect(htmlTabInventory.totalHost).toBe(browserBaseline.host + 1) expect(htmlTabInventory.clientUnifiedTabs[0]?.groupId).not.toBe(sourceGroupId) expect( htmlTabInventory.hostTabGroups.some( (group) => group.id === htmlTabInventory.clientUnifiedTabs[0]?.groupId ) ).toBe(false) const hostBrowserGroupId = htmlTabInventory.hostTabGroups.find((group) => group.tabOrder.includes(htmlTabInventory.hostTabIds[0]!) )?.id expect(hostBrowserGroupId).toBeTruthy() await expect(page.locator(`[data-tab-group-body-id="${sourceGroupId}"]`)).toBeVisible() await expect( page.locator(`[data-tab-group-body-id="${htmlTabInventory.clientUnifiedTabs[0]!.groupId}"]`) ).toBeVisible() await expect(page.getByTestId('remote-browser-frame')).toBeVisible({ timeout: 60_000 }) const previewFocus = await page.evaluate( ({ sourceGroupId, sourceTabId, worktreeId: targetWorktreeId }) => { const state = window.__store?.getState() const activeGroup = (state?.groupsByWorktree[targetWorktreeId] ?? []).find( (group) => group.id === state?.activeGroupIdByWorktree[targetWorktreeId] ) return { activeGroupId: activeGroup?.id ?? null, activeTabId: activeGroup?.activeTabId ?? null, activeTabType: state?.activeTabTypeByWorktree[targetWorktreeId] ?? null, sourceGroupId, sourceTabId } }, { sourceGroupId, sourceTabId: sourceEditor.tabId, worktreeId } ) expect(previewFocus).toEqual({ activeGroupId: sourceGroupId, activeTabId: sourceEditor.tabId, activeTabType: 'editor', sourceGroupId, sourceTabId: sourceEditor.tabId }) const tabIds = await page.evaluate( ({ fixtureName, worktreeId: targetWorktreeId }) => { const state = window.__store?.getState() if (!state) { return null } const terminalId = state.tabsByWorktree[targetWorktreeId]?.[0]?.id ?? null const browserId = (state.browserTabsByWorktree[targetWorktreeId] ?? []).find((tab) => tab.url.endsWith(`/${fixtureName}`) )?.id return terminalId && browserId ? { browserId, terminalId } : null }, { fixtureName: FIXTURE_NAME, worktreeId } ) if (!tabIds) { throw new Error('paired client did not retain both terminal and HTML browser tabs') } await page.locator(`[data-tab-id="${tabIds.terminalId}"]`).click() await expect .poll( () => page.evaluate((targetWorktreeId) => { const state = window.__store?.getState() return state?.activeTabTypeByWorktree[targetWorktreeId] ?? null }, worktreeId), { message: 'terminal tab never became active before the browser click' } ) .toBe('terminal') await expect .poll( () => page.evaluate( async ({ environmentId, worktreeId }) => { const response = await window.api.runtimeEnvironments.call({ selector: environmentId, method: 'session.tabs.list', params: { worktree: `id:${worktreeId}` }, timeoutMs: 15_000 }) if (!response.ok) { return false } return ( response.result.tabs.find((tab) => tab.id === response.result.activeTabId)?.type === 'terminal' ) }, { environmentId: client.environmentId, worktreeId } ), { timeout: 30_000, message: 'host never accepted terminal activation' } ) .toBe(true) const hostBrowserTab = await page.evaluate( async ({ environmentId, fixtureName, worktreeId }) => { const response = await window.api.runtimeEnvironments.call({ selector: environmentId, method: 'session.tabs.list', params: { worktree: `id:${worktreeId}` }, timeoutMs: 15_000 }) const tab = response.ok ? response.result.tabs.find( (candidate) => candidate.type === 'browser' && candidate.url.endsWith(`/${fixtureName}`) ) : null return tab?.type === 'browser' ? { browserPageId: tab.browserPageId, id: tab.id } : null }, { environmentId: client.environmentId, fixtureName: FIXTURE_NAME, worktreeId } ) if (!hostBrowserTab?.browserPageId) { throw new Error('host HTML browser tab disappeared before activation') } const clientRemotePageId = await page.evaluate( ({ fixtureName, worktreeId }) => { const state = window.__store?.getState() const workspace = (state?.browserTabsByWorktree[worktreeId] ?? []).find((tab) => tab.url.endsWith(`/${fixtureName}`) ) const browserPage = workspace ? (state?.browserPagesByWorkspace[workspace.id] ?? [])[0] : null return browserPage ? (state?.remoteBrowserPageHandlesByPageId[browserPage.id]?.remotePageId ?? null) : null }, { fixtureName: FIXTURE_NAME, worktreeId } ) expect(clientRemotePageId).toBe(hostBrowserTab.browserPageId) const content = await page.evaluate( async ({ browserPageId, environmentId, worktreeId }) => window.api.runtimeEnvironments.call({ selector: environmentId, method: 'browser.eval', params: { worktree: `id:${worktreeId}`, page: browserPageId, expression: 'document.querySelector("h1")?.textContent' }, timeoutMs: 15_000 }), { browserPageId: hostBrowserTab.browserPageId, environmentId: client.environmentId, worktreeId } ) expect(content).toMatchObject({ ok: true, result: { result: 'paired html focus' } }) await expect .poll( () => page.evaluate( ({ browserTabId, environmentId }) => { const state = window.__store?.getState() return (state?.browserPagesByWorkspace[browserTabId] ?? []).some((browserPage) => { const handle = state?.remoteBrowserPageHandlesByPageId[browserPage.id] return ( handle?.environmentId === environmentId || browserPage.browserRuntimeEnvironmentId === environmentId ) }) }, { browserTabId: tabIds.browserId, environmentId: client.environmentId } ), { timeout: 30_000, message: 'client lost remote browser ownership before activation' } ) .toBe(true) await page.locator(`[data-tab-id="${tabIds.browserId}"]`).click() await expect .poll( () => page.evaluate( async ({ environmentId, fixtureName, worktreeId }) => { const state = window.__store?.getState() if (!state) { return null } const response = await window.api.runtimeEnvironments.call({ selector: environmentId, method: 'session.tabs.list', params: { worktree: `id:${worktreeId}` }, timeoutMs: 15_000 }) const activeGroup = (state.groupsByWorktree[worktreeId] ?? []).find( (group) => group.id === state.activeGroupIdByWorktree[worktreeId] ) const activeUnified = (state.unifiedTabsByWorktree[worktreeId] ?? []).find( (tab) => tab.id === activeGroup?.activeTabId ) const hostActive = response.ok ? response.result.tabs.find((tab) => tab.id === response.result.activeTabId) : null return { activeGroupType: activeUnified?.contentType ?? null, activeTabType: state.activeTabTypeByWorktree[worktreeId] ?? null, hostActiveHtml: hostActive?.type === 'browser' && hostActive.url.endsWith(`/${fixtureName}`) } }, { environmentId: client!.environmentId, fixtureName: FIXTURE_NAME, worktreeId } ), { timeout: 30_000, message: 'browser click did not remain authoritative' } ) .toEqual({ activeGroupType: 'browser', activeTabType: 'browser', hostActiveHtml: true }) await expect(page.getByTestId('remote-browser-frame')).toBeVisible() const browserTab = page.locator(`[data-tab-id="${tabIds.browserId}"]`) await browserTab.click({ button: 'right' }) await page.getByRole('menuitem', { name: 'Close', exact: true }).click() await expect .poll( () => page.evaluate( async ({ environmentId, hostTabId, sourceGroupId, unifiedTabId, workspaceId, worktreeId }) => { const state = window.__store?.getState() const response = await window.api.runtimeEnvironments.call({ selector: environmentId, method: 'session.tabs.list', params: { worktree: `id:${worktreeId}` }, timeoutMs: 15_000 }) return { clientUnifiedPresent: (state?.unifiedTabsByWorktree[worktreeId] ?? []).some( (tab) => tab.id === unifiedTabId ), clientWorkspacePresent: (state?.browserTabsByWorktree[worktreeId] ?? []).some( (tab) => tab.id === workspaceId ), hostTabPresent: response.ok ? response.result.tabs.some((tab) => tab.id === hostTabId) : true, sourceGroupPresent: (state?.groupsByWorktree[worktreeId] ?? []).some( (group) => group.id === sourceGroupId ) } }, { environmentId: client!.environmentId, hostTabId: hostBrowserTab.id, sourceGroupId, unifiedTabId: htmlTabInventory.clientUnifiedTabs[0]!.id, workspaceId: htmlTabInventory.clientWorkspaceIds[0]!, worktreeId } ), { timeout: 30_000, message: 'remote HTML browser close did not converge cleanly' } ) .toEqual({ clientUnifiedPresent: false, clientWorkspacePresent: false, hostTabPresent: false, sourceGroupPresent: true }) await expect(browserTab).toHaveCount(0) await expect(page.locator(`[data-tab-id="${tabIds.terminalId}"]`)).toBeVisible() await expect(page.locator(`[data-tab-id="${sourceEditor.tabId}"]`)).toBeVisible() await expect( page.locator(`[data-tab-group-body-id="${sourceGroupId}"] .monaco-editor`) ).toBeVisible() } finally { await client?.dispose() } })