import * as net from "node:net"; import { it as effectIt } from "@effect/vitest"; import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; import * as Net from "@t3tools/shared/Net"; import { Effect, Layer } from "effect"; import { expect } from "vite-plus/test"; import { ProcessRunner } from "../processRunner.ts"; import * as PortScanner from "./PortScanner.ts"; const TestProcessRunner = Layer.succeed(ProcessRunner, { run: () => Effect.die("ProcessRunner should not be used by Windows TCP probe tests"), }); const TestPortDiscoveryLive = PortScanner.layer.pipe( Layer.provide( Layer.mergeAll(TestProcessRunner, Net.layer, Layer.succeed(HostProcessPlatform, "win32")), ), ); const openServer = (port: number): Effect.Effect => Effect.callback((resume) => { const server = net.createServer(); server.once("error", () => { resume(Effect.succeed(null)); }); server.listen(port, "127.0.0.1", () => { resume(Effect.succeed(server)); }); return Effect.sync(() => { server.close(); }); }); const closeServer = (server: net.Server): Effect.Effect => Effect.callback((resume) => { server.close(() => resume(Effect.void)); }); const openCommonDevServer = Effect.fn("PortScannerTest.openCommonDevServer")(function* ( ports: ReadonlyArray, ) { for (const port of ports) { const server = yield* openServer(port); if (server !== null) return { port, server }; } return yield* Effect.die( new Error("No common development port was available for the preview scanner test"), ); }); const commonDevServer = Effect.acquireRelease( openCommonDevServer(PortScanner.COMMON_DEV_PORTS), ({ server }) => closeServer(server), ); /** * Integration tests against a real TCP listener. We provide the Windows host * platform so the tests exercise the TCP-probe fallback without depending on * `lsof` being installed. */ effectIt.layer(TestPortDiscoveryLive)("PortDiscovery integration (TCP probe fallback)", (it) => { it.effect( "scan() returns a server we just opened on a curated dev port", Effect.fn("PortScannerTest.scanFindsCommonDevServer")(function* () { const { port } = yield* commonDevServer; const scanner = yield* PortScanner.PortDiscovery; const result = yield* scanner.scan(); const found = result.find((server) => server.port === port); expect(found).toBeDefined(); expect(found?.host).toBe("localhost"); }), ); it.effect( "retain drives an immediate broadcast to subscribers", Effect.fn("PortScannerTest.retainBroadcastsImmediately")(function* () { const { port } = yield* commonDevServer; const received: number[] = []; const scanner = yield* PortScanner.PortDiscovery; yield* scanner.subscribe((servers) => Effect.sync(() => { for (const server of servers) received.push(server.port); }), ); yield* scanner.retain; expect(received).toContain(port); }), ); });