- 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
98 lines
3.7 KiB
Go
98 lines
3.7 KiB
Go
package server
|
|
|
|
import (
|
|
"bytes"
|
|
"html/template"
|
|
"io/fs"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.coopcloud.tech/wiki-cafe/member-console/internal/embeds"
|
|
"git.coopcloud.tech/wiki-cafe/member-console/internal/web"
|
|
)
|
|
|
|
// renderOperatorBilling executes the real operator_billing.html wrapper
|
|
// template, mirroring how NewOperatorPartialsHandler loads the operator
|
|
// partials. renderBody is stubbed (as in other isolated partial render
|
|
// tests): this test only exercises the wrapper's own markup (nav pills, the
|
|
// Stripe Sync vocabulary legend, the webhook-recency stamp), not the inner
|
|
// per-tab tables.
|
|
func renderOperatorBilling(t *testing.T, data OperatorBillingWrapperData) string {
|
|
t.Helper()
|
|
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 "" },
|
|
})
|
|
tmpl, err = tmpl.ParseFS(partialsSub, "operator_*.html")
|
|
if err != nil {
|
|
t.Fatalf("ParseFS: %v", err)
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := tmpl.ExecuteTemplate(&buf, "operator_billing.html", data); err != nil {
|
|
t.Fatalf("ExecuteTemplate: %v", err)
|
|
}
|
|
return buf.String()
|
|
}
|
|
|
|
// TestOperatorBillingNotMappedVocabularyIsDefinedInPlace covers the
|
|
// operator-billing-views delta: every one of the four billing sub-pages
|
|
// shares this one wrapper, so a legend rendered here reaches all four
|
|
// without per-tab duplication (design.md; tasks 4.1).
|
|
func TestOperatorBillingNotMappedVocabularyIsDefinedInPlace(t *testing.T) {
|
|
out := renderOperatorBilling(t, OperatorBillingWrapperData{
|
|
ActiveSection: "accounts",
|
|
InnerTemplate: "operator_billing_accounts.html",
|
|
DataAsOf: "Jan 2, 2026 15:04 MST",
|
|
})
|
|
if !strings.Contains(out, "Not Mapped") {
|
|
t.Error("legend missing the vocabulary term it defines")
|
|
}
|
|
if !strings.Contains(out, "no Stripe object is linked") {
|
|
t.Error("legend does not state what an unmapped record means")
|
|
}
|
|
if !strings.Contains(out, "check its sync status") && !strings.Contains(out, "Stripe integration settings") {
|
|
t.Error("legend does not say what to do about an unmapped record")
|
|
}
|
|
}
|
|
|
|
// TestOperatorBillingRecencyStamp covers the operator-billing-views delta's
|
|
// projection-recency requirement (design.md Decision 3; task 4.2): every
|
|
// billing sub-page states when data was last projected, or states plainly
|
|
// that nothing has been received yet, rather than presenting rows or
|
|
// emptiness as if current.
|
|
func TestOperatorBillingRecencyStamp(t *testing.T) {
|
|
t.Run("recency stamp renders with data", func(t *testing.T) {
|
|
out := renderOperatorBilling(t, OperatorBillingWrapperData{
|
|
ActiveSection: "invoices",
|
|
InnerTemplate: "operator_invoices.html",
|
|
DataAsOf: "Jan 2, 2026 15:04 MST",
|
|
})
|
|
if !strings.Contains(out, "Data as of Jan 2, 2026 15:04 MST") {
|
|
t.Errorf("recency stamp missing or malformed: %s", out)
|
|
}
|
|
if strings.Contains(out, "No billing events have been received") {
|
|
t.Error("no-events copy rendered even though DataAsOf was set")
|
|
}
|
|
})
|
|
|
|
t.Run("no events ever processed is stated", func(t *testing.T) {
|
|
out := renderOperatorBilling(t, OperatorBillingWrapperData{
|
|
ActiveSection: "payments",
|
|
InnerTemplate: "operator_payments.html",
|
|
NoEventsProcessed: true,
|
|
})
|
|
if !strings.Contains(out, "No billing events have been received") {
|
|
t.Errorf("missing the no-events-ever statement: %s", out)
|
|
}
|
|
if strings.Contains(out, "Data as of") {
|
|
t.Error("stale 'Data as of' copy rendered with no processed events")
|
|
}
|
|
})
|
|
}
|