Skip to content

Commit 94bf2e0

Browse files
author
Kautilya Tripathi
committed
frontend: Add tests for websocket multiplexer
Signed-off-by: Kautilya Tripathi <ktripathi@microsoft.com>
1 parent b1b02b4 commit 94bf2e0

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { WebSocketManager } from './webSocket';
3+
4+
// Mock WebSocket
5+
class MockWebSocket {
6+
onopen: (() => void) | null = null;
7+
onmessage: ((event: MessageEvent) => void) | null = null;
8+
onclose: (() => void) | null = null;
9+
onerror: ((event: Event) => void) | null = null;
10+
readyState = 0; // WebSocket.CONNECTING
11+
send = vi.fn();
12+
13+
constructor() {
14+
setTimeout(() => {
15+
this.readyState = 1; // WebSocket.OPEN
16+
this.onopen?.();
17+
}, 0);
18+
}
19+
20+
close() {
21+
this.readyState = 3; // WebSocket.CLOSED
22+
this.onclose?.();
23+
}
24+
}
25+
26+
// Mock localStorage
27+
const mockGetUserId = vi.fn().mockReturnValue('test-user-id');
28+
vi.mock('../../../helpers', () => ({
29+
getUserIdFromLocalStorage: () => mockGetUserId(),
30+
}));
31+
32+
describe('WebSocketManager', () => {
33+
let originalWebSocket: typeof WebSocket;
34+
35+
beforeEach(() => {
36+
// Save original WebSocket
37+
originalWebSocket = global.WebSocket;
38+
// Replace with mock
39+
(global as any).WebSocket = MockWebSocket;
40+
41+
// Reset WebSocketManager state
42+
WebSocketManager.socketMultiplexer = null;
43+
WebSocketManager.connecting = false;
44+
WebSocketManager.isReconnecting = false;
45+
WebSocketManager.listeners.clear();
46+
WebSocketManager.completedPaths.clear();
47+
WebSocketManager.activeSubscriptions.clear();
48+
WebSocketManager.pendingUnsubscribes.clear();
49+
50+
// Reset mocks
51+
vi.clearAllMocks();
52+
});
53+
54+
afterEach(() => {
55+
// Restore original WebSocket
56+
global.WebSocket = originalWebSocket;
57+
});
58+
59+
describe('createKey', () => {
60+
it('should create a unique key from clusterId, path, and query', () => {
61+
const key = WebSocketManager.createKey('cluster1', '/api/v1/pods', 'watch=true');
62+
expect(key).toBe('cluster1:/api/v1/pods:watch=true');
63+
});
64+
});
65+
66+
describe('connect', () => {
67+
it('should establish a WebSocket connection', async () => {
68+
const socket = await WebSocketManager.connect();
69+
expect(socket).toBeDefined();
70+
expect(WebSocketManager.socketMultiplexer).toBe(socket);
71+
expect(WebSocketManager.connecting).toBe(false);
72+
});
73+
74+
it('should reuse existing connection if available', async () => {
75+
const socket1 = await WebSocketManager.connect();
76+
const socket2 = await WebSocketManager.connect();
77+
expect(socket1).toBe(socket2);
78+
});
79+
});
80+
81+
describe('handleWebSocketMessage', () => {
82+
it('should handle COMPLETE messages', async () => {
83+
// First connect
84+
await WebSocketManager.connect();
85+
86+
const key = WebSocketManager.createKey('cluster1', '/api/v1/pods', 'watch=true');
87+
88+
// Simulate receiving a COMPLETE message
89+
const message = {
90+
clusterId: 'cluster1',
91+
path: '/api/v1/pods',
92+
query: 'watch=true',
93+
type: 'COMPLETE',
94+
};
95+
96+
WebSocketManager.handleWebSocketMessage({ data: JSON.stringify(message) } as MessageEvent);
97+
98+
expect(WebSocketManager.completedPaths.has(key)).toBe(true);
99+
});
100+
});
101+
});

0 commit comments

Comments
 (0)