import React from 'react'; import { Text, View } from 'react-native'; import { render } from '@testing-library/react-native'; import { AnimatedFlashList } from '../../AnimatedFlashList'; import type { AnimatedRenderItemInfo } from '../../types'; interface TestItem { id: string; title: string; } const createTestItems = (count: number): TestItem[] => Array.from({ length: count }, (_, i) => ({ id: `item-${i + 1}`, title: `Test Item ${i + 1}`, })); describe('AnimatedFlashList', () => { const defaultRenderItem = ({ item }: AnimatedRenderItemInfo) => ( {item.title} ); const defaultKeyExtractor = (item: TestItem) => item.id; it('renders without crashing', async () => { const data = createTestItems(3); await expect( render( data={data} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} estimatedItemSize={80} />, ), ).resolves.toBeDefined(); }); it('renders items from data array', async () => { const data = createTestItems(3); const { getByText } = await render( data={data} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} estimatedItemSize={80} />, ); expect(getByText('Test Item 1')).toBeTruthy(); expect(getByText('Test Item 2')).toBeTruthy(); expect(getByText('Test Item 3')).toBeTruthy(); }); it('returns null for empty data when no ListFooterComponent', async () => { const { toJSON } = await render( data={[]} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} estimatedItemSize={80} />, ); expect(toJSON()).toBeNull(); }); it('renders ListFooterComponent for empty data', async () => { const FooterComponent = () => ( No items ); const { getByText } = await render( data={[]} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} estimatedItemSize={80} ListFooterComponent={FooterComponent} />, ); expect(getByText('No items')).toBeTruthy(); }); it('supports dragEnabled prop', async () => { const data = createTestItems(3); await expect( render( data={data} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} dragEnabled estimatedItemSize={80} />, ), ).resolves.toBeDefined(); }); it('supports dragEnabled=false (disabled)', async () => { const data = createTestItems(3); await expect( render( data={data} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} dragEnabled={false} estimatedItemSize={80} />, ), ).resolves.toBeDefined(); }); it('calls onReorder callback when provided', async () => { const data = createTestItems(3); const onReorder = jest.fn(); await render( data={data} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} dragEnabled onReorder={onReorder} estimatedItemSize={80} />, ); // onReorder should be provided but not called until user drags expect(onReorder).not.toHaveBeenCalled(); }); it('supports canDrag filter function', async () => { const data = createTestItems(5); const canDrag = (item: TestItem, index: number) => index % 2 === 0; await expect( render( data={data} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} dragEnabled canDrag={canDrag} estimatedItemSize={80} />, ), ).resolves.toBeDefined(); }); it('supports custom drag config', async () => { const data = createTestItems(3); await expect( render( data={data} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} dragEnabled config={{ drag: { longPressDuration: 500, dragScale: 1.1, itemHeight: 100, }, }} estimatedItemSize={80} />, ), ).resolves.toBeDefined(); }); it('supports haptic feedback callback', async () => { const data = createTestItems(3); const onHapticFeedback = jest.fn(); await render( data={data} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} dragEnabled onHapticFeedback={onHapticFeedback} estimatedItemSize={80} />, ); // Haptic feedback should not be called until drag starts expect(onHapticFeedback).not.toHaveBeenCalled(); }); it('supports onRefresh and refreshing props', async () => { const data = createTestItems(3); const onRefresh = jest.fn(); await expect( render( data={data} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} onRefresh={onRefresh} refreshing={false} estimatedItemSize={80} />, ), ).resolves.toBeDefined(); }); it('supports onEndReached prop', async () => { const data = createTestItems(3); const onEndReached = jest.fn(); await expect( render( data={data} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} onEndReached={onEndReached} onEndReachedThreshold={0.5} estimatedItemSize={80} />, ), ).resolves.toBeDefined(); }); it('supports contentContainerStyle prop', async () => { const data = createTestItems(3); await expect( render( data={data} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} contentContainerStyle={{ padding: 16 }} estimatedItemSize={80} />, ), ).resolves.toBeDefined(); }); it('re-renders when data changes', async () => { const data1 = createTestItems(2); const data2 = createTestItems(4); const { rerender, getByText, queryByText } = await render( data={data1} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} estimatedItemSize={80} />, ); expect(getByText('Test Item 1')).toBeTruthy(); expect(getByText('Test Item 2')).toBeTruthy(); expect(queryByText('Test Item 3')).toBeNull(); await rerender( data={data2} keyExtractor={defaultKeyExtractor} renderItem={defaultRenderItem} estimatedItemSize={80} />, ); expect(getByText('Test Item 3')).toBeTruthy(); expect(getByText('Test Item 4')).toBeTruthy(); }); it('passes dragHandleProps when drag is enabled', async () => { const data = createTestItems(1); let receivedDragHandleProps: unknown = null; const renderItem = ({ item, dragHandleProps }: AnimatedRenderItemInfo) => { receivedDragHandleProps = dragHandleProps; return ( {item.title} ); }; await render( data={data} keyExtractor={defaultKeyExtractor} renderItem={renderItem} dragEnabled estimatedItemSize={80} />, ); expect(receivedDragHandleProps).not.toBeNull(); expect((receivedDragHandleProps as any).gesture).toBeDefined(); }); it('passes null dragHandleProps when drag is disabled', async () => { const data = createTestItems(1); let receivedDragHandleProps: unknown = 'initial'; const renderItem = ({ item, dragHandleProps }: AnimatedRenderItemInfo) => { receivedDragHandleProps = dragHandleProps; return ( {item.title} ); }; await render( data={data} keyExtractor={defaultKeyExtractor} renderItem={renderItem} dragEnabled={false} estimatedItemSize={80} />, ); expect(receivedDragHandleProps).toBeNull(); }); it('provides triggerExitAnimation function', async () => { const data = createTestItems(1); let receivedTriggerExit: unknown = null; const renderItem = ({ item, triggerExitAnimation, }: AnimatedRenderItemInfo) => { receivedTriggerExit = triggerExitAnimation; return ( {item.title} ); }; await render( data={data} keyExtractor={defaultKeyExtractor} renderItem={renderItem} estimatedItemSize={80} />, ); expect(typeof receivedTriggerExit).toBe('function'); }); });