package web import ( "io/fs" "net/http" "net/http/httptest" "strings" "testing" "github.com/gin-gonic/gin" ) func TestSPA(t *testing.T) { gin.SetMode(gin.TestMode) r := gin.New() Register(r) get := func(path string) *httptest.ResponseRecorder { w := httptest.NewRecorder() r.ServeHTTP(w, httptest.NewRequest(http.MethodGet, path, nil)) return w } for _, p := range []string{"/admin/ui/", "/admin/ui/addons/123", "/admin/ui/index.html"} { w := get(p) if w.Code != http.StatusOK || !strings.Contains(w.Header().Get("Content-Type"), "text/html") { t.Errorf("%s: got %d %s", p, w.Code, w.Header().Get("Content-Type")) } if w.Header().Get("Content-Security-Policy") == "" { t.Errorf("%s: missing CSP", p) } } if w := get("/admin/ui/assets/missing.js"); w.Code != http.StatusNotFound { t.Errorf("missing asset: got %d, want 404", w.Code) } if w := get("/admin"); w.Code != http.StatusFound || w.Header().Get("Location") != "/admin/ui/" { t.Errorf("/admin: got %d -> %s", w.Code, w.Header().Get("Location")) } // when the UI is built, hashed assets are served with long caching sub, _ := fs.Sub(dist, "dist") entries, _ := fs.ReadDir(sub, "assets") for _, e := range entries { w := get("/admin/ui/assets/" + e.Name()) if w.Code != http.StatusOK || !strings.Contains(w.Header().Get("Cache-Control"), "immutable") { t.Errorf("asset %s: got %d cache %q", e.Name(), w.Code, w.Header().Get("Cache-Control")) } break } }