import { createRawSnippet } from "svelte"; import { describe, expect, it, vi } from "vitest"; import { Card } from "./fixtures/surface-separation-consumer"; import { classes, render, rendered } from "./mount"; // `info` is feedback-info here as on every component (ADR 0026); `brand` is a // deprecated value kept one release with its accent fill. const tones = ["neutral", "brand", "success", "warning", "danger", "info"] as const; const variants = ["outline", "plain"] as const; const orientations = ["vertical", "horizontal"] as const; const contracts = { neutral: { surface: "bg-elevation-raised-surface", border: "border-muted", foreground: "text-foreground", description: "text-ink-muted", }, brand: { surface: "bg-[var(--reddb-color-primary)]", border: "border-[var(--reddb-color-primary)]", foreground: "text-[var(--reddb-color-on-primary)]", description: "text-[var(--reddb-color-on-primary)]", }, success: { surface: "bg-[var(--reddb-color-feedback-success-surface)]", border: "border-[var(--reddb-color-feedback-success-border)]", foreground: "text-[var(--reddb-color-feedback-success-foreground)]", description: "text-[var(--reddb-color-feedback-success-foreground)]", }, warning: { surface: "bg-[var(--reddb-color-feedback-warning-surface)]", border: "border-[var(--reddb-color-feedback-warning-border)]", foreground: "text-[var(--reddb-color-feedback-warning-foreground)]", description: "text-[var(--reddb-color-feedback-warning-foreground)]", }, danger: { surface: "bg-[var(--reddb-color-feedback-danger-surface)]", border: "border-[var(--reddb-color-feedback-danger-border)]", foreground: "text-[var(--reddb-color-feedback-danger-foreground)]", description: "text-[var(--reddb-color-feedback-danger-foreground)]", }, info: { surface: "bg-[var(--reddb-color-feedback-info-surface)]", border: "border-[var(--reddb-color-feedback-info-border)]", foreground: "text-[var(--reddb-color-feedback-info-foreground)]", description: "text-[var(--reddb-color-feedback-info-foreground)]", }, } as const; const content = createRawSnippet(() => ({ render: () => "Body" })); const media = createRawSnippet(() => ({ render: () => '' })); describe("the Base Card tone contract", () => { it("warns once in development when the deprecated brand tone is used", () => { const warn = vi.spyOn(console, "warn").mockImplementation(() => {}); try { rendered(render(Card, { tone: "info", title: "Info" })); expect(warn).not.toHaveBeenCalled(); rendered(render(Card, { tone: "brand", title: "Brand" })); rendered(render(Card, { tone: "brand", title: "Brand" })); expect(warn).toHaveBeenCalledTimes(1); expect(String(warn.mock.calls[0]![0])).toMatch(/\[reddb Card\] tone="brand" is deprecated/); } finally { warn.mockRestore(); } }); it("composes every token-owned tone with both variants and orientations", () => { for (const tone of tones) { for (const variant of variants) { for (const orientation of orientations) { const card = rendered( render(Card, { tone, variant, orientation, title: "Title", description: "Description", children: content, footer: content, media, }), ); const contract = contracts[tone]; expect(card.dataset.tone).toBe(tone); expect(classes(card).has(contract.surface), `${tone}/${variant}/${orientation}`).toBe(true); expect(classes(card).has(contract.foreground), `${tone}/${variant}/${orientation}`).toBe(true); expect(classes(card).has(variant === "outline" ? contract.border : "border-transparent")).toBe(true); for (const selector of ["[data-card-header]", "[data-card-title]", "[data-card-body]", "[data-card-footer]"]) { expect(classes(card.querySelector(selector)!).has(contract.foreground), `${tone} ${selector}`).toBe(true); } expect(classes(card.querySelector("[data-card-description]")!).has(contract.description)).toBe(true); const mediaClasses = classes(card.querySelector("[data-card-media]")!); expect([...mediaClasses].some((name) => name.startsWith("bg-") || name.startsWith("text-"))).toBe(false); } } } }); });