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