228 lines
6.1 KiB
TypeScript
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()
|
|
})
|
|
})
|
|
})
|