13 new test files for untested components (color-palette, player-management, stat-block, settings-modal, export/import dialogs, bulk-import-prompt, source-fetch-prompt, player-character-section) and hooks (use-long-press, use-swipe-to-dismiss, use-bulk-import, use-initiative-rolls). Expand combatant-row tests with inline editing, HP popover, and condition picker. Component coverage: 59% → 80% lines, 55% → 71% branches Hook coverage: 72% → 83% lines, 55% → 66% branches Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
105 lines
2.9 KiB
TypeScript
105 lines
2.9 KiB
TypeScript
// @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>): 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();
|
|
});
|
|
});
|