PageTemplate/BlockTemplate/EmailWrapper return errors instead of panicking so hosts can compile artifact-supplied templates at load time (codeless themes) without a malformed artifact taking down the process; Must* variants delegate. The 'lines' filter splits a string into trimmed non-empty lines — pongo2 string literals cannot express \n, so multi-line textarea fields (per-line <div> addresses) were previously inexpressible in templates. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
67 lines
2.2 KiB
Go
67 lines
2.2 KiB
Go
package pongo
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"testing/fstest"
|
|
|
|
"git.dev.alexdunmow.com/block/core/templates"
|
|
)
|
|
|
|
func TestNonPanickingCompileVariants(t *testing.T) {
|
|
fsys := fstest.MapFS{
|
|
"templates/theme/default.ninjatpl": {Data: []byte(`<main>{{ slots.main|safe }}</main>`)},
|
|
"templates/overrides/theme/heading.ninjatpl": {Data: []byte(`<h2>{{ text }}</h2>`)},
|
|
"templates/email/theme.ninjatpl": {Data: []byte(`<table>{{ body|safe }} {{ colors.mutedForeground }}</table>`)},
|
|
"templates/broken.ninjatpl": {Data: []byte(`{% if %}`)},
|
|
}
|
|
e := NewEngine(fsys)
|
|
|
|
if _, err := e.PageTemplate("templates/theme/default.ninjatpl"); err != nil {
|
|
t.Fatalf("PageTemplate: %v", err)
|
|
}
|
|
bf, err := e.BlockTemplate("templates/overrides/theme/heading.ninjatpl")
|
|
if err != nil {
|
|
t.Fatalf("BlockTemplate: %v", err)
|
|
}
|
|
if got := bf(t.Context(), map[string]any{"text": "hi"}); got != "<h2>hi</h2>" {
|
|
t.Errorf("override render = %q", got)
|
|
}
|
|
ef, err := e.EmailWrapper("templates/email/theme.ninjatpl")
|
|
if err != nil {
|
|
t.Fatalf("EmailWrapper: %v", err)
|
|
}
|
|
ectx := templates.EmailContext{}
|
|
ectx.Colors.MutedForeground = "#6c5b35"
|
|
if got := ef("<p>x</p>", ectx); got != "<table><p>x</p> #6c5b35</table>" {
|
|
t.Errorf("email render = %q", got)
|
|
}
|
|
|
|
// Malformed templates return errors — no panic (hot-install safety).
|
|
if _, err := e.PageTemplate("templates/broken.ninjatpl"); err == nil {
|
|
t.Error("PageTemplate on broken template: want error")
|
|
}
|
|
if _, err := e.BlockTemplate("templates/missing.ninjatpl"); err == nil {
|
|
t.Error("BlockTemplate on missing file: want error")
|
|
}
|
|
}
|
|
|
|
func TestLinesFilter(t *testing.T) {
|
|
fsys := fstest.MapFS{
|
|
"t.ninjatpl": {Data: []byte(`{% for l in address|lines %}<div>{{ l }}</div>{% endfor %}`)},
|
|
}
|
|
e := NewEngine(fsys)
|
|
bf, err := e.BlockTemplate("t.ninjatpl")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := bf(t.Context(), map[string]any{"address": "1 Meridian Plaza\r\n Floor 2 \n\nNew Gotham"})
|
|
want := "<div>1 Meridian Plaza</div><div>Floor 2</div><div>New Gotham</div>"
|
|
if got != want {
|
|
t.Errorf("lines render = %q, want %q", got, want)
|
|
}
|
|
if strings.Contains(got, "\n") {
|
|
t.Error("unexpected raw newline in output")
|
|
}
|
|
}
|