Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions src/lib/wait-port.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ export const waitPort = async (
port: number,
host: string,
timeout: number,
maxRetries?: number,
): Promise<{ open: boolean; ipVersion?: 4 | 6 }> => {
const startTime = Date.now()
const retries = maxRetries ?? Math.ceil(timeout / 2000)

for (let attempt = 0; attempt < retries; attempt++) {
for (let attempt = 0; ; attempt++) {
if (Date.now() - startTime > timeout) {
return { open: false }
}
Expand Down Expand Up @@ -52,6 +50,4 @@ export const waitPort = async (
continue
}
}

return { open: false }
}
1 change: 0 additions & 1 deletion src/utils/framework-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ export const startFrameworkServer = async function ({
settings.frameworkPort!,
'localhost',
FRAMEWORK_PORT_TIMEOUT_MS,
20,
)

const timerId = setTimeout(() => {
Expand Down
63 changes: 63 additions & 0 deletions tests/unit/lib/wait-port.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import net from 'node:net'

import { afterEach, describe, expect, test } from 'vitest'

import { waitPort } from '../../../src/lib/wait-port.js'

const getFreePort = () =>
new Promise<number>((resolve, reject) => {
const server = net.createServer()
server.once('error', reject)
server.listen(0, () => {
const { port } = server.address() as net.AddressInfo
server.close(() => {
resolve(port)
})
})
})

describe('waitPort', () => {
const servers: net.Server[] = []

afterEach(async () => {
await Promise.all(servers.splice(0).map((server) => new Promise((resolve) => server.close(resolve))))
})

test('resolves as open when the port starts listening later but within the timeout', async () => {
const port = await getFreePort()
setTimeout(() => {
const server = net.createServer()
servers.push(server)
server.listen(port)
}, 1500)

const result = await waitPort(port, 'localhost', 5000)

expect(result.open).toBe(true)
})

test('resolves as open without crashing when the server resets the connection', async () => {
const port = await getFreePort()
const server = net.createServer((socket) => {
socket.resetAndDestroy()
})
servers.push(server)
await new Promise<void>((resolve) => server.listen(port, resolve))

const result = await waitPort(port, 'localhost', 5000)
await new Promise((resolve) => setTimeout(resolve, 200))

expect(result.open).toBe(true)
})

test('keeps waiting until the timeout elapses when the port never opens', async () => {
const port = await getFreePort()
const timeout = 1500
const startTime = Date.now()

const result = await waitPort(port, 'localhost', timeout)

expect(result).toEqual({ open: false })
expect(Date.now() - startTime).toBeGreaterThanOrEqual(timeout)
})
})