From b5577b4babe6f1e90466ad4dbbcd0b4ebcf6a90f Mon Sep 17 00:00:00 2001 From: Adnaan Badr Date: Sat, 23 May 2026 11:58:37 +0000 Subject: [PATCH] fix(examples/cmd): honor LVT_DEV_MODE env var (chromedp test green) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cross-repo cross-repo-test.yml's new test-docs-examples job (and local `go test -run` invocations under e2etest.StartTestServer) shells out to `go run ./cmd` without passing flags. The cmd/main.go entry points only enabled dev mode via the `--dev` flag, so the spawned server got the production origin allowlist — which rejects Chrome's `http://host.docker.internal:/` WebSocket upgrades: WARN WebSocket origin rejected origin=http://host.docker.internal:37823 ERROR WebSocket upgrade failed component=live_handler error="websocket: request origin not allowed by Upgrader.CheckOrigin" Result: TestLogin_E2E/ServerPushedWelcome, all patterns realtime tests, TestPE_TierA_BrowserE2E, TestSharedNotepad_E2E, TestTodosE2E all failed in the cross-repo job (~30+ test FAILures total). Fix: honor LVT_DEV_MODE=true in addition to the --dev flag. e2etest. StartTestServer already sets `LVT_DEV_MODE=true` in the subprocess environment (see lvt/testing/chrome.go), so the production allowlist branch is correctly bypassed when the test framework invokes cmd/main. Applied to all 6 in-tree examples (counter, todos, patterns, progressive-enhancement, login, shared-notepad). This bug existed in PR #35 from the start — I missed it locally because `go test -short ./examples/...` skips chromedp browser tests. The cross-repo CI ran the full suite (no -short) and surfaced it. Verified fix locally with `go test -run TestLogin_E2E$ ./examples/login/`: TestLogin_E2E/ServerPushedWelcome now PASSES. Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/counter/cmd/main.go | 5 ++++- examples/login/cmd/main.go | 5 ++++- examples/patterns/cmd/main.go | 5 ++++- examples/progressive-enhancement/cmd/main.go | 5 ++++- examples/shared-notepad/cmd/main.go | 5 ++++- examples/todos/cmd/main.go | 5 ++++- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/examples/counter/cmd/main.go b/examples/counter/cmd/main.go index 5d0aafa..4866b15 100644 --- a/examples/counter/cmd/main.go +++ b/examples/counter/cmd/main.go @@ -8,6 +8,9 @@ // Flags / environment: // // PORT listen port (default 8080) +// LVT_DEV_MODE=true alias for --dev (set by e2etest.StartTestServer so the +// subprocess inherits dev-mode without needing to pass +// flags through the test harness) // --dev relax origin checks for localhost development (so the // WebSocket upgrader accepts requests from arbitrary // localhost ports); the production allowlist applies when @@ -35,7 +38,7 @@ func main() { } var opts []livetemplate.Option - if *dev { + if *dev || os.Getenv("LVT_DEV_MODE") == "true" { opts = append(opts, livetemplate.WithDevMode(true), livetemplate.WithPermissiveOriginCheck(), diff --git a/examples/login/cmd/main.go b/examples/login/cmd/main.go index e694e00..40efa22 100644 --- a/examples/login/cmd/main.go +++ b/examples/login/cmd/main.go @@ -12,6 +12,9 @@ // Flags / environment: // // PORT listen port (default 8080) +// LVT_DEV_MODE=true alias for --dev (set by e2etest.StartTestServer so the +// subprocess inherits dev-mode without needing to pass +// flags through the test harness) // MOUNT_PATH mount path (default "/") // --dev relax origin checks for localhost development and enable // livetemplate's DevMode. Production allowlist applies when @@ -48,7 +51,7 @@ func main() { } var opts []livetemplate.Option - if *dev { + if *dev || os.Getenv("LVT_DEV_MODE") == "true" { opts = append(opts, livetemplate.WithDevMode(true), livetemplate.WithPermissiveOriginCheck(), diff --git a/examples/patterns/cmd/main.go b/examples/patterns/cmd/main.go index 755a63a..2a44f59 100644 --- a/examples/patterns/cmd/main.go +++ b/examples/patterns/cmd/main.go @@ -17,6 +17,9 @@ // Flags / environment: // // PORT listen port (default 8080) +// LVT_DEV_MODE=true alias for --dev (set by e2etest.StartTestServer so the +// subprocess inherits dev-mode without needing to pass +// flags through the test harness) // --dev relax origin checks for localhost development and enable // livetemplate's DevMode (verbose logging tests capture). // The production allowlist applies when absent. @@ -43,7 +46,7 @@ func main() { } var opts []livetemplate.Option - if *dev { + if *dev || os.Getenv("LVT_DEV_MODE") == "true" { opts = append(opts, livetemplate.WithDevMode(true), livetemplate.WithPermissiveOriginCheck(), diff --git a/examples/progressive-enhancement/cmd/main.go b/examples/progressive-enhancement/cmd/main.go index 8177c8b..2d7660d 100644 --- a/examples/progressive-enhancement/cmd/main.go +++ b/examples/progressive-enhancement/cmd/main.go @@ -21,6 +21,9 @@ // Flags / environment: // // PORT listen port (default 8080) +// LVT_DEV_MODE=true alias for --dev (set by e2etest.StartTestServer so the +// subprocess inherits dev-mode without needing to pass +// flags through the test harness) // --dev relax origin checks for localhost development and enable // livetemplate's DevMode (verbose logging tests capture). // The production allowlist applies when absent. @@ -47,7 +50,7 @@ func main() { } var baseOpts []livetemplate.Option - if *dev { + if *dev || os.Getenv("LVT_DEV_MODE") == "true" { baseOpts = append(baseOpts, livetemplate.WithDevMode(true), livetemplate.WithPermissiveOriginCheck(), diff --git a/examples/shared-notepad/cmd/main.go b/examples/shared-notepad/cmd/main.go index a88de37..bfdf1ed 100644 --- a/examples/shared-notepad/cmd/main.go +++ b/examples/shared-notepad/cmd/main.go @@ -10,6 +10,9 @@ // Flags / environment: // // PORT listen port (default 8080) +// LVT_DEV_MODE=true alias for --dev (set by e2etest.StartTestServer so the +// subprocess inherits dev-mode without needing to pass +// flags through the test harness) // --dev relax origin checks for localhost development and enable // livetemplate's DevMode. Production allowlist applies when // absent. @@ -38,7 +41,7 @@ func main() { opts := []livetemplate.Option{ livetemplate.WithAuthenticator(notepad.NewDemoBasicAuth()), } - if *dev { + if *dev || os.Getenv("LVT_DEV_MODE") == "true" { opts = append(opts, livetemplate.WithDevMode(true), livetemplate.WithPermissiveOriginCheck(), diff --git a/examples/todos/cmd/main.go b/examples/todos/cmd/main.go index 5ea5786..187b24f 100644 --- a/examples/todos/cmd/main.go +++ b/examples/todos/cmd/main.go @@ -12,6 +12,9 @@ // Flags / environment: // // PORT listen port (default 8080) +// LVT_DEV_MODE=true alias for --dev (set by e2etest.StartTestServer so the +// subprocess inherits dev-mode without needing to pass +// flags through the test harness) // --dev relax origin checks for localhost development and enable // livetemplate's DevMode (verbose logging the e2e framework // captures). The production allowlist applies when absent. @@ -38,7 +41,7 @@ func main() { } var opts []livetemplate.Option - if *dev { + if *dev || os.Getenv("LVT_DEV_MODE") == "true" { opts = append(opts, livetemplate.WithDevMode(true), livetemplate.WithPermissiveOriginCheck(),