import { renderHook, act } from '@testing-library/react' import { useSelection } from '../../hooks/useSelection' interface TestData { id: string name: string } describe('useSelection', () => { const mockData: TestData[] = [ { id: '1', name: 'Item 1' }, { id: '2', name: 'Item 2' }, { id: '3', name: 'Item 3' }, ] const getRowId = (row: TestData) => row.id const defaultProps = { currentPageData: mockData, totalCount: 10, getRowId, } describe('Initialization', () => { it('should initialize with no selection', () => { const { result } = renderHook(() => useSelection(defaultProps)) expect(result.current.selectedIds.size).toBe(0) expect(result.current.selectAllPages).toBe(false) expect(result.current.getSelectedCount()).toBe(0) }) }) describe('Single Row Selection', () => { it('should toggle a single row selection', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.toggleRow('1') }) expect(result.current.selectedIds.has('1')).toBe(true) expect(result.current.selectedIds.size).toBe(1) expect(result.current.getSelectedCount()).toBe(1) }) it('should deselect a selected row', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.toggleRow('1') }) expect(result.current.selectedIds.has('1')).toBe(true) act(() => { result.current.toggleRow('1') }) expect(result.current.selectedIds.has('1')).toBe(false) expect(result.current.selectedIds.size).toBe(0) }) it('should select multiple rows individually', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.toggleRow('1') result.current.toggleRow('2') result.current.toggleRow('3') }) expect(result.current.selectedIds.size).toBe(3) expect(result.current.selectedIds.has('1')).toBe(true) expect(result.current.selectedIds.has('2')).toBe(true) expect(result.current.selectedIds.has('3')).toBe(true) }) it('should call onSelectionChange callback', () => { const onSelectionChange = jest.fn() const { result } = renderHook(() => useSelection({ ...defaultProps, onSelectionChange }) ) act(() => { result.current.toggleRow('1') }) expect(onSelectionChange).toHaveBeenCalledWith(expect.any(Set)) expect(onSelectionChange.mock.calls[0][0].has('1')).toBe(true) }) }) describe('Toggle All (Current Page)', () => { it('should select all rows on current page', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.toggleAll() }) expect(result.current.selectedIds.size).toBe(3) expect(result.current.selectedIds.has('1')).toBe(true) expect(result.current.selectedIds.has('2')).toBe(true) expect(result.current.selectedIds.has('3')).toBe(true) }) it('should deselect all rows on current page', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.toggleAll() }) expect(result.current.selectedIds.size).toBe(3) act(() => { result.current.toggleAll() }) expect(result.current.selectedIds.size).toBe(0) }) it('should select all when some are selected', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.toggleRow('1') }) expect(result.current.selectedIds.size).toBe(1) act(() => { result.current.toggleAll() }) // Should select all since not all were selected expect(result.current.selectedIds.size).toBe(3) }) it('should deselect selectAllPages when toggling individual page', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.selectAllPagesToggle() }) expect(result.current.selectAllPages).toBe(true) act(() => { result.current.toggleAll() }) expect(result.current.selectAllPages).toBe(false) }) }) describe('Select All Pages', () => { it('should toggle selectAllPages flag', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.selectAllPagesToggle() }) expect(result.current.selectAllPages).toBe(true) act(() => { result.current.selectAllPagesToggle() }) expect(result.current.selectAllPages).toBe(false) }) it('should clear individual selections when selecting all pages', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.toggleRow('1') result.current.toggleRow('2') }) expect(result.current.selectedIds.size).toBe(2) act(() => { result.current.selectAllPagesToggle() }) expect(result.current.selectAllPages).toBe(true) expect(result.current.selectedIds.size).toBe(0) }) it('should call onSelectAllPages callback', () => { const onSelectAllPages = jest.fn() const { result } = renderHook(() => useSelection({ ...defaultProps, onSelectAllPages }) ) act(() => { result.current.selectAllPagesToggle() }) expect(onSelectAllPages).toHaveBeenCalledWith(true) act(() => { result.current.selectAllPagesToggle() }) expect(onSelectAllPages).toHaveBeenCalledWith(false) }) it('should disable selectAllPages when toggling individual row', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.selectAllPagesToggle() }) expect(result.current.selectAllPages).toBe(true) act(() => { result.current.toggleRow('1') }) expect(result.current.selectAllPages).toBe(false) }) }) describe('Clear Selection', () => { it('should clear all selections', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.toggleRow('1') result.current.toggleRow('2') }) expect(result.current.selectedIds.size).toBe(2) act(() => { result.current.clearSelection() }) expect(result.current.selectedIds.size).toBe(0) expect(result.current.selectAllPages).toBe(false) }) it('should clear selectAllPages flag', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.selectAllPagesToggle() }) expect(result.current.selectAllPages).toBe(true) act(() => { result.current.clearSelection() }) expect(result.current.selectAllPages).toBe(false) }) it('should call callbacks when clearing', () => { const onSelectionChange = jest.fn() const onSelectAllPages = jest.fn() const { result } = renderHook(() => useSelection({ ...defaultProps, onSelectionChange, onSelectAllPages }) ) act(() => { result.current.toggleRow('1') }) onSelectionChange.mockClear() act(() => { result.current.clearSelection() }) expect(onSelectionChange).toHaveBeenCalledWith(expect.any(Set)) expect(onSelectionChange.mock.calls[0][0].size).toBe(0) expect(onSelectAllPages).toHaveBeenCalledWith(false) }) }) describe('Get Selected Count', () => { it('should return correct count for individual selections', () => { const { result } = renderHook(() => useSelection(defaultProps)) expect(result.current.getSelectedCount()).toBe(0) act(() => { result.current.toggleRow('1') }) expect(result.current.getSelectedCount()).toBe(1) act(() => { result.current.toggleRow('2') }) expect(result.current.getSelectedCount()).toBe(2) }) it('should return totalCount when selectAllPages is true', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.selectAllPagesToggle() }) expect(result.current.getSelectedCount()).toBe(10) // totalCount }) }) describe('Edge Cases', () => { it('should handle empty current page data', () => { const { result } = renderHook(() => useSelection({ ...defaultProps, currentPageData: [] }) ) act(() => { result.current.toggleAll() }) expect(result.current.selectedIds.size).toBe(0) }) it('should handle selecting non-existent row', () => { const { result } = renderHook(() => useSelection(defaultProps)) act(() => { result.current.toggleRow('non-existent') }) expect(result.current.selectedIds.has('non-existent')).toBe(true) expect(result.current.selectedIds.size).toBe(1) }) it('should maintain selection across page changes', () => { const { result, rerender } = renderHook( ({ data }) => useSelection({ ...defaultProps, currentPageData: data }), { initialProps: { data: mockData } } ) act(() => { result.current.toggleRow('1') result.current.toggleRow('2') }) expect(result.current.selectedIds.size).toBe(2) // Simulate page change const newPageData = [ { id: '4', name: 'Item 4' }, { id: '5', name: 'Item 5' }, ] rerender({ data: newPageData }) // Previous selections should be maintained expect(result.current.selectedIds.size).toBe(2) expect(result.current.selectedIds.has('1')).toBe(true) expect(result.current.selectedIds.has('2')).toBe(true) }) }) })