Files
Epicnabbo-Catalogus-Updated…/playwright.ui.config.ts
T
openhands 1e81cac504 test(ui): isolate the fixture port so parallel runs stop colliding
The self-hosted CI runner packs several jobs onto the shared host network
(capacity 4). The UI suite pinned the fixture server to 127.0.0.1:3107 and set
reuseExistingServer: true, so overlapping runs fought over the bind: one job
won it, and every browser in the other got "connection refused" on all four
projects. Pass one random high port per run through the environment (shared by
the main process and its worker) and only reuse an existing server outside CI.
Verified with the full ui suite: 150 passed, 2 skipped.
2026-10-19 20:16:28 +02:00

88 lines
2.6 KiB
TypeScript

import { randomInt } from "node:crypto";
import { defineConfig } from "@playwright/test";
// The fixture server binds a loopback port. The CI runner packs several jobs
// onto the shared host network (capacity > 1), so a fixed port makes concurrent
// runs fight over the bind: one wins, the other's browser then gets
// "connection refused". Pick one random high port for the whole run and pass it
// to every worker through the environment, unless a port is pinned explicitly
// (e.g. a developer reusing a manually started fixture server).
function fixturePort() {
const requested = Number(process.env.UI_TEST_PORT);
if (Number.isInteger(requested) && requested >= 1024 && requested <= 65535)
return requested;
const shared = Number(process.env.PW_UI_TEST_PORT);
if (Number.isInteger(shared) && shared >= 1024 && shared <= 65535)
return shared;
const port = randomInt(30000, 50000);
process.env.PW_UI_TEST_PORT = String(port);
return port;
}
const port = fixturePort();
const baseURL = `http://127.0.0.1:${port}`;
export default defineConfig({
testDir: "./e2e/ui",
testMatch: "**/*.spec.ts",
fullyParallel: false,
workers: 1,
retries: process.env.CI ? 1 : 0,
timeout: 45000,
expect: {
timeout: 10000,
toHaveScreenshot: {
animations: "disabled",
caret: "hide",
maxDiffPixelRatio: 0.002,
},
},
snapshotPathTemplate: `{testDir}/__screenshots__/${process.platform}/{projectName}/{testFilePath}/{arg}{ext}`,
reporter: [
["list"],
["html", { outputFolder: "playwright-report/ui", open: "never" }],
],
outputDir: "test-results/ui",
use: {
baseURL,
locale: "en-US",
timezoneId: "UTC",
colorScheme: "dark",
contextOptions: { reducedMotion: "reduce" },
trace: "retain-on-failure",
screenshot: "only-on-failure",
launchOptions: process.env.UI_TEST_BROWSER_PATH
? { executablePath: process.env.UI_TEST_BROWSER_PATH }
: {},
},
projects: [
{
name: "desktop-chromium",
use: { browserName: "chromium", viewport: { width: 1280, height: 900 } },
},
{
name: "mobile-chromium",
use: {
browserName: "chromium",
viewport: { width: 390, height: 844 },
isMobile: true,
deviceScaleFactor: 1,
hasTouch: true,
},
},
{
name: "desktop-firefox",
use: { browserName: "firefox", viewport: { width: 1280, height: 900 } },
},
{
name: "desktop-webkit",
use: { browserName: "webkit", viewport: { width: 1280, height: 900 } },
},
],
webServer: {
command: "node e2e/ui/fixture-server.mjs",
url: `${baseURL}/health`,
timeout: 120000,
reuseExistingServer: !process.env.CI,
env: { UI_TEST_PORT: String(port) },
},
});