Add fonts, autotable, autotable examples
This commit is contained in:
116
go/webui/icons_test.go
Normal file
116
go/webui/icons_test.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package webui
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"kjol/vdom"
|
||||
)
|
||||
|
||||
// An unregistered icon name renders as an empty box: right size, no glyph. Nothing
|
||||
// errors, nothing logs — the icons just quietly aren't there. That is exactly how
|
||||
// this broke, so scan our own source for every name we ask for and assert the
|
||||
// registry has it.
|
||||
func TestEveryIconTheKitUsesIsRegistered(t *testing.T) {
|
||||
// Icon("name", …), IconInline("name", …), and the Icon: "name" struct field.
|
||||
calls := regexp.MustCompile(`\bIcon(?:Inline|Success|Error)?\("([a-z0-9-]+)"`)
|
||||
fields := regexp.MustCompile(`\bIcon:\s*"([a-z0-9-]+)"`)
|
||||
|
||||
files, err := filepath.Glob("*.go")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
used := map[string][]string{} // icon name -> files that ask for it
|
||||
for _, f := range files {
|
||||
if strings.HasSuffix(f, "_test.go") || f == "icons.go" {
|
||||
continue // icons.go is the registry itself
|
||||
}
|
||||
src, err := os.ReadFile(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, re := range []*regexp.Regexp{calls, fields} {
|
||||
for _, m := range re.FindAllStringSubmatch(string(src), -1) {
|
||||
if m[1] == "" {
|
||||
continue
|
||||
}
|
||||
used[m[1]] = append(used[m[1]], f)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Icon names also reach Icon() through lookup tables. Those cannot be found by
|
||||
// scanning call sites, so add them from the tables themselves.
|
||||
for _, name := range toastTypeIcons {
|
||||
if name != "" {
|
||||
used[name] = append(used[name], "toast.go (toastTypeIcons)")
|
||||
}
|
||||
}
|
||||
if len(used) == 0 {
|
||||
t.Fatal("scanned no icon usages — the regexes have rotted")
|
||||
}
|
||||
|
||||
var missing []string
|
||||
for name, where := range used {
|
||||
if _, ok := iconRegistry[name]; !ok {
|
||||
missing = append(missing, name+" (used in "+strings.Join(dedupe(where), ", ")+")")
|
||||
}
|
||||
}
|
||||
sort.Strings(missing)
|
||||
for _, m := range missing {
|
||||
t.Errorf("icon not registered, renders as an empty box: %s", m)
|
||||
}
|
||||
}
|
||||
|
||||
// A registered icon must actually draw something. An entry with empty content is
|
||||
// the same silent failure as a missing one.
|
||||
func TestRegisteredIconsHaveContent(t *testing.T) {
|
||||
for name, def := range iconRegistry {
|
||||
if strings.TrimSpace(def.content) == "" {
|
||||
t.Errorf("icon %q is registered with no SVG content", name)
|
||||
}
|
||||
if !strings.Contains(def.content, "<path") {
|
||||
t.Errorf("icon %q has no <path>: %q", name, def.content)
|
||||
}
|
||||
if def.viewBox == "" {
|
||||
t.Errorf("icon %q has no viewBox", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIconRendersRegisteredContent(t *testing.T) {
|
||||
html := renderNode(Icon("check", 20, "text-red-500"))
|
||||
if !strings.Contains(html, "<path") {
|
||||
t.Errorf("Icon did not render its path: %s", html)
|
||||
}
|
||||
for _, want := range []string{`width="20"`, `height="20"`, "text-red-500", `viewBox="0 0 24 24"`} {
|
||||
if !strings.Contains(html, want) {
|
||||
t.Errorf("Icon output missing %s: %s", want, html)
|
||||
}
|
||||
}
|
||||
// An unknown name still renders a correctly sized, empty box rather than
|
||||
// collapsing the layout.
|
||||
if empty := renderNode(Icon("no-such-icon", 16, "")); strings.Contains(empty, "<path") {
|
||||
t.Errorf("unknown icon drew something: %s", empty)
|
||||
}
|
||||
}
|
||||
|
||||
// renderNode serializes a component's VNode the way the server does.
|
||||
func renderNode(n *vdom.VNode) string { return vdom.RenderHTML(n) }
|
||||
|
||||
func dedupe(xs []string) []string {
|
||||
seen := map[string]bool{}
|
||||
out := []string{}
|
||||
for _, x := range xs {
|
||||
if !seen[x] {
|
||||
seen[x] = true
|
||||
out = append(out, x)
|
||||
}
|
||||
}
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user