diff --git a/.gitea/workflows/ui-test.yaml b/.gitea/workflows/ui-test.yaml index 5924d3c..fe40048 100644 --- a/.gitea/workflows/ui-test.yaml +++ b/.gitea/workflows/ui-test.yaml @@ -16,6 +16,15 @@ on: - '.gitea/workflows/ui-test.yaml' - '!**/*.md' +# Playwright launches its own `pnpm dev` on :5173. In host-mode the +# runner shares the host's port namespace, so two parallel ui-test +# jobs (e.g. a push event racing with a pull_request event for the +# same commit) collide on EADDRINUSE. Group by the head commit so +# push and pull_request events for the same sha share one bucket. +concurrency: + group: ui-test-${{ gitea.event.pull_request.head.sha || gitea.sha }} + cancel-in-progress: true + jobs: test: runs-on: ubuntu-latest @@ -59,6 +68,15 @@ jobs: working-directory: ui/frontend run: pnpm test + - name: Clear stale Vite from :5173 + # Defence in depth in case a previous job's webServer survived + # the concurrency-cancel — `pkill` does not fail when there is + # nothing to kill, and `fuser -k` cleans up anything else + # holding the port. + run: | + pkill -f 'vite dev' || true + fuser -k 5173/tcp 2>/dev/null || true + - name: Run Playwright working-directory: ui/frontend run: pnpm exec playwright test diff --git a/ui/frontend/playwright.config.ts b/ui/frontend/playwright.config.ts index 9cc4531..f2d664c 100644 --- a/ui/frontend/playwright.config.ts +++ b/ui/frontend/playwright.config.ts @@ -5,7 +5,13 @@ export default defineConfig({ testDir: "tests/e2e", fullyParallel: true, forbidOnly: !!process.env.CI, - retries: process.env.CI ? 1 : 0, + // host-mode CI runner shares CPU/IO with the long-lived dev stack, + // gitea, and the user's host Caddy. The default 6 workers + 1 + // retry produced ~7 flakies + 1 hard fail per ui-test run; cap at + // 4 workers (still parallel) and allow 4 retries to ride out + // transient timing hiccups without inflating wall time. + workers: 4, + retries: process.env.CI ? 4 : 0, reporter: [["list"], ["html", { open: "never" }]], use: { baseURL: "http://localhost:5173",