package jsbundler
import (
"os"
"path/filepath"
"testing"
)
// scanIconNames has to see every authoring style used across the apps. Both are
// live in the same file in practice: a page written as a solid-js/html tagged
// template says icon=${"bell"}, while a .tsx page says icon={"bell"} or
// icon="bell". An icon the scanner misses is not a build error — it is simply
// absent from the generated registry and renders as a blank space at runtime,
// which is exactly how a missing bell/circle-question went unnoticed.
func TestScanIconNamesAcrossAuthoringStyles(t *testing.T) {
dir := t.TempDir()
src := `
// plain attribute (JSX or template)
// JSX dynamic expression
// solid-js/html tagged template — interpolated string
<${Icon} icon=${"bell"} size=${28} />
<${Icon} icon=${"circle-question"} size=${28} />
// object-literal property
const item = { icon: "chart-line", label: "Reports" };
// dynamic expressions: every string literal inside is a candidate
<${Icon} icon=${busy ? "spinner" : "check"} />
// an in-app custom icon
registerIcon("playground", "");
`
if err := os.WriteFile(filepath.Join(dir, "page.tsx"), []byte(src), 0644); err != nil {
t.Fatal(err)
}
names, custom, err := scanIconNames([]string{dir})
if err != nil {
t.Fatalf("scanIconNames: %v", err)
}
found := make(map[string]bool, len(names))
for _, n := range names {
found[n] = true
}
for _, want := range []string{
"notebook", // icon="name"
"gear", // icon={"name"}
"bell", // icon=${"name"} <- the regression
"circle-question", // icon=${"name"} <- the regression
"chart-line", // icon: "name"
"chevron-up", "chevron-down", // JSX ternary
"spinner", "check", // template-literal ternary
} {
if !found[want] {
t.Errorf("icon %q was not scanned; it would render blank at runtime", want)
}
}
if !custom["playground"] {
t.Error("registerIcon(\"playground\") was not picked up as a custom icon")
}
}