import { beforeEach, describe, expect, it } from 'vitest'; import { WebSocket } from 'ws'; import { connectedUsers } from './state'; import { ConnectedUser } from './types'; import { broadcastToServer, findUserByOderId, findVoiceActiveConnection } from './broadcast'; function createMockWs(): WebSocket & { sentMessages: string[] } { const sent: string[] = []; const ws = { readyState: WebSocket.OPEN, send: (data: string) => { sent.push(data); }, close: () => {}, sentMessages: sent } as unknown as WebSocket & { sentMessages: string[] }; return ws; } function createConnectedUser( connectionId: string, oderId: string, overrides: Partial = {} ): ConnectedUser { const user: ConnectedUser = { oderId, ws: createMockWs(), authenticated: true, serverIds: new Set(['server-1']), displayName: 'Test User', lastPong: Date.now(), ...overrides }; connectedUsers.set(connectionId, user); return user; } describe('broadcastToServer', () => { beforeEach(() => { connectedUsers.clear(); }); it('delivers chat_message to every connection in the server except the sender connection', () => { createConnectedUser('conn-a1', 'user-1'); const connA2 = createConnectedUser('conn-a2', 'user-1'); const connB = createConnectedUser('conn-b', 'user-2'); broadcastToServer('server-1', { type: 'chat_message', text: 'hello' }, { excludeConnectionId: 'conn-a1' }); expect((connA2.ws as WebSocket & { sentMessages: string[] }).sentMessages).toHaveLength(1); expect((connB.ws as WebSocket & { sentMessages: string[] }).sentMessages).toHaveLength(1); expect(connectedUsers.get('conn-a1')?.ws).toBeDefined(); expect((connectedUsers.get('conn-a1')!.ws as WebSocket & { sentMessages: string[] }).sentMessages).toHaveLength(0); }); it('excludes every connection for an identity when excludeIdentityOderId is set', () => { const connA1 = createConnectedUser('conn-a1', 'user-1'); const connA2 = createConnectedUser('conn-a2', 'user-1'); const connB = createConnectedUser('conn-b', 'user-2'); broadcastToServer('server-1', { type: 'user_left', oderId: 'user-1' }, { excludeIdentityOderId: 'user-1' }); expect((connA1.ws as WebSocket & { sentMessages: string[] }).sentMessages).toHaveLength(0); expect((connA2.ws as WebSocket & { sentMessages: string[] }).sentMessages).toHaveLength(0); expect((connB.ws as WebSocket & { sentMessages: string[] }).sentMessages).toHaveLength(1); }); }); describe('findVoiceActiveConnection', () => { beforeEach(() => { connectedUsers.clear(); }); it('returns the connection marked voiceActive for the user', () => { createConnectedUser('conn-passive', 'user-1', { voiceActive: false }); const active = createConnectedUser('conn-active', 'user-1', { voiceActive: true }); expect(findVoiceActiveConnection('user-1')).toBe(active); }); it('returns undefined when no voiceActive connection exists', () => { createConnectedUser('conn-1', 'user-1'); expect(findVoiceActiveConnection('user-1')).toBeUndefined(); }); it('findUserByOderId falls back to any open connection when no voiceActive connection exists', () => { const fallback = createConnectedUser('conn-1', 'user-1'); expect(findUserByOderId('user-1')).toBe(fallback); }); });