import { describe, it, expect, beforeEach } from 'vitest' import { renderHook, act } from '@testing-library/react' import { useSort } from './use-sort' import { useWidgetStore } from '../../stores/widget-store' import type { TableRow } from '../types' describe('useSort', () => { const testData: TableRow[] = [ { id: 1, name: 'Charlie', age: 30 }, { id: 2, name: 'Alice', age: 25 }, { id: 3, name: 'Bob', age: 35 }, ] // Clear widget store before each test beforeEach(() => { useWidgetStore.getState().clearWidgets() }) describe('initialization', () => { it('should initialize with default values', () => { const { result } = renderHook(() => useSort('test-widget', testData)) expect(result.current.columnId).toBeNull() expect(result.current.direction).toBe('asc') expect(result.current.sortedData).toEqual(testData) }) it('should initialize with custom values', () => { const { result } = renderHook(() => useSort('test-widget', testData)) expect(result.current.columnId).toBeNull() expect(result.current.direction).toBe('asc') }) it('should sort data when column is set', () => { const { result } = renderHook(() => useSort('test-widget', testData)) act(() => { result.current.setSort('name', 'asc') }) expect(result.current.sortedData.map((r) => r.name)).toEqual([ 'Alice', 'Bob', 'Charlie', ]) }) }) describe('local mode', () => { it('should toggle sort direction on same column', () => { const { result } = renderHook(() => useSort('test-widget', testData)) // First toggle - set to asc act(() => { result.current.toggleSort('name') }) expect(result.current.columnId).toBe('name') expect(result.current.direction).toBe('asc') // Second toggle - change to desc act(() => { result.current.toggleSort('name') }) expect(result.current.columnId).toBe('name') expect(result.current.direction).toBe('desc') // Third toggle - back to asc act(() => { result.current.toggleSort('name') }) expect(result.current.direction).toBe('asc') }) it('should reset to asc when changing column', () => { const { result } = renderHook(() => useSort('test-widget', testData)) // First set name column to desc act(() => { result.current.setSort('name', 'desc') }) // Then toggle to age column act(() => { result.current.toggleSort('age') }) expect(result.current.columnId).toBe('age') expect(result.current.direction).toBe('asc') }) it('should sort data ascending', () => { const { result } = renderHook(() => useSort('test-widget', testData)) act(() => { result.current.toggleSort('name') }) expect(result.current.sortedData.map((r) => r.name)).toEqual([ 'Alice', 'Bob', 'Charlie', ]) }) it('should sort data descending', () => { const { result } = renderHook(() => useSort('test-widget', testData)) // First toggle sets to asc act(() => { result.current.toggleSort('name') }) // Second toggle sets to desc act(() => { result.current.toggleSort('name') }) expect(result.current.sortedData.map((r) => r.name)).toEqual([ 'Charlie', 'Bob', 'Alice', ]) }) it('should sort numbers correctly', () => { const { result } = renderHook(() => useSort('test-widget', testData)) act(() => { result.current.toggleSort('age') }) expect(result.current.sortedData.map((r) => r.age)).toEqual([25, 30, 35]) }) it('should set sort state directly', () => { const { result } = renderHook(() => useSort('test-widget', testData)) act(() => { result.current.setSort('age', 'desc') }) expect(result.current.columnId).toBe('age') expect(result.current.direction).toBe('desc') expect(result.current.sortedData.map((r) => r.age)).toEqual([35, 30, 25]) }) it('should clear sort', () => { const { result } = renderHook(() => useSort('test-widget', testData)) // First set a sort act(() => { result.current.setSort('name', 'desc') }) // Then clear it act(() => { result.current.clearSort() }) expect(result.current.columnId).toBeNull() expect(result.current.direction).toBe('asc') expect(result.current.sortedData).toEqual(testData) }) it('should persist state in widget store', () => { const { result, unmount } = renderHook(() => useSort('test-widget', testData), ) act(() => { result.current.toggleSort('name') result.current.toggleSort('name') // toggle to desc }) expect(result.current.columnId).toBe('name') expect(result.current.direction).toBe('desc') // Unmount and remount - state should persist unmount() const { result: newResult } = renderHook(() => useSort('test-widget', testData), ) expect(newResult.current.columnId).toBe('name') expect(newResult.current.direction).toBe('desc') }) }) describe('remote mode', () => { it('should return data as-is in remote mode', () => { useWidgetStore.getState().setWidget('test-widget', { mode: 'remote', sort: { columnId: null, direction: 'asc' }, }) const { result } = renderHook(() => useSort('test-widget', testData)) // In remote mode, sortedData should be the original data // since server handles sorting expect(result.current.sortedData).toEqual(testData) }) it('should update store state when toggling sort in remote mode', () => { useWidgetStore.getState().setWidget('test-widget', { mode: 'remote', sort: { columnId: null, direction: 'asc' }, }) const { result } = renderHook(() => useSort('test-widget', testData)) act(() => { result.current.toggleSort('name') }) expect(result.current.columnId).toBe('name') expect(result.current.direction).toBe('asc') }) it('should update store state when setting sort in remote mode', () => { useWidgetStore.getState().setWidget('test-widget', { mode: 'remote', sort: { columnId: null, direction: 'asc' }, }) const { result } = renderHook(() => useSort('test-widget', testData)) act(() => { result.current.setSort('age', 'desc') }) expect(result.current.columnId).toBe('age') expect(result.current.direction).toBe('desc') // Data should still be unmodified in remote mode expect(result.current.sortedData).toEqual(testData) }) }) describe('edge cases', () => { it('should handle empty data', () => { const { result } = renderHook(() => useSort('test-widget', [])) expect(result.current.sortedData).toEqual([]) act(() => { result.current.toggleSort('name') }) expect(result.current.sortedData).toEqual([]) }) it('should handle single item data', () => { const singleItem = [{ id: 1, name: 'Alice' }] const { result } = renderHook(() => useSort('test-widget', singleItem)) act(() => { result.current.toggleSort('name') }) expect(result.current.sortedData).toEqual(singleItem) }) it('should preserve sort when data changes', () => { const { result, rerender } = renderHook( ({ data }) => useSort('test-widget', data), { initialProps: { data: testData } }, ) act(() => { result.current.toggleSort('name') }) expect(result.current.sortedData.map((r) => r.name)).toEqual([ 'Alice', 'Bob', 'Charlie', ]) // Add new data const newData: TableRow[] = [ ...testData, { id: 4, name: 'David', age: 28 }, ] rerender({ data: newData }) expect(result.current.sortedData.map((r) => r.name)).toEqual([ 'Alice', 'Bob', 'Charlie', 'David', ]) }) }) })