Domains leaves the member nav everywhere; GET /domains 302s to the dashboard and domains.html is deleted. Claims are managed where they are used: the fedwiki sites card embeds the core claims partial, a server-conditional dashboard notice carries pending verifications (the durable re-entry now that the page is gone), and the member_domains partials retarget to 'closest .domains-surface' so multiple hosts coexist on one page. Adding an external domain starts only from the create form; the fedwiki banner slims to verified-unplaced one-click creates, since the notice and embedded section own the pending state. Verified at the surface end-to-end (stack + Chrome): nav absence, redirect, notice lifecycle through claim-cancel, and cross-host swap isolation with two claim views open. Archives the change with spec deltas synced (domains-registry point-of-use rewrite, fedwiki-sites and member-dashboard additions); files the entitlement-gate placement debt in issues.md; adds the repo verify skill.
97 lines
3.3 KiB
Go
97 lines
3.3 KiB
Go
// Render coverage for the member-side domains dissolution
|
|
// (dissolve-member-domains): the member shells carry no Domains navigation,
|
|
// and the dashboard carries the pending-claim notice — the durable re-entry
|
|
// point for an in-flight DNS verification now that the standalone page is
|
|
// gone. DB-free: templates render with literal data.
|
|
package server_test
|
|
|
|
import (
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.coopcloud.tech/wiki-cafe/member-console/internal/server"
|
|
)
|
|
|
|
// shellData mirrors the anonymous structs the products/billing handlers
|
|
// render their shells with.
|
|
type shellData struct {
|
|
KeycloakAccountURL string
|
|
CSRFToken string
|
|
IsOperator bool
|
|
}
|
|
|
|
// TestMemberShellsHaveNoDomainsNav pins the de-centering: no member shell
|
|
// offers Domains as a destination.
|
|
func TestMemberShellsHaveNoDomainsNav(t *testing.T) {
|
|
st := rootTemplates(t)
|
|
|
|
render := func(name string, data any) string {
|
|
t.Helper()
|
|
rec := httptest.NewRecorder()
|
|
st.Render(rec, name, data)
|
|
if rec.Code != 200 {
|
|
t.Fatalf("%s: expected 200, got %d: %s", name, rec.Code, rec.Body.String())
|
|
}
|
|
return rec.Body.String()
|
|
}
|
|
|
|
for name, body := range map[string]string{
|
|
"index.html": render("index.html", dashboardData{}),
|
|
"products.html": render("products.html", shellData{}),
|
|
"billing.html": render("billing.html", shellData{}),
|
|
} {
|
|
if strings.Contains(body, `href="/domains"`) {
|
|
t.Errorf("%s still links /domains", name)
|
|
}
|
|
if strings.Contains(body, ">Domains<") {
|
|
t.Errorf("%s still renders a Domains nav label", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestDashboardPendingDomainNotice covers the notice's contract: present and
|
|
// claim-naming while a claim is pending, absent without one (no empty
|
|
// chrome), opening a claim is a pure GET into the notice's own
|
|
// .domains-surface wrapper, and the notice is core content — not one of the
|
|
// registry-declared integration cards.
|
|
func TestDashboardPendingDomainNotice(t *testing.T) {
|
|
st := rootTemplates(t)
|
|
|
|
rec := httptest.NewRecorder()
|
|
st.Render(rec, "index.html", dashboardData{
|
|
PendingDomainClaims: []server.PendingDomainClaim{
|
|
{ClaimID: "claim-1", Root: "wiki.example.org"},
|
|
{ClaimID: "claim-2", Root: "docs.example.net"},
|
|
},
|
|
})
|
|
body := rec.Body.String()
|
|
for _, want := range []string{
|
|
"Domain verification in progress",
|
|
"wiki.example.org", "docs.example.net",
|
|
`hx-get="/partials/domains/claims/claim-1"`,
|
|
`hx-target="closest .domains-surface"`,
|
|
"View DNS records",
|
|
} {
|
|
if !strings.Contains(body, want) {
|
|
t.Errorf("pending notice missing %q", want)
|
|
}
|
|
}
|
|
// Opening instructions is a pure read: the notice must not POST anything.
|
|
if strings.Contains(body, `hx-post="/partials/domains/claims/claim-1`) {
|
|
t.Error("the notice must open instructions via GET, never a mutating request")
|
|
}
|
|
// Core content, not a card: this render declares zero DashboardCards, and
|
|
// the notice still appears — so it cannot be riding the card registry.
|
|
// (The presence assertions above are that proof; nothing more to check.)
|
|
|
|
empty := httptest.NewRecorder()
|
|
st.Render(empty, "index.html", dashboardData{})
|
|
if strings.Contains(empty.Body.String(), "Domain verification") {
|
|
t.Error("no pending claims must mean no notice and no empty chrome")
|
|
}
|
|
if strings.Contains(empty.Body.String(), "domains-surface") {
|
|
t.Error("no pending claims must leave no dangling domains-surface wrapper")
|
|
}
|
|
}
|