From 724690567d709af5406b22edb911ff7c7dee923d Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 15 Aug 2026 02:34:40 -0700 Subject: [PATCH] test(ssh): cover a full-screen frame across a reconnect, not just scrollback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The case a byte tail cannot serve, and the one that reached a user twice. A tail can begin mid-escape and misses the alt-screen enter and absolute positioning that built the frame, so replaying it paints fragments — which is what a reconnected Claude Code showed. Uses top: present on any Linux image, and it repaints on a fixed interval, so a whole header after the reconnect is unambiguous rather than a timing artifact. Asserts the header AND the column row, because a tail that lost the frame start still shows rows. The spec now covers all three payloads one reconnect has to get right: a shell's scrollback, a full-screen app's frame, and a tab opened afterwards reaching a shell that answers. --- .../ssh-docker-reconnect-pane-restore.spec.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/e2e/ssh-docker-reconnect-pane-restore.spec.ts b/tests/e2e/ssh-docker-reconnect-pane-restore.spec.ts index c05877c7248..2b8bf71aab5 100644 --- a/tests/e2e/ssh-docker-reconnect-pane-restore.spec.ts +++ b/tests/e2e/ssh-docker-reconnect-pane-restore.spec.ts @@ -68,7 +68,7 @@ async function openTerminalTab(page: Page): Promise { test.describe('SSH reconnect pane restore', () => { test.skip(!RUN_DOCKER_SSH, 'Set ORCA_E2E_SSH_DOCKER=1 to run the dockerized SSH relay tests') - test('restores pane content on reconnect and still opens a usable new tab', async ({ + test('restores shell scrollback, a full-screen frame, and a usable new tab across a reconnect', async ({ orcaPage }, testInfo) => { test.slow() @@ -113,6 +113,23 @@ test.describe('SSH reconnect pane restore', () => { const freshContent = await getTerminalContent(orcaPage, 8000) expect(freshContent).not.toContain(marker) + // A FULL-SCREEN app is the third case, and the one a byte tail cannot serve: a tail can begin + // mid-escape and misses the alt-screen enter and absolute positioning that built the frame, so + // replaying it paints fragments. `top` is used because it is present on any Linux image and + // repaints on a fixed interval, so a coherent frame after the reconnect is unambiguous. + await execInTerminal(orcaPage, freshPtyId, 'top -b -n 1 > /dev/null; top') + await waitForTerminalOutput(orcaPage, 'load average', 30_000, 8000) + + await reconnectDockerSshRelayTarget(orcaPage, target.targetId) + await waitForActiveTerminalManager(orcaPage, 60_000) + await waitForActivePanePtyId(orcaPage, 60_000) + + // The header only survives as a whole if a grid was repainted; a tail that lost the frame + // start shows rows without it. + await waitForTerminalOutput(orcaPage, 'load average', 60_000, 8000) + const tuiContent = await getTerminalContent(orcaPage, 8000) + expect(tuiContent).toContain('PID') + // The title is the cheap signal the reported bug showed: it only stays generic when the shell // never printed a prompt for Orca to read one from. await expect