import { act, cleanup, render, renderHook, screen } from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { I18nProvider } from "@/translations/provider"; import { MatchProfileOverlay, useMatchProfileOverlay, } from "./match-profile-overlay"; vi.mock("next/navigation", () => ({ useRouter: () => ({ push: vi.fn(), replace: vi.fn(), back: vi.fn(), }), })); vi.mock("@/hooks/marriage/use-profile-main", () => ({ useMarriageProfileQuery: () => ({ data: { status: "matched", gender: "female", active_case: { case_id: "test-case-1", status: "introduced" }, match_summary: { gender: "male", public_info: [{ key: "full_name", label: "نام", value: "علی احمدی" }], }, }, isLoading: false, refetch: vi.fn(), }), })); vi.mock("@/hooks/marriage/use-case-respond", () => ({ useRespondToMarriageCaseMutation: () => ({ mutateAsync: vi.fn(), isPending: false, }), })); function createWrapper() { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, }, }); return function Wrapper({ children }: { children: React.ReactNode }) { return ( {children} ); }; } describe("MatchProfileOverlay & useMatchProfileOverlay", () => { beforeEach(() => { vi.useFakeTimers({ toFake: ["setTimeout", "clearTimeout"] }); vi.stubGlobal("requestAnimationFrame", (cb: FrameRequestCallback) => { return setTimeout(() => cb(Date.now()), 0); }); vi.stubGlobal("cancelAnimationFrame", (id: number) => { clearTimeout(id); }); document.body.className = ""; }); afterEach(() => { cleanup(); vi.restoreAllMocks(); vi.useRealTimers(); document.body.className = ""; }); it("hook manages open and close state with history sync", () => { const { result } = renderHook(() => useMatchProfileOverlay()); expect(result.current.isProfileOpen).toBe(false); act(() => { result.current.openProfile(); }); expect(result.current.isProfileOpen).toBe(true); act(() => { result.current.closeProfile(); }); expect(result.current.isProfileOpen).toBe(false); }); it("renders overlay dialog and profile page when open is true", () => { const handleClose = vi.fn(); const wrapper = createWrapper(); render( , { wrapper }, ); act(() => { vi.advanceTimersByTime(16); }); const overlay = screen.getByRole("dialog"); expect(overlay).toBeInTheDocument(); expect(overlay).toHaveClass("section-overlay"); expect(document.body.classList.contains("section-overlay-open")).toBe(true); }); it("handles closing animation and removes body class when open becomes false", () => { const handleClose = vi.fn(); const wrapper = createWrapper(); const { rerender } = render( , { wrapper }, ); act(() => { vi.advanceTimersByTime(16); }); expect(screen.getByRole("dialog")).toHaveAttribute("data-state", "open"); expect(document.body.classList.contains("section-overlay-open")).toBe(true); rerender(); expect(screen.getByRole("dialog")).toHaveAttribute("data-state", "closing"); expect(document.body.classList.contains("section-overlay-open")).toBe(false); act(() => { vi.advanceTimersByTime(210); }); expect(screen.queryByRole("dialog")).not.toBeInTheDocument(); }); });