Files
vibedns/internal/web/templates_test.go
T
2026-08-16 21:18:45 -05:00

121 lines
3.4 KiB
Go

package web
import (
"io/fs"
"path"
"strings"
"testing"
webui "github.com/owen/vibedns/web"
)
// TestTemplatesParse fails the build if any embedded template has a syntax
// error or calls a function that is not registered. Without this, a typo in a
// template only surfaces when a user opens that particular page.
func TestTemplatesParse(t *testing.T) {
tmpl, err := loadTemplates(templateFuncs())
if err != nil {
t.Fatalf("templates did not parse: %v", err)
}
pages, err := fs.Glob(webui.Templates(), "pages/*.html")
if err != nil {
t.Fatalf("could not list pages: %v", err)
}
if len(pages) == 0 {
t.Fatal("no page templates were embedded")
}
for _, p := range pages {
name := strings.TrimSuffix(path.Base(p), ".html")
if _, ok := tmpl.sets[name]; !ok {
t.Errorf("page %s produced no template set", name)
}
}
t.Logf("parsed %d page templates", len(pages))
}
// TestEveryRoutedPageHasTemplate guards against a handler rendering a page name
// that does not exist, which would otherwise be a 500 at runtime.
func TestEveryRoutedPageHasTemplate(t *testing.T) {
tmpl, err := loadTemplates(templateFuncs())
if err != nil {
t.Fatalf("templates did not parse: %v", err)
}
// Every name passed to s.render anywhere in the package.
rendered := []string{
"dashboard", "error", "zones", "zone_form", "records", "records_all",
"resolver", "cache", "networks", "network_form", "policies", "policy_form",
"lists", "list_detail", "querylog", "audit", "tools", "account",
"settings_dns", "settings_resolver", "settings_cache", "settings_logging",
"settings_http", "settings_database", "settings_api",
}
for _, name := range rendered {
if _, ok := tmpl.sets[name]; !ok {
t.Errorf("handler renders %q but no such template exists", name)
}
}
}
// TestStaticAssetsEmbedded confirms the offline assets actually made it into
// the binary. The management interface must work without Internet access.
func TestStaticAssetsEmbedded(t *testing.T) {
static := webui.Static()
required := []string{
"css/bootstrap.min.css",
"css/bootstrap-icons.min.css",
"css/app.css",
"js/bootstrap.bundle.min.js",
"js/chart.umd.js",
"js/app.js",
"fonts/bootstrap-icons.woff2",
"img/favicon.svg",
}
for _, name := range required {
f, err := static.Open(name)
if err != nil {
t.Errorf("static asset %s is missing from the binary: %v", name, err)
continue
}
info, err := f.Stat()
if err == nil && info.Size() == 0 {
t.Errorf("static asset %s is empty", name)
}
f.Close()
}
}
// TestNoCDNReferences guards the offline guarantee: a stray absolute URL in a
// template or stylesheet would silently break the UI on an air-gapped network.
func TestNoCDNReferences(t *testing.T) {
check := func(fsys fs.FS, label string) {
err := fs.WalkDir(fsys, ".", func(p string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() {
return err
}
switch path.Ext(p) {
case ".html", ".css", ".js":
default:
return nil
}
body, err := fs.ReadFile(fsys, p)
if err != nil {
return err
}
for _, bad := range []string{"https://cdn.", "http://cdn.", "//cdn.jsdelivr", "//unpkg.com"} {
if strings.Contains(string(body), bad) {
t.Errorf("%s/%s references an external CDN (%q); assets must be served from the binary",
label, p, bad)
}
}
return nil
})
if err != nil {
t.Fatalf("walking %s: %v", label, err)
}
}
check(webui.Templates(), "templates")
check(webui.Static(), "static")
}