assessment-model/scripts/start_viewer.sh
Jun-te Kim b914aca3ee chore(devcontainer): add Playwright with chromium and a headed noVNC viewer
Mirrors the Model devcontainer's Playwright setup for this Next.js repo, so
agents and humans can drive the running app in a browser.

The image bakes in chromium's apt libraries (as root) and the browser binary
(as vscode, so it lands in that user's cache), meaning a fresh container is
ready to run with no first-use download. The @playwright/test version and the
Dockerfile's PLAYWRIGHT_VERSION are pinned to the same number because Playwright
ties browser builds to a library version.

Also ports Model's headed viewer stack (Xvfb -> fluxbox -> x11vnc -> noVNC on
:6080) as scripts/start_viewer.sh, for watching a headed run.

Cypress is untouched; Playwright specs live in e2e/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 17:15:38 +00:00

91 lines
3 KiB
Bash
Executable file

#!/usr/bin/env bash
# Stand up a *viewable* desktop inside the dev container so you can watch and
# click a headed Playwright browser. Pipeline:
#
# Xvfb (:99 virtual screen) -> fluxbox (window manager)
# -> x11vnc (exposes :99 over VNC on 5900)
# -> websockify/noVNC (serves VNC in a browser tab on 6080)
#
# Then run Playwright headed with DISPLAY=:99 and the browser appears on that
# desktop:
#
# bash scripts/start_viewer.sh # start it
# DISPLAY=:99 npx playwright test --headed # watch it drive
# bash scripts/start_viewer.sh stop # tear it down
#
# Headless runs (the default) need none of this. Idempotent: re-running won't
# stack duplicate servers.
set -euo pipefail
DISPLAY_NUM=":99"
SCREEN="1600x1000x24"
VNC_PORT=5900
WEB_PORT=6080
RUN_DIR="/tmp/pw-viewer"
mkdir -p "$RUN_DIR"
_pids() { pgrep -f "$1" 2>/dev/null || true; }
stop() {
echo "Stopping viewer..."
for pat in "websockify.*$WEB_PORT" "x11vnc.*$DISPLAY_NUM" "fluxbox" "Xvfb $DISPLAY_NUM"; do
for pid in $(_pids "$pat"); do kill "$pid" 2>/dev/null || true; done
done
rm -f "/tmp/.X${DISPLAY_NUM#:}-lock" 2>/dev/null || true
echo "Stopped."
}
start() {
# Xvfb — the virtual screen everything draws into.
if [ -z "$(_pids "Xvfb $DISPLAY_NUM")" ]; then
Xvfb "$DISPLAY_NUM" -screen 0 "$SCREEN" -ac >"$RUN_DIR/xvfb.log" 2>&1 &
sleep 1
echo "Xvfb up on $DISPLAY_NUM ($SCREEN)"
else
echo "Xvfb already running on $DISPLAY_NUM"
fi
# fluxbox — a window manager, so the browser window is movable/resizable.
if [ -z "$(_pids "fluxbox")" ]; then
DISPLAY="$DISPLAY_NUM" fluxbox >"$RUN_DIR/fluxbox.log" 2>&1 &
sleep 1
echo "fluxbox window manager up"
fi
# x11vnc — exposes the screen over VNC. -forever keeps it alive across client
# reconnects; -nopw is fine because the port is only reachable through the
# container's forwarded port, not the public internet.
if [ -z "$(_pids "x11vnc.*$DISPLAY_NUM")" ]; then
x11vnc -display "$DISPLAY_NUM" -rfbport "$VNC_PORT" -forever -shared \
-nopw -quiet -bg -o "$RUN_DIR/x11vnc.log"
echo "x11vnc up on VNC port $VNC_PORT"
else
echo "x11vnc already running"
fi
# noVNC/websockify — serves the VNC stream as a web page on WEB_PORT.
if [ -z "$(_pids "websockify.*$WEB_PORT")" ]; then
websockify --web=/usr/share/novnc "$WEB_PORT" "localhost:$VNC_PORT" \
>"$RUN_DIR/websockify.log" 2>&1 &
sleep 1
echo "noVNC up on web port $WEB_PORT"
fi
cat <<EOF
Desktop ready.
1. Open the forwarded port $WEB_PORT in your browser:
http://localhost:$WEB_PORT/vnc.html?autoconnect=1&resize=remote
(In VS Code: PORTS tab -> open $WEB_PORT in browser.)
2. Run Playwright headed, pointing at this display:
DISPLAY=$DISPLAY_NUM npx playwright test --headed
The browser window appears on the desktop from step 1.
EOF
}
case "${1:-start}" in
start) start ;;
stop) stop ;;
restart) stop; start ;;
*) echo "usage: $0 [start|stop|restart]"; exit 2 ;;
esac