fix(web): browser smoke reads the mount marker from the console stream

The editor now holds a live SSE stream, and an in-flight network
request pauses headless Chrome's virtual clock — so --dump-dom never
flushes, the DOM grep never matches, and the smoke either timed out
(CI, 45s) or hung on a TERM-immune Chrome behind a bare wait (observed
12 hours locally). The mount marker is now mirrored to the console,
which reaches the stderr log incrementally, and the poll loop treats
that line as readiness, synthesizing the DOM marker the assertions
expect; the timeout path uses SIGKILL. Verified end to end locally:
both the pure CanvasKit page and the daemon host page mount.
This commit is contained in:
Kayshen-X 2026-08-09 11:27:59 +08:00
parent f58c5bf9b3
commit c4a2d5e0d7
3 changed files with 24 additions and 1 deletions

View file

@ -48,6 +48,11 @@
const errorPane = document.getElementById('op-error');
const markSmoke = (state) => {
document.documentElement.setAttribute('data-op-smoke', state);
// Mirrored to the console for the headless browser smoke: the
// editor keeps a live SSE stream open, which freezes headless
// Chrome's virtual clock, so --dump-dom never flushes — stderr
// console logging is the only channel that arrives incrementally.
console.log(`op-smoke:${state}`);
};
const showError = (msg) => {
markSmoke('error');

View file

@ -59,6 +59,10 @@
const status = document.getElementById('status');
const markSmoke = (state) => {
document.documentElement.setAttribute('data-op-smoke', state);
// Console mirror for the headless smoke; see the host page note —
// stderr logging arrives incrementally while --dump-dom waits for
// a quiescence the live editor never reaches.
console.log(`op-smoke:${state}`);
};
const log = (cls, msg) => {
const block = document.createElement('pre');

View file

@ -101,10 +101,22 @@ chrome_dump() {
--enable-unsafe-swiftshader \
--window-size=1280,800 \
--user-data-dir="$profile" \
--enable-logging=stderr \
--virtual-time-budget="${OPENPENCIL_BROWSER_SMOKE_VIRTUAL_TIME_MS:-15000}" \
--dump-dom "$url" >"$out" 2>"$out.stderr" &
local chrome_pid=$!
for _ in $(seq 1 "$timeout"); do
# The editor holds a live SSE stream, which pauses headless Chrome's
# virtual clock and keeps --dump-dom from ever flushing. The console
# mirror on stderr arrives incrementally, so it is the readiness
# signal; a successful mount synthesizes the DOM line the assertions
# expect.
if grep -Fq 'op-smoke:ok' "$out.stderr" 2>/dev/null; then
printf '<html data-op-smoke="ok"><!-- synthesized from console marker --></html>\n' >"$out"
kill -9 "$chrome_pid" >/dev/null 2>&1 || true
wait "$chrome_pid" >/dev/null 2>&1 || true
return 0
fi
if grep -Fq 'data-op-smoke="ok"' "$out" 2>/dev/null; then
kill "$chrome_pid" >/dev/null 2>&1 || true
wait "$chrome_pid" >/dev/null 2>&1 || true
@ -116,7 +128,9 @@ chrome_dump() {
fi
sleep 1
done
kill "$chrome_pid" >/dev/null 2>&1 || true
# SIGKILL, not SIGTERM: a headless Chrome wedged mid-GPU-stall has been
# observed ignoring TERM, which turns the wait below into a permanent hang.
kill -9 "$chrome_pid" >/dev/null 2>&1 || true
wait "$chrome_pid" >/dev/null 2>&1 || true
printf 'headless Chrome timed out for %s after %ss\n' "$url" "$timeout" >&2
return 124