import { act } from "react"; import { createRoot, type Root } from "react-dom/client"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { StripePaymentDialogLoading } from "../lazy-stripe-payment-dialog"; import { StripePaymentDialog } from "../stripe-payment-dialog"; describe("Stripe payment portal states", () => { let container: HTMLDivElement; let root: Root; beforeEach(() => { (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }) .IS_REACT_ACT_ENVIRONMENT = true; container = document.createElement("div"); container.style.transform = "translateX(50%)"; document.body.appendChild(container); root = createRoot(container); }); afterEach(() => { act(() => root.unmount()); container.remove(); document.body.style.overflow = ""; }); it("portals the unavailable state and keeps its explicit close action", () => { const onClose = vi.fn(); act(() => root.render( , ), ); const dialog = document.body.querySelector('[role="alertdialog"]'); expect(dialog).not.toBeNull(); expect(container.contains(dialog)).toBe(false); expect(dialog?.textContent).toContain("Payment unavailable"); expect(dialog?.getAttribute("aria-labelledby")).toBeTruthy(); expect(dialog?.getAttribute("aria-describedby")).toBeTruthy(); const okButton = Array.from(dialog?.querySelectorAll("button") ?? []).find( (button) => button.textContent === "OK", ); act(() => okButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }))); expect(onClose).toHaveBeenCalledOnce(); }); it("portals the lazy loading state", () => { act(() => root.render()); const dialog = document.body.querySelector('[role="dialog"]'); expect(dialog).not.toBeNull(); expect(container.contains(dialog)).toBe(false); expect(dialog?.textContent).toContain("Preparing secure payment"); expect(dialog?.textContent).toContain("Loading payment methods..."); expect(dialog?.querySelector('[aria-busy="true"]')).not.toBeNull(); }); });