/** * Playwright Configuration for Local Deep Research * * This configuration enables proper mobile UI testing with: * - Visual regression testing (screenshot comparison) * - Multiple mobile device profiles * - Cross-browser testing (Chromium, Firefox, WebKit/Safari) * - Parallel execution for faster CI runs * - Single authentication to avoid rate limiting * * Migration from Puppeteer: This provides the "real" testing * that Puppeteer emulation cannot deliver. */ import { defineConfig, devices } from '@playwright/test'; import path from 'path'; const authFile = path.join(__dirname, '.auth/user.json'); /** * See https://playwright.dev/docs/test-configuration */ export default defineConfig({ testDir: './tests', /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code */ forbidOnly: !!process.env.CI, /* Retry failed tests - helps with flaky timing-sensitive tests */ retries: process.env.CI ? 2 : 1, /* Opt out of parallel tests on CI for more consistent results */ workers: process.env.CI ? 1 : undefined, /* Reporter to use */ reporter: [ ['html', { open: 'never' }], ['json', { outputFile: 'test-results/results.json' }], ['junit', { outputFile: 'test-results/results.xml' }], ], /* Shared settings for all projects */ use: { /* Base URL to use in actions like `await page.goto('/')` */ baseURL: process.env.TEST_BASE_URL || 'http://127.0.0.1:5000', /* Collect trace when retrying the failed test */ trace: 'on-first-retry', /* Take screenshot on failure */ screenshot: 'only-on-failure', /* Record video on failure */ video: 'on-first-retry', /* * Cap navigation-class waits (goto, reload, waitForLoadState, * waitForURL) at 15s. Playwright's default is 30s — equal to our * test timeout — which means a single slow nav can silently consume * the entire budget, especially when wrapped in `.catch(() => {})`. * See PR #4215 / issue #4060 for the concrete failure shape. */ navigationTimeout: 15000, }, /* Configure projects for major browsers and mobile devices */ projects: [ // ========================================== // AUTHENTICATION SETUP (runs first) // ========================================== { name: 'setup', testMatch: /auth\.setup\.js/, use: { ...devices['Desktop Chrome'], }, }, // ========================================== // MOBILE DEVICES - Primary Testing Targets // ========================================== // Small iPhones (most constrained viewport) { name: 'iPhone SE', dependencies: ['setup'], use: { ...devices['iPhone SE'], // Additional settings for thorough testing hasTouch: true, isMobile: true, storageState: authFile, }, }, // Standard iPhone (most popular) { name: 'iPhone 14', dependencies: ['setup'], use: { ...devices['iPhone 14'], hasTouch: true, isMobile: true, storageState: authFile, }, }, // Large iPhone (Pro Max) { name: 'iPhone 14 Pro Max', dependencies: ['setup'], use: { ...devices['iPhone 14 Pro Max'], hasTouch: true, isMobile: true, storageState: authFile, }, }, // Android - Small (budget phones) { name: 'Pixel 5', dependencies: ['setup'], use: { ...devices['Pixel 5'], hasTouch: true, isMobile: true, storageState: authFile, }, }, // Android - Large (Samsung Galaxy) { name: 'Galaxy S23', dependencies: ['setup'], use: { viewport: { width: 360, height: 780 }, deviceScaleFactor: 3, hasTouch: true, isMobile: true, userAgent: 'Mozilla/5.0 (Linux; Android 13; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36', storageState: authFile, }, }, // ========================================== // TABLETS // ========================================== { name: 'iPad Mini', dependencies: ['setup'], use: { ...devices['iPad Mini'], hasTouch: true, isMobile: true, storageState: authFile, }, }, { name: 'iPad Pro 11', dependencies: ['setup'], use: { ...devices['iPad Pro 11'], hasTouch: true, isMobile: true, storageState: authFile, }, }, // ========================================== // LANDSCAPE ORIENTATIONS (Critical for layout bugs) // ========================================== { name: 'iPhone SE Landscape', dependencies: ['setup'], use: { ...devices['iPhone SE landscape'], hasTouch: true, isMobile: true, storageState: authFile, }, }, { name: 'iPhone 14 Landscape', dependencies: ['setup'], use: { ...devices['iPhone 14 landscape'], hasTouch: true, isMobile: true, storageState: authFile, }, }, // ========================================== // DESKTOP BROWSERS // ========================================== { name: 'Desktop Chrome', dependencies: ['setup'], use: { ...devices['Desktop Chrome'], storageState: authFile, }, }, { name: 'Desktop Firefox', dependencies: ['setup'], use: { ...devices['Desktop Firefox'], storageState: authFile, }, }, { name: 'Desktop Safari', dependencies: ['setup'], use: { ...devices['Desktop Safari'], storageState: authFile, }, }, // ========================================== // WEBKIT/SAFARI MOBILE (Critical for iOS bugs) // ========================================== { name: 'Mobile Safari', dependencies: ['setup'], use: { ...devices['iPhone 14'], browserName: 'webkit', // This uses WebKit, closer to real Safari storageState: authFile, }, }, ], /* Run your local dev server before starting the tests */ webServer: process.env.CI ? undefined : { command: 'cd ../../../ && pdm run python -m local_deep_research.web.app', url: 'http://127.0.0.1:5000', reuseExistingServer: !process.env.CI, timeout: 120000, }, });