import { renderHook } from '@testing-library/react-native' import { FlatList, LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent } from 'react-native' import { useRestAwayFromDismissEdge } from '../../hooks/use_rest_away_from_dismiss_edge' const VIEWPORT_HEIGHT = 800 const LIST_WIDTH = 390 const layoutEvent = (height: number) => ({ nativeEvent: { layout: { x: 0, y: 0, width: LIST_WIDTH, height } } }) as LayoutChangeEvent const settledEvent = (y: number) => ({ nativeEvent: { contentOffset: { x: 0, y } } }) as NativeSyntheticEvent const renderEnabledHook = () => { const scrollToOffset = jest.fn() const listRef = { current: { scrollToOffset } as unknown as FlatList } const { result } = renderHook(() => useRestAwayFromDismissEdge({ listRef, enabled: true })) return { scrollToOffset, handlers: result.current } } describe('useRestAwayFromDismissEdge', () => { test('leaves a list that fits in its viewport alone', () => { const { scrollToOffset, handlers } = renderEnabledHook() handlers.onLayout(layoutEvent(VIEWPORT_HEIGHT)) handlers.onContentSizeChange(LIST_WIDTH, VIEWPORT_HEIGHT / 2) handlers.onMomentumScrollEnd(settledEvent(0)) handlers.onScrollEndDrag(settledEvent(0)) expect(scrollToOffset).not.toHaveBeenCalled() }) test('leaves a list with less than 1pt of overflow alone', () => { const { scrollToOffset, handlers } = renderEnabledHook() handlers.onLayout(layoutEvent(VIEWPORT_HEIGHT)) handlers.onContentSizeChange(LIST_WIDTH, VIEWPORT_HEIGHT + 0.5) handlers.onMomentumScrollEnd(settledEvent(0.333)) expect(scrollToOffset).not.toHaveBeenCalled() }) test('rests a scrollable list 1pt off the dismiss edge on open and after it settles there', () => { const { scrollToOffset, handlers } = renderEnabledHook() handlers.onLayout(layoutEvent(VIEWPORT_HEIGHT)) handlers.onContentSizeChange(LIST_WIDTH, VIEWPORT_HEIGHT * 2) expect(scrollToOffset).toHaveBeenCalledTimes(1) expect(scrollToOffset).toHaveBeenCalledWith({ animated: false, offset: 1 }) handlers.onMomentumScrollEnd(settledEvent(0)) expect(scrollToOffset).toHaveBeenCalledTimes(2) handlers.onMomentumScrollEnd(settledEvent(1)) handlers.onMomentumScrollEnd(settledEvent(-20)) expect(scrollToOffset).toHaveBeenCalledTimes(2) }) test('applies the initial offset once a short list grows past its viewport', () => { const { scrollToOffset, handlers } = renderEnabledHook() handlers.onLayout(layoutEvent(VIEWPORT_HEIGHT)) handlers.onContentSizeChange(LIST_WIDTH, VIEWPORT_HEIGHT / 2) expect(scrollToOffset).not.toHaveBeenCalled() handlers.onContentSizeChange(LIST_WIDTH, VIEWPORT_HEIGHT * 2) handlers.onContentSizeChange(LIST_WIDTH, VIEWPORT_HEIGHT * 3) expect(scrollToOffset).toHaveBeenCalledTimes(1) }) })