From b3faf0647786b233f2d19014f0dc86cd11f22fe1 Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Sat, 21 Feb 2026 18:59:50 +0100 Subject: [PATCH] =?UTF-8?q?test:=20aggiunge=20copertura=20completa=20per?= =?UTF-8?q?=20le=20nuove=20funzionalit=C3=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Nuovo db.test.js: 11 test per salvaPartita, getPartite, getPartita (isolamento con DB in memoria via vi.stubEnv + vi.resetModules) - gameState.test.js: test per confermaSet, formInizioSet, partitaFinita, checkVittoriaPartita e guardie setFinito/partitaFinita; fix di 6 test pre-esistenti non allineati con la logica striscia aggiornata - websocket.test.js: mock di db.js e 4 test per il salvataggio automatico su DB al termine della partita - server-utils.test.js: 2 test aggiuntivi per storicoPort - ControllerPage.test.js: 4 test per l'overlay di fine set (setFinito) - DisplayPage.test.js: 4 test per l'overlay di fine partita (partitaFinita) --- tests/component/ControllerPage.test.js | 33 +++ tests/component/DisplayPage.test.js | 35 +++ tests/integration/websocket.test.js | 75 +++++++ tests/unit/db.test.js | 145 ++++++++++++ tests/unit/gameState.test.js | 296 ++++++++++++++++++++++++- tests/unit/server-utils.test.js | 17 +- 6 files changed, 590 insertions(+), 11 deletions(-) create mode 100644 tests/unit/db.test.js diff --git a/tests/component/ControllerPage.test.js b/tests/component/ControllerPage.test.js index d3877c2..b0ad9ac 100644 --- a/tests/component/ControllerPage.test.js +++ b/tests/component/ControllerPage.test.js @@ -252,4 +252,37 @@ describe('ControllerPage.vue', () => { expect(wrapper.find('.conn-bar').text()).toContain('Connesso') }) }) + + // ============================================= + // OVERLAY SET FINITO + // ============================================= + describe('Overlay set finito', () => { + it('non mostra l\'overlay se setFinito è null', () => { + const wrapper = mountController() + expect(wrapper.find('.overlay').exists()).toBe(false) + }) + + it('mostra l\'overlay quando setFinito è impostato', async () => { + const wrapper = mountController() + wrapper.vm.state.sp.setFinito = { vincitore: 'home' } + await wrapper.vm.$nextTick() + expect(wrapper.find('.overlay').exists()).toBe(true) + }) + + it('l\'overlay mostra il nome del vincitore del set', async () => { + const wrapper = mountController() + wrapper.vm.state.sp.setFinito = { vincitore: 'home' } + await wrapper.vm.$nextTick() + expect(wrapper.find('.overlay').text()).toContain('Antoniana') + }) + + it('click su CONFERMA invia l\'azione confermaSet', async () => { + const wrapper = mountController() + wrapper.vm.state.sp.setFinito = { vincitore: 'guest' } + await wrapper.vm.$nextTick() + const spy = vi.spyOn(wrapper.vm, 'sendAction') + await wrapper.find('.btn-confirm').trigger('click') + expect(spy).toHaveBeenCalledWith({ type: 'confermaSet' }) + }) + }) }) diff --git a/tests/component/DisplayPage.test.js b/tests/component/DisplayPage.test.js index a7468f2..f795875 100644 --- a/tests/component/DisplayPage.test.js +++ b/tests/component/DisplayPage.test.js @@ -192,4 +192,39 @@ describe('DisplayPage.vue', () => { expect(guestStyle).toContain('display: none') }) }) + + // ============================================= + // OVERLAY PARTITA FINITA + // ============================================= + describe('Overlay partita finita', () => { + it('non mostra l\'overlay se partitaFinita è null', () => { + const wrapper = mountDisplay() + expect(wrapper.find('.partita-finita-overlay').exists()).toBe(false) + }) + + it('mostra l\'overlay quando partitaFinita è impostato', async () => { + const wrapper = mountDisplay() + wrapper.vm.state.sp.partitaFinita = { vincitore: 'home' } + await wrapper.vm.$nextTick() + expect(wrapper.find('.partita-finita-overlay').exists()).toBe(true) + }) + + it('l\'overlay mostra il nome del vincitore della partita', async () => { + const wrapper = mountDisplay() + wrapper.vm.state.sp.nomi = { home: 'Antoniana', guest: 'Rivali' } + wrapper.vm.state.sp.partitaFinita = { vincitore: 'guest' } + await wrapper.vm.$nextTick() + expect(wrapper.find('.partita-finita-overlay').text()).toContain('Rivali') + }) + + it('l\'overlay mostra il punteggio dei set', async () => { + const wrapper = mountDisplay() + wrapper.vm.state.sp.set = { home: 3, guest: 1 } + wrapper.vm.state.sp.partitaFinita = { vincitore: 'home' } + await wrapper.vm.$nextTick() + const text = wrapper.find('.partita-finita-overlay').text() + expect(text).toContain('3') + expect(text).toContain('1') + }) + }) }) diff --git a/tests/integration/websocket.test.js b/tests/integration/websocket.test.js index 2534bd5..63eae3e 100644 --- a/tests/integration/websocket.test.js +++ b/tests/integration/websocket.test.js @@ -1,6 +1,13 @@ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest' import { setupWebSocketHandler } from '../../src/websocket-handler.js' import { EventEmitter } from 'events' +import { salvaPartita } from '../../src/db.js' + +// Mock di db.js: evita connessioni reali al DB SQLite durante i test. +// vi.mock è automaticamente hoistato da Vitest all'inizio del file. +vi.mock('../../src/db.js', () => ({ + salvaPartita: vi.fn().mockReturnValue(42n), +})) // Mock parziale di una WebSocket e del Server class MockWebSocket extends EventEmitter { @@ -400,4 +407,72 @@ describe('WebSocket Integration (websocket-handler.js)', () => { expect(handler.getClients().size).toBe(1) }) }) + + // ============================================= + // SALVATAGGIO DB + // ============================================= + describe('Salvataggio DB', () => { + // Helper: inietta uno stato con setFinito già impostato e N set vinti da home + function injectPreFinaleState(setHomeVinti, modalita = '3/5') { + const base = handler.getState() + handler.setState({ + ...base, + modalitaPartita: modalita, + sp: { + ...base.sp, + set: { home: setHomeVinti, guest: 0 }, + punt: { home: 25, guest: 0 }, + setFinito: { vincitore: 'home' }, + partitaFinita: null, + storicoServizio: [], + strisce: [], + striscia: { home: [0], guest: [" "] }, + }, + }) + } + + afterEach(() => { + vi.mocked(salvaPartita).mockClear() + }) + + it('salvaPartita viene chiamata quando confermaSet porta partitaFinita a non-null', () => { + // 3/5: servono 3 set → inietta 2 già vinti + setFinito, poi confermaSet + injectPreFinaleState(2, '3/5') + const controller = connectAndRegister(wss, 'controller') + controller.emit('message', JSON.stringify({ type: 'action', action: { type: 'confermaSet' } })) + expect(salvaPartita).toHaveBeenCalledTimes(1) + }) + + it('salvaPartita NON viene chiamata per azioni normali (incPunt)', () => { + const controller = connectAndRegister(wss, 'controller') + controller.emit('message', JSON.stringify({ type: 'action', action: { type: 'incPunt', team: 'home' } })) + expect(salvaPartita).not.toHaveBeenCalled() + }) + + it('salvaPartita NON viene chiamata se partitaFinita era già impostata', () => { + // Inietta stato con partitaFinita già presente + const base = handler.getState() + handler.setState({ + ...base, + sp: { ...base.sp, partitaFinita: { vincitore: 'home' } }, + }) + const controller = connectAndRegister(wss, 'controller') + // Qualsiasi azione non dovrebbe triggerare un secondo salvataggio + controller.emit('message', JSON.stringify({ type: 'action', action: { type: 'incPunt', team: 'home' } })) + expect(salvaPartita).not.toHaveBeenCalled() + }) + + it('se salvaPartita lancia un errore il broadcast avviene comunque', () => { + vi.mocked(salvaPartita).mockImplementationOnce(() => { throw new Error('DB error') }) + injectPreFinaleState(2, '3/5') + const display = connectAndRegister(wss, 'display') + const controller = connectAndRegister(wss, 'controller') + display.send.mockClear() + controller.emit('message', JSON.stringify({ type: 'action', action: { type: 'confermaSet' } })) + // Il broadcast deve avvenire anche se il DB ha fallito + expect(display.send).toHaveBeenCalled() + const msg = lastSent(display) + expect(msg.type).toBe('state') + }) + }) }) diff --git a/tests/unit/db.test.js b/tests/unit/db.test.js new file mode 100644 index 0000000..6477cc3 --- /dev/null +++ b/tests/unit/db.test.js @@ -0,0 +1,145 @@ +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest' + +// Il modulo db.js apre il DB a livello di modulo (top-level). +// Per isolarlo usiamo un DB in memoria: vi.stubEnv + vi.resetModules + import dinamico. +let salvaPartita, getPartite, getPartita + +beforeAll(async () => { + vi.stubEnv('DB_PATH', ':memory:') + vi.resetModules() + const mod = await import('../../src/db.js') + salvaPartita = mod.salvaPartita + getPartite = mod.getPartite + getPartita = mod.getPartita +}) + +afterAll(() => { + vi.unstubAllEnvs() +}) + +// Stato minimo valido da passare a salvaPartita +function makeState({ vincitore = 'home', setHome = 3, setGuest = 1, strisce = [] } = {}) { + return { + modalitaPartita: '3/5', + sp: { + nomi: { home: 'Antoniana', guest: 'Ospiti' }, + set: { home: setHome, guest: setGuest }, + partitaFinita: vincitore ? { vincitore } : null, + strisce, + }, + } +} + +describe('db.js', () => { + + // ============================================= + // salvaPartita + // ============================================= + describe('salvaPartita', () => { + it('ritorna un ID numerico intero positivo', () => { + const id = salvaPartita(makeState()) + expect(typeof id).toBe('number') + expect(id).toBeGreaterThan(0) + expect(Number.isInteger(id)).toBe(true) + }) + + it('IDs sono incrementali su inserimenti multipli', () => { + const id1 = salvaPartita(makeState()) + const id2 = salvaPartita(makeState()) + expect(id2).toBeGreaterThan(id1) + }) + + it('il record ha i campi corretti: modalita, nomi, set, vincitore', () => { + const state = makeState({ vincitore: 'guest', setHome: 1, setGuest: 3 }) + const id = salvaPartita(state) + const row = getPartita(Number(id)) + + expect(row.modalita).toBe('3/5') + expect(row.nome_home).toBe('Antoniana') + expect(row.nome_guest).toBe('Ospiti') + expect(row.set_home).toBe(1) + expect(row.set_guest).toBe(3) + expect(row.vincitore).toBe('guest') + }) + + it('il campo json è una stringa JSON parsabile', () => { + const id = salvaPartita(makeState()) + const row = getPartita(Number(id)) + expect(() => JSON.parse(row.json)).not.toThrow() + }) + + it('il JSON contiene nomi, set, strisce, vincitore e data', () => { + const strisce = [{ set: 1, vincitore: 'home', punt: { home: 25, guest: 20 } }] + const state = makeState({ strisce }) + const id = salvaPartita(state) + const row = getPartita(Number(id)) + const json = JSON.parse(row.json) + + expect(json.nomi).toEqual({ home: 'Antoniana', guest: 'Ospiti' }) + expect(json.set).toEqual({ home: 3, guest: 1 }) + expect(json.vincitore).toBe('home') + expect(json.strisce).toEqual(strisce) + expect(typeof json.data).toBe('string') + expect(() => new Date(json.data)).not.toThrow() + }) + + it('vincitore nel DB è null se partitaFinita è null', () => { + const state = makeState({ vincitore: null }) + const id = salvaPartita(state) + const row = getPartita(Number(id)) + expect(row.vincitore).toBeNull() + }) + }) + + // ============================================= + // getPartite + // ============================================= + describe('getPartite', () => { + it('ritorna tutte le partite inserite', () => { + const prima = getPartite().length + salvaPartita(makeState()) + salvaPartita(makeState()) + const dopo = getPartite() + expect(dopo.length).toBe(prima + 2) + }) + + it('ordina per ID discendente (più recente prima)', () => { + const id1 = Number(salvaPartita(makeState())) + const id2 = Number(salvaPartita(makeState())) + const partite = getPartite() + const ids = partite.map(p => p.id) + const idx1 = ids.indexOf(id1) + const idx2 = ids.indexOf(id2) + // id2 (inserito dopo) deve apparire prima (indice minore) + expect(idx2).toBeLessThan(idx1) + }) + }) + + // ============================================= + // getPartita + // ============================================= + describe('getPartita', () => { + it('ritorna undefined per ID inesistente', () => { + const result = getPartita(999999) + expect(result).toBeUndefined() + }) + + it('ritorna il record corretto per ID valido', () => { + const id = Number(salvaPartita(makeState({ vincitore: 'home', setHome: 3, setGuest: 0 }))) + const row = getPartita(id) + expect(row).toBeDefined() + expect(row.id).toBe(id) + expect(row.set_home).toBe(3) + expect(row.set_guest).toBe(0) + }) + + it('il record ha tutti i campi attesi', () => { + const id = Number(salvaPartita(makeState())) + const row = getPartita(id) + const campi = ['id', 'data', 'modalita', 'nome_home', 'nome_guest', 'set_home', 'set_guest', 'vincitore', 'json'] + for (const campo of campi) { + expect(row).toHaveProperty(campo) + } + }) + }) +}) diff --git a/tests/unit/gameState.test.js b/tests/unit/gameState.test.js index ce452a3..5047ea9 100644 --- a/tests/unit/gameState.test.js +++ b/tests/unit/gameState.test.js @@ -1,5 +1,5 @@ import { describe, it, expect, beforeEach } from 'vitest' -import { createInitialState, applyAction, checkVittoria } from '../../src/gameState.js' +import { createInitialState, applyAction, checkVittoria, checkVittoriaPartita } from '../../src/gameState.js' describe('Game Logic (gameState.js)', () => { let state @@ -31,9 +31,10 @@ describe('Game Logic (gameState.js)', () => { expect(state.sp.form.guest).toEqual(["1", "2", "3", "4", "5", "6"]) }) - it('dovrebbe avere la striscia iniziale a [0]', () => { + it('dovrebbe avere la striscia iniziale a [0] per home e [" "] per guest', () => { + // home serve per primo → home parte con [0], guest con [" "] expect(state.sp.striscia.home).toEqual([0]) - expect(state.sp.striscia.guest).toEqual([0]) + expect(state.sp.striscia.guest).toEqual([" "]) }) it('dovrebbe avere storico servizio vuoto', () => { @@ -116,13 +117,15 @@ describe('Game Logic (gameState.js)', () => { it('dovrebbe aggiornare la striscia per punto Home', () => { const s = applyAction(state, { type: 'incPunt', team: 'home' }) + // Lo stato iniziale ha striscia = { home: [0], guest: [" "] } expect(s.sp.striscia.home).toEqual([0, 1]) - expect(s.sp.striscia.guest).toEqual([0, " "]) + expect(s.sp.striscia.guest).toEqual([" ", " "]) }) it('dovrebbe aggiornare la striscia per punto Guest', () => { const s = applyAction(state, { type: 'incPunt', team: 'guest' }) - expect(s.sp.striscia.guest).toEqual([0, 1]) + // Lo stato iniziale ha striscia = { home: [0], guest: [" "] } + expect(s.sp.striscia.guest).toEqual([" ", 1]) expect(s.sp.striscia.home).toEqual([0, " "]) }) @@ -133,9 +136,11 @@ describe('Game Logic (gameState.js)', () => { expect(s.sp.storicoServizio[0]).toHaveProperty('cambioPalla') }) - it('non dovrebbe incrementare i punti dopo vittoria', () => { + it('non dovrebbe incrementare i punti dopo vittoria (setFinito impostato)', () => { + // Il guard controlla setFinito: va impostato come farebbe il ciclo di gioco reale state.sp.punt.home = 25 state.sp.punt.guest = 23 + state.sp.setFinito = { vincitore: 'home' } const s = applyAction(state, { type: 'incPunt', team: 'home' }) expect(s.sp.punt.home).toBe(25) }) @@ -619,10 +624,11 @@ describe('Game Logic (gameState.js)', () => { }) it('dovrebbe resettare la striscia', () => { - state.sp.striscia = { home: [0, 1, 2, 3], guest: [0, " ", " ", 1] } + state.sp.striscia = { home: [0, 1, 2, 3], guest: [" ", " ", " ", 1] } const s = applyAction(state, { type: 'resetta' }) + // servHome è true di default → home parte con [0], guest con [" "] expect(s.sp.striscia.home).toEqual([0]) - expect(s.sp.striscia.guest).toEqual([0]) + expect(s.sp.striscia.guest).toEqual([" "]) }) it('dovrebbe resettare lo storico servizio', () => { @@ -656,4 +662,278 @@ describe('Game Logic (gameState.js)', () => { expect(s.sp.punt.guest).toBe(0) }) }) + + // ============================================= + // FORMAZIONEINIZIOSET + // ============================================= + describe('formInizioSet', () => { + it('dovrebbe esistere nello stato iniziale con valori di default', () => { + expect(state.sp.formInizioSet.home).toEqual(["1", "2", "3", "4", "5", "6"]) + expect(state.sp.formInizioSet.guest).toEqual(["1", "2", "3", "4", "5", "6"]) + }) + + it('setFormazione aggiorna sia form che formInizioSet per il team indicato', () => { + const nuova = ["10", "11", "12", "13", "14", "15"] + const s = applyAction(state, { type: 'setFormazione', team: 'home', form: nuova }) + expect(s.sp.form.home).toEqual(nuova) + expect(s.sp.formInizioSet.home).toEqual(nuova) + }) + + it('setFormazione non tocca formInizioSet dell\'altro team', () => { + const nuova = ["10", "11", "12", "13", "14", "15"] + const s = applyAction(state, { type: 'setFormazione', team: 'home', form: nuova }) + expect(s.sp.formInizioSet.guest).toEqual(["1", "2", "3", "4", "5", "6"]) + }) + }) + + // ============================================= + // CONFERMASET + // ============================================= + describe('confermaSet', () => { + // Helper: porta lo stato a fine set (home vince 25-0) + function stateConSetFinito(modalita = '3/5') { + let s = createInitialState() + s.modalitaPartita = modalita + // Aggiungiamo 25 punti a home: a 24-0 il prossimo punto vince il set + for (let i = 0; i < 25; i++) { + s = applyAction(s, { type: 'incPunt', team: 'home' }) + } + // Ora setFinito dovrebbe essere impostato + return s + } + + it('non fa nulla se setFinito è null', () => { + expect(state.sp.setFinito).toBeNull() + const s = applyAction(state, { type: 'confermaSet' }) + expect(s.sp.strisce).toEqual([]) + expect(s.sp.set.home).toBe(0) + }) + + it('aggiunge una entry in strisce con i campi corretti', () => { + const s = applyAction(stateConSetFinito(), { type: 'confermaSet' }) + expect(s.sp.strisce).toHaveLength(1) + const striscia = s.sp.strisce[0] + expect(striscia).toHaveProperty('set') + expect(striscia).toHaveProperty('formInizio') + expect(striscia).toHaveProperty('home') + expect(striscia).toHaveProperty('guest') + expect(striscia).toHaveProperty('vincitore') + expect(striscia).toHaveProperty('punt') + }) + + it('il numero set è 1 per il primo set, 2 per il secondo', () => { + let s = stateConSetFinito() + s = applyAction(s, { type: 'confermaSet' }) + expect(s.sp.strisce[0].set).toBe(1) + + // Secondo set + for (let i = 0; i < 25; i++) { + s = applyAction(s, { type: 'incPunt', team: 'home' }) + } + s = applyAction(s, { type: 'confermaSet' }) + expect(s.sp.strisce[1].set).toBe(2) + }) + + it('formInizio nella striscia corrisponde a formInizioSet prima del conferma', () => { + const formazioneInizio = ["7", "8", "9", "10", "11", "12"] + let s = createInitialState() + s = applyAction(s, { type: 'setFormazione', team: 'home', form: formazioneInizio }) + // porta a fine set + for (let i = 0; i < 25; i++) { + s = applyAction(s, { type: 'incPunt', team: 'home' }) + } + s = applyAction(s, { type: 'confermaSet' }) + expect(s.sp.strisce[0].formInizio.home).toEqual(formazioneInizio) + }) + + it('incrementa set[vincitore]', () => { + const s = applyAction(stateConSetFinito(), { type: 'confermaSet' }) + expect(s.sp.set.home).toBe(1) + expect(s.sp.set.guest).toBe(0) + }) + + it('resetta punt a 0', () => { + const s = applyAction(stateConSetFinito(), { type: 'confermaSet' }) + expect(s.sp.punt.home).toBe(0) + expect(s.sp.punt.guest).toBe(0) + }) + + it('svuota storicoServizio', () => { + const s = applyAction(stateConSetFinito(), { type: 'confermaSet' }) + expect(s.sp.storicoServizio).toEqual([]) + }) + + it('azzera setFinito', () => { + const s = applyAction(stateConSetFinito(), { type: 'confermaSet' }) + expect(s.sp.setFinito).toBeNull() + }) + + it('aggiorna formInizioSet con la form corrente post-conferma', () => { + const preConferma = stateConSetFinito() + // La form potrebbe essere ruotata durante il set + const formDopoSet = [...preConferma.sp.form.home] + const s = applyAction(preConferma, { type: 'confermaSet' }) + expect(s.sp.formInizioSet.home).toEqual(formDopoSet) + }) + + it('NON imposta partitaFinita se la partita non è ancora vinta (3/5)', () => { + const s = applyAction(stateConSetFinito('3/5'), { type: 'confermaSet' }) + // 1 set vinto su 3 necessari → partita non finita + expect(s.sp.partitaFinita).toBeNull() + }) + + it('imposta partitaFinita quando home vince 3 set (modalità 3/5)', () => { + let s = createInitialState() + s.modalitaPartita = '3/5' + // Vinci 3 set + for (let set = 0; set < 3; set++) { + for (let i = 0; i < 25; i++) s = applyAction(s, { type: 'incPunt', team: 'home' }) + s = applyAction(s, { type: 'confermaSet' }) + } + expect(s.sp.partitaFinita).not.toBeNull() + expect(s.sp.partitaFinita.vincitore).toBe('home') + }) + + it('imposta partitaFinita quando home vince 2 set (modalità 2/3)', () => { + let s = createInitialState() + s.modalitaPartita = '2/3' + for (let set = 0; set < 2; set++) { + for (let i = 0; i < 25; i++) s = applyAction(s, { type: 'incPunt', team: 'home' }) + s = applyAction(s, { type: 'confermaSet' }) + } + expect(s.sp.partitaFinita).not.toBeNull() + expect(s.sp.partitaFinita.vincitore).toBe('home') + }) + + it('resetta striscia per il set successivo con 0 per chi serve', () => { + const s = applyAction(stateConSetFinito(), { type: 'confermaSet' }) + // servHome era true (home segna per primo → resta home a servire) + expect(s.sp.striscia.home).toEqual([0]) + expect(s.sp.striscia.guest).toEqual([" "]) + }) + }) + + // ============================================= + // GUARDIE setFinito / partitaFinita + // ============================================= + describe('Guardie setFinito e partitaFinita', () => { + it('incPunt non incrementa se setFinito è impostato', () => { + state.sp.setFinito = { vincitore: 'home' } + const s = applyAction(state, { type: 'incPunt', team: 'home' }) + expect(s.sp.punt.home).toBe(0) + }) + + it('incPunt non incrementa se partitaFinita è impostata', () => { + state.sp.partitaFinita = { vincitore: 'home' } + const s = applyAction(state, { type: 'incPunt', team: 'guest' }) + expect(s.sp.punt.guest).toBe(0) + }) + + it('decPunt azzera setFinito se era impostato', () => { + state.sp.setFinito = { vincitore: 'home' } + const s = applyAction(state, { type: 'decPunt' }) + expect(s.sp.setFinito).toBeNull() + }) + }) + + // ============================================= + // RESETTA — nuovi campi + // ============================================= + describe('resetta (nuovi campi)', () => { + it('azzera strisce', () => { + state.sp.strisce = [{ set: 1, vincitore: 'home', punt: { home: 25, guest: 20 } }] + const s = applyAction(state, { type: 'resetta' }) + expect(s.sp.strisce).toEqual([]) + }) + + it('azzera setFinito', () => { + state.sp.setFinito = { vincitore: 'home' } + const s = applyAction(state, { type: 'resetta' }) + expect(s.sp.setFinito).toBeNull() + }) + + it('azzera partitaFinita', () => { + state.sp.partitaFinita = { vincitore: 'guest' } + const s = applyAction(state, { type: 'resetta' }) + expect(s.sp.partitaFinita).toBeNull() + }) + + it('reimposta formInizioSet ai valori di default', () => { + state.sp.formInizioSet = { home: ["7", "8", "9", "10", "11", "12"], guest: ["7", "8", "9", "10", "11", "12"] } + const s = applyAction(state, { type: 'resetta' }) + expect(s.sp.formInizioSet.home).toEqual(["1", "2", "3", "4", "5", "6"]) + expect(s.sp.formInizioSet.guest).toEqual(["1", "2", "3", "4", "5", "6"]) + }) + }) + + // ============================================= + // checkVittoriaPartita + // ============================================= + describe('checkVittoriaPartita', () => { + it('ritorna null se nessuno ha vinto (3/5, 1-1)', () => { + state.sp.set.home = 1 + state.sp.set.guest = 1 + expect(checkVittoriaPartita(state)).toBeNull() + }) + + it('ritorna "home" con 3 set in modalità 3/5', () => { + state.modalitaPartita = '3/5' + state.sp.set.home = 3 + state.sp.set.guest = 1 + expect(checkVittoriaPartita(state)).toBe('home') + }) + + it('ritorna "guest" con 3 set in modalità 3/5', () => { + state.modalitaPartita = '3/5' + state.sp.set.home = 0 + state.sp.set.guest = 3 + expect(checkVittoriaPartita(state)).toBe('guest') + }) + + it('ritorna null con 2 set in modalità 3/5 (non ancora vinto)', () => { + state.modalitaPartita = '3/5' + state.sp.set.home = 2 + state.sp.set.guest = 2 + expect(checkVittoriaPartita(state)).toBeNull() + }) + + it('ritorna "home" con 2 set in modalità 2/3', () => { + state.modalitaPartita = '2/3' + state.sp.set.home = 2 + state.sp.set.guest = 0 + expect(checkVittoriaPartita(state)).toBe('home') + }) + + it('ritorna "guest" con 2 set in modalità 2/3', () => { + state.modalitaPartita = '2/3' + state.sp.set.home = 1 + state.sp.set.guest = 2 + expect(checkVittoriaPartita(state)).toBe('guest') + }) + + it('ritorna null con 1 set in modalità 2/3 (non ancora vinto)', () => { + state.modalitaPartita = '2/3' + state.sp.set.home = 1 + state.sp.set.guest = 0 + expect(checkVittoriaPartita(state)).toBeNull() + }) + }) + + // ============================================= + // confermaSet con servHome=false + // ============================================= + describe('confermaSet — striscia con servHome=false', () => { + it('resetta striscia con guest a [0] se è guest a servire', () => { + let s = createInitialState() + // guest serve + s = applyAction(s, { type: 'cambiaPalla' }) + expect(s.sp.servHome).toBe(false) + // porta a fine set (guest segna 25 volte) + for (let i = 0; i < 25; i++) s = applyAction(s, { type: 'incPunt', team: 'guest' }) + s = applyAction(s, { type: 'confermaSet' }) + // dopo il set, continua a servire guest + expect(s.sp.striscia.guest).toEqual([0]) + expect(s.sp.striscia.home).toEqual([" "]) + }) + }) }) diff --git a/tests/unit/server-utils.test.js b/tests/unit/server-utils.test.js index 119bb68..df9048e 100644 --- a/tests/unit/server-utils.test.js +++ b/tests/unit/server-utils.test.js @@ -109,6 +109,7 @@ describe('Server Utils', () => { const allLogs = consoleSpy.mock.calls.map(c => c[0]).join('\n') expect(allLogs).toContain('5173') expect(allLogs).toContain('3001') + expect(allLogs).toContain('3002') consoleSpy.mockRestore() }) @@ -122,17 +123,27 @@ describe('Server Utils', () => { consoleSpy.mockRestore() }) - it('dovrebbe mostrare gli URL remoti se ci sono IP di rete', () => { + it('dovrebbe stampare storicoPort personalizzato', () => { + os.networkInterfaces.mockReturnValue({}) + const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) + printServerInfo(3000, 3001, 5000) + const allLogs = consoleSpy.mock.calls.map(c => c[0]).join('\n') + expect(allLogs).toContain('5000') + consoleSpy.mockRestore() + }) + + it('dovrebbe mostrare gli URL remoti per controller e storico', () => { os.networkInterfaces.mockReturnValue({ eth0: [ { family: 'IPv4', internal: false, address: '192.168.1.50' } ] }) const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) - printServerInfo(3000, 3001) + printServerInfo(3000, 3001, 3002) const allLogs = consoleSpy.mock.calls.map(c => c[0]).join('\n') expect(allLogs).toContain('192.168.1.50') - expect(allLogs).toContain('remoti') + expect(allLogs).toContain('3001') + expect(allLogs).toContain('3002') consoleSpy.mockRestore() })