diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 2de8843..62097db 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -24,9 +24,17 @@ bundler, no build step for assets. - MeshCore binding: `github.com/meshcore-go/meshcore-go`. Run/lint/etc. via mise: `mise run dev` (serves on the configured hosts), -`mise run lint`, `mise run seed`, `mise run reset`. Dev uses `leighthaus.dev` + -local mkcert TLS. **The dev server owns :8080 — run your own test instance on -:8090** and kill only your own PID. +`mise run lint`, `mise run seed`, `mise run reset`, `mise run e2e`. Dev uses +`leighthaus.dev` + local mkcert TLS. **The dev server owns :8080 — run your own +test instance on :8090** and kill only your own PID. + +**When a mise task exists for what you're doing, run the task — don't hand-roll +its command.** The tasks encode the correct setup (env, flags, container +lifecycle) and clean up after themselves. This matters most for `mise run e2e`: +never reimplement the headless-browser container by hand (it leaks orphaned +containers holding :9222). Filter to specific tests with `mise run e2e --run +` (see `mise run e2e --help`). Plain `go test`/`go build`/`go vet` for a +package or `-run` are fine — those aren't tasks. **MeshCore, not Meshtastic.** Don't introduce Meshtastic concepts (e.g. a `node_id`). MeshCore identifies contacts by public key. diff --git a/.config/mise/config.toml b/.config/mise/config.toml index 076d740..4dd128d 100644 --- a/.config/mise/config.toml +++ b/.config/mise/config.toml @@ -21,13 +21,23 @@ run = "go run ./cmd/meshtender --seed" [tasks.reset] run = "go run ./cmd/meshtender --reset" +# Runs the browser e2e suite against a throwaway chromedp/headless-shell container. +# Always use this rather than hand-rolling the container — the trap guarantees the +# container is torn down however the run ends (success, failure, or interrupt), so +# no orphaned containers hold port 9222. Filter to specific tests with +# `mise run e2e --run ` (see `mise run e2e --help`). [tasks.e2e] +usage = ''' +flag "-r --run " help="Only run browser tests matching this regex (go test -run), verbosely" +''' run = """ +docker rm -f mt-headless >/dev/null 2>&1 || true docker run -d --rm --name mt-headless -p 9222:9222 \ --add-host=host.docker.internal:host-gateway \ --entrypoint bash chromedp/headless-shell:latest -c \ 'socat TCP4-LISTEN:9222,fork TCP4:127.0.0.1:9223 & exec /headless-shell/headless-shell --no-sandbox --use-gl=angle --use-angle=swiftshader --remote-debugging-address=0.0.0.0 --remote-debugging-port=9223 "--host-resolver-rules=MAP *.host.docker.internal host.docker.internal"' >/dev/null -trap 'docker stop mt-headless >/dev/null' EXIT -until curl -sf http://127.0.0.1:9222/json/version >/dev/null; do sleep 0.5; done -go test -tags browser ./internal/e2e/ +trap 'docker rm -f mt-headless >/dev/null 2>&1' EXIT +# Bounded readiness wait (~20s cap) so a container that never comes up can't hang. +for _ in $(seq 1 40); do curl -sf http://127.0.0.1:9222/json/version >/dev/null 2>&1 && break; sleep 0.5; done +go test -tags browser ./internal/e2e/ -timeout 180s ${usage_run:+-run "$usage_run" -v} """