test(wsMixin): copri cleanup, riconnessione e guardie residue

Aggiunge test per beforeUnmount con connessione OPEN e con ws.close
che lancia, l'annullamento del reconnectTimeout allo smontaggio, la
guardia isConnecting, la chiusura della WebSocket precedente prima
di riconnettersi (incluso il caso in cui close lancia), gli errori
di registrazione/parsing nei gestori onopen/onmessage e la guardia
di scheduleReconnect contro timer doppi.
This commit is contained in:
2026-07-03 12:00:12 +02:00
parent 3d54d162e6
commit cbf927255a
+97
View File
@@ -224,5 +224,102 @@ describe('createWsMixin (wsMixin.js)', () => {
wrapper.unmount() wrapper.unmount()
expect(ws.close).toHaveBeenCalled() expect(ws.close).toHaveBeenCalled()
}) })
it('beforeUnmount con connessione OPEN chiude con codice 1000', () => {
const wrapper = mountWith()
const ws = ultimaWs()
ws.readyState = MockWebSocket.OPEN
wrapper.unmount()
expect(ws.close).toHaveBeenCalledWith(1000, 'Component unmounting')
})
it('beforeUnmount non lancia se ws.close lancia', () => {
const wrapper = mountWith()
const ws = ultimaWs()
ws.readyState = MockWebSocket.OPEN
ws.close.mockImplementation(() => { throw new Error('già chiusa') })
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
expect(() => wrapper.unmount()).not.toThrow()
expect(consoleSpy).toHaveBeenCalled()
})
it('beforeUnmount annulla un reconnectTimeout pendente', () => {
vi.useFakeTimers()
try {
const wrapper = mountWith()
wrapper.vm.isConnecting = false
wrapper.vm.scheduleReconnect()
expect(wrapper.vm.reconnectTimeout).not.toBe(null)
wrapper.unmount()
// se il timer non fosse stato annullato, allo scoccare del delay
// verrebbe creata una nuova connessione anche a componente smontato
const primaDelTimeout = MockWebSocket.instances.length
vi.advanceTimersByTime(30000)
expect(MockWebSocket.instances.length).toBe(primaDelTimeout)
} finally {
vi.useRealTimers()
}
})
})
describe('rami aggiuntivi', () => {
it('connectWebSocket non fa nulla se è già in corso un tentativo di connessione', () => {
const wrapper = mountWith()
const primaDelTimeout = MockWebSocket.instances.length
wrapper.vm.isConnecting = true
wrapper.vm.connectWebSocket()
expect(MockWebSocket.instances.length).toBe(primaDelTimeout)
})
it('riconnettendosi con la WebSocket precedente OPEN, la chiude con codice 1000', () => {
const wrapper = mountWith()
const prima = ultimaWs()
prima.readyState = MockWebSocket.OPEN
wrapper.vm.isConnecting = false
wrapper.vm.connectWebSocket()
expect(prima.close).toHaveBeenCalledWith(1000, 'Reconnecting')
})
it('se la chiusura della WebSocket precedente lancia, logga e continua a riconnettersi', () => {
const wrapper = mountWith()
const prima = ultimaWs()
prima.readyState = MockWebSocket.OPEN
prima.close.mockImplementation(() => { throw new Error('già chiusa') })
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
wrapper.vm.isConnecting = false
expect(() => wrapper.vm.connectWebSocket()).not.toThrow()
expect(consoleSpy).toHaveBeenCalled()
expect(ultimaWs()).not.toBe(prima)
})
it('onopen non lancia se il registro fallisce (send che lancia)', () => {
const wrapper = mountWith()
const ws = ultimaWs()
ws.readyState = MockWebSocket.OPEN
ws.send.mockImplementation(() => { throw new Error('boom') })
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
expect(() => ws.onopen()).not.toThrow()
expect(wrapper.vm.wsConnected).toBe(true)
expect(consoleSpy).toHaveBeenCalled()
})
it('onmessage non lancia su JSON non valido', () => {
mountWith()
const ws = ultimaWs()
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
expect(() => ws.onmessage({ data: 'non è JSON {{{' })).not.toThrow()
expect(consoleSpy).toHaveBeenCalled()
})
it('scheduleReconnect non arma un secondo timer se uno è già pendente', () => {
const wrapper = mountWith()
const spy = vi.spyOn(globalThis, 'setTimeout')
wrapper.vm.reconnectTimeout = 123 // timer già pendente (valore fittizio)
wrapper.vm.scheduleReconnect()
expect(spy).not.toHaveBeenCalled()
})
}) })
}) })