import assert from 'node:assert/strict'; import {readFile} from 'node:fs/promises'; import vm from 'node:vm'; import test from 'node:test'; import {transformSync} from 'esbuild'; const source = await readFile(new URL('../index.ts', import.meta.url), 'utf8'); const lifecycle = source.slice(source.indexOf(' let reconnect_timer:'), source.indexOf(" main_server_socket.on('connect',")); const disconnect = source.slice(source.indexOf(" main_server_socket.on('disconnect',"), source.indexOf(' main_server_socket.onAny(')); const code = transformSync(`${lifecycle}\n${disconnect}`, {loader: 'ts'}).code; function setup(enabled = true, max_attempts = 2) { const timers = new Map(); const handlers = new Map(); const state = {connects: 0, disconnects: 0}; const process = {once() {}}; let id = 0; vm.runInNewContext(code, { auto_reconnect: {enabled, max_attempts, interval: 100}, reconnect_interval: 100, main_server_socket: { on: (event, handler) => handlers.set(event, handler), connect: () => state.connects++, disconnect: () => state.disconnects++, }, console_print: {log() {}, info() {}, error() {}, warning() {}}, clear_node_session() {}, get_bot_context_status: async () => [], stop_bot_context: async () => {}, process, setTimeout(callback, delay) { if (delay === 10_000) return ++id; assert.equal(delay, 100); timers.set(++id, callback); return id; }, clearTimeout: id => timers.delete(id), }); return { state, process, timers, disconnect: reason => handlers.get('disconnect')(reason), tick() { assert.equal(timers.size, 1); const [id, callback] = timers.entries().next().value; timers.delete(id); callback(); }, }; } test('server disconnect retries indefinitely without duplicate timers after the configured limit', () => { const app = setup(); for (let attempt = 0; attempt < 12; attempt++) { app.disconnect('io server disconnect'); app.disconnect('io server disconnect'); app.tick(); assert.equal(app.state.connects, attempt + 1); } app.disconnect('io server disconnect'); assert.equal(app.state.disconnects, 0); assert.equal(app.timers.size, 1); assert.equal(app.process.exitCode, undefined); }); test('disabled reconnect and a zero attempt limit still retry every disconnect reason', () => { const app = setup(false, 0); for (const reason of ['io server disconnect', 'io client disconnect', 'transport close', 'ping timeout', 'transport error']) { app.disconnect(reason); app.tick(); } assert.equal(app.state.connects, 5); app.disconnect('io client disconnect'); assert.equal(app.timers.size, 1); assert.equal(app.process.exitCode, undefined); });