// @vitest-environment jsdom import { act, renderHook } from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { useLongPress } from "../use-long-press.js"; function touchEvent(overrides?: Partial): React.TouchEvent { return { preventDefault: vi.fn(), ...overrides, } as unknown as React.TouchEvent; } describe("useLongPress", () => { beforeEach(() => { vi.useFakeTimers(); }); afterEach(() => { vi.useRealTimers(); }); it("returns onTouchStart, onTouchEnd, onTouchMove handlers", () => { const { result } = renderHook(() => useLongPress(vi.fn())); expect(result.current.onTouchStart).toBeInstanceOf(Function); expect(result.current.onTouchEnd).toBeInstanceOf(Function); expect(result.current.onTouchMove).toBeInstanceOf(Function); }); it("fires onLongPress after 500ms hold", () => { const onLongPress = vi.fn(); const { result } = renderHook(() => useLongPress(onLongPress)); const e = touchEvent(); act(() => result.current.onTouchStart(e)); expect(onLongPress).not.toHaveBeenCalled(); act(() => { vi.advanceTimersByTime(500); }); expect(onLongPress).toHaveBeenCalledOnce(); }); it("does not fire if released before 500ms", () => { const onLongPress = vi.fn(); const { result } = renderHook(() => useLongPress(onLongPress)); act(() => result.current.onTouchStart(touchEvent())); act(() => { vi.advanceTimersByTime(300); }); act(() => result.current.onTouchEnd(touchEvent())); act(() => { vi.advanceTimersByTime(500); }); expect(onLongPress).not.toHaveBeenCalled(); }); it("cancels on touch move", () => { const onLongPress = vi.fn(); const { result } = renderHook(() => useLongPress(onLongPress)); act(() => result.current.onTouchStart(touchEvent())); act(() => { vi.advanceTimersByTime(200); }); act(() => result.current.onTouchMove()); act(() => { vi.advanceTimersByTime(500); }); expect(onLongPress).not.toHaveBeenCalled(); }); it("onTouchEnd calls preventDefault after long press fires", () => { const onLongPress = vi.fn(); const { result } = renderHook(() => useLongPress(onLongPress)); act(() => result.current.onTouchStart(touchEvent())); act(() => { vi.advanceTimersByTime(500); }); const preventDefaultSpy = vi.fn(); const endEvent = touchEvent({ preventDefault: preventDefaultSpy }); act(() => result.current.onTouchEnd(endEvent)); expect(preventDefaultSpy).toHaveBeenCalled(); }); it("onTouchEnd does not preventDefault when long press did not fire", () => { const onLongPress = vi.fn(); const { result } = renderHook(() => useLongPress(onLongPress)); act(() => result.current.onTouchStart(touchEvent())); act(() => { vi.advanceTimersByTime(100); }); const preventDefaultSpy = vi.fn(); const endEvent = touchEvent({ preventDefault: preventDefaultSpy }); act(() => result.current.onTouchEnd(endEvent)); expect(preventDefaultSpy).not.toHaveBeenCalled(); }); });