expo-popcore-app/hooks/use-swipe-navigation.test.ts

228 lines
6.1 KiB
TypeScript

/**
* @file use-swipe-navigation.test.ts
* @description Tests for useSwipeNavigation hook
*
* This hook provides swipe gesture handling for tab navigation.
* It calculates swipe direction and triggers tab changes based on gesture velocity and distance.
*/
import { renderHook, act } from '@testing-library/react-native'
import { useSwipeNavigation } from './use-swipe-navigation'
describe('useSwipeNavigation', () => {
const mockOnSwipeLeft = jest.fn()
const mockOnSwipeRight = jest.fn()
beforeEach(() => {
jest.clearAllMocks()
})
describe('initialization', () => {
it('should initialize with default values', () => {
const { result } = renderHook(() =>
useSwipeNavigation({
onSwipeLeft: mockOnSwipeLeft,
onSwipeRight: mockOnSwipeRight,
})
)
expect(result.current.handleGestureEvent).toBeDefined()
expect(result.current.handleGestureStateChange).toBeDefined()
})
it('should accept custom threshold', () => {
const { result } = renderHook(() =>
useSwipeNavigation({
onSwipeLeft: mockOnSwipeLeft,
onSwipeRight: mockOnSwipeRight,
threshold: 100,
})
)
expect(result.current.handleGestureEvent).toBeDefined()
})
it('should accept custom velocity threshold', () => {
const { result } = renderHook(() =>
useSwipeNavigation({
onSwipeLeft: mockOnSwipeLeft,
onSwipeRight: mockOnSwipeRight,
velocityThreshold: 500,
})
)
expect(result.current.handleGestureEvent).toBeDefined()
})
})
describe('swipe detection', () => {
it('should call onSwipeLeft when swiping left with sufficient distance', () => {
const { result } = renderHook(() =>
useSwipeNavigation({
onSwipeLeft: mockOnSwipeLeft,
onSwipeRight: mockOnSwipeRight,
threshold: 50,
})
)
// Simulate gesture state change with left swipe
act(() => {
result.current.handleGestureStateChange({
nativeEvent: {
state: 5, // END state
translationX: -100,
velocityX: -200,
},
} as any)
})
expect(mockOnSwipeLeft).toHaveBeenCalledTimes(1)
expect(mockOnSwipeRight).not.toHaveBeenCalled()
})
it('should call onSwipeRight when swiping right with sufficient distance', () => {
const { result } = renderHook(() =>
useSwipeNavigation({
onSwipeLeft: mockOnSwipeLeft,
onSwipeRight: mockOnSwipeRight,
threshold: 50,
})
)
// Simulate gesture state change with right swipe
act(() => {
result.current.handleGestureStateChange({
nativeEvent: {
state: 5, // END state
translationX: 100,
velocityX: 200,
},
} as any)
})
expect(mockOnSwipeRight).toHaveBeenCalledTimes(1)
expect(mockOnSwipeLeft).not.toHaveBeenCalled()
})
it('should call onSwipeLeft when velocity is high even with small distance', () => {
const { result } = renderHook(() =>
useSwipeNavigation({
onSwipeLeft: mockOnSwipeLeft,
onSwipeRight: mockOnSwipeRight,
threshold: 100,
velocityThreshold: 300,
})
)
// Simulate gesture with high velocity but small distance
act(() => {
result.current.handleGestureStateChange({
nativeEvent: {
state: 5, // END state
translationX: -30,
velocityX: -500,
},
} as any)
})
expect(mockOnSwipeLeft).toHaveBeenCalledTimes(1)
})
it('should not trigger swipe when distance and velocity are below thresholds', () => {
const { result } = renderHook(() =>
useSwipeNavigation({
onSwipeLeft: mockOnSwipeLeft,
onSwipeRight: mockOnSwipeRight,
threshold: 100,
velocityThreshold: 500,
})
)
// Simulate gesture with small distance and low velocity
act(() => {
result.current.handleGestureStateChange({
nativeEvent: {
state: 5, // END state
translationX: -30,
velocityX: -100,
},
} as any)
})
expect(mockOnSwipeLeft).not.toHaveBeenCalled()
expect(mockOnSwipeRight).not.toHaveBeenCalled()
})
})
describe('disabled state', () => {
it('should not trigger swipe when disabled', () => {
const { result } = renderHook(() =>
useSwipeNavigation({
onSwipeLeft: mockOnSwipeLeft,
onSwipeRight: mockOnSwipeRight,
enabled: false,
})
)
act(() => {
result.current.handleGestureStateChange({
nativeEvent: {
state: 5, // END state
translationX: -100,
velocityX: -500,
},
} as any)
})
expect(mockOnSwipeLeft).not.toHaveBeenCalled()
expect(mockOnSwipeRight).not.toHaveBeenCalled()
})
})
describe('boundary conditions', () => {
it('should not call onSwipeLeft when canSwipeLeft is false', () => {
const { result } = renderHook(() =>
useSwipeNavigation({
onSwipeLeft: mockOnSwipeLeft,
onSwipeRight: mockOnSwipeRight,
canSwipeLeft: false,
})
)
act(() => {
result.current.handleGestureStateChange({
nativeEvent: {
state: 5, // END state
translationX: -100,
velocityX: -500,
},
} as any)
})
expect(mockOnSwipeLeft).not.toHaveBeenCalled()
})
it('should not call onSwipeRight when canSwipeRight is false', () => {
const { result } = renderHook(() =>
useSwipeNavigation({
onSwipeLeft: mockOnSwipeLeft,
onSwipeRight: mockOnSwipeRight,
canSwipeRight: false,
})
)
act(() => {
result.current.handleGestureStateChange({
nativeEvent: {
state: 5, // END state
translationX: 100,
velocityX: 500,
},
} as any)
})
expect(mockOnSwipeRight).not.toHaveBeenCalled()
})
})
})