Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8ca8e01

Browse files
mtojekdannykopping
andauthored
fix(site): wait until port is available in e2e (#15537)
Related: coder/internal#212 This PR modifies the logic responsible for creating a server in E2E tests to check if the port is free. Alternatively, we could refactor the framework to dynamically create server instances, but this solution might be a cheaper quick win. Note: I'll leave it as is now, it might be worth asking somebody with a frontend skillset to double-check this contribution. --------- Signed-off-by: Danny Kopping <[email protected]> Co-authored-by: Danny Kopping <[email protected]>
1 parent 5861e51 commit 8ca8e01

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

site/e2e/helpers.ts

+41
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { type ChildProcess, exec, spawn } from "node:child_process";
22
import { randomUUID } from "node:crypto";
3+
import net from "node:net";
34
import path from "node:path";
45
import { Duplex } from "node:stream";
56
import { type BrowserContext, type Page, expect, test } from "@playwright/test";
@@ -687,6 +688,8 @@ export class Awaiter {
687688
export const createServer = async (
688689
port: number,
689690
): Promise<ReturnType<typeof express>> => {
691+
await waitForPort(port); // Wait until the port is available
692+
690693
const e = express();
691694
// We need to specify the local IP address as the web server
692695
// tends to fail with IPv6 related error:
@@ -695,6 +698,44 @@ export const createServer = async (
695698
return e;
696699
};
697700

701+
async function waitForPort(
702+
port: number,
703+
host = "0.0.0.0",
704+
timeout = 30000,
705+
): Promise<void> {
706+
const start = Date.now();
707+
while (Date.now() - start < timeout) {
708+
const available = await isPortAvailable(port, host);
709+
if (available) {
710+
return;
711+
}
712+
console.warn(`${host}:${port} is in use, checking again in 1s`);
713+
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second before retrying
714+
}
715+
throw new Error(
716+
`Timeout: port ${port} is still in use after ${timeout / 1000} seconds.`,
717+
);
718+
}
719+
720+
function isPortAvailable(port: number, host = "0.0.0.0"): Promise<boolean> {
721+
return new Promise((resolve) => {
722+
const probe = net
723+
.createServer()
724+
.once("error", (err: NodeJS.ErrnoException) => {
725+
if (err.code === "EADDRINUSE") {
726+
resolve(false); // port is in use
727+
} else {
728+
resolve(false); // some other error occurred
729+
}
730+
})
731+
.once("listening", () => {
732+
probe.close();
733+
resolve(true); // port is available
734+
})
735+
.listen(port, host);
736+
});
737+
}
738+
698739
export const findSessionToken = async (page: Page): Promise<string> => {
699740
const cookies = await page.context().cookies();
700741
const sessionCookie = cookies.find((c) => c.name === "coder_session_token");

0 commit comments

Comments
 (0)