import { defineConfig } from "cypress"; import { readFileSync } from "node:fs"; import { join } from "node:path"; import { Client } from "pg"; /** * Freight e2e suite. Three origins: * backoffice http://localhost:5383 (baseUrl — most specs live here) * portal http://localhost:5373 (env.portalUrl; portal specs cy.visit it, * cross-app flows reach it via cy.origin) * api http://localhost:3101 (env.apiUrl; cy.request only) * * All URLs are host-published ports from docker-compose.e2e.yaml. The cypress * container in that compose file runs with network_mode: host, so the same * localhost URLs work identically for `cypress open` on the host and for the * containerized headless run. */ export default defineConfig({ e2e: { baseUrl: process.env.CYPRESS_BASE_URL ?? "http://localhost:5383", specPattern: "cypress/e2e/**/*.cy.ts", supportFile: "cypress/support/e2e.ts", video: process.env.CI === "true" || process.env.CYPRESS_VIDEO === "true", screenshotOnRunFailure: true, viewportWidth: 1440, viewportHeight: 900, defaultCommandTimeout: 10000, requestTimeout: 15000, retries: { runMode: 1, openMode: 0 }, env: { apiUrl: process.env.CYPRESS_API_URL ?? "http://localhost:3101", portalUrl: process.env.CYPRESS_PORTAL_URL ?? "http://localhost:5373", backofficeUrl: process.env.CYPRESS_BASE_URL ?? "http://localhost:5383", // Staff users: DEFAULT_PASSWORD from docker-compose.e2e.yaml. defaultPassword: process.env.CYPRESS_DEFAULT_PASSWORD ?? "password@tria", // Demo portal users: hardcoded in DemoUsersSeeder. demoPassword: "12345678", }, setupNodeEvents(on) { const dbUrl = process.env.E2E_DB_URL ?? "postgres://edr_e2e:edr_e2e@localhost:5533/edr_freight_e2e"; on("task", { /** Run an arbitrary SQL statement against the ephemeral e2e database. */ async "db:query"({ sql, params = [] }: { sql: string; params?: unknown[] }) { const client = new Client({ connectionString: dbUrl }); await client.connect(); try { const result = await client.query(sql, params as never[]); return { rowCount: result.rowCount, rows: result.rows }; } finally { await client.end(); } }, /** * Seed the test users (staff + demo) directly in SQL. The API's * user seeders are disabled in app code, so the fixture replicates * their output. Idempotent — safe to run before every spec file. */ async "db:seedUsers"() { // cwd = the e2e/freight project root when Cypress runs. // seed-company.sql depends on rows from seed-users.sql — keep order. const client = new Client({ connectionString: dbUrl }); await client.connect(); try { for (const file of ["seed-users.sql", "seed-company.sql"]) { const sql = readFileSync( join(process.cwd(), "cypress", "fixtures", file), "utf8", ); await client.query(sql); } return true; } finally { await client.end(); } }, }); }, }, });