import { defineConfig, devices } from '@playwright/test'; import { existsSync } from 'node:fs'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; const frontendPort = process.env.PLAYWRIGHT_FRONTEND_PORT ?? '3100'; const backendPort = process.env.PLAYWRIGHT_BACKEND_PORT ?? '4100'; const baseURL = `http://127.0.0.1:${frontendPort}`; const graphqlURL = `http://127.0.0.1:${backendPort}/graphql`; const skipWebServer = process.env.PW_SKIP_WEBSERVER === 'true'; const isStatefulRun = process.env.PLAYWRIGHT_STATEFUL === 'true'; const useBuiltFrontend = process.env.PLAYWRIGHT_USE_BUILT_FRONTEND === 'true'; const repoRoot = dirname(fileURLToPath(import.meta.url)); const backendCandidates = [ resolve(repoRoot, 'gennit-backend'), resolve(repoRoot, '../gennit-backend'), resolve(repoRoot, '../../gennit-backend'), ]; const backendRoot = process.env.PLAYWRIGHT_BACKEND_CWD ?? backendCandidates.find((candidate) => existsSync(candidate)) ?? backendCandidates[0]; const webServers = [ ...(isStatefulRun ? [ { name: 'backend', command: 'node ./ts_emitted/index.js', cwd: backendRoot, env: { AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID ?? 'playwright-test-client', AUTH0_DOMAIN: process.env.AUTH0_DOMAIN ?? 'example.com', CYPRESS_ADMIN_TEST_EMAIL: process.env.CYPRESS_ADMIN_TEST_EMAIL ?? 'catherine.luse@gmail.com', CYPRESS_ADMIN_TEST_USERNAME: process.env.CYPRESS_ADMIN_TEST_USERNAME ?? 'cluse', NEO4J_PASSWORD: process.env.NEO4J_PASSWORD ?? 'playwright-ci-password', NEO4J_URI: process.env.NEO4J_URI ?? 'bolt://127.0.0.1:7688', NEO4J_USER: process.env.NEO4J_USER ?? 'neo4j', E2E_MOCK_AUTH: 'true', NODE_ENV: 'development', GOOGLE_CREDENTIALS_BASE64: '', MULTIFORUM_AUTH_PROVIDER: 'local-dev', MULTIFORUM_AUTO_PROVISION: 'true', MULTIFORUM_BOOTSTRAP_EMAIL: 'catherine.luse@gmail.com', MULTIFORUM_BOOTSTRAP_PASSWORD: 'playwright-local-password', MULTIFORUM_BOOTSTRAP_USERNAME: 'cluse', PLAYWRIGHT_MOCK_AUTH: 'true', PORT: backendPort, SERVER_CONFIG_NAME: 'Playwright Test Server', SUPERADMIN_EMAIL: 'catherine.luse@gmail.com', }, url: `http://127.0.0.1:${backendPort}`, reuseExistingServer: true, timeout: 120_000, }, ] : []), { name: 'frontend', // CI serves the prebuilt node artifact so cold Nuxt compilation cannot // consume the web-server readiness window. Local runs retain fast HMR. command: useBuiltFrontend ? 'node .output/server/index.mjs' : isStatefulRun ? `NODE_OPTIONS='--max-old-space-size=4096' pnpm exec nuxt dev --host 127.0.0.1 --port ${frontendPort}` : `pnpm exec nuxt dev --host 127.0.0.1 --port ${frontendPort}`, env: { NITRO_HOST: '127.0.0.1', NITRO_PORT: frontendPort, NUXT_BACKEND_GRAPHQL_URL: graphqlURL, NUXT_PUBLIC_AUTH_PROVIDER: 'local-dev', VITE_E2E_MOCK_MODE: 'true', VITE_GRAPHQL_URL: graphqlURL, VITE_SERVER_NAME: 'Playwright Test Server', }, url: baseURL, reuseExistingServer: true, timeout: 120_000, }, ]; export default defineConfig({ testDir: './tests/playwright', // Increase timeout for stateful tests that need database reset timeout: isStatefulRun ? 180_000 : 60_000, // Retry failed stateful tests once to handle transient infrastructure issues retries: isStatefulRun ? 1 : 0, workers: 1, expect: { timeout: 30_000, }, fullyParallel: false, reporter: [['list'], ['html', { open: 'never' }]], use: { baseURL, trace: 'retain-on-failure', screenshot: 'only-on-failure', video: 'retain-on-failure', headless: true, }, webServer: skipWebServer ? undefined : webServers, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'], }, }, ], });