From bae4ff3c6aa82e09723e2a87faa7ab9810764895 Mon Sep 17 00:00:00 2001 From: ekklesia Date: Mon, 12 Oct 2026 22:02:35 -0500 Subject: [PATCH] test(deploy): re-pair the kiosk after the revoke scenario The revoke scenario left the kiosk revoked, so any display check after it - the post-recreation restart check in particular - failed by construction. That is why Signage could never run it. Finish the scenario the way the roadmap states the requirement: a revoked screen shows a fresh code, is paired again, resumes without a reload, and for Signage keeps its existing roster entry rather than appearing as a new screen. Co-Authored-By: Claude Opus 5.5 --- scripts/lib/deploy-smoke-display.mjs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/scripts/lib/deploy-smoke-display.mjs b/scripts/lib/deploy-smoke-display.mjs index d155549..5a8f7fc 100644 --- a/scripts/lib/deploy-smoke-display.mjs +++ b/scripts/lib/deploy-smoke-display.mjs @@ -14,7 +14,7 @@ // stream-failure the first realtime connection is refused: is realtime re-established? // caching-probe can a display on the API origin store storage-origin images in Cache Storage? // stream-recycle one page past the five-minute realtime recycle, with a timestamped timeline -// revoke revoke the paired kiosk while its display is open +// revoke revoke the paired kiosk while its display is open, then pair it again // // Every DevTools command and every page-side request has its own deadline, and a step has an overall // budget. A call that never answers fails the step with a line naming that exact call, because a call @@ -976,6 +976,32 @@ async function run() { result.stopped, `a revoked display returns to the pairing screen without a reload (within ${watchMs / 1000}s)`, ); + // Revocation is recoverable: the same screen pairs again and resumes, keeping its place in the + // module's roster. It also leaves the kiosk paired for the steps that run after this one. + const rosterBefore = moduleId === "signage" ? (await signageViewers(owner.page)).length : 0; + if (await page.waitFor(find("display-pairing-code"), "a fresh pairing code after revocation")) { + const code = ( + await page.evaluate(`${find("display-pairing-code")}.textContent`, "reading the code") + ).replace(/\D/gu, ""); + const approved = await owner.page.api("POST", "/api/v1/device-pairing/approvals", { + code, + deviceName: "Repro kiosk", + }); + check(approved.status === 200, "the owner approves the revoked screen's new code"); + check( + await waitLive(page, "the re-paired display to go live"), + "a revoked screen is paired again and resumes without a reload", + ); + if (moduleId === "signage") { + const rosterAfter = (await signageViewers(owner.page)).length; + check( + rosterAfter === rosterBefore, + `re-pairing keeps the screen's existing roster entry (${rosterBefore} before, ${rosterAfter} after)`, + ); + } + } else { + check(false, "a revoked screen shows a fresh pairing code"); + } await page.close(); kiosk.close(); await finishOwner(owner);