From 04c16540864c52d6cfba24cb0f1a6489abed6db8 Mon Sep 17 00:00:00 2001 From: Rogee Date: Fri, 21 Aug 2026 16:02:54 +0800 Subject: [PATCH] HH-427: add runtime config browser smoke (#81) * HH-427: add runtime config browser smoke * HH-427: enforce browser smoke in CI --------- Co-authored-by: Rogee --- .github/workflows/ci.yml | 19 ++++++++++++++++++- backend/internal/router/router_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49297f42..d7d3a698 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,11 +19,28 @@ jobs: with: go-version-file: backend/go.mod cache-dependency-path: backend/go.sum + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - uses: browser-actions/setup-chrome@v2 + id: chrome + - name: Install browser harness + run: python -m pip install browser-harness==0.1.9 - name: Test working-directory: backend env: GOCHAT_TEST_DB: sqlite - run: go test ./internal/... ./pkg/... ./cmd/... + GOCHAT_BROWSER_SMOKE: "1" + BU_CDP_URL: http://127.0.0.1:9222 + run: | + "${{ steps.chrome.outputs.chrome-path }}" --headless=new --no-sandbox --disable-dev-shm-usage --remote-debugging-port=9222 --user-data-dir="$RUNNER_TEMP/chrome" about:blank & + chrome_pid=$! + trap 'kill "$chrome_pid" 2>/dev/null || true; browser-harness --reload > /dev/null 2>&1 || true' EXIT + curl --fail --silent --show-error --retry 10 --retry-connrefused --retry-delay 1 http://127.0.0.1:9222/json/version > /dev/null + browser-harness <<'PY' + print(page_info()) + PY + go test ./internal/... ./pkg/... ./cmd/... - name: Build working-directory: backend run: go build ./... diff --git a/backend/internal/router/router_test.go b/backend/internal/router/router_test.go index 4f260db5..73776203 100644 --- a/backend/internal/router/router_test.go +++ b/backend/internal/router/router_test.go @@ -8,7 +8,9 @@ import ( "net/http/httptest" "net/url" "os" + "os/exec" "path/filepath" + "strconv" "strings" "testing" "time" @@ -887,6 +889,9 @@ func TestDashboardIndexServesChatwootShell(t *testing.T) { if err := os.WriteFile(filepath.Join(dist, "assets", "app.css"), []byte("body{}"), 0o644); err != nil { t.Fatal(err) } + if err := os.WriteFile(filepath.Join(dist, "assets", "app.js"), []byte(`document.documentElement.dataset.runtimeHost = window.__GOCHAT_CONFIG__?.hostURL || "missing";`), 0o644); err != nil { + t.Fatal(err) + } t.Setenv("GOCHAT_FRONTEND_DIST", dist) t.Setenv("INSTALLATION_NAME", "GoChat Test") t.Setenv("FRONTEND_URL", "https://app.example.test/") @@ -926,6 +931,26 @@ func TestDashboardIndexServesChatwootShell(t *testing.T) { t.Fatalf("runtime config must be external JavaScript, got %s", runtimeConfig.Body.String()) } + if os.Getenv("GOCHAT_BROWSER_SMOKE") == "1" { + browserHarness, err := exec.LookPath("browser-harness") + if err != nil { + t.Fatal("browser-harness is required when GOCHAT_BROWSER_SMOKE=1") + } + server := httptest.NewServer(engine) + defer server.Close() + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + cmd := exec.CommandContext(ctx, browserHarness) + cmd.Stdin = strings.NewReader("new_tab(" + strconv.Quote(server.URL+"/app") + ")\nwait_for_load()\nprint(js(\"document.documentElement.dataset.runtimeHost\"))\nclose_tab()\n") + dom, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("load dashboard in browser: %v: %s", err, dom) + } + if !strings.Contains(string(dom), "https://app.example.test") { + t.Fatalf("runtime config was not available before the app module: %s", dom) + } + } + asset := performGet(engine, "/assets/app.css") if asset.Code != http.StatusOK || asset.Body.String() != "body{}" { t.Fatalf("expected built asset, got %d %q", asset.Code, asset.Body.String())