import { TranslationProvider } from "@suaveplan/react-i18n"; import { describe, expect, it } from "@suaveplan/testing/runner"; import { renderComponent } from "@suaveplan/testing-dom"; import { createRef } from "react"; import { createTestI18n } from "../../../tests/setup/test-i18n.js"; import { ThemeProvider } from "../../theme/theme-provider/theme-provider.js"; import { lightTheme } from "../../theme/themes/light.js"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "./alert-dialog.js"; import { alertDialogActionVariants, alertDialogCancelVariants, alertDialogContentVariants, alertDialogDescriptionVariants, alertDialogFooterVariants, alertDialogHeaderVariants, alertDialogOverlayVariants, alertDialogTitleVariants, } from "./alert-dialog.variants.js"; async function withProviders( node: React.ReactElement ): Promise { const i18n = await createTestI18n({ locale: "en-GB" }); return ( {node} ); } describe("", () => { it("opens via the trigger and renders alertdialog role", { timeout: 5000, }, async () => { const tree = await withProviders( Delete Confirm OK ); const { getByText, findByRole, user } = renderComponent(tree); await user.click(getByText("Delete")); const alertDialog = await findByRole("alertdialog"); expect(alertDialog).not.toBeNull(); }); it("Escape closes the dialog (cancel)", { timeout: 5000 }, async () => { const tree = await withProviders( Delete Confirm OK ); const { getByText, findByRole, queryByRole, user } = renderComponent(tree); const trigger = getByText("Delete") as HTMLElement; await user.click(trigger); await findByRole("alertdialog"); await user.keyboard("{Escape}"); expect(queryByRole("alertdialog")).toBeNull(); expect(document.activeElement).toBe(trigger); }); it("AlertDialogAction closes the dialog when activated", { timeout: 5000, }, async () => { const tree = await withProviders( Heading Body Confirm ); const { findByRole, queryByRole, user } = renderComponent(tree); const action = await findByRole("button", { name: "Confirm" }); await user.click(action); expect(queryByRole("alertdialog")).toBeNull(); }); it("AlertDialogCancel closes the dialog when activated", { timeout: 5000, }, async () => { const tree = await withProviders( Confirm Cancel ); const { findByText, queryByRole, user } = renderComponent(tree); await user.click(await findByText("Cancel")); expect(queryByRole("alertdialog")).toBeNull(); }); it("does NOT close on overlay backdrop click (modal confirmation)", { timeout: 5000, }, async () => { const tree = await withProviders( Modal OK ); const { findByRole, queryByRole, user } = renderComponent(tree); const dialog = await findByRole("alertdialog"); // Find the overlay (sibling of the content) and click it. const overlay = dialog.parentElement?.querySelector( "[data-state]:not([role])" ) as HTMLElement | null; if (overlay !== null) { await user.click(overlay); } expect(queryByRole("alertdialog")).not.toBeNull(); }); it("forwards refs on every sub-component", { timeout: 5000 }, async () => { const triggerRef = createRef(); const contentRef = createRef(); const titleRef = createRef(); const descRef = createRef(); const headerRef = createRef(); const footerRef = createRef(); const actionRef = createRef(); const cancelRef = createRef(); const tree = await withProviders( Open T D C A ); renderComponent(tree); expect(triggerRef.current).not.toBeNull(); expect(contentRef.current).not.toBeNull(); expect(titleRef.current).not.toBeNull(); expect(descRef.current).not.toBeNull(); expect(headerRef.current).not.toBeNull(); expect(footerRef.current).not.toBeNull(); expect(actionRef.current).not.toBeNull(); expect(cancelRef.current).not.toBeNull(); }); it("merges custom className", { timeout: 5000 }, async () => { const tree = await withProviders( T D OK Cancel ); const { findByRole } = renderComponent(tree); const dialog = await findByRole("alertdialog"); expect(dialog.className).toContain("c-extra"); expect(dialog.querySelector(".h-extra")).not.toBeNull(); expect(dialog.querySelector(".t-extra")).not.toBeNull(); expect(dialog.querySelector(".d-extra")).not.toBeNull(); expect(dialog.querySelector(".f-extra")).not.toBeNull(); expect(dialog.querySelector(".a-extra")).not.toBeNull(); expect(dialog.querySelector(".x-extra")).not.toBeNull(); }); it("applies the size variant to AlertDialogContent", { timeout: 5000, }, async () => { const tree = await withProviders( T ); const { findByRole } = renderComponent(tree); const dialog = await findByRole("alertdialog"); expect(dialog.className).toContain("max-w-4xl"); }); it("renders Cancel + Action buttons with their canonical styling", { timeout: 5000, }, async () => { const tree = await withProviders( T OK Cancel ); const { findByText } = renderComponent(tree); const action = await findByText("OK"); const cancel = await findByText("Cancel"); expect(action.className).toContain("bg-primary"); expect(cancel.className).toContain("border"); }); it("exposes every alert-dialog cva resolver", { timeout: 5000 }, () => { expect(alertDialogOverlayVariants().length).toBeGreaterThan(0); for (const size of ["sm", "default", "lg", "xl"] as const) { expect(alertDialogContentVariants({ size }).length).toBeGreaterThan( 0 ); } expect(alertDialogHeaderVariants().length).toBeGreaterThan(0); expect(alertDialogFooterVariants().length).toBeGreaterThan(0); expect(alertDialogTitleVariants().length).toBeGreaterThan(0); expect(alertDialogDescriptionVariants().length).toBeGreaterThan(0); expect(alertDialogActionVariants().length).toBeGreaterThan(0); expect(alertDialogCancelVariants().length).toBeGreaterThan(0); }); });