Download desktop/src/api/websocket.test.ts from chenbhao/codev: direct link, hf CLI and curl.
- Browser
- Download file 3.52 kB
-
https://huggingface.co/chenbhao/codev/resolve/e40073cc959cd4729bf4009662bca374c5c4e266/desktop/src/api/websocket.test.ts
- Command line
-
hf download hf://chenbhao/codev@e40073cc959cd4729bf4009662bca374c5c4e266/desktop/src/api/websocket.test.ts
-
curl -L -o websocket.test.ts https://huggingface.co/chenbhao/codev/resolve/e40073cc959cd4729bf4009662bca374c5c4e266/desktop/src/api/websocket.test.ts
3.52 kB
| import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' | |
| const clientMocks = vi.hoisted(() => ({ | |
| baseUrl: 'http://127.0.0.1:3456', | |
| authToken: null as string | null, | |
| })) | |
| vi.mock('./client', () => ({ | |
| getBaseUrl: () => clientMocks.baseUrl, | |
| getAuthToken: () => clientMocks.authToken, | |
| })) | |
| import { buildSessionWebSocketUrl, wsManager } from './websocket' | |
| type SocketHandler = (() => void) | ((event: { data: string }) => void) | |
| class FakeWebSocket { | |
| static readonly CONNECTING = 0 | |
| static readonly OPEN = 1 | |
| static readonly CLOSING = 2 | |
| static readonly CLOSED = 3 | |
| static instances: FakeWebSocket[] = [] | |
| readonly url: string | |
| readyState = FakeWebSocket.CONNECTING | |
| onopen: SocketHandler | null = null | |
| onmessage: SocketHandler | null = null | |
| onclose: SocketHandler | null = null | |
| onerror: SocketHandler | null = null | |
| sent: string[] = [] | |
| constructor(url: string) { | |
| this.url = url | |
| FakeWebSocket.instances.push(this) | |
| } | |
| send(data: string) { | |
| this.sent.push(data) | |
| } | |
| close() { | |
| this.readyState = FakeWebSocket.CLOSED | |
| ;(this.onclose as (() => void) | null)?.() | |
| } | |
| open() { | |
| this.readyState = FakeWebSocket.OPEN | |
| ;(this.onopen as (() => void) | null)?.() | |
| } | |
| fail() { | |
| this.readyState = FakeWebSocket.CLOSED | |
| ;(this.onclose as (() => void) | null)?.() | |
| } | |
| } | |
| describe('wsManager reconnect buffering', () => { | |
| const originalWebSocket = globalThis.WebSocket | |
| beforeEach(() => { | |
| vi.useFakeTimers() | |
| clientMocks.baseUrl = 'http://127.0.0.1:3456' | |
| clientMocks.authToken = null | |
| FakeWebSocket.instances = [] | |
| globalThis.WebSocket = FakeWebSocket as unknown as typeof WebSocket | |
| wsManager.disconnectAll() | |
| }) | |
| afterEach(() => { | |
| wsManager.disconnectAll() | |
| globalThis.WebSocket = originalWebSocket | |
| vi.useRealTimers() | |
| }) | |
| it('replays queued messages after an unexpected reconnect', async () => { | |
| wsManager.connect('session-reconnect') | |
| const firstSocket = FakeWebSocket.instances[0] | |
| expect(firstSocket?.url).toContain('/ws/session-reconnect') | |
| firstSocket!.open() | |
| wsManager.send('session-reconnect', { type: 'user_message', content: 'first' }) | |
| expect(firstSocket!.sent).toEqual([ | |
| JSON.stringify({ type: 'user_message', content: 'first' }), | |
| ]) | |
| firstSocket!.fail() | |
| wsManager.send('session-reconnect', { type: 'user_message', content: 'queued while offline' }) | |
| await vi.advanceTimersByTimeAsync(1000) | |
| const secondSocket = FakeWebSocket.instances[1] | |
| expect(secondSocket).toBeDefined() | |
| secondSocket!.open() | |
| expect(secondSocket!.sent).toEqual([ | |
| JSON.stringify({ type: 'user_message', content: 'queued while offline' }), | |
| ]) | |
| }) | |
| it('builds websocket URLs from http and encodes token query params', () => { | |
| clientMocks.baseUrl = 'http://10.0.0.2:3456' | |
| clientMocks.authToken = 'h5 token/with?chars' | |
| expect(buildSessionWebSocketUrl('session-reconnect')).toBe( | |
| 'ws://10.0.0.2:3456/ws/session-reconnect?token=h5+token%2Fwith%3Fchars', | |
| ) | |
| }) | |
| it('upgrades https backends to wss', () => { | |
| clientMocks.baseUrl = 'https://remote.example.com' | |
| expect(buildSessionWebSocketUrl('secure-session')).toBe( | |
| 'wss://remote.example.com/ws/secure-session', | |
| ) | |
| }) | |
| it('preserves reverse-proxy subpaths when building websocket URLs', () => { | |
| clientMocks.baseUrl = 'https://public.example.com/app' | |
| expect(buildSessionWebSocketUrl('s1')).toBe( | |
| 'wss://public.example.com/app/ws/s1', | |
| ) | |
| }) | |
| }) | |