learnlytics-go/templ/examples/blog/posts_test.go

211 lines
6.4 KiB
Go
Raw Normal View History

2025-03-20 12:35:13 +01:00
package main
import (
"context"
"errors"
"fmt"
"io"
"log"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/PuerkitoBio/goquery"
)
func TestHeader(t *testing.T) {
// Pipe the rendered template into goquery.
r, w := io.Pipe()
go func() {
_ = headerTemplate("Posts").Render(context.Background(), w)
_ = w.Close()
}()
doc, err := goquery.NewDocumentFromReader(r)
if err != nil {
t.Fatalf("failed to read template: %v", err)
}
// Expect the component to include a testid.
if doc.Find(`[data-testid="headerTemplate"]`).Length() == 0 {
t.Error("expected data-testid attribute to be rendered, but it wasn't")
}
// Expect the page name to be set correctly.
expectedPageName := "Posts"
if actualPageName := doc.Find("h1").Text(); actualPageName != expectedPageName {
t.Errorf("expected page name %q, got %q", expectedPageName, actualPageName)
}
}
func TestFooter(t *testing.T) {
// Pipe the rendered template into goquery.
r, w := io.Pipe()
go func() {
_ = footerTemplate().Render(context.Background(), w)
_ = w.Close()
}()
doc, err := goquery.NewDocumentFromReader(r)
if err != nil {
t.Fatalf("failed to read template: %v", err)
}
// Expect the component to include a testid.
if doc.Find(`[data-testid="footerTemplate"]`).Length() == 0 {
t.Error("expected data-testid attribute to be rendered, but it wasn't")
}
// Expect the copyright notice to include the current year.
expectedCopyrightNotice := fmt.Sprintf("© %d", time.Now().Year())
if actualCopyrightNotice := doc.Find("div").Text(); actualCopyrightNotice != expectedCopyrightNotice {
t.Errorf("expected copyright notice %q, got %q", expectedCopyrightNotice, actualCopyrightNotice)
}
}
func TestNav(t *testing.T) {
r, w := io.Pipe()
go func() {
_ = navTemplate().Render(context.Background(), w)
_ = w.Close()
}()
doc, err := goquery.NewDocumentFromReader(r)
if err != nil {
t.Fatalf("failed to read template: %v", err)
}
// Expect the component to include a testid.
if doc.Find(`[data-testid="navTemplate"]`).Length() == 0 {
t.Error("expected data-testid attribute to be rendered, but it wasn't")
}
}
func TestHome(t *testing.T) {
r, w := io.Pipe()
go func() {
_ = home().Render(context.Background(), w)
_ = w.Close()
}()
doc, err := goquery.NewDocumentFromReader(r)
if err != nil {
t.Fatalf("failed to read template: %v", err)
}
// Expect the page title to be set correctly.
expectedTitle := "Home"
if actualTitle := doc.Find("title").Text(); actualTitle != expectedTitle {
t.Errorf("expected title name %q, got %q", expectedTitle, actualTitle)
}
// Expect the header to be rendered.
if doc.Find(`[data-testid="headerTemplate"]`).Length() == 0 {
t.Error("expected data-testid attribute to be rendered, but it wasn't")
}
// Expect the navigation to be rendered.
if doc.Find(`[data-testid="navTemplate"]`).Length() == 0 {
t.Error("expected nav to be rendered, but it wasn't")
}
// Expect the home template be rendered.
if doc.Find(`[data-testid="homeTemplate"]`).Length() == 0 {
t.Error("expected homeTemplate to be rendered, but it wasn't")
}
}
func TestPosts(t *testing.T) {
testPosts := []Post{
{Name: "Name1", Author: "Author1"},
{Name: "Name2", Author: "Author2"},
}
r, w := io.Pipe()
go func() {
_ = posts(testPosts).Render(context.Background(), w)
_ = w.Close()
}()
doc, err := goquery.NewDocumentFromReader(r)
if err != nil {
t.Fatalf("failed to read template: %v", err)
}
// Assert.
// Expect the page title to be set correctly.
expectedTitle := "Posts"
if actualTitle := doc.Find("title").Text(); actualTitle != expectedTitle {
t.Errorf("expected title name %q, got %q", expectedTitle, actualTitle)
}
// Expect the header to be rendered.
if doc.Find(`[data-testid="headerTemplate"]`).Length() == 0 {
t.Error("expected data-testid attribute to be rendered, but it wasn't")
}
// Expect the navigation to be rendered.
if doc.Find(`[data-testid="navTemplate"]`).Length() == 0 {
t.Error("expected nav to be rendered, but it wasn't")
}
// Expect the posts to be rendered.
if doc.Find(`[data-testid="postsTemplate"]`).Length() == 0 {
t.Error("expected posts to be rendered, but it wasn't")
}
// Expect both posts to be rendered.
if actualPostCount := doc.Find(`[data-testid="postsTemplatePost"]`).Length(); actualPostCount != len(testPosts) {
t.Fatalf("expected %d posts to be rendered, found %d", len(testPosts), actualPostCount)
}
// Expect the posts to contain the author name.
doc.Find(`[data-testid="postsTemplatePost"]`).Each(func(index int, sel *goquery.Selection) {
expectedName := testPosts[index].Name
if actualName := sel.Find(`[data-testid="postsTemplatePostName"]`).Text(); actualName != expectedName {
t.Errorf("expected name %q, got %q", actualName, expectedName)
}
expectedAuthor := testPosts[index].Author
if actualAuthor := sel.Find(`[data-testid="postsTemplatePostAuthor"]`).Text(); actualAuthor != expectedAuthor {
t.Errorf("expected author %q, got %q", actualAuthor, expectedAuthor)
}
})
}
func TestPostsHandler(t *testing.T) {
tests := []struct {
name string
postGetter func() (posts []Post, err error)
expectedStatus int
assert func(doc *goquery.Document)
}{
{
name: "database errors result in a 500 error",
postGetter: func() (posts []Post, err error) {
return nil, errors.New("database error")
},
expectedStatus: http.StatusInternalServerError,
assert: func(doc *goquery.Document) {
expected := "failed to retrieve posts\n"
if actual := doc.Text(); actual != expected {
t.Errorf("expected error message %q, got %q", expected, actual)
}
},
},
{
name: "database success renders the posts",
postGetter: func() (posts []Post, err error) {
return []Post{
{Name: "Name1", Author: "Author1"},
{Name: "Name2", Author: "Author2"},
}, nil
},
expectedStatus: http.StatusInternalServerError,
assert: func(doc *goquery.Document) {
if doc.Find(`[data-testid="postsTemplate"]`).Length() == 0 {
t.Error("expected posts to be rendered, but it wasn't")
}
},
},
}
for _, test := range tests {
// Arrange.
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/posts", nil)
ph := NewPostsHandler()
ph.Log = log.New(io.Discard, "", 0) // Suppress logging.
ph.GetPosts = test.postGetter
// Act.
ph.ServeHTTP(w, r)
doc, err := goquery.NewDocumentFromReader(w.Result().Body)
if err != nil {
t.Fatalf("failed to read template: %v", err)
}
// Assert.
test.assert(doc)
}
}