diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index 31968b3bb7ebd..cd4f48a64fcff 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -7,6 +7,7 @@ import { playwright } from "vite-plus/test/browser-playwright"; import { defineProject, type TestProjectInlineConfiguration } from "vite-plus/test/config"; import "vite-plus/test/config"; import { defineConfig, type Connect, type Plugin } from "vite-plus"; +import * as Hash from "effect/Hash"; import pkg from "./package.json" with { type: "json" }; import { @@ -80,6 +81,12 @@ const unitTestProject = { // Anything that renders React or touches the DOM is named *.browser.test.{ts,tsx} and runs // in headless Chromium through the same plugins as the app, so it exercises compiled code. +// Vitest's fixed browser API port (63315) collides when two checkouts run +// browser tests at once, and `server.strictPort` above is inherited, so the +// second run fails instead of moving on. Hash the checkout path like +// scripts/dev-runner.ts does, into 61000-64999 (above Linux's ephemeral range). +const browserTestApiPort = 61_000 + ((Hash.string(import.meta.dirname) >>> 0) % 4_000); + const browserTestProject = { extends: true, // Pre-bundled so the first test importing userEvent does not trigger a mid-run reload. @@ -89,6 +96,7 @@ const browserTestProject = { include: ["src/**/*.browser.test.{ts,tsx}"], hookTimeout: 15_000, testTimeout: 15_000, + api: { port: browserTestApiPort, strictPort: false }, browser: { enabled: true, headless: true,