// BUG-8: ws adapter has NO reconnect. WS dies (idle/error/close) → wsReady=null, // subscribers dead forever, no re-subscribe. Display frozen until full reload. // Test: subscribe, write (cb fires), force-drop WS, write again (must still fire). // RED on current. 'use strict'; const path = require('path'); const os = require('os'); const { createServer } = require('../index'); const { createWsStorage } = require('../../src/storage/ws'); const flush = (ms = 150) => new Promise(r => setTimeout(r, ms)); async function makeStorage() { const dbPath = path.join(os.tmpdir(), `ws-recon-${Date.now()}-${Math.random().toString(36).slice(2)}.sqlite`); const handle = createServer({ dbPath, port: 0 }); await new Promise((resolve, reject) => { handle.server.on('error', reject); handle.server.listen(0, resolve); }); const port = handle.server.address().port; const baseUrl = `http://127.0.0.1:${port}`; const wsUrl = `ws://127.0.0.1:${port}/ws`; const storage = createWsStorage({ baseUrl, wsUrl }); storage.dispose = (done) => handle.close(done); return storage; } describe('BUG-8: ws adapter reconnect after drop', () => { test('subscribe fires cb after WS dropped + restored', async () => { const storage = await makeStorage(); try { await storage.setDoc('campaigns/a', { name: 'V1' }); const calls = []; storage.subscribeDoc('campaigns/a', (doc) => calls.push(doc)); await flush(); expect(calls.length).toBeGreaterThanOrEqual(1); // force-drop WS (simulates idle timeout / network blip) storage._test.forceDrop(); await flush(300); // wsReady should be null now expect(storage._test.getReady()).toBeNull(); // write again — subscriber must re-fire after reconnect await storage.setDoc('campaigns/a', { name: 'V2' }); await flush(1000); const last = calls[calls.length - 1]; expect(last).toEqual({ name: 'V2' }); } finally { await new Promise(r => storage.dispose(r)); } }, 15000); });