Files
crypto_trader/frontend/src/hooks/__tests__/useRealtimeData.test.ts

135 lines
4.3 KiB
TypeScript

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 }) => (
<QueryClientProvider client= { queryClient } > { children } </QueryClientProvider>
)
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()
})
})