import { describe, it, expect } from "vitest"; import { filterPlaceholders, generateContext, type ContextOptions, } from "./index.js"; import { makeCompiledFragment, makeCompiledBlock } from "../test-utils.js"; // --------------------------------------------------------------------------- // filterPlaceholders // --------------------------------------------------------------------------- describe("filterPlaceholders", () => { it("returns empty array for undefined input", () => { expect(filterPlaceholders(undefined)).toEqual([]); }); it("returns empty array for empty array input", () => { expect(filterPlaceholders([])).toEqual([]); }); it("filters text matching pattern 1: ' component is needed'", () => { expect(filterPlaceholders(["Button component is needed"])).toEqual([]); }); it("filters text matching pattern 2: 'Alternative component is more appropriate'", () => { expect( filterPlaceholders(["Alternative component is more appropriate"]) ).toEqual([]); }); it("filters text matching pattern 3: 'Use when you need'", () => { expect(filterPlaceholders(["Use Button when you need"])).toEqual([]); }); it("keeps real usage text", () => { const items = ["Triggering an action", "Submitting a form"]; expect(filterPlaceholders(items)).toEqual(items); }); it("keeps text that partially matches but does not fully match patterns", () => { const items = [ "The Button component is needed for this", "Use wisely", ]; expect(filterPlaceholders(items)).toEqual(items); }); it("filters placeholder text with leading/trailing whitespace", () => { expect( filterPlaceholders([" Button component is needed "]) ).toEqual([]); }); }); // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function makeFragmentPair() { const button = makeCompiledFragment(); const input = makeCompiledFragment({ meta: { name: "Input", description: "A text input field", category: "forms", status: "stable", tags: ["form"], }, usage: { when: ["Collecting text from user"], whenNot: ["Selecting from predefined options"], }, props: { placeholder: { type: "string", description: "Placeholder text", }, }, variants: [{ name: "Default", description: "Default input", code: "" }], }); return [button, input]; } // --------------------------------------------------------------------------- // generateContext — markdown format // --------------------------------------------------------------------------- describe("generateContext — markdown format", () => { const fragments = makeFragmentPair(); it("contains '# Design System Reference' header", () => { const { content } = generateContext(fragments); expect(content).toContain("# Design System Reference"); }); it("contains '## Quick Reference' table", () => { const { content } = generateContext(fragments); expect(content).toContain("## Quick Reference"); expect(content).toContain("| Component | Category | Use For |"); }); it("table rows are sorted by category then name", () => { const { content } = generateContext(fragments); const tableRows = content .split("\n") .filter((l) => l.startsWith("| ") && !l.startsWith("| Component") && !l.startsWith("|---")); expect(tableRows[0]).toContain("Button"); expect(tableRows[0]).toContain("actions"); expect(tableRows[1]).toContain("Input"); expect(tableRows[1]).toContain("forms"); }); it("non-compact output contains '## Components' section", () => { const { content } = generateContext(fragments); expect(content).toContain("## Components"); }); it("component sections have ### heading with name", () => { const { content } = generateContext(fragments); expect(content).toContain("### Button"); expect(content).toContain("### Input"); }); it("shows category and status", () => { const { content } = generateContext(fragments); expect(content).toContain("**Category:** actions"); expect(content).toContain("**Status:** stable"); }); it("shows description", () => { const { content } = generateContext(fragments); expect(content).toContain("A clickable button element"); }); it("shows 'When to use' and 'When NOT to use' lists", () => { const { content } = generateContext(fragments); expect(content).toContain("**When to use:**"); expect(content).toContain("- Triggering an action"); expect(content).toContain("**When NOT to use:**"); expect(content).toContain("- Navigating to another page"); }); it("shows props with formatted types", () => { const { content } = generateContext(fragments); expect(content).toContain('`variant`: "primary" | "secondary" | "ghost"'); expect(content).toContain('`size`: "sm" | "md" | "lg"'); expect(content).toContain("`disabled`:"); }); it("shows variant names", () => { const { content } = generateContext(fragments); expect(content).toContain("**Variants:** Primary, Secondary"); }); it("with code option shows code blocks for variants", () => { const { content } = generateContext(fragments, { include: { code: true }, }); expect(content).toContain("```tsx"); expect(content).toContain(""); }); it("with relations option shows related components", () => { const seg = makeCompiledFragment({ relations: [ { component: "Link", relationship: "alternative", note: "For navigation" }, ], }); const { content } = generateContext([seg], { include: { relations: true }, }); expect(content).toContain("**Related:**"); expect(content).toContain("- Link (alternative): For navigation"); }); it("includes blocks section when blocks provided", () => { const block = makeCompiledBlock(); const { content } = generateContext(fragments, {}, [block]); expect(content).toContain("## Blocks"); expect(content).toContain("Composition patterns"); }); it("block has name, description, category, components, and code", () => { const block = makeCompiledBlock(); const { content } = generateContext(fragments, {}, [block]); expect(content).toContain("### Login Form"); expect(content).toContain("A standard login form"); expect(content).toContain("**Category:** authentication"); expect(content).toContain("**Components:** Input, Button"); expect(content).toContain("**Tags:** auth, form"); expect(content).toContain(''); }); }); // --------------------------------------------------------------------------- // generateContext — markdown compact // --------------------------------------------------------------------------- describe("generateContext — markdown compact", () => { const fragments = makeFragmentPair(); it("contains Quick Reference table", () => { const { content } = generateContext(fragments, { compact: true }); expect(content).toContain("## Quick Reference"); expect(content).toContain("| Button |"); }); it("does NOT contain '## Components' section", () => { const { content } = generateContext(fragments, { compact: true }); expect(content).not.toContain("## Components"); }); it("tokenEstimate equals Math.ceil(content.length / 4)", () => { const result = generateContext(fragments, { compact: true }); expect(result.tokenEstimate).toBe(Math.ceil(result.content.length / 4)); }); }); // --------------------------------------------------------------------------- // generateContext — markdown include options // --------------------------------------------------------------------------- describe("generateContext — markdown include options", () => { const fragments = makeFragmentPair(); it("include.props=false omits props listing", () => { const { content } = generateContext(fragments, { include: { props: false }, }); expect(content).not.toContain("**Props:**"); }); it("include.variants=false omits variants listing", () => { const { content } = generateContext(fragments, { include: { variants: false }, }); expect(content).not.toContain("**Variants:**"); }); it("include.usage=false omits when/whenNot lists", () => { const { content } = generateContext(fragments, { include: { usage: false }, }); expect(content).not.toContain("**When to use:**"); expect(content).not.toContain("**When NOT to use:**"); }); }); // --------------------------------------------------------------------------- // generateContext — JSON format // --------------------------------------------------------------------------- describe("generateContext — JSON format", () => { const fragments = makeFragmentPair(); const opts: ContextOptions = { format: "json" }; it("returns valid JSON", () => { const { content } = generateContext(fragments, opts); expect(() => JSON.parse(content)).not.toThrow(); }); it("has version '1.0' and a valid generatedAt ISO string", () => { const { content } = generateContext(fragments, opts); const json = JSON.parse(content); expect(json.version).toBe("1.0"); expect(json.generatedAt).toMatch( /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/ ); }); it("has summary with totalComponents and categories", () => { const { content } = generateContext(fragments, opts); const json = JSON.parse(content); expect(json.summary.totalComponents).toBe(2); expect(json.summary.categories).toEqual(["actions", "forms"]); }); it("has components keyed by name", () => { const { content } = generateContext(fragments, opts); const json = JSON.parse(content); expect(json.components).toHaveProperty("Button"); expect(json.components).toHaveProperty("Input"); }); it("component has category, description, and status", () => { const { content } = generateContext(fragments, opts); const json = JSON.parse(content); const btn = json.components.Button; expect(btn.category).toBe("actions"); expect(btn.description).toBe("A clickable button element"); expect(btn.status).toBe("stable"); }); it("has whenToUse and whenNotToUse arrays", () => { const { content } = generateContext(fragments, opts); const json = JSON.parse(content); const btn = json.components.Button; expect(btn.whenToUse).toEqual(["Triggering an action", "Submitting a form"]); expect(btn.whenNotToUse).toEqual(["Navigating to another page"]); }); it("has props with type, description, required, and default", () => { const { content } = generateContext(fragments, opts); const json = JSON.parse(content); const variantProp = json.components.Button.props.variant; expect(variantProp.type).toBe('"primary" | "secondary" | "ghost"'); expect(variantProp.description).toBe("Visual style variant"); expect(variantProp.default).toBe("primary"); }); it("has variants as string array", () => { const { content } = generateContext(fragments, opts); const json = JSON.parse(content); expect(json.components.Button.variants).toEqual(["Primary", "Secondary"]); }); it("has blocks section when blocks provided", () => { const block = makeCompiledBlock(); const { content } = generateContext(fragments, opts, [block]); const json = JSON.parse(content); expect(json.blocks).toHaveProperty("Login Form"); expect(json.summary.totalBlocks).toBe(1); expect(json.blocks["Login Form"].components).toEqual(["Input", "Button"]); }); }); // --------------------------------------------------------------------------- // generateContext — JSON compact // --------------------------------------------------------------------------- describe("generateContext — JSON compact", () => { it("omits whenToUse, props, and variants from components", () => { const fragments = makeFragmentPair(); const { content } = generateContext(fragments, { format: "json", compact: true, }); const json = JSON.parse(content); const btn = json.components.Button; expect(btn.whenToUse).toBeUndefined(); expect(btn.props).toBeUndefined(); expect(btn.variants).toBeUndefined(); // Still has basic info expect(btn.category).toBe("actions"); expect(btn.description).toBe("A clickable button element"); }); }); // --------------------------------------------------------------------------- // Indirect testing (formatPropType, truncate, estimateTokens) // --------------------------------------------------------------------------- describe("Indirect testing", () => { it("enum prop type formatted as '\"val1\" | \"val2\"'", () => { const seg = makeCompiledFragment({ props: { color: { type: "enum", values: ["red", "blue"], description: "Color", }, }, }); const { content } = generateContext([seg]); expect(content).toContain('"red" | "blue"'); }); it("prop with default formatted as 'type (default: value)'", () => { const seg = makeCompiledFragment({ props: { disabled: { type: "boolean", default: false, description: "Disabled state", }, }, }); const { content } = generateContext([seg]); expect(content).toContain("boolean (default: false)"); }); it("simple prop type returned as-is", () => { const seg = makeCompiledFragment({ props: { label: { type: "string", description: "Label text", }, }, }); const { content } = generateContext([seg]); expect(content).toContain("`label`: string"); }); it("long useFor text truncated with '...' at 50 chars", () => { const longText = "This is a very long description that definitely exceeds fifty characters in length"; const seg = makeCompiledFragment({ usage: { when: [longText], whenNot: [] }, }); const { content } = generateContext([seg]); // Quick Reference table should contain truncated text const tableLines = content .split("\n") .filter((l) => l.startsWith("| ") && l.includes("Button")); expect(tableLines[0].length).toBeLessThan( tableLines[0].indexOf("| ", 2) + longText.length ); expect(tableLines[0]).toContain("..."); }); it("tokenEstimate approximately equals Math.ceil(content.length / 4)", () => { const seg = makeCompiledFragment(); const result = generateContext([seg]); expect(result.tokenEstimate).toBe(Math.ceil(result.content.length / 4)); }); }); // --------------------------------------------------------------------------- // Composition and contract data in markdown // --------------------------------------------------------------------------- describe("generateContext — composition and contract", () => { it("includes composition pattern and sub-components in markdown", () => { const seg = makeCompiledFragment({ ai: { compositionPattern: "compound", subComponents: ["Header", "Body", "Footer"], requiredChildren: ["Body"], commonPatterns: ["{content}"], }, }); const { content } = generateContext([seg]); expect(content).toContain("**Composition:** compound"); expect(content).toContain("Button.Header"); expect(content).toContain("Button.Body"); expect(content).toContain("Button.Footer"); expect(content).toContain("Required: Button.Body"); }); it("includes common patterns in markdown", () => { const seg = makeCompiledFragment({ ai: { compositionPattern: "compound", subComponents: ["Body"], commonPatterns: [ "{x}", "{x}", ], }, }); const { content } = generateContext([seg]); expect(content).toContain("**Patterns:**"); expect(content).toContain("`{x}`"); expect(content).toContain("`{x}`"); }); it("uses contract.propsSummary when available in markdown", () => { const seg = makeCompiledFragment({ contract: { propsSummary: ["variant: primary|secondary (default: primary)", "size: sm|md|lg"], }, }); const { content } = generateContext([seg]); expect(content).toContain("**Props:** variant: primary|secondary (default: primary), size: sm|md|lg"); }); it("includes a11yRules in markdown", () => { const seg = makeCompiledFragment({ contract: { a11yRules: ["Must have aria-label", "Focus visible required"], }, }); const { content } = generateContext([seg]); expect(content).toContain("**A11y:** Must have aria-label, Focus visible required"); }); it("includes bans in markdown", () => { const seg = makeCompiledFragment({ contract: { bans: [{ pattern: "onClick", message: "Use onPress instead" }], }, }); const { content } = generateContext([seg]); expect(content).toContain("**Banned patterns:**"); expect(content).toContain("`onClick`: Use onPress instead"); }); it("includes composition in JSON format", () => { const seg = makeCompiledFragment({ ai: { compositionPattern: "compound", subComponents: ["Header", "Body"], requiredChildren: ["Body"], commonPatterns: [""], }, }); const { content } = generateContext([seg], { format: "json" }); const json = JSON.parse(content); expect(json.components.Button.composition).toEqual({ pattern: "compound", subComponents: ["Header", "Body"], requiredChildren: ["Body"], commonPatterns: [""], }); }); it("includes propsSummary in JSON format", () => { const seg = makeCompiledFragment({ contract: { propsSummary: ["variant: enum", "size: enum"], }, }); const { content } = generateContext([seg], { format: "json" }); const json = JSON.parse(content); expect(json.components.Button.propsSummary).toEqual(["variant: enum", "size: enum"]); }); it("includes a11yRules and bans in JSON format", () => { const seg = makeCompiledFragment({ contract: { a11yRules: ["Must be focusable"], bans: [{ pattern: "div>", message: "Use semantic elements" }], }, }); const { content } = generateContext([seg], { format: "json" }); const json = JSON.parse(content); expect(json.components.Button.a11yRules).toEqual(["Must be focusable"]); expect(json.components.Button.bans).toEqual([{ pattern: "div>", message: "Use semantic elements" }]); }); it("includes compoundChildren in markdown", () => { const seg = makeCompiledFragment({ contract: { compoundChildren: { Header: { description: "Card header section" }, Body: { required: true, description: "Card body content" }, Footer: { accepts: ["children"] }, }, }, }); const { content } = generateContext([seg]); expect(content).toContain("**Sub-components:**"); expect(content).toContain("`Button.Header`"); expect(content).toContain("`Button.Body` (required)"); expect(content).toContain("— Card body content"); expect(content).toContain("`Button.Footer`"); }); it("includes canonicalUsage in markdown", () => { const seg = makeCompiledFragment({ contract: { canonicalUsage: [ '\n Title\n Content\n', ], }, }); const { content } = generateContext([seg]); expect(content).toContain("**Usage examples:**"); expect(content).toContain("```tsx"); expect(content).toContain("Title"); }); it("includes compoundChildren in JSON format", () => { const seg = makeCompiledFragment({ contract: { compoundChildren: { Header: { description: "Header slot" }, Body: { required: true }, }, }, }); const { content } = generateContext([seg], { format: "json" }); const json = JSON.parse(content); expect(json.components.Button.compoundChildren).toEqual({ Header: { description: "Header slot" }, Body: { required: true }, }); }); it("includes canonicalUsage in JSON format", () => { const seg = makeCompiledFragment({ contract: { canonicalUsage: ["..."], }, }); const { content } = generateContext([seg], { format: "json" }); const json = JSON.parse(content); expect(json.components.Button.canonicalUsage).toEqual([ "...", ]); }); });