mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 16:02:24 +00:00
* test(e2e): register a real runtime host and publish the alt-screen frame as its snapshot Two long-running scheduled-E2E failures on main were stale test setup, not product defects. `onboarding.spec.ts:420` seeded the Active Server by faking a runtime environment in the renderer store and writing `activeRuntimeEnvironmentId` through the generic `settings:set` IPC. Since #10011 that setter strips the key, and the dedicated `settings:set-active-runtime-environment-preference` handler resolves the id against the main-process environment store — CI logged `RuntimeEnvironmentStoreError: Unknown environment: env-e2e` from `runtimeEnvironments:subscribe`/`:call` alongside the assertion failure. Register the host for real via `runtimeEnvironments:addFromPairingCode` (offline; no live server) and write the preference through its own channel. `terminal-tab-switch-visual-restore.spec.ts:604` wrote alt-screen frames straight into the renderer's xterm, so those bytes never transited the PTY and main's model could not contain them. On cycle 0 the freshly spawned shell still has queued startup output, so hiding the pane makes main's hidden-delivery gate drop bytes and latch a reveal restore, which repaints main's snapshot over the fabricated frame; later cycles run against an idle shell and survive. Arm the existing `setHiddenSnapshotOverride` seam (already used by sibling tests in this file) with the same frame so the live-write and restore paths render identically, and keep the `markerPresent` assertion. Co-authored-by: Orca <help@stably.ai> * test(e2e): keep the alt-screen restore path observable Numbering the snapshot frame one higher than the live-written frame keeps the marker assertion path-agnostic while leaving the frame number on screen as the signal for which path painted. An unrecognised frame now fails, and the per-cycle path is recorded rather than asserted because which cycles latch a restore is load-dependent. Frame authoring and readback move to a helper module; the additions crossed the spec's max-lines cap. Co-authored-by: Orca <help@stably.ai> * Escape regex metacharacters in alt-screen marker pattern Marker is treated as a literal string, so escape regex metacharacters to prevent them from being interpreted as regex syntax. --------- Co-authored-by: Orca <help@stably.ai>
77 lines
3.0 KiB
TypeScript
77 lines
3.0 KiB
TypeScript
import type { Page } from '@stablyai/playwright-test'
|
|
|
|
// Boxed alt-screen TUI frame: enters the alternate buffer, clears it, and paints
|
|
// a marker line carrying a zero-padded frame number.
|
|
export function buildAltScreenFrame(marker: string, frame: number): string {
|
|
const progress = `${'█'.repeat((frame % 8) + 1)}${'░'.repeat(8 - ((frame % 8) + 1))}`
|
|
return [
|
|
'\x1b[?2026h',
|
|
'\x1b[?1049h',
|
|
'\x1b[2J\x1b[H',
|
|
'\x1b[?25l',
|
|
`╭────────────────────────────────────────────────────────────────────╮`,
|
|
`│ ${marker} frame ${String(frame).padStart(3, '0')} ${progress} │`,
|
|
`│ Dimension │ Rating │`,
|
|
`╰────────────────────────────────────────────────────────────────────╯`,
|
|
'\x1b[?2026l'
|
|
].join('\r\n')
|
|
}
|
|
|
|
// Why: the live-write and the reveal restore paint the same layout, so the frame
|
|
// number is the only thing on screen that says which of the two landed last.
|
|
export async function readRenderedAltScreenFrame(
|
|
page: Page,
|
|
tabId: string,
|
|
marker: string
|
|
): Promise<number | null> {
|
|
return page.evaluate(
|
|
({ tabId, marker }) => {
|
|
const manager = window.__paneManagers?.get(tabId)
|
|
const pane = manager?.getActivePane?.() ?? manager?.getPanes?.()[0]
|
|
if (!pane) {
|
|
throw new Error(`No terminal pane for tab ${tabId}`)
|
|
}
|
|
// marker is a literal, so escape it rather than letting `[`/`.`/`+` act as regex syntax.
|
|
const pattern = new RegExp(`${marker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')} frame (\\d{3})`)
|
|
const buffer = pane.terminal.buffer.active
|
|
for (let row = 0; row < pane.terminal.rows; row += 1) {
|
|
const line = buffer.getLine(buffer.viewportY + row)?.translateToString(true) ?? ''
|
|
const match = pattern.exec(line)
|
|
if (match) {
|
|
return Number(match[1])
|
|
}
|
|
}
|
|
return null
|
|
},
|
|
{ tabId, marker }
|
|
)
|
|
}
|
|
|
|
export function describeAltScreenRenderPath(
|
|
renderedFrame: number | null,
|
|
liveFrame: number,
|
|
restoreFrame: number
|
|
): string {
|
|
if (renderedFrame === restoreFrame) {
|
|
return 'reveal restore'
|
|
}
|
|
if (renderedFrame === liveFrame) {
|
|
return 'live write (no restore)'
|
|
}
|
|
return renderedFrame === null ? 'no marker' : `unexpected frame ${renderedFrame}`
|
|
}
|
|
|
|
export async function writeToPaneTerminal(page: Page, tabId: string, data: string): Promise<void> {
|
|
await page.evaluate(
|
|
({ tabId, data }) => {
|
|
const manager = window.__paneManagers?.get(tabId)
|
|
const pane = manager?.getActivePane?.() ?? manager?.getPanes?.()[0]
|
|
if (!pane) {
|
|
throw new Error(`No terminal pane for tab ${tabId}`)
|
|
}
|
|
return new Promise<void>((resolve) => pane.terminal.write(data, resolve))
|
|
},
|
|
{ tabId, data }
|
|
)
|
|
}
|