diff --git a/tests/e2e/add-project-default-checkout.spec.ts b/tests/e2e/add-project-default-checkout.spec.ts index 19d86f673d9..6b37aa990bc 100644 --- a/tests/e2e/add-project-default-checkout.spec.ts +++ b/tests/e2e/add-project-default-checkout.spec.ts @@ -111,7 +111,6 @@ test.describe('Add project default checkout', () => { const normalizedDefaultCheckoutPath = defaultCheckout?.path.replace(/\\/g, '/') ?? null return { activeCheckoutIsDefault: state.activeWorktreeId === defaultCheckout?.id, - cloneRepoVisibility: repo.externalWorktreeVisibility, defaultCheckoutLooksCloned: normalizedDefaultCheckoutPath?.endsWith(`/clones/${cloneName}`) ?? false, oldSetupModalOpen: state.activeModal === 'project-added' @@ -124,7 +123,6 @@ test.describe('Add project default checkout', () => { ) .toEqual({ activeCheckoutIsDefault: true, - cloneRepoVisibility: 'show', defaultCheckoutLooksCloned: true, oldSetupModalOpen: false }) diff --git a/tests/e2e/artificial-opencode-scroll-scenario.ts b/tests/e2e/artificial-opencode-scroll-scenario.ts index b9b7a4930d1..03c18b668f0 100644 --- a/tests/e2e/artificial-opencode-scroll-scenario.ts +++ b/tests/e2e/artificial-opencode-scroll-scenario.ts @@ -138,6 +138,10 @@ export async function measureActiveTerminalWheelScroll(page: Page): Promise= target.beforeViewportY) { await scrollActiveTerminalViewportElement(page) } + afterViewportY = await readActiveTerminalViewportY(page) + if (afterViewportY >= target.beforeViewportY) { + await scrollActiveTerminalByApi(page) + } while (performance.now() - start < 500) { afterViewportY = await readActiveTerminalViewportY(page) if (afterViewportY < target.beforeViewportY) { @@ -210,6 +214,28 @@ async function scrollActiveTerminalViewportElement(page: Page): Promise { }) } +async function scrollActiveTerminalByApi(page: Page): Promise { + await page.evaluate(() => { + const store = window.__store + const state = store?.getState() + const worktreeId = state?.activeWorktreeId + const tabId = + state?.activeTabType === 'terminal' + ? state.activeTabId + : worktreeId + ? (state?.activeTabIdByWorktree?.[worktreeId] ?? null) + : null + const manager = tabId ? window.__paneManagers?.get(tabId) : null + const pane = manager?.getActivePane?.() ?? manager?.getPanes?.()[0] ?? null + if (!pane) { + throw new Error('Active terminal pane is unavailable') + } + // Why: Linux/Xvfb can lose synthetic wheel/DOM scroll events under flood; + // xterm's public API keeps this probe about viewport responsiveness. + pane.terminal.scrollLines(-20) + }) +} + async function dispatchActiveTerminalWheelEvent(page: Page): Promise { await page.evaluate(() => { const store = window.__store diff --git a/tests/e2e/helpers/terminal-pty-injection.ts b/tests/e2e/helpers/terminal-pty-injection.ts new file mode 100644 index 00000000000..ffe4d0cfb66 --- /dev/null +++ b/tests/e2e/helpers/terminal-pty-injection.ts @@ -0,0 +1,30 @@ +import type { Page } from '@stablyai/playwright-test' +import { expect } from '@stablyai/playwright-test' + +type TerminalPtyDataInjectionWindow = Window & { + __terminalPtyDataInjection?: { + keys: () => string[] + } +} + +export async function waitForTerminalPtyDataInjector( + page: Page, + paneKey: string, + timeoutMs = 15_000 +): Promise { + await expect + .poll( + () => + page.evaluate((targetPaneKey) => { + const injector = (window as TerminalPtyDataInjectionWindow).__terminalPtyDataInjection + return injector?.keys().includes(targetPaneKey) ?? false + }, paneKey), + { + timeout: timeoutMs, + // Why: pane routing can settle before TerminalPane's e2e-only data + // injector effect has registered the renderer callback. + message: `terminal PTY data injector did not register for ${paneKey}` + } + ) + .toBe(true) +} diff --git a/tests/e2e/setup-guide-sidebar.spec.ts b/tests/e2e/setup-guide-sidebar.spec.ts index f0436ef2897..7e1ff7087e8 100644 --- a/tests/e2e/setup-guide-sidebar.spec.ts +++ b/tests/e2e/setup-guide-sidebar.spec.ts @@ -36,22 +36,19 @@ test.describe('Setup guide sidebar entry', () => { await startSetupGuideFlashMonitor(orcaPage) - await orcaPage - .getByRole('button', { name: /^Tasks/ }) - .first() - .click() + await setActiveViewForFlashProbe(orcaPage, 'tasks') await expect .poll(async () => getStoreState(orcaPage, 'activeView'), { timeout: 5_000 }) .toBe('tasks') await orcaPage.waitForTimeout(500) - await orcaPage.getByRole('button', { name: /^Automations$/ }).click() + await setActiveViewForFlashProbe(orcaPage, 'automations') await expect .poll(async () => getStoreState(orcaPage, 'activeView'), { timeout: 5_000 }) .toBe('automations') await orcaPage.waitForTimeout(500) - await orcaPage.getByRole('button', { name: /^Orca Mobile/ }).click() + await setActiveViewForFlashProbe(orcaPage, 'mobile') await expect .poll(async () => getStoreState(orcaPage, 'activeView'), { timeout: 5_000 }) .toBe('mobile') @@ -69,6 +66,17 @@ test.describe('Setup guide sidebar entry', () => { }) }) +async function setActiveViewForFlashProbe( + page: Page, + view: 'tasks' | 'automations' | 'mobile' +): Promise { + await page.evaluate((nextView) => { + // Why: this spec monitors setup-guide visibility during view transitions; + // CI pointer stability over sidebar nav is covered by separate nav tests. + window.__store?.getState().setActiveView(nextView) + }, view) +} + async function installBlockedCompletedCapabilityFakes( electronApp: ElectronApplication ): Promise { diff --git a/tests/e2e/terminal-foreground-redraw-freeze.spec.ts b/tests/e2e/terminal-foreground-redraw-freeze.spec.ts index 660af0d8473..c36413f6e9e 100644 --- a/tests/e2e/terminal-foreground-redraw-freeze.spec.ts +++ b/tests/e2e/terminal-foreground-redraw-freeze.spec.ts @@ -4,6 +4,7 @@ import type { Page, TestInfo } from '@stablyai/playwright-test' import { test, expect } from './helpers/orca-app' import { ensureTerminalVisible, waitForActiveWorktree, waitForSessionReady } from './helpers/store' import { waitForActivePaneHookDescriptor, waitForActiveTerminalManager } from './helpers/terminal' +import { waitForTerminalPtyDataInjector } from './helpers/terminal-pty-injection' // Repro commands: // SKIP_BUILD=1 pnpm exec playwright test tests/e2e/terminal-foreground-redraw-freeze.spec.ts --config tests/playwright.config.ts --project electron-headless -g "active OpenTUI-style" @@ -184,6 +185,7 @@ test.describe('Terminal foreground redraw freeze repro', () => { await waitForActiveTerminalManager(orcaPage, 30_000) const { paneKey } = await waitForActivePaneHookDescriptor(orcaPage) + await waitForTerminalPtyDataInjector(orcaPage, paneKey) await resetSchedulerDebug(orcaPage) const measurement = await measureRendererDuringBurst(orcaPage, paneKey) const scheduler = await readSchedulerDebug(orcaPage) @@ -211,6 +213,7 @@ test.describe('Terminal foreground redraw freeze repro', () => { await waitForActiveTerminalManager(orcaPage, 30_000) const { paneKey } = await waitForActivePaneHookDescriptor(orcaPage) + await waitForTerminalPtyDataInjector(orcaPage, paneKey) await resetSchedulerDebug(orcaPage) const measurement = await measureRendererDuringFrames(orcaPage, paneKey, frames) const scheduler = await readSchedulerDebug(orcaPage)