/** * Tests for the #4431 fix: Socket.IO connects lazily on /chat/. * * The chat page must NOT open a Socket.IO connection on page load — that * per-navigation connect/disconnect churn freezes the werkzeug dev server. * Other realtime pages keep their eager auto-connect. * * We drive the module's auto-init (a setTimeout scheduled at import time) * with fake timers and assert whether io() — the connection factory — was * called, per page path. resetModules + dynamic import gives each case a * fresh evaluation of the IIFE with its own window.location.pathname. */ import { beforeEach, afterEach, describe, it, expect, vi } from 'vitest'; function setupEnv(pathname) { vi.resetModules(); Object.defineProperty(window, 'location', { configurable: true, value: { pathname, protocol: 'http:', host: 'localhost' }, }); const io = vi.fn(() => ({ on: vi.fn(), emit: vi.fn(), off: vi.fn(), connected: false, })); globalThis.io = io; window.api = { getResearchStatus: vi.fn(), getCsrfToken: () => '' }; window.ResearchStates = { isTerminal: () => false, logLevel: () => 'info' }; return io; } describe('Socket.IO auto-connect gating (#4431)', () => { beforeEach(() => vi.useFakeTimers()); afterEach(() => { vi.useRealTimers(); delete globalThis.io; }); it('does NOT auto-connect on a /chat/ page (lazy)', async () => { const io = setupEnv('/chat/some-session-id'); await import('@js/services/socket.js'); // Fire the auto-init setTimeout(…, 100) scheduled at import. vi.advanceTimersByTime(300); expect(io).not.toHaveBeenCalled(); }); it('DOES auto-connect on a /progress/ page (eager, unchanged)', async () => { const io = setupEnv('/progress/abc-123'); await import('@js/services/socket.js'); vi.advanceTimersByTime(300); expect(io).toHaveBeenCalledTimes(1); }); it('DOES auto-connect on a /research page (eager, unchanged)', async () => { const io = setupEnv('/research'); await import('@js/services/socket.js'); vi.advanceTimersByTime(300); expect(io).toHaveBeenCalledTimes(1); }); it('still connects lazily on /chat/ when a research is subscribed', async () => { const io = setupEnv('/chat/some-session-id'); await import('@js/services/socket.js'); vi.advanceTimersByTime(300); expect(io).not.toHaveBeenCalled(); // confirmed lazy at load // Subscribing to a research must initialize the socket on demand. window.socket.subscribeToResearch('research-1', () => {}); expect(io).toHaveBeenCalledTimes(1); }); });