Files
orca/tests/e2e/helpers/terminal-hidden-parking.ts
Jinjing 220811cbad fix(e2e): repair release e2e suite (parking regression tests, stale/flaky specs, profile switcher gate) (#8486)
* fix(e2e): repair release e2e suite — parking regression tests, stale/flaky specs, profile switcher gate

Diagnosed 20 failing tests across the release e2e shards. Most are test debt,
plus two genuine product-side issues.

Product fixes:
- OrcaProfileSwitcher: the PROD gate hid the "Switch profile" button in the
  e2e build (electron-vite build bakes NODE_ENV=production). Exempt
  MODE==='e2e' so the specs render it while packaged prod builds stay hidden.

Parking cluster (8 tests): #8262 intentionally keeps the most-recently-hidden
tab warm (exempt from cold-park). The specs hid exactly one tab — always the
exempt one — so it never parked. Open a throwaway decoy tab that absorbs the
last-active exemption so the target parks. (terminal-hidden-view-parking,
terminal-pane-close-layout-consistency)

Stale tests updated to match intended product behavior:
- rich-markdown-link-bubble: match Edit link by aria-label (title dropped in #8307)
- terminal-codex-hidden-startup-background: drop the dead hiddenRendererSkipCount
  poll (Phase-4 main-side delivery gate #7214 bypasses that renderer path)

Brittle threshold/geometry/timing hardening (no product regression):
- agent-session-log-tail-stability: assert full-model length instead of a
  machine-specific word-wrap pixel baseline
- artificial-opencode revisit: dedicated under-backpressure latency bound
- terminal-history-size-typing-latency: gate p90 not max (tolerate one
  checkpoint-in-window spike; median stays strict)
- combined-diff-scroll-restore: assert viewport barely moved vs exact anchor key
- terminal-shortcuts: idempotent kitty-flag reset instead of a racing stack pop
- agent-session-live-force-exit-resume: drive the product quit-capture path
- renderer-crash-recovery-terminal-input: poll the transport probe over the
  recovery budget (still flags a permanently frozen pane)

terminal-push-delivery-loss-recovery left unchanged (no safe test-only
improvement; recovery is wall-clock bounded with ample slack).

* Extract shared parking helpers into terminal-hidden-parking.ts for e2e s

- Deduplicate waitForTabParked/parkHiddenTabBehindDecoy, previously
  copy-pasted across the parking and layout-consistency specs
- Parameterize parkDelayMs so the helper no longer depends on a
  file-local PARKING_DELAY_MS constant
2026-07-12 22:40:57 -07:00

66 lines
2.5 KiB
TypeScript

import type { Page } from '@stablyai/playwright-test'
import { expect } from '@stablyai/playwright-test'
import { getActiveTabId } from './store'
import { waitForActiveTerminalManager, waitForPaneIdentitySnapshot } from './terminal'
function resolveParkWaitTimeoutMs(parkDelayMs?: number): number {
const delay = parkDelayMs ?? (Number(process.env.ORCA_E2E_TERMINAL_PARKING_DELAY_MS) || 500)
return Math.max(20_000, delay * 10)
}
// Why: TerminalPane unmount deletes its entry from window.__paneManagers, so a
// missing manager is the observable signal that the tab's xterm was parked.
export async function waitForTabParked(
page: Page,
tabId: string,
options?: { parkDelayMs?: number }
): Promise<number> {
const parkWaitStartedAt = Date.now()
await expect
.poll(async () => page.evaluate((id) => window.__paneManagers?.get(id) !== undefined, tabId), {
timeout: resolveParkWaitTimeoutMs(options?.parkDelayMs),
message: `terminal tab ${tabId} did not park (pane manager still mounted)`
})
.toBe(false)
return Date.now() - parkWaitStartedAt
}
async function createActiveTerminalTab(page: Page, worktreeId: string): Promise<string> {
const tabId = await page.evaluate((worktreeId) => {
const store = window.__store
if (!store) {
throw new Error('createActiveTerminalTab: window.__store is unavailable')
}
const state = store.getState()
const tab = state.createTab(worktreeId, undefined, undefined, { activate: true })
state.setActiveTab(tab.id)
state.setActiveTabType('terminal')
return tab.id
}, worktreeId)
await expect
.poll(() => getActiveTabId(page), {
timeout: 5_000,
message: 'newly created terminal tab did not become active'
})
.toBe(tabId)
await waitForActiveTerminalManager(page, 30_000)
await waitForPaneIdentitySnapshot(page, 1)
return tabId
}
// Why: #8262 exempts the single most-recently-hidden tab from cold-park to keep
// the just-left view instantly warm, so a lone hidden tab never parks. Opening
// one more tab hides the current view (which then holds that exemption) and
// leaves the older `targetTabId` free to cold-park. Returns waitForTabParked's
// elapsed-ms so callers keep their parking annotations.
export async function parkHiddenTabBehindDecoy(
page: Page,
worktreeId: string,
targetTabId: string,
options?: { parkDelayMs?: number }
): Promise<number> {
await createActiveTerminalTab(page, worktreeId)
return waitForTabParked(page, targetTabId, options)
}