Files
member-console/internal/integrations/fedwiki/web/operator_render_test.go
T
cgalo5758 88db730fcc Add dual licensing and SPDX headers
Introduce a commercial license option alongside AGPL-3.0-only, require a
CLA for contributors, and document the terms in COMMERCIAL.md and
NOTICE. Add a script to stamp SPDX headers on Go files and apply it
across the tree.
2026-09-06 02:29:42 -05:00

112 lines
4.1 KiB
Go

// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial
// SPDX-FileCopyrightText: 2025-2026 Christian Galo
package web
import (
"log/slog"
"net/http/httptest"
"os"
"strings"
"testing"
"git.coopcloud.tech/wiki-cafe/member-console/internal/server"
)
// Scenario: the operator shell's landing branch references
// operator_lookup_result.html, and html/template's escape analysis demands
// every referenced template exist in the set even on branches this page
// never takes — a handler that parses only operator.html + its own body
// partial 500s on EVERY render ("no such template"). This regressed live
// on /operator/fedwiki-sites (discourse-integration findings #8); guard
// the template-set composition without needing a DB or auth session.
func TestOperatorSitesPageRenders(t *testing.T) {
h, err := NewFedWikiOperatorHandler(FedWikiOperatorHandlerConfig{
Logger: slog.Default(),
TemplatesFS: os.DirFS("../templates"),
})
if err != nil {
t.Fatalf("construct handler: %v", err)
}
page := server.OperatorPageData{
IAPosition: "integration:fedwiki-sites",
ActiveCapability: "fedwiki-sites",
BodyTemplate: "fedwiki_operator_sites.html",
BodyData: FedWikiSitesData{
Configured: true,
Sites: []FedWikiSiteViewModel{{
ID: "site-1", Domain: "wiki.example.test", URL: "https://wiki.example.test",
OwnerOrgName: "Test Org", CreatedAt: "Jan 2, 2026", Status: "active",
}},
},
}
rec := httptest.NewRecorder()
h.Templates.Render(rec, "operator.html", page)
if rec.Code != 200 {
t.Fatalf("render = %d (template-set regression?), body: %s", rec.Code, rec.Body.String())
}
out := rec.Body.String()
for _, want := range []string{
"wiki.example.test", // a site row
`<h1 class="h2 mb-0">FedWiki sites</h1>`, // titled by pageHeader
`<li class="breadcrumb-item"><a href="/operator/integrations">Integrations</a>`, // the trail
`>Settings</a>`, // header action slot
`<h2 class="h5 mb-0">Sync health`, // section header outside the card
`<h2 class="h5 mb-0">Sites`, // sites section with count slot
`<span class="badge text-bg-light border">Subdomain</span>`, // type through statusBadge
`<span class="badge text-bg-success">Active</span>`, // status through statusBadge
`<th scope="row" class="text-nowrap">`, // domain is the row primary, never wraps
} {
if !strings.Contains(out, want) {
t.Errorf("rendered page missing %q", want)
}
}
for _, banned := range []string{"Total: ", "card-header", ">ID</th>"} {
if strings.Contains(out, banned) {
t.Errorf("rendered page still contains %q", banned)
}
}
}
// TestOperatorSitesPageNotConfigured covers ACC-2 (fedwiki-sites spec:
// "Operator panel site listing" — "FedWiki is not configured"): when
// FedWiki's required configuration is unresolved, the page states what is
// missing and links to its settings page, the same blocked shape the
// Discourse operator page renders, instead of an empty sites listing that
// reads as "no sites".
func TestOperatorSitesPageNotConfigured(t *testing.T) {
h, err := NewFedWikiOperatorHandler(FedWikiOperatorHandlerConfig{
Logger: slog.Default(),
TemplatesFS: os.DirFS("../templates"),
})
if err != nil {
t.Fatalf("construct handler: %v", err)
}
page := server.OperatorPageData{
BodyTemplate: "fedwiki_operator_sites.html",
BodyData: FedWikiSitesData{Configured: false},
}
rec := httptest.NewRecorder()
h.Templates.Render(rec, "operator.html", page)
if rec.Code != 200 {
t.Fatalf("render = %d, body: %s", rec.Code, rec.Body.String())
}
out := rec.Body.String()
for _, want := range []string{
"FedWiki is not configured",
"fedwiki-farm-api-url", "fedwiki-admin-token",
`href="/operator/integrations/fedwiki/settings"`,
} {
if !strings.Contains(out, want) {
t.Errorf("not-configured render missing %q, got:\n%s", want, out)
}
}
if strings.Contains(out, `<h2 class="h5 mb-0">Sites`) {
t.Error("not-configured render must not show the sites listing")
}
}