161 lines
3.7 KiB
Go
161 lines
3.7 KiB
Go
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||
|
|
|
||
|
|
package render
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"net/http"
|
||
|
|
"net/http/httptest"
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"kode.naiv.no/olemd/favoritter/internal/config"
|
||
|
|
)
|
||
|
|
|
||
|
|
func testRenderer(t *testing.T) *Renderer {
|
||
|
|
t.Helper()
|
||
|
|
cfg := &config.Config{
|
||
|
|
SiteName: "Test Site",
|
||
|
|
BasePath: "/test",
|
||
|
|
}
|
||
|
|
r, err := New(cfg)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("create renderer: %v", err)
|
||
|
|
}
|
||
|
|
return r
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRenderPage(t *testing.T) {
|
||
|
|
r := testRenderer(t)
|
||
|
|
|
||
|
|
req := httptest.NewRequest("GET", "/", nil)
|
||
|
|
rr := httptest.NewRecorder()
|
||
|
|
|
||
|
|
r.Page(rr, req, "login", PageData{
|
||
|
|
Title: "Logg inn",
|
||
|
|
})
|
||
|
|
|
||
|
|
if rr.Code != http.StatusOK {
|
||
|
|
t.Errorf("render page: got %d, want 200", rr.Code)
|
||
|
|
}
|
||
|
|
|
||
|
|
body := rr.Body.String()
|
||
|
|
if !strings.Contains(body, "Logg inn") {
|
||
|
|
t.Error("page should contain title")
|
||
|
|
}
|
||
|
|
ct := rr.Header().Get("Content-Type")
|
||
|
|
if !strings.Contains(ct, "text/html") {
|
||
|
|
t.Errorf("content-type = %q, want text/html", ct)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRenderPageWithData(t *testing.T) {
|
||
|
|
r := testRenderer(t)
|
||
|
|
|
||
|
|
req := httptest.NewRequest("GET", "/", nil)
|
||
|
|
rr := httptest.NewRecorder()
|
||
|
|
|
||
|
|
r.Page(rr, req, "login", PageData{
|
||
|
|
Title: "Test Page",
|
||
|
|
SiteName: "My Site",
|
||
|
|
BasePath: "/base",
|
||
|
|
})
|
||
|
|
|
||
|
|
body := rr.Body.String()
|
||
|
|
if !strings.Contains(body, "Test Page") {
|
||
|
|
t.Error("should contain title in output")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRenderMissingTemplate(t *testing.T) {
|
||
|
|
r := testRenderer(t)
|
||
|
|
|
||
|
|
req := httptest.NewRequest("GET", "/", nil)
|
||
|
|
rr := httptest.NewRecorder()
|
||
|
|
|
||
|
|
r.Page(rr, req, "nonexistent_template_xyz", PageData{})
|
||
|
|
|
||
|
|
if rr.Code != http.StatusInternalServerError {
|
||
|
|
t.Errorf("missing template: got %d, want 500", rr.Code)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRenderErrorPage(t *testing.T) {
|
||
|
|
r := testRenderer(t)
|
||
|
|
|
||
|
|
req := httptest.NewRequest("GET", "/", nil)
|
||
|
|
rr := httptest.NewRecorder()
|
||
|
|
|
||
|
|
r.Error(rr, req, http.StatusNotFound, "Ikke funnet")
|
||
|
|
|
||
|
|
if rr.Code != http.StatusNotFound {
|
||
|
|
t.Errorf("error page: got %d, want 404", rr.Code)
|
||
|
|
}
|
||
|
|
body := rr.Body.String()
|
||
|
|
if !strings.Contains(body, "Ikke funnet") {
|
||
|
|
t.Error("error page should contain message")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRenderPopulatesCommonData(t *testing.T) {
|
||
|
|
cfg := &config.Config{
|
||
|
|
SiteName: "Favoritter",
|
||
|
|
BasePath: "/app",
|
||
|
|
ExternalURL: "https://example.com",
|
||
|
|
}
|
||
|
|
r, err := New(cfg)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("create renderer: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
req := httptest.NewRequest("GET", "/", nil)
|
||
|
|
// Add a CSRF token to the context.
|
||
|
|
type contextKey string
|
||
|
|
ctx := context.WithValue(req.Context(), contextKey("csrf_token"), "test-token")
|
||
|
|
req = req.WithContext(ctx)
|
||
|
|
|
||
|
|
rr := httptest.NewRecorder()
|
||
|
|
r.Page(rr, req, "login", PageData{Title: "Test"})
|
||
|
|
|
||
|
|
// BasePath and SiteName should be populated from config.
|
||
|
|
body := rr.Body.String()
|
||
|
|
if !strings.Contains(body, "/app") {
|
||
|
|
t.Error("should contain basePath from config")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestTemplateFuncs(t *testing.T) {
|
||
|
|
cfg := &config.Config{BasePath: "/test", ExternalURL: "https://example.com"}
|
||
|
|
r, _ := New(cfg)
|
||
|
|
|
||
|
|
funcs := r.templateFuncs()
|
||
|
|
|
||
|
|
// Test truncate function.
|
||
|
|
truncate := funcs["truncate"].(func(int, string) string)
|
||
|
|
if got := truncate(5, "Hello, world!"); got != "Hello..." {
|
||
|
|
t.Errorf("truncate(5, long) = %q, want Hello...", got)
|
||
|
|
}
|
||
|
|
if got := truncate(20, "Short"); got != "Short" {
|
||
|
|
t.Errorf("truncate(20, short) = %q, want Short", got)
|
||
|
|
}
|
||
|
|
// Test with Norwegian characters (Ærlig = 5 runes: Æ r l i g).
|
||
|
|
if got := truncate(3, "Ærlig"); got != "Ærl..." {
|
||
|
|
t.Errorf("truncate(3, Ærlig) = %q, want Ærl...", got)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test add/subtract.
|
||
|
|
add := funcs["add"].(func(int, int) int)
|
||
|
|
if add(2, 3) != 5 {
|
||
|
|
t.Error("add(2,3) should be 5")
|
||
|
|
}
|
||
|
|
sub := funcs["subtract"].(func(int, int) int)
|
||
|
|
if sub(5, 3) != 2 {
|
||
|
|
t.Error("subtract(5,3) should be 2")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test basePath function.
|
||
|
|
bp := funcs["basePath"].(func() string)
|
||
|
|
if bp() != "/test" {
|
||
|
|
t.Errorf("basePath() = %q", bp())
|
||
|
|
}
|
||
|
|
}
|