import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import TermsSheet from "./terms-sheet"; vi.mock("@/translations/provider", () => ({ useI18n: () => ({ locale: "fa", dictionary: { "terms & conditions": "قوانین و مقررات", "Got it": "متوجه شدم", "Close terms and conditions": "بستن قوانین و مقررات", }, }), })); describe("TermsSheet Component (DraggableScrollableSheet Parity)", () => { beforeEach(() => { vi.clearAllMocks(); }); afterEach(() => { cleanup(); }); it("does not render when isOpen is false", () => { render(); expect(screen.queryByRole("dialog")).toBeNull(); }); it("renders with initial 75% height when isOpen is true", () => { render(); const dialog = screen.getByRole("dialog"); expect(dialog).toBeInTheDocument(); const section = dialog.querySelector("section")!; expect(section).toHaveClass("h-[calc(var(--sheet-size,0.75)*100svh)]"); expect(screen.getByText("قوانین و مقررات")).toBeInTheDocument(); expect(screen.getByText("متوجه شدم")).toBeInTheDocument(); }); it("grows sheet when pulling up at top of content", () => { render(); const dialog = screen.getByRole("dialog"); const section = dialog.querySelector("section")!; const content = screen.getByTestId("terms-sheet-content"); Object.defineProperty(content, "scrollHeight", { value: 1200, configurable: true }); Object.defineProperty(content, "clientHeight", { value: 400, configurable: true }); Object.defineProperty(content, "scrollTop", { value: 0, configurable: true }); fireEvent.touchStart(content, { touches: [{ clientX: 0, clientY: 400 }] }); fireEvent.touchMove(content, { touches: [{ clientX: 0, clientY: 300 }] }); expect(section.style.getPropertyValue("--sheet-size")).toBe( (0.75 + 100 / window.innerHeight).toFixed(4), ); }); it("grows sheet on wheel event at top of content", () => { render(); const dialog = screen.getByRole("dialog"); const section = dialog.querySelector("section")!; const content = screen.getByTestId("terms-sheet-content"); Object.defineProperty(content, "scrollHeight", { value: 1200, configurable: true }); Object.defineProperty(content, "clientHeight", { value: 400, configurable: true }); Object.defineProperty(content, "scrollTop", { value: 0, configurable: true }); fireEvent.wheel(content, { deltaY: 120 }); expect(section.style.getPropertyValue("--sheet-size")).toBe( (0.75 + 120 / window.innerHeight).toFixed(4), ); }); it("shrinks to 60% floor and closes when pulled past it (shouldCloseOnMinExtent: true)", async () => { const handleClose = vi.fn(); render(); const dialog = screen.getByRole("dialog"); const section = dialog.querySelector("section")!; const content = screen.getByTestId("terms-sheet-content"); Object.defineProperty(content, "scrollTop", { value: 0, configurable: true }); // Pull down at the top: sheet shrinks and clamps at 0.6 floor fireEvent.touchStart(content, { touches: [{ clientX: 0, clientY: 400 }] }); fireEvent.touchMove(content, { touches: [{ clientX: 0, clientY: 560 }] }); expect(section.style.getPropertyValue("--sheet-size")).toBe("0.6000"); // Pull further past 0.6: triggers close fireEvent.touchMove(content, { touches: [{ clientX: 0, clientY: 580 }] }); await waitFor(() => { expect(handleClose).toHaveBeenCalled(); }); }); it("calls onClose when Got it button is clicked", async () => { const handleClose = vi.fn(); render(); const gotItButton = screen.getByRole("button", { name: "متوجه شدم" }); fireEvent.click(gotItButton); await waitFor(() => { expect(handleClose).toHaveBeenCalled(); }); }); it("calls onClose when close X button is clicked", async () => { const handleClose = vi.fn(); render(); const closeButton = screen.getByRole("button", { name: "بستن قوانین و مقررات" }); fireEvent.click(closeButton); await waitFor(() => { expect(handleClose).toHaveBeenCalled(); }); }); });