package fiesta import ( "bytes" "io/fs" "slices" "sort" "strings" "testing" ) // The root package is the design system's files, embedded, behind a // handful of accessors. These tests hold the accessors to the tree: // every name a list returns is a file that is there, every file that // is there is a name a list returns, and what an accessor hands back // is the same bytes a caller would read from FS(). // readFS reads one path from FS(), failing the test when the tree // is not there at all rather than letting a nil fs.FS panic the // binary and hide every other test's verdict. func readFS(t *testing.T, path string) []byte { t.Helper() tree := FS() if tree == nil { t.Fatalf("FS() is nil; the embedded tree is missing") } b, err := fs.ReadFile(tree, path) if err != nil { t.Fatalf("FS() has no %s: %v", path, err) } return b } // listFS names the files under one directory of FS(), base names // only, sorted. func listFS(t *testing.T, dir string) []string { t.Helper() tree := FS() if tree == nil { t.Fatalf("FS() is nil; the embedded tree is missing") } entries, err := fs.ReadDir(tree, dir) if err != nil { t.Fatalf("FS() has no directory %s: %v", dir, err) } var names []string for _, e := range entries { if !e.IsDir() { names = append(names, e.Name()) } } sort.Strings(names) return names } func TestTheStylesheetsAreEmbedded(t *testing.T) { for _, tc := range []struct { name string got []byte path string }{ {"TokensCSS", TokensCSS(), "css/tokens.css"}, {"ShellCSS", ShellCSS(), "css/shell.css"}, } { if len(tc.got) == 0 { t.Errorf("%s() is empty", tc.name) continue } if want := readFS(t, tc.path); !bytes.Equal(tc.got, want) { t.Errorf("%s() differs from FS()'s %s", tc.name, tc.path) } } } func TestEveryThemeIsEmbedded(t *testing.T) { want := []string{"day", "plain", "signal"} if got := ThemeNames(); !slices.Equal(got, want) { t.Fatalf("ThemeNames() = %q, want %q", got, want) } for _, name := range want { css, ok := ThemeCSS(name) if !ok { t.Errorf("ThemeCSS(%q) reports no such theme", name) continue } if !bytes.Contains(css, []byte(":root")) { t.Errorf("ThemeCSS(%q) has no :root block", name) } if embedded := readFS(t, "css/themes/"+name+".css"); !bytes.Equal(css, embedded) { t.Errorf("ThemeCSS(%q) differs from FS()'s css/themes/%s.css", name, name) } } if _, ok := ThemeCSS("nope"); ok { t.Errorf("ThemeCSS(%q) reports a theme that is not shipped", "nope") } var files []string for _, f := range listFS(t, "css/themes") { files = append(files, strings.TrimSuffix(f, ".css")) } if !slices.Equal(files, want) { t.Errorf("css/themes/ holds %q, but ThemeNames() lists %q", files, want) } } func TestEveryScriptIsEmbedded(t *testing.T) { want := []string{"fiesta.js", "busy.js", "light.js", "anchor.js", "shell.js", "transition.js", "copy.js", "select.js", "datetime.js", "calendar.js"} if got := ScriptNames(); !slices.Equal(got, want) { t.Fatalf("ScriptNames() = %q, want %q", got, want) } for _, name := range want { js, ok := Script(name) if !ok { t.Errorf("Script(%q) reports no such script", name) continue } if len(js) == 0 { t.Errorf("Script(%q) is empty", name) } if embedded := readFS(t, "js/"+name); !bytes.Equal(js, embedded) { t.Errorf("Script(%q) differs from FS()'s js/%s", name, name) } } if _, ok := Script("nope.js"); ok { t.Errorf("Script(%q) reports a script that is not shipped", "nope.js") } files := listFS(t, "js") sorted := slices.Clone(want) sort.Strings(sorted) if !slices.Equal(files, sorted) { t.Errorf("js/ holds %q, but ScriptNames() lists %q", files, want) } } func TestEveryLanguageIsEmbedded(t *testing.T) { want := []string{"en", "ar", "bn", "es", "ga", "hi", "ja", "pt-PT", "ru", "vi", "yue", "zh-Hans"} if got := Languages(); !slices.Equal(got, want) { t.Fatalf("Languages() = %q, want %q", got, want) } for _, lang := range want { b, ok := Strings(lang) if !ok { t.Errorf("Strings(%q) reports no such language", lang) continue } if len(b) == 0 { t.Errorf("Strings(%q) is empty", lang) } if embedded := readFS(t, "i18n/"+lang+".json"); !bytes.Equal(b, embedded) { t.Errorf("Strings(%q) differs from FS()'s i18n/%s.json", lang, lang) } } // pt is the test alias, never a file; a miss is false, not a panic. for _, bad := range []string{"pt", "nope", "../LICENSE"} { if _, ok := Strings(bad); ok { t.Errorf("Strings(%q) reports a language that is not shipped", bad) } } files := listFS(t, "i18n") var sorted []string for _, lang := range want { sorted = append(sorted, lang+".json") } sort.Strings(sorted) if !slices.Equal(files, sorted) { t.Errorf("i18n/ holds %q, but Languages() lists %q", files, want) } } func TestEveryIconIsOneLucideSVG(t *testing.T) { want := []string{ "alert-triangle", "check", "check-circle", "chevron-down", "help-circle", "info", "kebab", "menu", "plus", "search", "x", "x-circle", } got := IconSlugs() if len(got) != 12 { t.Errorf("IconSlugs() lists %d slugs, want 12: %q", len(got), got) } if !sort.StringsAreSorted(got) { t.Errorf("IconSlugs() is not sorted: %q", got) } if !slices.Equal(got, want) { t.Fatalf("IconSlugs() = %q, want %q", got, want) } const open = `") { t.Errorf("Icon(%q) does not end : %q", slug, s) } if strings.Count(s, " elements, want 1", slug, strings.Count(s, "