test harness: default to localhost, not the prod deploy

Testing is a dev process — point the harness at a local build you can
edit, rebuild, and screenshot in seconds. Pointing it at the prod
deploy by default was wrong: the deploy lags local code by a deploy
cycle, so visual changes you make wouldn't appear there until rebuilt
on the Linode.

test/launch.py:
  - DEFAULT_URL is now http://localhost:8080/.
  - Friendly pre-flight check: if --url is localhost and nothing is
    listening on the port, print a clear "start ./run.sh --no-tunnel"
    message and exit 1. Avoids the silent ERR_CONNECTION_REFUSED
    failure mode.
  - --url https://voxel.mxvs.art/ still works for one-off remote
    sanity checks.

test/README.md:
  - Lead with the dev-loop instruction: terminal 1 runs the local
    server, terminal 2 runs launch.py, terminal 3 drives scenarios.
  - Note the "pointing at deploy" path as a rarely-used escape hatch.
This commit is contained in:
Maximus Gorog 2026-05-24 11:29:55 -06:00
parent f1e007dd63
commit e7a232ba97
2 changed files with 96 additions and 6 deletions

View file

@ -1,5 +1,9 @@
# Test harness — declarative visual + behavioral scenarios
**Dev-only. Runs entirely on your machine against a local build.**
Nothing here ever touches the production deploy — that's a release
target, not a test surface.
Mirrors the cucucaracha (lacucarachanews) toolkit pattern: `launch.py`
opens a Chromium with persistent profile + CDP on port 9222; small
attach-only tools drive the *same* session via Playwright.
@ -9,22 +13,71 @@ scenarios can declaratively set scene state and read back telemetry,
not just click DOM elements. See `src/bridges.rs` `wasm_api` for the
exports.
## Setup (once)
## Setup (once per machine)
```sh
# In the repo root, install the Python harness deps.
cd test
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
playwright install chromium
```
## Open the game in a controllable browser
## The dev loop
Two terminals. Both run on **your machine**, never on the production VPS.
**Terminal 1 — local game server:**
```sh
python3 launch.py # opens https://voxel.mxvs.art
python3 launch.py --url http://localhost:8080 # local dev server
cd /home/maximus/.env/web/voxel-game
./run.sh --no-tunnel
# Builds wasm + server, serves on http://localhost:8080
# (Or `docker compose up` if you prefer the same container we deploy.)
```
Leave that running. Edit Rust / WGSL / JS → re-run `./run.sh
--no-tunnel` → refresh the browser tab.
**Terminal 2 — Playwright session against the local server:**
```sh
cd /home/maximus/.env/web/voxel-game/test
. .venv/bin/activate
python3 launch.py # default: http://localhost:8080/
```
That opens a Chromium window pointed at your local game with CDP on
port 9222. `launch.py` exits to idle; the browser stays up so you can
attach tools to it. If nothing's listening on `:8080` you'll get a
clear error message — start the dev server first.
**Terminal 3 — drive scenarios + take screenshots:**
```sh
python3 peek.py # snapshot + telemetry
python3 run.py scenarios/lighting-times-of-day.yaml # 6 screenshots
python3 run.py scenarios/god-rays-look-at-sun.yaml
python3 run.py scenarios/voxel-construction-darkness.yaml
```
Screenshots land in `test/screenshots/`. Diff them against your
baseline (visually or with `magick compare`) to catch regressions.
## Pointing at the deployed build (rarely)
You almost never want this. The deploy lags your local code, so a bug
you fixed locally still appears there until you push + rebuild the
container. But if you want a one-off sanity check:
```sh
python3 launch.py --url https://voxel.mxvs.art/
```
The harness will happily attach; just remember you're looking at
whatever tag is currently deployed, not your in-progress work.
The browser stays open; profile lives at `./.browser_profile/`. CDP
listens on `localhost:9222` so the other tools can attach.

View file

@ -29,12 +29,23 @@ from playwright.sync_api import sync_playwright
HERE = Path(__file__).resolve().parent
USER_DATA_DIR = HERE / ".browser_profile"
DEFAULT_URL = "https://voxel.mxvs.art/"
# Default: local dev server (./run.sh --no-tunnel or docker-compose up).
# Tests run against a build *you control* on this machine, never against
# the deployed production site. Use --url https://voxel.mxvs.art/
# explicitly if you want to point at prod for a one-off sanity check.
DEFAULT_URL = "http://localhost:8080/"
CDP_PORT = 9222
def main() -> int:
ap = argparse.ArgumentParser()
ap = argparse.ArgumentParser(
description=(
"Open Chromium against the local voxel-game dev server. "
"Tests are a dev process — defaults to http://localhost:8080/. "
"Start the local server first (./run.sh --no-tunnel or docker "
"compose up)."
),
)
ap.add_argument("--url", default=DEFAULT_URL, help="game URL to open")
ap.add_argument(
"--headless",
@ -43,6 +54,32 @@ def main() -> int:
)
args = ap.parse_args()
# Friendly check: if pointed at localhost, verify something is
# actually listening. Avoids the "browser opens with ERR_CONNECTION
# _REFUSED and you spend 5 minutes debugging Playwright" failure mode.
if "localhost" in args.url or "127.0.0.1" in args.url:
import socket
from urllib.parse import urlparse
u = urlparse(args.url)
host = u.hostname or "127.0.0.1"
port = u.port or (443 if u.scheme == "https" else 80)
s = socket.socket()
s.settimeout(0.5)
try:
s.connect((host, port))
s.close()
except OSError:
print(
f"[!] nothing listening on {host}:{port}.\n"
f" Start the local dev server first, e.g.:\n"
f" ./run.sh --no-tunnel\n"
f" (from the repo root)\n"
f" Or pass --url <other> if you really want a remote target.",
file=sys.stderr,
)
return 1
USER_DATA_DIR.mkdir(exist_ok=True)
chrome_args = [