package main import ( "os" "path/filepath" "strings" "testing" ) func TestCheckTemplColorsFlagsHardcodedColorsAndInlineStyles(t *testing.T) { root := t.TempDir() file := filepath.Join(root, "sample.templ") content := `package sample templ Example() {
} ` if err := os.WriteFile(file, []byte(content), 0644); err != nil { t.Fatalf("write sample templ: %v", err) } violations := checkTemplColors(root) if len(violations) < 5 { t.Fatalf("checkTemplColors() returned %d violations, want at least 5: %#v", len(violations), violations) } rules := map[string]bool{} for _, violation := range violations { rules[violation.rule] = true } for _, rule := range []string{ "no-hardcoded-tw-color", "no-hex-in-class", "no-tw-arbitrary-hex", "no-inline-hex-style", "no-inline-rgb-style", } { if !rules[rule] { t.Fatalf("missing rule %q in violations: %#v", rule, violations) } } } func TestCheckTemplColorsAllowsSemanticTokensAndCSSVariables(t *testing.T) { root := t.TempDir() file := filepath.Join(root, "sample.templ") content := `package sample templ Example() {
} ` if err := os.WriteFile(file, []byte(content), 0644); err != nil { t.Fatalf("write sample templ: %v", err) } violations := checkTemplColors(root) if len(violations) != 0 { t.Fatalf("checkTemplColors() returned %d violations, want 0: %#v", len(violations), violations) } } func TestCheckNinjaTplColorsFlagsHardcodedColors(t *testing.T) { root := t.TempDir() tplDir := filepath.Join(root, "templates", "blocks") if err := os.MkdirAll(tplDir, 0755); err != nil { t.Fatalf("mkdir: %v", err) } file := filepath.Join(tplDir, "hero.ninjatpl") content := `

{{ headline }}

{{ subtext }}

{{ primary_cta }}
hardcoded hex
badge named color
` if err := os.WriteFile(file, []byte(content), 0644); err != nil { t.Fatalf("write ninjatpl: %v", err) } violations := checkNinjaTplColors(root) if len(violations) < 6 { t.Fatalf("checkNinjaTplColors() returned %d violations, want at least 6: %#v", len(violations), violations) } rules := map[string]bool{} for _, v := range violations { rules[v.rule] = true } for _, rule := range []string{ "no-hardcoded-hsl", "no-tw-arbitrary-color", "no-inline-hex", "no-hardcoded-tw-color", } { if !rules[rule] { t.Fatalf("missing rule %q in violations: %#v", rule, violations) } } } func TestCheckNinjaTplColorsAllowsCSSVariablesAndNeutralOverlays(t *testing.T) { root := t.TempDir() tplDir := filepath.Join(root, "templates", "blocks") if err := os.MkdirAll(tplDir, 0755); err != nil { t.Fatalf("mkdir: %v", err) } file := filepath.Join(tplDir, "hero.ninjatpl") content := `

{{ headline }}

{{ subtext }}

{{ cta }}
dark overlay
light overlay
badge
` if err := os.WriteFile(file, []byte(content), 0644); err != nil { t.Fatalf("write ninjatpl: %v", err) } violations := checkNinjaTplColors(root) if len(violations) != 0 { t.Fatalf("checkNinjaTplColors() returned %d violations, want 0: %#v", len(violations), violations) } } func TestFormatColorViolationsGroupsByFile(t *testing.T) { report := formatColorViolations(".ninjatpl files", []colorViolation{ {file: "b.ninjatpl", line: 12, rule: "no-hardcoded-rgb", snippet: "rgba(1,2,3,0.5)"}, {file: "a.ninjatpl", line: 9, rule: "no-hardcoded-hsl", snippet: "hsl(10,20%,30%)"}, {file: "a.ninjatpl", line: 9, rule: "no-tw-arbitrary-color", snippet: "text-[hsl(10,20%,30%)]"}, {file: "a.ninjatpl", line: 4, rule: "no-inline-hex", snippet: "#fff"}, }) expected := strings.Join([]string{ " FAIL: 4 hardcoded color(s) in .ninjatpl files:", " a.ninjatpl", " 4 [no-inline-hex] #fff", " 9 [no-hardcoded-hsl] hsl(10,20%,30%)", " 9 [no-tw-arbitrary-color] text-[hsl(10,20%,30%)]", " b.ninjatpl", " 12 [no-hardcoded-rgb] rgba(1,2,3,0.5)", }, "\n") if report != expected { t.Fatalf("formatColorViolations() mismatch\nwant:\n%s\n\ngot:\n%s", expected, report) } } func TestCollectColorHintsDeduplicatesAndSorts(t *testing.T) { hints := collectColorHints( []colorViolation{ {snippet: "text-blue-500"}, {snippet: "bg-amber-100"}, }, []colorViolation{ {snippet: "text-blue-500"}, {snippet: "text-[hsl(38,52%,54%)]"}, }, ) expected := []string{"bg-warning/10", "hsl(var(--token))", "text-info"} if strings.Join(hints, "|") != strings.Join(expected, "|") { t.Fatalf("collectColorHints() = %#v, want %#v", hints, expected) } }