From cf40e86a8e8d77e12a7ac3c7039fa573d2c83fc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C5=ABdolfs=20O=C5=A1i=C5=86=C5=A1?= Date: Mon, 23 Mar 2026 10:59:39 -0600 Subject: [PATCH] Use a dynamic port for the test-http-api to avoid conflicts Pick a free port at config load time using a TCP probe on port 0, inject it into the Vite dev server via VITE_TEST_HTTP_API_PORT, and have globalSetup start the test-http-api on the same port. The frontend reads the env var at build time instead of the previously hardcoded 8081. --- playwright.config.ts | 19 +++++++++++++++++-- src/lib/invoke.ts | 13 ++++++++----- tests/support/fixtures.ts | 1 - tests/support/globalSetup.ts | 5 ++--- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 2b44c7293..0f825a3c5 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,7 +1,23 @@ import type { PlaywrightTestConfig } from "@playwright/test"; +import * as net from "node:net"; + import { devices } from "@playwright/test"; +function getFreePort(): Promise { + return new Promise((resolve, reject) => { + const server = net.createServer(); + server.listen(0, "127.0.0.1", () => { + const port = (server.address() as net.AddressInfo).port; + server.close(err => (err ? reject(err) : resolve(port))); + }); + server.on("error", reject); + }); +} + +const testHttpApiPort = await getFreePort(); +process.env.VITE_TEST_HTTP_API_PORT = String(testHttpApiPort); + const config: PlaywrightTestConfig = { outputDir: "./tests/artifacts", testDir: "./tests/e2e", @@ -33,8 +49,7 @@ const config: PlaywrightTestConfig = { webServer: [ { - command: - "VITE_AUTH_LONG_DELAY=1000 npm run start -- --strictPort --port 3001", + command: `VITE_AUTH_LONG_DELAY=1000 VITE_TEST_HTTP_API_PORT=${testHttpApiPort} npm run start -- --strictPort --port 3001`, port: 3001, }, ], diff --git a/src/lib/invoke.ts b/src/lib/invoke.ts index cf93bb552..df0b1ce21 100644 --- a/src/lib/invoke.ts +++ b/src/lib/invoke.ts @@ -49,11 +49,14 @@ async function withTestBackend( } }); } else { - return fetch(`http://127.0.0.1:8081/${cmd}`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(args), - }).then(async response => { + return fetch( + `http://127.0.0.1:${import.meta.env.VITE_TEST_HTTP_API_PORT ?? 8081}/${cmd}`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(args), + }, + ).then(async response => { if (response.status === 404) { console.log("Got a 404 response:", response); return null; diff --git a/tests/support/fixtures.ts b/tests/support/fixtures.ts index 0edd87cba..0d1eaba24 100644 --- a/tests/support/fixtures.ts +++ b/tests/support/fixtures.ts @@ -503,7 +503,6 @@ export const shortBobHead = formatOid(bobHead); export const cobRid = "rad:z3fpY7nttPPa6MBnAv2DccHzQJnqe"; export const markdownRid = "rad:z2tchH2Ti4LxRKdssPQYs6VHE5rsg"; export const shortNodeRemote = "z6MktU…1xB22S"; -export const defaultHttpdPort = 8081; export const gitOptions = { alice: { GIT_AUTHOR_NAME: "Alice Liddell", diff --git a/tests/support/globalSetup.ts b/tests/support/globalSetup.ts index 91b80bcdb..2faacc67a 100644 --- a/tests/support/globalSetup.ts +++ b/tests/support/globalSetup.ts @@ -5,7 +5,6 @@ import { createCobsFixture, createMarkdownFixture, defaultConfig, - defaultHttpdPort, gitOptions, } from "@tests/support/fixtures.js"; import { createPeerManager } from "@tests/support/peerManager.js"; @@ -68,7 +67,7 @@ export default async function globalSetup(): Promise<() => void> { alias: "palm", }, }); - await palm.startHttpd(defaultHttpdPort); + await palm.startHttpd(parseInt(process.env.VITE_TEST_HTTP_API_PORT ?? "0")); try { console.log("Creating markdown fixture"); @@ -87,7 +86,7 @@ export default async function globalSetup(): Promise<() => void> { } await palm.stopNode(); } else { - await palm.startHttpd(defaultHttpdPort); + await palm.startHttpd(parseInt(process.env.VITE_TEST_HTTP_API_PORT ?? "0")); } return async () => {