import { defineConfig, devices } from '@playwright/test'; /** * EventSnap E2E config. * * Defaults assume the test stack is already up (`npm run stack:up`). The * stack is *not* started by webServer because Playwright would clobber the * compose volumes between retries. CI calls `npm run stack:up` once before * `npm run test:e2e` runs. * * UA matrix: the `@smoke` happy-path runs across every project to catch * engine-level divergences. The rest of the suite only runs against * `chromium-desktop` to keep the wall-clock reasonable. */ export default defineConfig({ testDir: './specs', outputDir: './test-results', fullyParallel: false, // Single shared backend → tests TRUNCATE between, so don't run in parallel. forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: 1, // One worker. Multi-worker needs per-worker isolated DBs (Phase 2+). reporter: [ ['list'], ['html', { open: 'never', outputFolder: './playwright-report' }], ], globalSetup: './global-setup.ts', globalTeardown: './global-teardown.ts', timeout: 60_000, expect: { timeout: 10_000 }, use: { baseURL: process.env.E2E_FRONTEND_URL ?? 'http://localhost:3101', trace: 'retain-on-failure', screenshot: 'only-on-failure', video: 'retain-on-failure', actionTimeout: 10_000, navigationTimeout: 30_000, // Camera/mic permissions granted by default; the fake-media launch args // (set per-project below for Chromium) supply the actual stream. permissions: ['camera', 'microphone', 'clipboard-read', 'clipboard-write'], }, projects: [ // ── Baseline desktop ───────────────────────────────────────────────── { name: 'chromium-desktop', // 09-mobile/ specs only run on the chromium-mobile project below — they // require `hasTouch: true` and a phone viewport. testIgnore: ['**/09-mobile/**'], use: { ...devices['Desktop Chrome'], launchOptions: { args: [ '--use-fake-ui-for-media-stream', '--use-fake-device-for-media-stream', // A video file would be loaded with --use-file-for-fake-video-capture // — we ship a tiny .y4m in fixtures/media/ as a follow-up. ], }, }, }, // ── Phase 3 mobile gestures ────────────────────────────────────────── // Runs ONLY the 09-mobile/ specs. Uses the Pixel 7 device descriptor so // hasTouch + isMobile + mobile viewport are all set, then dispatches // pointer events via page.mouse / locator helpers. Real touch events // come from `page.touchscreen` when needed. { name: 'chromium-mobile', testMatch: ['**/09-mobile/**/*.spec.ts'], use: { ...devices['Pixel 7'] }, }, // ── Mobile UA smoke matrix (runs only @smoke specs in CI) ──────────── { name: 'chromium-pixel7', use: { ...devices['Pixel 7'] }, grep: /@smoke/, }, { name: 'chromium-galaxy-s22', use: { ...devices['Galaxy S9+'], // Playwright doesn't ship S22 yet — S9+ is the closest Samsung descriptor. viewport: { width: 360, height: 780 }, userAgent: 'Mozilla/5.0 (Linux; Android 14; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36', }, grep: /@smoke/, }, { name: 'samsung-internet', use: { ...devices['Galaxy S9+'], viewport: { width: 360, height: 780 }, userAgent: 'Mozilla/5.0 (Linux; Android 14; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/24.0 Chrome/124.0.0.0 Mobile Safari/537.36', }, grep: /@smoke/, }, { name: 'edge-android', use: { ...devices['Pixel 7'], userAgent: 'Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36 EdgA/124.0.0.0', }, grep: /@smoke/, }, { name: 'chrome-ios', use: { ...devices['iPhone 14 Pro'], userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/124.0.0.0 Mobile/15E148 Safari/604.1', }, grep: /@smoke/, }, { name: 'webkit-iphone', use: { ...devices['iPhone 14 Pro'] }, grep: /@smoke/, }, { name: 'firefox-android', use: { ...devices['Pixel 7'], defaultBrowserType: 'firefox', userAgent: 'Mozilla/5.0 (Android 14; Mobile; rv:124.0) Gecko/124.0 Firefox/124.0', }, grep: /@smoke/, }, { name: 'firefox-desktop', use: { ...devices['Desktop Firefox'] }, grep: /@smoke/, }, ], });