Add missing component and hook tests, raise coverage thresholds
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>
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
// @vitest-environment jsdom
|
||||
import { act, renderHook } from "@testing-library/react";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { useSwipeToDismiss } from "../use-swipe-to-dismiss.js";
|
||||
|
||||
const PANEL_WIDTH = 300;
|
||||
|
||||
function makeTouchEvent(clientX: number, clientY = 0): React.TouchEvent {
|
||||
return {
|
||||
touches: [{ clientX, clientY }],
|
||||
currentTarget: {
|
||||
getBoundingClientRect: () => ({ width: PANEL_WIDTH }),
|
||||
},
|
||||
} as unknown as React.TouchEvent;
|
||||
}
|
||||
|
||||
describe("useSwipeToDismiss", () => {
|
||||
beforeEach(() => {
|
||||
vi.spyOn(Date, "now").mockReturnValue(0);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("starts with offsetX 0 and isSwiping false", () => {
|
||||
const { result } = renderHook(() => useSwipeToDismiss(vi.fn()));
|
||||
expect(result.current.offsetX).toBe(0);
|
||||
expect(result.current.isSwiping).toBe(false);
|
||||
});
|
||||
|
||||
it("horizontal drag updates offsetX and sets isSwiping", () => {
|
||||
const { result } = renderHook(() => useSwipeToDismiss(vi.fn()));
|
||||
|
||||
act(() => result.current.handlers.onTouchStart(makeTouchEvent(0)));
|
||||
act(() => result.current.handlers.onTouchMove(makeTouchEvent(50)));
|
||||
|
||||
expect(result.current.offsetX).toBe(50);
|
||||
expect(result.current.isSwiping).toBe(true);
|
||||
});
|
||||
|
||||
it("vertical drag is ignored after direction lock", () => {
|
||||
const { result } = renderHook(() => useSwipeToDismiss(vi.fn()));
|
||||
|
||||
act(() => result.current.handlers.onTouchStart(makeTouchEvent(0, 0)));
|
||||
// Move vertically > 10px to lock vertical
|
||||
act(() => result.current.handlers.onTouchMove(makeTouchEvent(0, 20)));
|
||||
|
||||
expect(result.current.offsetX).toBe(0);
|
||||
});
|
||||
|
||||
it("small movement does not lock direction", () => {
|
||||
const { result } = renderHook(() => useSwipeToDismiss(vi.fn()));
|
||||
|
||||
act(() => result.current.handlers.onTouchStart(makeTouchEvent(0)));
|
||||
act(() => result.current.handlers.onTouchMove(makeTouchEvent(5)));
|
||||
|
||||
// No direction locked yet, no update
|
||||
expect(result.current.offsetX).toBe(0);
|
||||
expect(result.current.isSwiping).toBe(false);
|
||||
});
|
||||
|
||||
it("leftward drag is clamped to 0", () => {
|
||||
const { result } = renderHook(() => useSwipeToDismiss(vi.fn()));
|
||||
|
||||
act(() => result.current.handlers.onTouchStart(makeTouchEvent(100)));
|
||||
act(() => result.current.handlers.onTouchMove(makeTouchEvent(50)));
|
||||
|
||||
expect(result.current.offsetX).toBe(0);
|
||||
});
|
||||
|
||||
it("calls onDismiss when ratio exceeds threshold", () => {
|
||||
const onDismiss = vi.fn();
|
||||
const { result } = renderHook(() => useSwipeToDismiss(onDismiss));
|
||||
|
||||
act(() => result.current.handlers.onTouchStart(makeTouchEvent(0)));
|
||||
// Move > 35% of panel width (300 * 0.35 = 105)
|
||||
act(() => result.current.handlers.onTouchMove(makeTouchEvent(120)));
|
||||
|
||||
vi.spyOn(Date, "now").mockReturnValue(5000); // slow swipe
|
||||
act(() => result.current.handlers.onTouchEnd());
|
||||
|
||||
expect(onDismiss).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls onDismiss with fast velocity", () => {
|
||||
const onDismiss = vi.fn();
|
||||
const { result } = renderHook(() => useSwipeToDismiss(onDismiss));
|
||||
|
||||
act(() => result.current.handlers.onTouchStart(makeTouchEvent(0)));
|
||||
// Small distance but fast
|
||||
act(() => result.current.handlers.onTouchMove(makeTouchEvent(30)));
|
||||
|
||||
// Very fast: 30px in 0.1s = 300px/s, velocity = 300/300 = 1.0 > 0.5
|
||||
vi.spyOn(Date, "now").mockReturnValue(100);
|
||||
act(() => result.current.handlers.onTouchEnd());
|
||||
|
||||
expect(onDismiss).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not dismiss when below thresholds", () => {
|
||||
const onDismiss = vi.fn();
|
||||
const { result } = renderHook(() => useSwipeToDismiss(onDismiss));
|
||||
|
||||
act(() => result.current.handlers.onTouchStart(makeTouchEvent(0)));
|
||||
// Small distance, slow speed
|
||||
act(() => result.current.handlers.onTouchMove(makeTouchEvent(20)));
|
||||
|
||||
vi.spyOn(Date, "now").mockReturnValue(5000);
|
||||
act(() => result.current.handlers.onTouchEnd());
|
||||
|
||||
expect(onDismiss).not.toHaveBeenCalled();
|
||||
expect(result.current.offsetX).toBe(0);
|
||||
expect(result.current.isSwiping).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user