import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest' import { setupWebSocketHandler } from '../../src/websocket-handler.js' import { EventEmitter } from 'events' class MockWebSocket extends EventEmitter { constructor() { super() this.readyState = 1 } send = vi.fn() terminate = vi.fn() } class MockWebSocketServer extends EventEmitter { clients = new Set() } function connectAndRegister(wss, role) { const ws = new MockWebSocket() wss.emit('connection', ws) wss.clients.add(ws) ws.emit('message', JSON.stringify({ type: 'register', role })) ws.send.mockClear() return ws } describe('Stress Test WebSocket', () => { let wss let handler beforeEach(() => { wss = new MockWebSocketServer() handler = setupWebSocketHandler(wss) }) afterEach(() => { vi.restoreAllMocks() }) it('dovrebbe gestire 50 client display connessi simultaneamente', () => { const displays = [] for (let i = 0; i < 50; i++) { displays.push(connectAndRegister(wss, 'display')) } expect(handler.getClients().size).toBe(50) // Un controller invia un'azione const controller = connectAndRegister(wss, 'controller') controller.emit('message', JSON.stringify({ type: 'action', action: { type: 'incPunt', team: 'home' } })) // Tutti i display devono aver ricevuto il broadcast for (const display of displays) { expect(display.send).toHaveBeenCalled() const msg = JSON.parse(display.send.mock.calls[display.send.mock.calls.length - 1][0]) expect(msg.type).toBe('state') expect(msg.state.sp.punt.home).toBe(1) } }) it('dovrebbe gestire 100 azioni rapide in sequenza con stato finale corretto', () => { const controller = connectAndRegister(wss, 'controller') // 60 punti home, 40 punti guest for (let i = 0; i < 60; i++) { controller.emit('message', JSON.stringify({ type: 'action', action: { type: 'incPunt', team: 'home' } })) } for (let i = 0; i < 40; i++) { controller.emit('message', JSON.stringify({ type: 'action', action: { type: 'incPunt', team: 'guest' } })) } // Lo stato finale dipende da checkVittoria che blocca a 25+2 // Home arriva a 25-0 → vittoria → blocca. Quindi punti home = 25 const state = handler.getState() expect(state.sp.punt.home).toBe(25) // Guest: non può segnare dopo vittoria? No, checkVittoria blocca solo il team che ha vinto? // Controlliamo: checkVittoria controlla ENTRAMBI i team. // A 25-0 → vittoria=true → incPunt per guest è anche bloccato expect(state.sp.punt.guest).toBe(0) }) it('dovrebbe garantire che tutti i display ricevano ogni update sotto carico', () => { const displays = [] for (let i = 0; i < 10; i++) { displays.push(connectAndRegister(wss, 'display')) } const controller = connectAndRegister(wss, 'controller') // 5 azioni rapide for (let i = 0; i < 5; i++) { controller.emit('message', JSON.stringify({ type: 'action', action: { type: 'incPunt', team: 'home' } })) } // Ogni display deve aver ricevuto esattamente 5 broadcast for (const display of displays) { expect(display.send).toHaveBeenCalledTimes(5) } // Verifica stato finale su tutti i display for (const display of displays) { const lastMsg = JSON.parse(display.send.mock.calls[4][0]) expect(lastMsg.state.sp.punt.home).toBe(5) } }) })