test(01-02): add ui package smoke tests
- TestButton_DefaultSolidMD: asserts root class and label
- TestButton_PassesThroughAttrs: asserts hx-* attribute spread
- TestButton_ExplicitTypeSubmit: type override
- TestCard_RendersChildren: templ.WithChildren child injection
- TestBadge_{Info,Success}Variant + zero-value normalization
- TestButtonClass_String / TestBadgeClass_String: class contract
- TestNormalizers_ZeroValueDefaults: every Normalized* returns safe default
This commit is contained in:
parent
d056b33241
commit
75cbd29d44
1 changed files with 132 additions and 0 deletions
132
backend/internal/web/ui/ui_test.go
Normal file
132
backend/internal/web/ui/ui_test.go
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
)
|
||||
|
||||
// render is a tiny helper that renders a templ.Component to a string for
|
||||
// substring assertions. Uses context.Background to match production calls.
|
||||
func render(t *testing.T, ctx context.Context, c templ.Component) string {
|
||||
t.Helper()
|
||||
var buf bytes.Buffer
|
||||
if err := c.Render(ctx, &buf); err != nil {
|
||||
t.Fatalf("render: unexpected error: %v", err)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestButton_DefaultSolidMD(t *testing.T) {
|
||||
out := render(t, context.Background(), Button(ButtonProps{Label: "Fetch server time"}))
|
||||
|
||||
wantClass := `class="ui-button ui-button-solid-default-md"`
|
||||
if !strings.Contains(out, wantClass) {
|
||||
t.Errorf("output missing class %q\ngot: %s", wantClass, out)
|
||||
}
|
||||
if !strings.Contains(out, "Fetch server time") {
|
||||
t.Errorf("output missing label literal; got: %s", out)
|
||||
}
|
||||
if !strings.Contains(out, `type="button"`) {
|
||||
t.Errorf("output missing default type=\"button\"; got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestButton_PassesThroughAttrs(t *testing.T) {
|
||||
props := ButtonProps{
|
||||
Label: "x",
|
||||
Attrs: templ.Attributes{
|
||||
"hx-get": "/demo/time",
|
||||
"hx-target": "#demo-out",
|
||||
},
|
||||
}
|
||||
out := render(t, context.Background(), Button(props))
|
||||
|
||||
if !strings.Contains(out, `hx-get="/demo/time"`) {
|
||||
t.Errorf("output missing hx-get; got: %s", out)
|
||||
}
|
||||
if !strings.Contains(out, `hx-target="#demo-out"`) {
|
||||
t.Errorf("output missing hx-target; got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestButton_ExplicitTypeSubmit(t *testing.T) {
|
||||
out := render(t, context.Background(), Button(ButtonProps{Label: "Go", Type: "submit"}))
|
||||
if !strings.Contains(out, `type="submit"`) {
|
||||
t.Errorf("expected type=\"submit\"; got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
// Card injects children via templ.WithChildren. The test feeds a raw child
|
||||
// component through context and asserts the rendered wrapper + child content.
|
||||
func TestCard_RendersChildren(t *testing.T) {
|
||||
child := templ.Raw("<p>x</p>")
|
||||
ctx := templ.WithChildren(context.Background(), child)
|
||||
out := render(t, ctx, Card(nil))
|
||||
|
||||
if !strings.Contains(out, `<section class="ui-card"`) {
|
||||
t.Errorf("output missing <section class=\"ui-card\">; got: %s", out)
|
||||
}
|
||||
if !strings.Contains(out, "<p>x</p>") {
|
||||
t.Errorf("output missing child markup; got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadge_InfoVariant(t *testing.T) {
|
||||
out := render(t, context.Background(), Badge(BadgeProps{Label: "OK", Variant: BadgeVariantInfo}))
|
||||
wantClass := `class="ui-badge ui-badge-info"`
|
||||
if !strings.Contains(out, wantClass) {
|
||||
t.Errorf("output missing %q; got: %s", wantClass, out)
|
||||
}
|
||||
if !strings.Contains(out, "OK") {
|
||||
t.Errorf("output missing label; got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadge_SuccessVariant(t *testing.T) {
|
||||
out := render(t, context.Background(), Badge(BadgeProps{Label: "OK", Variant: BadgeVariantSuccess}))
|
||||
if !strings.Contains(out, "ui-badge-success") {
|
||||
t.Errorf("output missing ui-badge-success; got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadge_ZeroValueDefaultsToInfo(t *testing.T) {
|
||||
out := render(t, context.Background(), Badge(BadgeProps{Label: "OK"}))
|
||||
if !strings.Contains(out, "ui-badge-info") {
|
||||
t.Errorf("zero-value Variant should normalize to info; got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestButtonClass_String(t *testing.T) {
|
||||
got := ButtonClass(ButtonVariantDefault, ButtonToneSolid, SizeMD)
|
||||
want := "ui-button ui-button-solid-default-md"
|
||||
if got != want {
|
||||
t.Errorf("ButtonClass = %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadgeClass_String(t *testing.T) {
|
||||
got := BadgeClass(BadgeVariantInfo)
|
||||
want := "ui-badge ui-badge-info"
|
||||
if got != want {
|
||||
t.Errorf("BadgeClass = %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizers_ZeroValueDefaults(t *testing.T) {
|
||||
if got := NormalizedSize(""); got != SizeMD {
|
||||
t.Errorf("NormalizedSize(\"\") = %q; want %q", got, SizeMD)
|
||||
}
|
||||
if got := NormalizedButtonVariant(""); got != ButtonVariantDefault {
|
||||
t.Errorf("NormalizedButtonVariant(\"\") = %q; want %q", got, ButtonVariantDefault)
|
||||
}
|
||||
if got := NormalizedButtonTone(""); got != ButtonToneSolid {
|
||||
t.Errorf("NormalizedButtonTone(\"\") = %q; want %q", got, ButtonToneSolid)
|
||||
}
|
||||
if got := NormalizedBadgeVariant(""); got != BadgeVariantInfo {
|
||||
t.Errorf("NormalizedBadgeVariant(\"\") = %q; want %q", got, BadgeVariantInfo)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue