From cb4e892b10ca119546bef93f75748b9750da6f69 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sun, 18 Oct 2026 12:30:55 -0400 Subject: [PATCH] =?UTF-8?q?test(templates):=20pin=20the=20rendering=20part?= =?UTF-8?q?ials=20=E2=80=94=20standalone=20render,=20OOB=20markers,=20empt?= =?UTF-8?q?y=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/partials_render_test.go | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 templates/partials_render_test.go diff --git a/templates/partials_render_test.go b/templates/partials_render_test.go new file mode 100644 index 00000000..22dfd0c1 --- /dev/null +++ b/templates/partials_render_test.go @@ -0,0 +1,49 @@ +package templates + +import ( + "context" + "strings" + "testing" + + "bookhoard/internal/handlers" +) + +// The rendering-ownership partials must render standalone (they are +// fetched by htmx.ajax at runtime) and must never leak templ literal +// expressions into their markup. +func TestRenderingPartialsRender(t *testing.T) { + var b strings.Builder + col := CollectionData{ID: "c1", Name: "Test Shelf", IsSmart: false} + books := []handlers.BookInfo{{MediaItemID: "m1", Title: "A Book", Author: "An Author"}} + if err := CollectionBooksGrid(col, books).Render(context.Background(), &b); err != nil { + t.Fatalf("CollectionBooksGrid: %v", err) + } + out := b.String() + for _, want := range []string{"A Book", `data-media-id="m1"`, "Remove from Collection"} { + if !strings.Contains(out, want) { + t.Errorf("books grid missing %q", want) + } + } + + // Empty collection renders the empty state, not a literal loop. + b.Reset() + if err := CollectionBooksGrid(col, nil).Render(context.Background(), &b); err != nil { + t.Fatalf("CollectionBooksGrid empty: %v", err) + } + if !strings.Contains(b.String(), "No books in this collection yet.") { + t.Error("books grid empty state missing") + } + + b.Reset() + user := User{ID: "u1", Timezone: "UTC"} + conflicts := []handlers.ConflictDetailResponse{{ID: "cf1", MediaItemTitle: "War and Peace", ConflictType: "progress"}} + if err := ConflictsRefreshFragment(user, conflicts, 3, 1).Render(context.Background(), &b); err != nil { + t.Fatalf("ConflictsRefreshFragment: %v", err) + } + out = b.String() + for _, want := range []string{`id="conflicts-list"`, `id="stats-bar"`, "hx-swap-oob", "Resolve"} { + if !strings.Contains(out, want) { + t.Errorf("conflicts fragment missing %q", want) + } + } +}