import { describe, it, expect, vi, beforeEach } from 'vitest' import { renderHook, waitFor } from '@testing-library/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { ReactNode } from 'react' import { useRealtimeData } from '../useRealtimeData' const mockSubscribe = vi.fn(() => vi.fn()) const mockShowInfo = vi.fn() const mockShowWarning = vi.fn() vi.mock('../../components/WebSocketProvider', () => ({ useWebSocketContext: () => ({ isConnected: true, lastMessage: null, subscribe: mockSubscribe, }), })) vi.mock('../../contexts/SnackbarContext', () => ({ useSnackbar: () => ({ showInfo: mockShowInfo, showWarning: mockShowWarning, showError: vi.fn(), showSuccess: vi.fn(), }), })) describe('useRealtimeData', () => { let queryClient: QueryClient beforeEach(() => { queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, }, }) vi.clearAllMocks() }) const wrapper = ({ children }: { children: ReactNode }) => ( { children } ) it('subscribes to all message types on mount', () => { renderHook(() => useRealtimeData(), { wrapper }) expect(mockSubscribe).toHaveBeenCalledWith('order_update', expect.any(Function)) expect(mockSubscribe).toHaveBeenCalledWith('position_update', expect.any(Function)) expect(mockSubscribe).toHaveBeenCalledWith('price_update', expect.any(Function)) expect(mockSubscribe).toHaveBeenCalledWith('alert_triggered', expect.any(Function)) expect(mockSubscribe).toHaveBeenCalledWith('strategy_signal', expect.any(Function)) expect(mockSubscribe).toHaveBeenCalledWith('system_event', expect.any(Function)) }) it('handles order update messages', async () => { const unsubscribeMock = vi.fn() let orderHandler: ((message: any) => void) | undefined mockSubscribe.mockImplementation((type: string, handler: any) => { if (type === 'order_update') { orderHandler = handler } return unsubscribeMock }) const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries') renderHook(() => useRealtimeData(), { wrapper }) // Simulate order filled message if (orderHandler) { orderHandler({ type: 'order_update', order_id: '123', status: 'filled' }) } await waitFor(() => { expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: ['orders'] }) expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: ['balance'] }) }) expect(mockShowInfo).toHaveBeenCalledWith('Order 123 filled') }) it('handles alert triggered messages', async () => { let alertHandler: ((message: any) => void) | undefined mockSubscribe.mockImplementation((type: string, handler: any) => { if (type === 'alert_triggered') { alertHandler = handler } return vi.fn() }) const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries') renderHook(() => useRealtimeData(), { wrapper }) // Simulate alert triggered if (alertHandler) { alertHandler({ type: 'alert_triggered', alert_name: 'BTC Price Alert' }) } await waitFor(() => { expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: ['alerts'] }) }) expect(mockShowWarning).toHaveBeenCalledWith('Alert triggered: BTC Price Alert') }) it('unsubscribes from all message types on unmount', () => { const unsubscribeMocks = { order_update: vi.fn(), position_update: vi.fn(), price_update: vi.fn(), alert_triggered: vi.fn(), strategy_signal: vi.fn(), system_event: vi.fn(), } mockSubscribe.mockImplementation((type: string) => { return unsubscribeMocks[type as keyof typeof unsubscribeMocks] || vi.fn() }) const { unmount } = renderHook(() => useRealtimeData(), { wrapper }) unmount() expect(unsubscribeMocks.order_update).toHaveBeenCalled() expect(unsubscribeMocks.position_update).toHaveBeenCalled() expect(unsubscribeMocks.price_update).toHaveBeenCalled() expect(unsubscribeMocks.alert_triggered).toHaveBeenCalled() expect(unsubscribeMocks.strategy_signal).toHaveBeenCalled() expect(unsubscribeMocks.system_event).toHaveBeenCalled() }) })