You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

140 lines
3.8 KiB

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 (
<QueryClientProvider client={queryClient}>
<I18nProvider locale="fa">{children}</I18nProvider>
</QueryClientProvider>
);
};
}
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(
<MatchProfileOverlay open={true} onClose={handleClose} />,
{ 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(
<MatchProfileOverlay open={true} onClose={handleClose} />,
{ wrapper },
);
act(() => {
vi.advanceTimersByTime(16);
});
expect(screen.getByRole("dialog")).toHaveAttribute("data-state", "open");
expect(document.body.classList.contains("section-overlay-open")).toBe(true);
rerender(<MatchProfileOverlay open={false} onClose={handleClose} />);
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();
});
});