Frontend Labs
⋯

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/,
    },
  ],
});

Generated from SOURCE.md · 8 Oct 2026 16:36