package web import ( "io/fs" "net/http" "net/http/httptest" "os" "strings" "testing" ) // TestEmbedCompleteness guards against a new template or static file being // added to disk but missing from the embedded FS (e.g. a new directory that // the //go:embed glob does not match). func TestEmbedCompleteness(t *testing.T) { cases := []struct { name string diskDir string embedFS fs.FS embedRoot string }{ {"templates", "templates", templateFS, "templates"}, {"static", "static", staticFS, "static"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { diskFS := os.DirFS(tc.diskDir) _ = fs.WalkDir(diskFS, ".", func(path string, d fs.DirEntry, err error) error { if err != nil || d.IsDir() { return err } embPath := tc.embedRoot + "/" + path if _, statErr := fs.Stat(tc.embedFS, embPath); statErr != nil { t.Errorf("file %q exists on disk but is missing from embed.FS (%v)", embPath, statErr) } return nil }) }) } } // TestStaticAssetsServed verifies that /static/* is served from the embedded // FS through the same mux wiring used in server.go, so a standalone binary // with no adjacent static/ directory still delivers assets. func TestStaticAssetsServed(t *testing.T) { subFS, err := fs.Sub(staticFS, "static") if err != nil { t.Fatalf("fs.Sub static: %v", err) } mux := http.NewServeMux() mux.Handle("/static/", http.StripPrefix("/static/", http.FileServerFS(subFS))) cases := []struct { path string wantCT string wantSnippet string }{ {"/static/css/app.css", "text/css", "body {"}, {"/static/js/member-detail.js", "javascript", "Member-detail modal"}, {"/static/js/filters.js", "javascript", ""}, {"/static/js/payment-qr.js", "javascript", ""}, } for _, tc := range cases { t.Run(tc.path, func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, tc.path, nil) w := httptest.NewRecorder() mux.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("GET %s: status %d, want 200", tc.path, w.Code) } ct := w.Header().Get("Content-Type") if !strings.Contains(ct, tc.wantCT) { t.Errorf("GET %s: Content-Type %q, want it to contain %q", tc.path, ct, tc.wantCT) } if tc.wantSnippet != "" && !strings.Contains(w.Body.String(), tc.wantSnippet) { t.Errorf("GET %s: body missing expected snippet %q", tc.path, tc.wantSnippet) } }) } // Sanity: unknown path → 404 (file server doesn't fall through silently) t.Run("missing-file", func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/static/css/nonexistent.css", nil) w := httptest.NewRecorder() mux.ServeHTTP(w, req) if w.Code != http.StatusNotFound { t.Errorf("unknown static path: status %d, want 404", w.Code) } }) }