package webui import ( "io" "net/http" "net/http/httptest" "strings" "testing" ) // get drives the handler with a GET for the given path and returns the response. func get(t *testing.T, h http.Handler, target string) *http.Response { t.Helper() rec := httptest.NewRecorder() h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, target, nil)) return rec.Result() } func body(t *testing.T, resp *http.Response) string { t.Helper() b, _ := io.ReadAll(resp.Body) return string(b) } // TestLandingMountServesLandingAndFallsBack: "/" serves the landing shell (no-cache) and // any unknown path falls back to it. func TestLandingMountServesLandingAndFallsBack(t *testing.T) { h := Handler("", "landing.html") resp := get(t, h, "/") if resp.StatusCode != http.StatusOK || !strings.Contains(body(t, resp), "scrabble-landing") { t.Fatalf("GET / did not serve the landing shell (status %d)", resp.StatusCode) } if cc := get(t, h, "/").Header.Get("Cache-Control"); cc != "no-cache" { t.Errorf("landing Cache-Control = %q, want no-cache", cc) } if resp := get(t, h, "/whatever"); resp.StatusCode != http.StatusOK { t.Fatalf("GET /whatever status = %d, want 200 (fallback)", resp.StatusCode) } } // TestAppMountServesShellStripsPrefixAndCachesAssets: "/app/" and "/telegram/" serve the app // shell (index.html), strip their prefix, fall back for deep links, and mark hash-named // assets immutable. func TestAppMountServesShellStripsPrefixAndCachesAssets(t *testing.T) { for _, prefix := range []string{"/app/", "/telegram/"} { h := Handler(prefix, "index.html") if resp := get(t, h, prefix); resp.StatusCode != http.StatusOK || !strings.Contains(body(t, resp), "scrabble-app-shell") { t.Fatalf("GET %s did not serve the app shell (status %d)", prefix, resp.StatusCode) } // A deep link falls back to the shell so the hash router can take over. if resp := get(t, h, prefix+"game/abc"); resp.StatusCode != http.StatusOK || !strings.Contains(body(t, resp), "scrabble-app-shell") { t.Fatalf("GET %sgame/abc did not fall back to the app shell (status %d)", prefix, resp.StatusCode) } // A hash-named asset is served directly and marked immutable. resp := get(t, h, prefix+"assets/.gitkeep") if resp.StatusCode != http.StatusOK { t.Fatalf("GET %sassets/.gitkeep status = %d, want 200", prefix, resp.StatusCode) } if cc := resp.Header.Get("Cache-Control"); !strings.Contains(cc, "immutable") { t.Errorf("asset Cache-Control = %q, want immutable", cc) } } }