- 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
111 lines
3.4 KiB
Go
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")
|
|
}
|
|
}
|