// @vitest-environment jsdom import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { useState } from "react"; import { describe, expect, it, vi } from "vitest"; import { Alert } from "../../src/presentation/components/ui/alert.jsx"; import { Badge } from "../../src/presentation/components/ui/badge.jsx"; import { Button } from "../../src/presentation/components/ui/button.jsx"; import { Card } from "../../src/presentation/components/ui/card.jsx"; import { Dialog } from "../../src/presentation/components/ui/dialog.jsx"; import { TextField } from "../../src/presentation/components/ui/text-field.jsx"; describe("domain-neutral UI primitives", () => { it("connects field help and validation errors to the input", () => { render( , ); const field = screen.getByRole("textbox", { name: "이름" }); expect(field).toBeRequired(); expect(field).toHaveAccessibleDescription( "표시할 이름입니다. 이름을 입력해 주세요.", ); expect(field).toHaveAttribute("aria-invalid", "true"); }); it("exposes semantic variants without changing native button behavior", async () => { const user = userEvent.setup(); const onClick = vi.fn(); render( <> , ); await user.click(screen.getByRole("button", { name: "제거" })); expect(onClick).toHaveBeenCalledOnce(); expect(screen.getByRole("button", { name: "제거" })).toHaveClass( "ui-button--danger", ); expect(screen.getByRole("button", { name: "사용 불가" })).toBeDisabled(); }); it("labels cards, alerts, and badges with visible content", async () => { const user = userEvent.setup(); const dismiss = vi.fn(); render( 준비됨}> 안전하게 반영했습니다. , ); expect(screen.getByRole("article", { name: "상태 카드" })).toBeVisible(); expect(screen.getByRole("status")).toHaveTextContent( "저장됨안전하게 반영했습니다.", ); expect(screen.getByText("준비됨")).toHaveClass("ui-badge--success"); await user.click(screen.getByRole("button", { name: "저장됨 알림 닫기" })); expect(dismiss).toHaveBeenCalledOnce(); }); it("closes a modal and restores focus to its trigger", async () => { const user = userEvent.setup(); function DialogHarness() { const [open, setOpen] = useState(false); return ( <> setOpen(false)} title="연동 확인" actions={} > 안전한 설명 ); } render(); const trigger = screen.getByRole("button", { name: "모달 열기" }); await user.click(trigger); expect(screen.getByRole("dialog", { name: "연동 확인" })).toHaveAttribute( "open", ); await user.click(screen.getByRole("button", { name: "확인" })); await waitFor(() => expect(trigger).toHaveFocus()); expect(screen.getByRole("dialog", { hidden: true })).not.toHaveAttribute( "open", ); }); });