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") }