Files
cgalo5758 8e3c68c6be Make UI surfaces honestly reflect system state
- Add deployment-name branding to titles, mastheads, and OG tags
- Share one grant delivery-state query with lineage across grants
  surfaces
- Show pool status/usage, org owners, and config readiness
- Make billing views projection-aware with recency and sync vocabulary
- Guard FedWiki creation without domains and render route-aware 404s
2026-08-23 01:45:52 -05:00

111 lines
3.4 KiB
Go

package server
import (
"html/template"
"io/fs"
"log/slog"
"net/http/httptest"
"strings"
"testing"
"git.coopcloud.tech/wiki-cafe/member-console/internal/config"
"git.coopcloud.tech/wiki-cafe/member-console/internal/embeds"
)
func errorPageTemplates(t *testing.T) *SafeTemplates {
t.Helper()
sub, err := fs.Sub(embeds.Templates, "templates")
if err != nil {
t.Fatalf("sub templates FS: %v", err)
}
tmpl, err := template.New("root").Funcs(template.FuncMap{
"deploymentName": config.DeploymentName,
}).ParseFS(sub, "error.html")
if err != nil {
t.Fatalf("parse error.html: %v", err)
}
return NewSafeTemplates(tmpl, slog.Default())
}
func TestRenderErrorPageNavigation404(t *testing.T) {
st := errorPageTemplates(t)
rec := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/no-such-page", nil)
st.RenderErrorPage(rec, req, 404, "The page you requested does not exist.")
if rec.Code != 404 {
t.Fatalf("status = %d, want 404", rec.Code)
}
body := rec.Body.String()
for _, want := range []string{"404", "Not Found", "The page you requested does not exist.", "navbar-brand"} {
if !strings.Contains(body, want) {
t.Errorf("styled 404 body missing %q", want)
}
}
if ct := rec.Header().Get("Content-Type"); !strings.HasPrefix(ct, "text/html") {
t.Errorf("Content-Type = %q, want text/html", ct)
}
}
func TestRenderErrorPagePanicBodyNeverLeaksInternals(t *testing.T) {
st := errorPageTemplates(t)
rec := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/", nil)
// The recovery middleware passes only a fixed message; assert the page
// carries exactly that and no request-derived or internal detail slot.
st.RenderErrorPage(rec, req, 500, "An unexpected error occurred. Please try again.")
if rec.Code != 500 {
t.Fatalf("status = %d, want 500", rec.Code)
}
body := rec.Body.String()
if !strings.Contains(body, "Internal Server Error") {
t.Errorf("styled 500 body missing status text")
}
for _, banned := range []string{"goroutine", "runtime error", ".go:"} {
if strings.Contains(body, banned) {
t.Errorf("styled 500 body leaks internals: %q", banned)
}
}
}
func TestRenderErrorPageHTMXKeepsPlainText(t *testing.T) {
st := errorPageTemplates(t)
rec := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/partials/whatever", nil)
req.Header.Set("HX-Request", "true")
st.RenderErrorPage(rec, req, 404, "not found")
if rec.Code != 404 {
t.Fatalf("status = %d, want 404", rec.Code)
}
body := rec.Body.String()
if strings.Contains(body, "<html") {
t.Errorf("HTMX request got a full HTML page; want plain text for the toast contract")
}
if strings.TrimSpace(body) != "not found" {
t.Errorf("body = %q, want the plain message", body)
}
}
func TestRenderErrorPageTemplateFailureFallsBack(t *testing.T) {
// A template set without error.html: rendering fails and must fall back
// to a plain-text error with the same status, never a partial page.
tmpl := template.Must(template.New("root").Parse(`{{ define "unrelated" }}x{{ end }}`))
st := NewSafeTemplates(tmpl, slog.Default())
rec := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/broken", nil)
st.RenderErrorPage(rec, req, 500, "An unexpected error occurred. Please try again.")
if rec.Code != 500 {
t.Fatalf("status = %d, want 500", rec.Code)
}
if strings.Contains(rec.Body.String(), "<html") {
t.Errorf("fallback emitted HTML; want plain text")
}
}