Files
member-console/internal/server/operator_template_smoke_test.go
T
cgalo5758 36e58cd821 Flatten operator sidebar to seven entries
Move sub-surfaces into their sections: billing views get a pill row,
org types a header button. Replace inline IdP handoff copy with an SVG
icon and tooltip, add help icons to dense form rows, and delete the
registry-driven sidebar nav plumbing. Update specs and tests.
2026-08-23 18:26:11 -05:00

166 lines
5.7 KiB
Go

package server
import (
"bytes"
"html/template"
"io/fs"
"strings"
"testing"
"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/web"
)
// TestOperatorTemplateRendersBothBranches parses operator.html and renders
// both dispatch branches (curated landing surface and the MPA BodyTemplate
// dispatch) to catch Go-template syntax errors that would otherwise only
// surface at request time. The legacy tabstrip branch was retired in slice
// 8 of operator-mpa-conversion §5.
func TestOperatorTemplateRendersBothBranches(t *testing.T) {
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)
}
// operator.html references the `renderBody` and `routeURL` template
// funcs and includes partials like operator_lookup_result.html via
// `{{ template "..." . }}`. Mirror NewOperatorPartialsHandler: load
// partials first, then the shell.
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,
})
tmpl, err = tmpl.ParseFS(partialsSub, "operator_*.html")
if err != nil {
t.Fatalf("ParseFS partials: %v", err)
}
tmpl, err = tmpl.ParseFS(sub, "operator.html")
if err != nil {
t.Fatalf("ParseFS operator.html: %v", err)
}
cases := []struct {
name string
data OperatorPageData
want string
}{
{
name: "landing",
data: OperatorPageData{
CSRFToken: "csrf",
IAPosition: "runtime:landing",
},
want: "Find a person or organization",
},
{
// BodyTemplate dispatch branch must short-circuit the landing
// surface; the stub renderBody returns "" so the assertion is
// that the shell still renders (no landing markup leaks in).
name: "body-template-dispatch",
data: OperatorPageData{
CSRFToken: "csrf",
IAPosition: "runtime:organizations",
ActiveCapability: "organizations",
BodyTemplate: "operator_organizations.html",
BodyData: nil,
},
want: `id="operator-main"`,
},
{
// Dedicated Integrations section: the sidebar renders a labeled
// "Integrations" home link to /operator/integrations. Provider
// surfaces are reached from that home's provider cards, not from
// sidebar children (maintainer 2026-08-23).
name: "integration-section-home",
data: OperatorPageData{
CSRFToken: "csrf",
ActiveCapability: "integrations",
},
want: `href="/operator/integrations">Integrations</a>`,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
var buf bytes.Buffer
if err := tmpl.ExecuteTemplate(&buf, "operator.html", tc.data); err != nil {
t.Fatalf("ExecuteTemplate: %v", err)
}
out := buf.String()
if !strings.Contains(out, tc.want) {
t.Errorf("rendered output missing %q", tc.want)
}
if !strings.Contains(out, `hx-boost="true"`) {
t.Errorf("rendered output missing hx-boost on body")
}
if !strings.Contains(out, `id="operator-main"`) {
t.Errorf("rendered output missing main#operator-main swap target")
}
// Slice 8 guard: legacy tabstrip markup must not reappear.
if strings.Contains(out, `id="operatorTabs"`) {
t.Errorf("legacy tabstrip leaked back into operator.html — re-check §5 retirement")
}
})
}
}
// TestOperatorIntegrationsTemplate renders the Integrations landing body
// partial directly (the operator.html smoke test stubs renderBody, so the body
// markup is not exercised there). Covers a populated provider row and the
// empty state.
func TestOperatorIntegrationsTemplate(t *testing.T) {
partialsSub, err := fs.Sub(embeds.Templates, "templates/partials")
if err != nil {
t.Fatalf("fs.Sub partials: %v", err)
}
tmpl := template.New("integrations").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 "" },
})
tmpl, err = tmpl.ParseFS(partialsSub, "operator_*.html")
if err != nil {
t.Fatalf("ParseFS partials: %v", err)
}
t.Run("populated", func(t *testing.T) {
var buf bytes.Buffer
data := IntegrationsData{Integrations: []IntegrationRow{{
Slug: "example",
DisplayName: "Example",
Kind: "provisioning",
Status: "active",
SurfacePath: "/operator/example-sites",
Operations: []string{"create", "delete", "set_status"},
ResourceKeys: []ResourceKeyOption{{ResourceKey: "example_sites", DisplayName: "Example sites"}},
}}}
if err := tmpl.ExecuteTemplate(&buf, "operator_integrations.html", data); err != nil {
t.Fatalf("ExecuteTemplate: %v", err)
}
out := buf.String()
for _, want := range []string{"Example", "example_sites", "Example sites", "set_status", `href="/operator/example-sites"`, "Active"} {
if !strings.Contains(out, want) {
t.Errorf("integrations landing missing %q", want)
}
}
})
t.Run("empty", func(t *testing.T) {
var buf bytes.Buffer
if err := tmpl.ExecuteTemplate(&buf, "operator_integrations.html", IntegrationsData{}); err != nil {
t.Fatalf("ExecuteTemplate empty: %v", err)
}
if !strings.Contains(buf.String(), "No integrations registered") {
t.Errorf("empty state not rendered")
}
})
}