Files
tapir/internal/web/flash_internal_test.go
T
mathiasandClaude Opus 4.8 2fe4833434 feat(web): reusable flash/notification banner (PRG)
Add a one-shot flash component used across the app — connect success,
disconnect, account delete, and registration — instead of per-page ad-hoc
markup. setFlash queues a short-lived HttpOnly+SameSite cookie carrying an
opaque code; takeFlash consumes it on the next full-page render (not on
HTMX fragments). flashBanner maps the code to a styled, role=status banner;
the message text lives server-side in flashMessages so the cookie never
carries free text and a forged/unknown code renders nothing.

Wire it into the list page (the PRG landing spot for connect/registration)
and set it on registration and connect-callback success. Styled with the
existing design-system tokens; header gains an Account nav link.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 16:52:03 +02:00

55 lines
1.7 KiB
Go

package web
import (
"context"
"strings"
"testing"
)
// TestFlashBannerRendersEachKind proves the reusable notification component
// renders a banner with the right message and severity class for every flash
// code, and renders nothing for an empty or unknown (e.g. forged) code.
func TestFlashBannerRendersEachKind(t *testing.T) {
cases := []struct {
code string
wantText string
wantKind string
}{
{flashConnected, "YouTube account connected", "flash-success"},
{flashConnectFailed, "Could not connect", "flash-error"},
{flashDisconnected, "Account disconnected", "flash-success"},
{flashDeleted, "account and all its data were deleted", "flash-success"},
{flashRegistered, "Welcome to Tapir", "flash-success"},
}
for _, tc := range cases {
t.Run(tc.code, func(t *testing.T) {
var sb strings.Builder
if err := flashBanner(tc.code).Render(context.Background(), &sb); err != nil {
t.Fatalf("render: %v", err)
}
got := sb.String()
if !strings.Contains(got, tc.wantText) {
t.Errorf("banner %q = %q, want it to contain %q", tc.code, got, tc.wantText)
}
if !strings.Contains(got, tc.wantKind) {
t.Errorf("banner %q = %q, want severity class %q", tc.code, got, tc.wantKind)
}
if !strings.Contains(got, `role="status"`) {
t.Errorf("banner %q must carry role=status for assistive tech, got %q", tc.code, got)
}
})
}
}
func TestFlashBannerRendersNothingForUnknownCode(t *testing.T) {
for _, code := range []string{"", "bogus", "<script>"} {
var sb strings.Builder
if err := flashBanner(code).Render(context.Background(), &sb); err != nil {
t.Fatalf("render: %v", err)
}
if got := strings.TrimSpace(sb.String()); got != "" {
t.Errorf("flashBanner(%q) = %q, want empty (no banner)", code, got)
}
}
}