Derive Stripe test/live mode from the API key prefix at boot, failing on unrecognized prefixes, and drop the separate `stripe-mode` config key. Refine disabled controls to render through the shared `disabledControl` part with the not-allowed cursor, and add a lint rule refusing hand-rolled disabled buttons. Adjust plan cards to offer no purchase control on free rungs, fix bound checkbox Bool handling, and rename "Public/Private" to "Listed/Unlisted" with enhanced readiness verdicts.
59 lines
2.6 KiB
Go
59 lines
2.6 KiB
Go
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial
|
|
// SPDX-FileCopyrightText: 2025-2026 Christian Galo
|
|
|
|
package server
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestDisabledControlRender pins form-conventions "Disabled controls carry
|
|
// their reason in the DOM" (design D10, ACC-8): the operator surface's
|
|
// default variant puts the reason in a visually-hidden span referenced by
|
|
// aria-describedby and shows it as a tooltip on a focusable wrapper; the
|
|
// member surface's Visible variant renders the same reason as ordinary
|
|
// <small> text instead, still referenced by aria-describedby, so a screen
|
|
// reader announces it either way regardless of which surface's
|
|
// presentation choice rendered it.
|
|
func TestDisabledControlRender(t *testing.T) {
|
|
dc := NewDisabledControl("extend-tier-reason", "Extend tier", "btn btn-outline-primary btn-sm",
|
|
"Nothing to extend: this delivery is not grant-backed.")
|
|
|
|
out, err := renderPart(t, "disabledControl", dc)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
button := `<button type="button" class="btn btn-outline-primary btn-sm" disabled aria-describedby="extend-tier-reason">Extend tier</button>`
|
|
wrapper := `<span class="disabled-control d-inline-block" tabindex="0" data-bs-toggle="tooltip" title="Nothing to extend: this delivery is not grant-backed.">` + button + `</span>`
|
|
reason := `<span id="extend-tier-reason" class="visually-hidden">Nothing to extend: this delivery is not grant-backed.</span>`
|
|
for _, want := range []string{wrapper, reason} {
|
|
if strings.Count(out, want) != 1 {
|
|
t.Errorf("disabledControl (tooltip variant) missing %q in:\n%s", want, out)
|
|
}
|
|
}
|
|
if strings.Contains(out, "<small") {
|
|
t.Errorf("the tooltip variant must not render visible <small> reason text, got:\n%s", out)
|
|
}
|
|
|
|
// dc is unmodified by the first render; AsVisible returns a copy.
|
|
if dc.Visible {
|
|
t.Fatal("dc must remain the tooltip variant before AsVisible is called")
|
|
}
|
|
|
|
out, err = renderPart(t, "disabledControl", dc.AsVisible())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
visibleWrapper := `<span class="disabled-control d-inline-block">` + button + `</span>`
|
|
visibleReason := `<small id="extend-tier-reason" class="text-muted d-block mt-1">Nothing to extend: this delivery is not grant-backed.</small>`
|
|
for _, want := range []string{visibleWrapper, visibleReason} {
|
|
if strings.Count(out, want) != 1 {
|
|
t.Errorf("disabledControl (visible variant) missing %q in:\n%s", want, out)
|
|
}
|
|
}
|
|
if strings.Contains(out, `data-bs-toggle="tooltip"`) || strings.Contains(out, "visually-hidden") {
|
|
t.Errorf("the visible variant must not render a tooltip wrapper or a hidden reason span, got:\n%s", out)
|
|
}
|
|
}
|