From e730d1395700c3bb8172de487346fc187ec493e7 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Fri, 24 Apr 2026 02:14:01 +0700 Subject: [PATCH] chore(lint): reduce relay test no-await-in-loop warnings Refactor while-loops and for-retry loops in e2e.test.ts and live-relay.e2e.test.ts into recursive poll/attempt helpers. Remaining 8 warnings in encrypted-channel.ts concern the custom Transport interface (on-handler slots, not DOM EventTarget) and a sequential send loop; both reflect deliberate runtime contracts. --- packages/relay/src/e2e.test.ts | 96 +++++++++++++---------- packages/relay/src/live-relay.e2e.test.ts | 12 +-- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/packages/relay/src/e2e.test.ts b/packages/relay/src/e2e.test.ts index d432402be..12bb6a8b0 100644 --- a/packages/relay/src/e2e.test.ts +++ b/packages/relay/src/e2e.test.ts @@ -92,17 +92,48 @@ async function waitForServer( relayProcess: ChildProcess, timeout = 15000, ): Promise { - const start = Date.now(); - while (Date.now() - start < timeout) { + const deadline = Date.now() + timeout; + async function poll(): Promise { + if (Date.now() >= deadline) { + throw new Error(`Server did not start on port ${port} within ${timeout}ms`); + } assertRelayStillRunning(relayProcess); try { await tryConnect(port); return; } catch { await sleep(100); + return poll(); } } - throw new Error(`Server did not start on port ${port} within ${timeout}ms`); + return poll(); +} + +function probeRelayWebSocket(port: number): Promise { + const serverId = `probe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`; + const probeUrl = `ws://127.0.0.1:${port}/ws?serverId=${serverId}&role=server&v=2`; + return new Promise((resolve) => { + const ws = new WebSocket(probeUrl); + let settled = false; + const settle = (value: boolean) => { + if (settled) return; + settled = true; + resolve(value); + }; + const timer = setTimeout(() => { + ws.terminate(); + settle(false); + }, 5000); + ws.once("open", () => { + clearTimeout(timer); + ws.close(1000, "probe"); + settle(true); + }); + ws.once("error", () => { + clearTimeout(timer); + settle(false); + }); + }); } async function waitForRelayWebSocketReady( @@ -110,39 +141,28 @@ async function waitForRelayWebSocketReady( relayProcess: ChildProcess, timeout = 60000, ): Promise { - const start = Date.now(); - while (Date.now() - start < timeout) { - assertRelayStillRunning(relayProcess); - const serverId = `probe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`; - const probeUrl = `ws://127.0.0.1:${port}/ws?serverId=${serverId}&role=server&v=2`; - const opened = await new Promise((resolve) => { - const ws = new WebSocket(probeUrl); - let settled = false; - const settle = (value: boolean) => { - if (settled) return; - settled = true; - resolve(value); - }; - const timer = setTimeout(() => { - ws.terminate(); - settle(false); - }, 5000); - ws.once("open", () => { - clearTimeout(timer); - ws.close(1000, "probe"); - settle(true); - }); - ws.once("error", () => { - clearTimeout(timer); - settle(false); - }); - }); - if (opened) { - return; + const deadline = Date.now() + timeout; + async function poll(): Promise { + if (Date.now() >= deadline) { + throw new Error(`Relay WebSocket endpoint not ready on port ${port} within ${timeout}ms`); } + assertRelayStillRunning(relayProcess); + const opened = await probeRelayWebSocket(port); + if (opened) return; await sleep(250); + return poll(); } - throw new Error(`Relay WebSocket endpoint not ready on port ${port} within ${timeout}ms`); + return poll(); +} + +async function waitForProcessExit( + relayProcess: ChildProcess, + deadline: number, +): Promise { + if (relayProcess.exitCode !== null) return; + if (Date.now() >= deadline) return; + await sleep(50); + return waitForProcessExit(relayProcess, deadline); } async function stopRelayProcess(relayProcess: ChildProcess): Promise { @@ -151,20 +171,14 @@ async function stopRelayProcess(relayProcess: ChildProcess): Promise { } relayProcess.kill("SIGTERM"); - const start = Date.now(); - while (relayProcess.exitCode === null && Date.now() - start < SHUTDOWN_TIMEOUT_MS) { - await sleep(50); - } + await waitForProcessExit(relayProcess, Date.now() + SHUTDOWN_TIMEOUT_MS); if (relayProcess.exitCode !== null) { return; } relayProcess.kill("SIGKILL"); - const killStart = Date.now(); - while (relayProcess.exitCode === null && Date.now() - killStart < 2000) { - await sleep(50); - } + await waitForProcessExit(relayProcess, Date.now() + 2000); if (relayProcess.exitCode === null) { throw new Error("relay process did not exit after SIGTERM/SIGKILL"); diff --git a/packages/relay/src/live-relay.e2e.test.ts b/packages/relay/src/live-relay.e2e.test.ts index 444006a0b..8fb521b46 100644 --- a/packages/relay/src/live-relay.e2e.test.ts +++ b/packages/relay/src/live-relay.e2e.test.ts @@ -15,18 +15,20 @@ async function withRetry( fn: () => Promise, options: { retries: number; delayMs: number }, ): Promise { - let lastError: unknown; - for (let attempt = 0; attempt <= options.retries; attempt++) { + async function attempt(attemptNumber: number, lastError: unknown): Promise { + if (attemptNumber > options.retries) { + throw lastError instanceof Error ? lastError : new Error(String(lastError)); + } try { return await fn(); } catch (error) { - lastError = error; - if (attempt < options.retries) { + if (attemptNumber < options.retries) { await new Promise((r) => setTimeout(r, options.delayMs)); } + return attempt(attemptNumber + 1, error); } } - throw lastError instanceof Error ? lastError : new Error(String(lastError)); + return attempt(0, null); } function waitOpen(ws: WebSocket, label: string): Promise {