import { describe, expect, test } from "bun:test"; import { cn } from "@/lib/utils"; // --------------------------------------------------------------------------- // Textarea placeholder - proper padding/margin // // Public interface under test: the resolved className string that the Textarea // component applies. We verify the *behaviour* — that the placeholder text will // always have visible horizontal spacing — not internal implementation details. // // Why class assertions? In a Tailwind / CSS-based component, the class string // IS the public contract. If the right classes are present the browser renders // the right visual; if they are absent the placeholder is flush with the edge. // --------------------------------------------------------------------------- // The base Textarea classes (copied from the component — this is the source of // truth we are locking down). const TEXTAREA_BASE = "border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"; describe("Textarea – placeholder spacing (base defaults)", () => { test("base className includes horizontal padding px-3 so placeholder is not flush", () => { const resolved = cn(TEXTAREA_BASE); // Must contain a non-zero px-* class so placeholder text has left/right space. expect(resolved).toMatch(/\bpx-[1-9]\d*\b/); }); test("base className includes vertical padding py-2 so placeholder is not flush", () => { const resolved = cn(TEXTAREA_BASE); expect(resolved).toMatch(/\bpy-[1-9]\d*\b/); }); }); describe("Textarea – placeholder spacing (with consumer overrides)", () => { // This is the ai-toolbar override — after the fix it uses px-3 py-1 instead of // the original px-0 py-0 which left the placeholder flush against the edge. const AI_TOOLBAR_OVERRIDE = "wrap-anywhere field-sizing-content resize-none w-full min-h-[2.5rem] max-h-64 overflow-y-auto bg-transparent border-0 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 px-3 py-1 text-sm placeholder:text-muted-foreground/60 placeholder:italic"; test("resolved className with ai-toolbar override still retains horizontal padding for placeholder", () => { const resolved = cn(TEXTAREA_BASE, AI_TOOLBAR_OVERRIDE); // After fix: px-0 must NOT win — there should be a positive px-* class present. // twMerge picks the last px-* class; the fix is to change px-0 → px-3 in the // ai-toolbar override so the placeholder keeps its breathing room. expect(resolved).not.toMatch(/\bpx-0\b/); expect(resolved).toMatch(/\bpx-[1-9]\d*\b/); }); test("resolved className with ai-toolbar override retains vertical padding for placeholder", () => { const resolved = cn(TEXTAREA_BASE, AI_TOOLBAR_OVERRIDE); // py-0 should not win; placeholder needs top/bottom breathing room too. expect(resolved).not.toMatch(/\bpy-0\b/); expect(resolved).toMatch(/\bpy-[1-9]\d*\b/); }); });