playwright.config.js
// Playwright config for Support Desk (§75).
// npm test run everything
// npx playwright test --ui watch mode with time-travel debugging
// npx playwright test --grep @a11y run one tag
import { defineConfig, devices } from "@playwright/test";
const PORT = 3101; // not the dev port: tests always get a fresh server in test mode
export default defineConfig({
testDir: "tests",
fullyParallel: true,
forbidOnly: !!process.env.CI, // a stray test.only must fail CI, not silently skip the suite
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 2 : undefined,
reporter: process.env.CI ? [["github"], ["html", { open: "never" }]] : [["list"]],
use: {
baseURL: `http://127.0.0.1:${PORT}`,
trace: "on-first-retry", // a full time-travel trace of any test that flaked
screenshot: "only-on-failure",
},
expect: {
toHaveScreenshot: { maxDiffPixelRatio: 0.01, animations: "disabled" },
},
webServer: {
command: "node server.mjs",
url: `http://127.0.0.1:${PORT}/healthz`,
// Every test shares Alice's session, so the per-session chat limit would
// throttle the suite itself. Tests of the limiter use their own keys.
env: { PORT: String(PORT), NODE_ENV: "test", CHAT_LIMIT: "10000" },
reuseExistingServer: false,
},
projects: [
// 1. Sign in once per user and save the cookies (§75).
{ name: "setup", testMatch: /auth\.setup\.js/ },
// 2. Everything else starts already signed in as Alice.
{
name: "chromium",
use: { ...devices["Desktop Chrome"], storageState: "playwright/.auth/alice.json" },
dependencies: ["setup"],
},
{
name: "mobile",
use: { ...devices["Pixel 7"], storageState: "playwright/.auth/alice.json" },
dependencies: ["setup"],
grep: /@mobile/,
},
],
});