package web_test import ( "io" "io/fs" "net/http" "net/http/httptest" "strings" "testing" "sourcecraft.dev/bigbes/lethe/internal/server/web" ) // TestHandler_InjectsConfigIntoIndex asserts that GET / returns 200 HTML // containing window.__LETHE_CONFIG__ with the supplied values, exactly once. func TestHandler_InjectsConfigIntoIndex(t *testing.T) { h := web.Handler(web.Config{ Issuer: "http://stub", ClientID: "lethe", }) req := httptest.NewRequest(http.MethodGet, "/", nil) rr := httptest.NewRecorder() h.ServeHTTP(rr, req) resp := rr.Result() if resp.StatusCode != http.StatusOK { t.Fatalf("status = %d; want 200", resp.StatusCode) } body, _ := io.ReadAll(resp.Body) bodyStr := string(body) want := `window.__LETHE_CONFIG__={"Issuer":"http://stub","ClientID":"lethe"}` if !strings.Contains(bodyStr, want) { t.Errorf("body does not contain %q\nbody (first 500 chars):\n%s", want, truncate(bodyStr, 500)) } // Exactly once. count := strings.Count(bodyStr, "__LETHE_CONFIG__") if count != 1 { t.Errorf("__LETHE_CONFIG__ appears %d times; want 1", count) } } // TestHandler_AssetsBypassInjection asserts that static asset paths do not // receive the script injection. We test by checking the response body does // not contain __LETHE_CONFIG__ — robust against asset filename changes. func TestHandler_AssetsBypassInjection(t *testing.T) { // Discover an asset file from the embedded FS via the handler's fallback // behavior, or just verify that a known asset path bypasses injection. // We check absence of __LETHE_CONFIG__ in any /assets/ response. h := web.Handler(web.Config{ Issuer: "http://stub", ClientID: "lethe", }) // Find an actual asset file name to request. sub, err := web.DistFS() if err != nil { t.Fatalf("DistFS: %v", err) } var assetFile string _ = fs.WalkDir(sub, "assets", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } if !d.IsDir() && assetFile == "" { assetFile = path } return nil }) if assetFile == "" { t.Skip("no asset files found in embedded FS — skip") } req := httptest.NewRequest(http.MethodGet, "/"+assetFile, nil) rr := httptest.NewRecorder() h.ServeHTTP(rr, req) resp := rr.Result() body, _ := io.ReadAll(resp.Body) if strings.Contains(string(body), "__LETHE_CONFIG__") { t.Errorf("asset %q response contains __LETHE_CONFIG__ — should be bypass", assetFile) } } // TestHandler_SPAFallbackInjects asserts that an unknown SPA route returns // 200 HTML with the config injection (SPA fallback returns index.html). func TestHandler_SPAFallbackInjects(t *testing.T) { h := web.Handler(web.Config{ Issuer: "http://stub", ClientID: "lethe", }) req := httptest.NewRequest(http.MethodGet, "/some/spa/route", nil) rr := httptest.NewRecorder() h.ServeHTTP(rr, req) resp := rr.Result() if resp.StatusCode != http.StatusOK { t.Fatalf("status = %d; want 200", resp.StatusCode) } body, _ := io.ReadAll(resp.Body) bodyStr := string(body) if !strings.Contains(bodyStr, "__LETHE_CONFIG__") { t.Errorf("SPA fallback response does not contain __LETHE_CONFIG__\nbody:\n%s", truncate(bodyStr, 500)) } } func truncate(s string, n int) string { if len(s) <= n { return s } return s[:n] + "..." }