package server import ( "bytes" "context" "errors" "html/template" "io" "io/fs" "log/slog" "regexp" "strconv" "strings" "testing" "git.coopcloud.tech/wiki-cafe/member-console/internal/billing" "git.coopcloud.tech/wiki-cafe/member-console/internal/config" "git.coopcloud.tech/wiki-cafe/member-console/internal/embeds" "git.coopcloud.tech/wiki-cafe/member-console/internal/entitlements" "git.coopcloud.tech/wiki-cafe/member-console/internal/identity" "git.coopcloud.tech/wiki-cafe/member-console/internal/organization" "git.coopcloud.tech/wiki-cafe/member-console/internal/web" ) // Render coverage for the operator landing surface's overview regions ("At a // glance" + "System"). Template-level only: it executes operator.html against // hand-built OperatorPageData, so it needs no database and runs in every // environment. The loader that fills that data (loadOverview) is exercised // separately by the pure-function tests at the bottom of this file. // overviewTemplate parses the operator template set the same way // NewOperatorPartialsHandler does — partials first, then the shell — so this // test fails on the same parse errors production would hit. func overviewTemplate(t *testing.T) *template.Template { t.Helper() sub, err := fs.Sub(embeds.Templates, "templates") if err != nil { t.Fatalf("fs.Sub: %v", err) } partialsSub, err := fs.Sub(embeds.Templates, "templates/partials") if err != nil { t.Fatalf("fs.Sub partials: %v", err) } tmpl := template.New("operator").Funcs(template.FuncMap{ "renderBody": func(string, any) (template.HTML, error) { return "", nil }, "routeURL": web.RouteURL, "fieldErr": func(_, _, _, _ string, _, _ any) string { return "" }, "stripeEntityURL": func(string, string) string { return "" }, "deploymentName": config.DeploymentName, }) if tmpl, err = tmpl.ParseFS(partialsSub, "operator_*.html"); err != nil { t.Fatalf("ParseFS partials: %v", err) } if tmpl, err = tmpl.ParseFS(sub, "operator.html"); err != nil { t.Fatalf("ParseFS operator.html: %v", err) } return tmpl } func renderOperator(t *testing.T, data OperatorPageData) string { t.Helper() var buf bytes.Buffer if err := overviewTemplate(t).ExecuteTemplate(&buf, "operator.html", data); err != nil { t.Fatalf("ExecuteTemplate: %v", err) } return buf.String() } // landingRegion slices the rendered document down to the landing surface // itself. The navbar, sidebar, toast container and confirmation modal are // outside
(or outside #operator-body) and carry their own markup — // including an
in the modal — so assertions about this page's structure // must not see them. func landingRegion(t *testing.T, out string) string { t.Helper() const openTag = `
` start := strings.Index(out, openTag) if start < 0 { t.Fatalf("rendered output has no #operator-body region") } end := strings.Index(out, "
") if end < start { t.Fatalf("rendered output has no after #operator-body") } return out[start+len(openTag) : end] } // populatedOverview is a representative landing payload: every tile // available, a mix of healthy and unhealthy integrations, and a draining // queue. func populatedOverview() OperatorPageData { return OperatorPageData{ CSRFToken: "csrf", IAPosition: "runtime:landing", Overview: OverviewData{ Stats: []OverviewStat{ {Label: "People", Value: "1,204", Caption: "212 joined in the last 30 days", Available: true}, {Label: "Team organizations", Value: "38", Caption: "Personal orgs excluded", Href: "/operator/organizations", Available: true}, {Label: "Monthly recurring", Value: "$2,295.00", Caption: "205 active subscriptions; 9 trialing", Href: "/operator/billing/subscriptions", Available: true}, {Label: "Open invoices", Value: "3", Caption: "$372.00 outstanding; issued and awaiting payment", Href: "/operator/billing/invoices", Available: true}, {Label: "Delivering grants", Value: "7", Caption: "Plus 80 signup defaults", Href: "/operator/grants", Available: true}, }, Providers: []OverviewProvider{ {Slug: "alpha", DisplayName: "Alpha", Kind: "provisioning", Status: "active", SurfacePath: "/operator/alpha-sites", Healthy: true, Configured: true}, {Slug: "beta", DisplayName: "Beta", Kind: "billing", Status: "disabled", MissingKeysText: "beta-api-key"}, }, Queue: OverviewQueue{Pending: 4, Retrying: 1, Available: true}, }, Activity: []ActivityEvent{{ EventType: "grant_issued", Timestamp: "Jan 2, 2026 3:04 PM", OrgID: "org-1", OrgName: "Example Org", Summary: "Issued Example Plan (promo)", LinkPath: "/operator/organizations/org-1", }}, } } func TestOperatorOverviewRendersStatTiles(t *testing.T) { out := landingRegion(t, renderOperator(t, populatedOverview())) for _, want := range []string{ "At a glance", "People", "1,204", // grouped value, formatted in Go "Team organizations", // deliberately created orgs, not personal ones `href="/operator/organizations"`, // tile drills into its section "Monthly recurring", // commitment as money, not a bare count "$2,295.00", // largest-currency-bucket value `href="/operator/billing/subscriptions"`, "Delivering grants", // operator-issued grants; defaults ride the caption "Plus 80 signup defaults", // composition caption `href="/operator/grants"`, "Open invoices", // receivables tile `href="/operator/billing/invoices"`, // drills into the invoices page "$372.00 outstanding", // caption leads with the balance } { if !strings.Contains(out, want) { t.Errorf("landing surface missing %q", want) } } // A tile with no Href must not render as a link — there is no persons // browse route, so the People tile is static by design. if strings.Contains(out, `href=""`) { t.Errorf("hrefless stat tile rendered an empty link target") } } // An unavailable count must render an em dash. Rendering 0 would be an // actively misleading answer to "how many organizations are there". func TestOperatorOverviewUnavailableStatIsNotZero(t *testing.T) { data := OperatorPageData{ CSRFToken: "csrf", Overview: OverviewData{Stats: []OverviewStat{ {Label: "Organizations", Caption: "Active organizations", Href: "/operator/organizations", Available: false}, }}, } out := landingRegion(t, renderOperator(t, data)) if !strings.Contains(out, "—") { t.Errorf("unavailable stat did not render an em dash") } if !strings.Contains(out, "Count unavailable") { t.Errorf("unavailable stat did not explain itself") } // The tile still renders its label and link; only the number is withheld. if !strings.Contains(out, "Organizations") { t.Errorf("unavailable stat dropped its label") } if regexp.MustCompile(`display-6[^>]*>\s*0\s*<`).MatchString(out) { t.Errorf("unavailable stat rendered a zero value") } } func TestOperatorOverviewSystemPanel(t *testing.T) { out := landingRegion(t, renderOperator(t, populatedOverview())) for _, want := range []string{ "System", "Integrations", "Alpha", `href="/operator/alpha-sites"`, // provider with a surface links to it "provisioning", // provider kind is shown `Beta`) { t.Errorf("surfaceless provider rendered an empty link") } // Alpha is fully configured; only Beta's row should carry the // not-configured marker (ux-honest-surfaces: the signal is a negative // marker, never a redundant positive claim). if n := strings.Count(out, "Not configured"); n != 1 { t.Errorf("system panel shows %d \"Not configured\" markers, want exactly 1 (Beta only)", n) } // The registry-status badge must not read as a live health/connectivity // claim (integration-settings spec: "cannot read as a health check"). if strings.Contains(out, "read live") || strings.Contains(out, "Connected") || strings.Contains(out, "connected to") { t.Errorf("system panel implies a live health/connectivity check") } } // Dead-lettered outbox work is the one queue bucket nothing will clear on its // own, so it must be called out rather than shown as another neutral number. func TestOperatorOverviewDeadLetterRaisesAlarm(t *testing.T) { data := populatedOverview() data.Overview.Queue = OverviewQueue{Pending: 2, Retrying: 0, DeadLetter: 3, Available: true} out := landingRegion(t, renderOperator(t, data)) if !strings.Contains(out, "text-danger") { t.Errorf("dead-lettered work did not render with alarm styling") } if !strings.Contains(out, "exhausted its retries") { t.Errorf("dead-letter state did not explain what an operator must do") } if strings.Contains(out, "draining normally") { t.Errorf("dead-lettered queue still claimed to be draining normally") } } // The landing surface is the first thing a fresh deployment shows, so every // region needs a legible empty state rather than a blank panel. func TestOperatorOverviewEmptyStates(t *testing.T) { out := landingRegion(t, renderOperator(t, OperatorPageData{CSRFToken: "csrf"})) for _, want := range []string{ "Counts are unavailable.", "No activity recorded yet.", "No integrations registered.", "Queue health is unavailable.", } { if !strings.Contains(out, want) { t.Errorf("empty landing surface missing %q", want) } } // The lookup affordance is the one thing that must work on an empty // deployment, so it renders regardless. if !strings.Contains(out, "Find a person or organization") { t.Errorf("empty landing surface dropped the lookup affordance") } } // The landing surface is the page screenshotted for the project README, so // its document outline has to be defensible: exactly one H1, no skipped // levels. The older operator pages run H1 straight to H6; that pattern must // not spread here. func TestOperatorOverviewHeadingHierarchy(t *testing.T) { out := landingRegion(t, renderOperator(t, populatedOverview())) matches := regexp.MustCompile(`(?i)]`).FindAllStringSubmatch(out, -1) if len(matches) == 0 { t.Fatalf("landing surface rendered no headings at all") } levels := make([]int, 0, len(matches)) for _, m := range matches { n, err := strconv.Atoi(m[1]) if err != nil { t.Fatalf("unparsable heading level %q", m[1]) } levels = append(levels, n) } if levels[0] != 1 { t.Errorf("first heading is h%d, want h1", levels[0]) } h1Count := 0 for _, l := range levels { if l == 1 { h1Count++ } } if h1Count != 1 { t.Errorf("found %d h1 elements, want exactly 1", h1Count) } for i := 1; i < len(levels); i++ { if levels[i] > levels[i-1]+1 { t.Errorf("heading level skips from h%d to h%d at position %d (levels: %v)", levels[i-1], levels[i], i, levels) } } // Guard the specific regression: no h4/h5/h6 on this surface at all. for _, l := range levels { if l > 3 { t.Errorf("landing surface uses h%d; the overview outline stops at h3 (levels: %v)", l, levels) } } } // Strict CSP: nothing on this surface may rely on an inline script, an inline // event handler, or a style attribute. func TestOperatorOverviewIsCSPClean(t *testing.T) { out := landingRegion(t, renderOperator(t, populatedOverview())) if regexp.MustCompile(`(?i)]*)?>[^<]`).MatchString(out) { t.Errorf("landing surface contains an inline