goldenChat base source add
This commit is contained in:
@@ -0,0 +1,321 @@
|
||||
/**
|
||||
* 실시간 업데이트 통합 테스트
|
||||
*/
|
||||
import { renderHook, act, waitFor } from '@testing-library/react';
|
||||
import { useRealtimeCandles } from '../hooks/useRealtimeCandles';
|
||||
import { marketSocket } from '../services/marketSocket';
|
||||
|
||||
// Mock marketSocket
|
||||
jest.mock('../services/marketSocket', () => ({
|
||||
marketSocket: {
|
||||
connect: jest.fn().mockResolvedValue(undefined),
|
||||
subscribe: jest.fn().mockReturnValue(() => {}),
|
||||
unsubscribe: jest.fn(),
|
||||
onConnectionStatusChange: jest.fn().mockReturnValue(() => {}),
|
||||
onError: jest.fn().mockReturnValue(() => {}),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('useRealtimeCandles Hook', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should connect and subscribe when enabled', async () => {
|
||||
const { result } = renderHook(() =>
|
||||
useRealtimeCandles({
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
enabled: true,
|
||||
})
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(marketSocket.connect).toHaveBeenCalled();
|
||||
expect(marketSocket.subscribe).toHaveBeenCalledWith(
|
||||
'KRW-BTC',
|
||||
'1m',
|
||||
expect.any(Function)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not connect when disabled', () => {
|
||||
renderHook(() =>
|
||||
useRealtimeCandles({
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
enabled: false,
|
||||
})
|
||||
);
|
||||
|
||||
expect(marketSocket.connect).not.toHaveBeenCalled();
|
||||
expect(marketSocket.subscribe).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update candles on snapshot', async () => {
|
||||
const onUpdate = jest.fn();
|
||||
const { result } = renderHook(() =>
|
||||
useRealtimeCandles({
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
enabled: true,
|
||||
onUpdate,
|
||||
})
|
||||
);
|
||||
|
||||
// Simulate snapshot update
|
||||
const mockUpdate = {
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
candles: [
|
||||
{ time: '2026-03-07T01:00', open: 100, high: 110, low: 90, close: 105, volume: 1000 },
|
||||
{ time: '2026-03-07T01:01', open: 105, high: 115, low: 95, close: 110, volume: 1200 },
|
||||
],
|
||||
timestamp: Date.now(),
|
||||
type: 'snapshot' as const,
|
||||
};
|
||||
|
||||
// Get the callback that was passed to subscribe
|
||||
const subscribeCall = (marketSocket.subscribe as jest.Mock).mock.calls[0];
|
||||
const callback = subscribeCall[2];
|
||||
|
||||
act(() => {
|
||||
callback(mockUpdate);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.candles).toHaveLength(2);
|
||||
expect(result.current.updateCount).toBe(1);
|
||||
expect(onUpdate).toHaveBeenCalledWith(mockUpdate.candles);
|
||||
});
|
||||
});
|
||||
|
||||
it('should update existing candle on incremental update', async () => {
|
||||
const onUpdate = jest.fn();
|
||||
const { result } = renderHook(() =>
|
||||
useRealtimeCandles({
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
enabled: true,
|
||||
onUpdate,
|
||||
})
|
||||
);
|
||||
|
||||
// Initial snapshot
|
||||
const snapshotUpdate = {
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
candles: [
|
||||
{ time: '2026-03-07T01:00', open: 100, high: 110, low: 90, close: 105, volume: 1000 },
|
||||
],
|
||||
timestamp: Date.now(),
|
||||
type: 'snapshot' as const,
|
||||
};
|
||||
|
||||
const subscribeCall = (marketSocket.subscribe as jest.Mock).mock.calls[0];
|
||||
const callback = subscribeCall[2];
|
||||
|
||||
act(() => {
|
||||
callback(snapshotUpdate);
|
||||
});
|
||||
|
||||
// Incremental update (same time, different values)
|
||||
const incrementalUpdate = {
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
candles: [
|
||||
{ time: '2026-03-07T01:00', open: 100, high: 115, low: 85, close: 108, volume: 1500 },
|
||||
],
|
||||
timestamp: Date.now(),
|
||||
type: 'update' as const,
|
||||
};
|
||||
|
||||
act(() => {
|
||||
callback(incrementalUpdate);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.candles).toHaveLength(1);
|
||||
expect(result.current.candles[0].close).toBe(108);
|
||||
expect(result.current.candles[0].volume).toBe(1500);
|
||||
expect(result.current.updateCount).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('should add new candle on incremental update', async () => {
|
||||
const onUpdate = jest.fn();
|
||||
const { result } = renderHook(() =>
|
||||
useRealtimeCandles({
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
enabled: true,
|
||||
onUpdate,
|
||||
})
|
||||
);
|
||||
|
||||
// Initial snapshot
|
||||
const snapshotUpdate = {
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
candles: [
|
||||
{ time: '2026-03-07T01:00', open: 100, high: 110, low: 90, close: 105, volume: 1000 },
|
||||
],
|
||||
timestamp: Date.now(),
|
||||
type: 'snapshot' as const,
|
||||
};
|
||||
|
||||
const subscribeCall = (marketSocket.subscribe as jest.Mock).mock.calls[0];
|
||||
const callback = subscribeCall[2];
|
||||
|
||||
act(() => {
|
||||
callback(snapshotUpdate);
|
||||
});
|
||||
|
||||
// New candle
|
||||
const newCandleUpdate = {
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
candles: [
|
||||
{ time: '2026-03-07T01:01', open: 105, high: 115, low: 95, close: 110, volume: 1200 },
|
||||
],
|
||||
timestamp: Date.now(),
|
||||
type: 'update' as const,
|
||||
};
|
||||
|
||||
act(() => {
|
||||
callback(newCandleUpdate);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.candles).toHaveLength(2);
|
||||
expect(result.current.candles[1].time).toBe('2026-03-07T01:01');
|
||||
expect(result.current.updateCount).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('should cleanup on unmount', () => {
|
||||
const { unmount } = renderHook(() =>
|
||||
useRealtimeCandles({
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
enabled: true,
|
||||
})
|
||||
);
|
||||
|
||||
const unsubscribeFn = jest.fn();
|
||||
(marketSocket.subscribe as jest.Mock).mockReturnValue(unsubscribeFn);
|
||||
|
||||
unmount();
|
||||
|
||||
// Note: In actual implementation, unsubscribe is called in cleanup
|
||||
// This test verifies the hook structure
|
||||
});
|
||||
});
|
||||
|
||||
describe('Real-time Chart Integration', () => {
|
||||
it('should handle timeframe switching', async () => {
|
||||
const { result, rerender } = renderHook(
|
||||
({ market, interval }) =>
|
||||
useRealtimeCandles({
|
||||
market,
|
||||
interval,
|
||||
enabled: true,
|
||||
}),
|
||||
{
|
||||
initialProps: { market: 'KRW-BTC', interval: '1m' },
|
||||
}
|
||||
);
|
||||
|
||||
// Initial subscription
|
||||
expect(marketSocket.subscribe).toHaveBeenCalledWith(
|
||||
'KRW-BTC',
|
||||
'1m',
|
||||
expect.any(Function)
|
||||
);
|
||||
|
||||
// Change interval
|
||||
rerender({ market: 'KRW-BTC', interval: '5m' });
|
||||
|
||||
await waitFor(() => {
|
||||
// Should resubscribe with new interval
|
||||
expect(marketSocket.subscribe).toHaveBeenCalledWith(
|
||||
'KRW-BTC',
|
||||
'5m',
|
||||
expect.any(Function)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle market switching', async () => {
|
||||
const { result, rerender } = renderHook(
|
||||
({ market, interval }) =>
|
||||
useRealtimeCandles({
|
||||
market,
|
||||
interval,
|
||||
enabled: true,
|
||||
}),
|
||||
{
|
||||
initialProps: { market: 'KRW-BTC', interval: '1m' },
|
||||
}
|
||||
);
|
||||
|
||||
// Change market
|
||||
rerender({ market: 'KRW-ETH', interval: '1m' });
|
||||
|
||||
await waitFor(() => {
|
||||
// Should resubscribe with new market
|
||||
expect(marketSocket.subscribe).toHaveBeenCalledWith(
|
||||
'KRW-ETH',
|
||||
'1m',
|
||||
expect.any(Function)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Indicator Recalculation', () => {
|
||||
it('should trigger indicator recalculation on candle update', async () => {
|
||||
// This test would require mocking the full CandlestickTestPage component
|
||||
// For now, we verify the hook behavior
|
||||
const onUpdate = jest.fn();
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useRealtimeCandles({
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
enabled: true,
|
||||
onUpdate,
|
||||
})
|
||||
);
|
||||
|
||||
const mockUpdate = {
|
||||
market: 'KRW-BTC',
|
||||
interval: '1m',
|
||||
candles: [
|
||||
{ time: '2026-03-07T01:00', open: 100, high: 110, low: 90, close: 105, volume: 1000 },
|
||||
],
|
||||
timestamp: Date.now(),
|
||||
type: 'update' as const,
|
||||
};
|
||||
|
||||
const subscribeCall = (marketSocket.subscribe as jest.Mock).mock.calls[0];
|
||||
const callback = subscribeCall[2];
|
||||
|
||||
act(() => {
|
||||
callback(mockUpdate);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(onUpdate).toHaveBeenCalled();
|
||||
expect(onUpdate).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
time: '2026-03-07T01:00',
|
||||
close: 105,
|
||||
}),
|
||||
])
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user