Skip to content

Commit 12fd447

Browse files
leopu00claude
andcommitted
test(ui): batch 6 — Card, AlertBanner, Badge (19 test)
Card: 3 varianti, padding 4 livelli, header/footer, hoverable, CardGrid, StatCard. AlertBanner: 4 tipi, Icon SVG, role=alert, dismissible, CTA, AlertBannerStack. Badge: 6 varianti, dot/removable, StatusBadge, CountBadge, BadgeGroup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1342ae8 commit 12fd447

1 file changed

Lines changed: 143 additions & 0 deletions

File tree

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/** Test UI batch 6 — Card, AlertBanner, Badge (LoadingButton non esiste) */
2+
import { describe, it, expect } from "vitest";
3+
import fs from "node:fs";
4+
import path from "node:path";
5+
6+
const WEB = path.resolve(__dirname, "../../../web");
7+
function readSrc(rel: string) { return fs.readFileSync(path.join(WEB, rel), "utf-8"); }
8+
9+
/* ── Card ── */
10+
describe("Card", () => {
11+
const src = readSrc("app/components/Card.tsx");
12+
13+
it("export Card + CardGrid + StatCard + tipi CardVariant/CardPadding + 3 interface", () => {
14+
expect(src).toMatch(/export function Card\b/);
15+
expect(src).toMatch(/export function CardGrid\b/);
16+
expect(src).toMatch(/export function StatCard\b/);
17+
expect(src).toContain("export type CardVariant"); expect(src).toContain("export type CardPadding");
18+
expect(src).toContain("export interface CardProps");
19+
expect(src).toContain("export interface CardGridProps");
20+
expect(src).toContain("export interface StatCardProps");
21+
});
22+
23+
it("VARIANT_STYLE 3: default/outlined/elevated + borderRadius 12", () => {
24+
expect(src).toContain("VARIANT_STYLE");
25+
for (const v of ["default", "outlined", "elevated"]) expect(src).toContain(`${v}:`);
26+
expect(src).toContain("borderRadius: 12");
27+
expect(src).toContain("boxShadow: 'none'"); // default + outlined
28+
expect(src).toContain("background: 'transparent'"); // outlined
29+
});
30+
31+
it("PADDING_CLS 4 livelli + HEADER_PAD + FOOTER_PAD maps", () => {
32+
expect(src).toContain("PADDING_CLS"); expect(src).toContain("HEADER_PAD"); expect(src).toContain("FOOTER_PAD");
33+
for (const p of ["none", "sm", "md", "lg"]) expect(src).toContain(`${p}:`);
34+
expect(src).toContain("p-3"); expect(src).toContain("p-5"); expect(src).toContain("p-7");
35+
});
36+
37+
it("header: title + subtitle + action slot, footer con borderTop", () => {
38+
expect(src).toContain("hasHeader"); expect(src).toContain("{title}"); expect(src).toContain("{subtitle}");
39+
expect(src).toContain("{action}"); expect(src).toContain("{footer}"); expect(src).toContain("borderTop");
40+
});
41+
42+
it("hoverable + onClick → role='button' + tabIndex 0 + keyboard Enter/Space", () => {
43+
expect(src).toContain("hoverable"); expect(src).toContain("isClickable");
44+
expect(src).toContain("card-interactive");
45+
expect(src).toContain("role={isClickable ? 'button'");
46+
expect(src).toContain("tabIndex={isClickable ? 0");
47+
expect(src).toContain("'Enter'"); expect(src).toContain("' '");
48+
expect(src).toContain("scale(0.995)"); // active
49+
});
50+
51+
it("CardGrid: cols 1-4 responsive + COLS/GAPS maps", () => {
52+
expect(src).toContain("COLS"); expect(src).toContain("GAPS");
53+
expect(src).toContain("grid-cols-1"); expect(src).toContain("sm:grid-cols-2");
54+
expect(src).toContain("lg:grid-cols-3"); expect(src).toContain("lg:grid-cols-4");
55+
for (const g of ["gap-3", "gap-5", "gap-7"]) expect(src).toContain(g);
56+
});
57+
58+
it("StatCard: label + value + trend ↑↓ verde/rosso + sub opzionale", () => {
59+
expect(src).toContain("trendColor");
60+
expect(src).toContain("var(--color-green)"); expect(src).toContain("var(--color-red)");
61+
expect(src).toContain("Math.abs(trend)");
62+
});
63+
});
64+
65+
/* ── AlertBanner ── */
66+
describe("AlertBanner", () => {
67+
const src = readSrc("app/components/AlertBanner.tsx");
68+
69+
it("export AlertBanner + AlertBannerStack + AlertType + 3 interface", () => {
70+
expect(src).toMatch(/export function AlertBanner\b/);
71+
expect(src).toMatch(/export function AlertBannerStack\b/);
72+
expect(src).toContain("export type AlertType");
73+
expect(src).toContain("export interface AlertBannerProps");
74+
expect(src).toContain("export interface BannerItem");
75+
expect(src).toContain("export interface AlertBannerStackProps");
76+
});
77+
78+
it("TYPE_STYLE + ACTION_STYLE per 4 tipi: info/warning/error/success", () => {
79+
expect(src).toContain("TYPE_STYLE"); expect(src).toContain("ACTION_STYLE");
80+
for (const t of ["info", "warning", "error", "success"]) expect(src).toContain(`${t}:`);
81+
});
82+
83+
it("Icon component SVG per tipo: polyline (success), circle (error/info), path (warning)", () => {
84+
expect(src).toContain("function Icon");
85+
expect(src).toContain("polyline"); expect(src).toContain("<circle"); expect(src).toContain("<path");
86+
});
87+
88+
it("role='alert' + aria-label='Chiudi' + banner-slide-down animation", () => {
89+
expect(src).toContain('role="alert"'); expect(src).toContain('aria-label="Chiudi"');
90+
expect(src).toContain("banner-slide-down");
91+
expect(src).toContain("translateY(-100%)"); expect(src).toContain("translateY(0)");
92+
});
93+
94+
it("dismissible + action CTA (label+onClick) + position fixed/inline + zIndex 100", () => {
95+
expect(src).toContain("dismissible"); expect(src).toContain("setVisible(false)");
96+
expect(src).toContain("action.label"); expect(src).toContain("action.onClick");
97+
expect(src).toContain("position: 'fixed'"); expect(src).toContain("position: 'relative'");
98+
expect(src).toContain("zIndex: 100");
99+
});
100+
101+
it("AlertBannerStack: banners.map position='inline' + onDismiss(id)", () => {
102+
expect(src).toContain("banners.map");
103+
expect(src).toContain('position="inline"');
104+
expect(src).toContain("onDismiss={() => onDismiss(b.id)}");
105+
});
106+
});
107+
108+
/* ── Badge ── */
109+
describe("Badge", () => {
110+
const src = readSrc("app/components/Badge.tsx");
111+
112+
it("export Badge + BadgeGroup + StatusBadge + CountBadge", () => {
113+
expect(src).toMatch(/export function Badge\b/);
114+
expect(src).toMatch(/export function BadgeGroup\b/);
115+
expect(src).toMatch(/export function StatusBadge\b/);
116+
expect(src).toMatch(/export function CountBadge\b/);
117+
});
118+
119+
it("BadgeVariant 6 + BadgeSize 3 + tipi esportati", () => {
120+
expect(src).toContain("export type BadgeVariant"); expect(src).toContain("export type BadgeSize");
121+
for (const v of ["default", "success", "warning", "error", "info", "outline"]) expect(src).toContain(`${v}:`);
122+
});
123+
124+
it("VARIANT + DOT_COLOR + SIZE_CLS + DOT_PX + RMV_PX + ICN_PX maps", () => {
125+
for (const m of ["VARIANT", "DOT_COLOR", "SIZE_CLS", "DOT_PX", "RMV_PX", "ICN_PX"])
126+
expect(src).toContain(m);
127+
});
128+
129+
it("dot puro (no label) + dot prefix + removable aria-label='Rimuovi'", () => {
130+
expect(src).toContain("dot && !label"); expect(src).toContain("removable");
131+
expect(src).toContain('aria-label="Rimuovi"'); expect(src).toContain("onRemove?.()");
132+
});
133+
134+
it("STATUS_MAP: attivo/completato/errore/pending/merged → varianti", () => {
135+
expect(src).toContain("STATUS_MAP");
136+
for (const s of ["attivo", "completato", "errore", "pending", "merged"]) expect(src).toContain(`${s}:`);
137+
});
138+
139+
it("CountBadge: count > max → '99+' + BadgeGroupProps wrap/gap", () => {
140+
expect(src).toContain("count > max"); expect(src).toContain("`${max}+`");
141+
expect(src).toContain("export interface BadgeGroupProps"); expect(src).toContain("wrap");
142+
});
143+
});

0 commit comments

Comments
 (0)