11import { spawn , execSync } from 'child_process'
2+ import { createServer } from 'net'
23import path from 'path'
34import http from 'http'
45
56import type { ChildProcess } from 'child_process'
7+ import type { AddressInfo } from 'net'
68
79const WEB_DIR = path . join ( __dirname , '../../../../web' )
810
@@ -14,26 +16,41 @@ export interface E2EServer {
1416}
1517
1618/**
17- * Find an available port for the web server
19+ * Find an available port for the web server.
20+ * Uses an ephemeral OS-assigned port to avoid EADDRINUSE races between parallel tests.
1821 */
19- export function findAvailableServerPort ( basePort : number = 3100 ) : number {
20- for ( let port = basePort ; port < basePort + 100 ; port ++ ) {
21- try {
22- execSync ( `lsof -i:${ port } ` , { stdio : 'pipe' } )
23- // Port is in use, try next
24- } catch {
25- // Port is available
26- return port
27- }
28- }
29- throw new Error ( `Could not find available port starting from ${ basePort } ` )
22+ export async function findAvailableServerPort ( _basePort : number = 3100 ) : Promise < number > {
23+ return await new Promise ( ( resolve , reject ) => {
24+ const server = createServer ( )
25+ server . unref ( )
26+
27+ server . on ( 'error' , ( error ) => {
28+ server . close ( )
29+ reject ( error )
30+ } )
31+
32+ server . listen ( 0 , ( ) => {
33+ const address = server . address ( )
34+ server . close ( ( closeErr ) => {
35+ if ( closeErr ) {
36+ reject ( closeErr )
37+ return
38+ }
39+ if ( address && typeof address === 'object' ) {
40+ resolve ( ( address as AddressInfo ) . port )
41+ return
42+ }
43+ reject ( new Error ( 'Could not determine an available port' ) )
44+ } )
45+ } )
46+ } )
3047}
3148
3249/**
3350 * Start the web server for e2e tests
3451 */
3552export async function startE2EServer ( databaseUrl : string ) : Promise < E2EServer > {
36- const port = findAvailableServerPort ( 3100 )
53+ const port = await findAvailableServerPort ( 3100 )
3754 const url = `http://localhost:${ port } `
3855 const backendUrl = url
3956
0 commit comments