Record the dashboard, and make the page capturable

node scripts/record-dashboard.mjs drives the gateway with real requests and
screenshots the real dashboard between them with headless Chrome. Screen
recording was the obvious route and the wrong one: it would photograph whatever
else happened to be on screen and needs a permission grant. Headless captures
only the page, needs no permission, and writes frames straight to disk.

The dashboard never finished loading under a headless browser, because it holds
an SSE connection open and polls on an interval — so ?nolive=1 now renders once
and goes quiet. That also makes the page screenshot-testable in general.

Chrome does not reliably exit after --screenshot, so the recorder waits for the
PNG to appear and stop growing rather than guessing a sleep, and treats profile
cleanup as best-effort since Chrome keeps flushing after SIGKILL.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Aryan SinghandClaude Opus 5 committed 2026-08-16 23:18:22 -05:00
1 parent eeb5cad4ce
commit 6c41b6d804
5 files changed
+160 -3

No files matched your search

+8
View File
@@ -317,6 +317,7 @@ td.n{font-family:var(--mono); white-space:nowrap}
const POLL_MS = 3000;
const KEY_STORAGE = 'freeway.key';
const STATIC = new URLSearchParams(location.search).has('nolive');
let apiKey = localStorage.getItem(KEY_STORAGE) || '';
let paused = false;
let timer = null;
@@ -786,6 +787,10 @@ function setPulse(kind) {
function schedule() {
clearInterval(timer);
// ?nolive=1 renders once and then goes quiet: no polling interval, no event
// stream. A page that never stops working never finishes loading, which is
// what screenshot tools and headless browsers wait for.
if (STATIC) return;
// Polling a hidden tab burns CPU for nobody; the visibilitychange handler
// brings it straight back with a fresh fetch.
timer = setInterval(() => { if (!paused && !document.hidden) refresh(); }, POLL_MS);
@@ -802,6 +807,9 @@ let liveBackoff = 1000;
let liveConnected = false;
async function connectLive() {
// ?nolive=1 keeps the page from holding an open SSE connection. Headless
// browsers and screenshot tools otherwise wait for a stream that never ends.
if (STATIC) { setLiveState(false); return; }
if (liveAbort) liveAbort.abort();
liveAbort = new AbortController();