chore: initial DSMMG v0.2 — refonte architecturale complète
Mise en place du Design System ManageMate Group v0.2 — refonte du
système de tokens (préfixe --mmg-color-*), 9 presets accent
user-themable validés WCAG AA, overlays Radix UI + Floating UI,
Storybook 8 + Vitest + axe-core en CI, doc Astro Starlight,
DESIGN.md (format google-labs-code) et exports tokens DTCG/CSS/
TS/Figma/Tailwind v3 et v4.
- 4 packages monorepo pnpm : @managemate/{tokens,css,react,icons}
- 62 composants React headless-first (Sheet, HoverCard, ContextMenu,
Slider, ToggleGroup, AvatarGroup, UserCard, ProfileHeader,
MetricCard, PricingCard, FeatureCard, Text/Display/Eyebrow/Lead…)
- Lint contraste WCAG : 37/37 paires AA, branché CI
- Toast pile Sonner-style avec ResizeObserver
- Theming user (9 presets) sans casser sémantique fixe
- Identité Synapse (rose #D12B6A) préservée
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { axe } from "vitest-axe";
|
||||
import { Button } from "./Button";
|
||||
|
||||
describe("Button", () => {
|
||||
it("rend le label", () => {
|
||||
render(<Button>Continuer</Button>);
|
||||
expect(screen.getByRole("button", { name: "Continuer" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("appelle onClick quand cliqué", async () => {
|
||||
const user = userEvent.setup();
|
||||
let clicks = 0;
|
||||
render(<Button onClick={() => clicks++}>Cliquer</Button>);
|
||||
await user.click(screen.getByRole("button"));
|
||||
expect(clicks).toBe(1);
|
||||
});
|
||||
|
||||
it("est focusable au clavier (Tab)", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Button>OK</Button>);
|
||||
await user.tab();
|
||||
expect(screen.getByRole("button")).toHaveFocus();
|
||||
});
|
||||
|
||||
it("active onClick avec Espace ou Entrée", async () => {
|
||||
const user = userEvent.setup();
|
||||
let clicks = 0;
|
||||
render(<Button onClick={() => clicks++}>Cliquer</Button>);
|
||||
const btn = screen.getByRole("button");
|
||||
btn.focus();
|
||||
await user.keyboard("{Enter}");
|
||||
await user.keyboard(" ");
|
||||
expect(clicks).toBe(2);
|
||||
});
|
||||
|
||||
it("respecte disabled", async () => {
|
||||
const user = userEvent.setup();
|
||||
let clicks = 0;
|
||||
render(
|
||||
<Button disabled onClick={() => clicks++}>
|
||||
OK
|
||||
</Button>,
|
||||
);
|
||||
await user.click(screen.getByRole("button"));
|
||||
expect(clicks).toBe(0);
|
||||
});
|
||||
|
||||
it("loading rend le bouton inactif aux clics", async () => {
|
||||
const user = userEvent.setup();
|
||||
let clicks = 0;
|
||||
render(
|
||||
<Button loading onClick={() => clicks++}>
|
||||
OK
|
||||
</Button>,
|
||||
);
|
||||
await user.click(screen.getByRole("button"));
|
||||
expect(clicks).toBe(0);
|
||||
});
|
||||
|
||||
it("n'a pas de violations axe-core (a11y)", async () => {
|
||||
const { container } = render(
|
||||
<>
|
||||
<Button>Primary</Button>
|
||||
<Button variant="ghost">Ghost</Button>
|
||||
<Button variant="danger">Danger</Button>
|
||||
<Button disabled>Disabled</Button>
|
||||
<Button icon="settings-3-line" aria-label="Paramètres" />
|
||||
</>,
|
||||
);
|
||||
expect(await axe(container)).toHaveNoViolations();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user