test(e2e): make the cold-hydration spec verify its own captured snapshot

`adds no tab when the host workspace snapshot stalls across a relaunch` replays
the bytes it reads off the relay, but only ever waited for the snapshot FILE to
exist -- never for it to carry the tabs the test had just seeded. A capture that
missed the baseline produced a failure that reads as a product regression and is
not one: an empty `session.tabsByWorktreePath` places nothing, so it reports
nothing unplaced, so `remote-workspace-snapshot-apply.ts` marks the target
hydrated and `hydrateTabsSession` replaces the worktree's tabs with none. That is
exactly the observed `baseline=3 duringStall=3 afterHydration=0`, and it is
correct behaviour for a host snapshot that genuinely holds no tabs.

Assert the precondition where it belongs -- on the capture, before the relaunch
that consumes it -- so an empty or unparseable fixture names itself instead of
surfacing later as a tab count the product appears to have lost.

No assertion is weakened: `afterHydration` still has to equal the baseline, and
no retry, sleep, or timeout was added.
This commit is contained in:
Brennan Benson
2026-08-28 07:46:31 -07:00
parent 94e7586665
commit 3d0282acda
@@ -101,6 +101,28 @@ function blockRemoteWorkspaceGet(target: DockerSshRelayTarget, snapshotPath: str
return saved
}
/**
* Tab ids the relay actually persisted, or null when the bytes are not parseable JSON.
*
* The spec replays this capture verbatim, so bytes that carry no tab make every downstream count
* meaningless: an empty session places nothing, therefore reports nothing unplaced, therefore
* hydrates cleanly and replaces the worktree's tabs with none. That is indistinguishable from the
* regression this test exists to catch, so the capture has to be checked before it is trusted.
*/
function capturedSnapshotTabIds(saved: string): string[] | null {
try {
const parsed = JSON.parse(saved) as {
session?: { tabsByWorktreePath?: Record<string, { id?: unknown }[]> }
}
return Object.values(parsed.session?.tabsByWorktreePath ?? {})
.flat()
.map((tab) => tab?.id)
.filter((id): id is string => typeof id === 'string')
} catch {
return null
}
}
function unblockRemoteWorkspaceGet(
target: DockerSshRelayTarget,
snapshotPath: string,
@@ -174,6 +196,18 @@ test.describe('SSH cold hydration gap tab seeding', () => {
app = null
const saved = blockRemoteWorkspaceGet(target, snapshotPath)
// Precondition, not an expectation about the product: everything below reads the bytes this
// capture holds, so a capture that never recorded the baseline has to fail here and name
// itself rather than surface later as a tab count the product appears to have lost.
const capturedTabIds = capturedSnapshotTabIds(saved)
expect(
capturedTabIds,
`the captured host snapshot ${snapshotPath} is not parseable JSON, so replaying it proves nothing: ${JSON.stringify(saved.slice(0, 200))}`
).not.toBeNull()
expect(
remote.tabIds.filter((id) => !(capturedTabIds ?? []).includes(id)),
`the captured host snapshot ${snapshotPath} holds ${capturedTabIds?.length ?? 0} tab(s) and is missing part of the ${BASELINE_TAB_COUNT}-tab baseline this test seeded, so the bytes it replays are not the workspace the assertions below describe`
).toEqual([])
const relaunch = await restart.launch()
app = relaunch.app
const page = relaunch.page