import { cpus } from "node:os"; import { defineConfig, devices } from "@playwright/test"; const isCI = !!process.env.CI; // Playwright defaults to CPU / 2 workers, // capping the number of workers to 4 to avoid overloading browsers. const workers = Math.min(4, Math.max(1, Math.floor(cpus().length / 2))); // When the app is already served elsewhere (e.g. the docker e2e job) set // E2E_NO_WEBSERVER=1 so Playwright does not start its own dev server. const useExternalServer = !!process.env.E2E_NO_WEBSERVER; const baseURL = process.env.E2E_BASE_URL ?? "http://localhost:8888/"; export default defineConfig({ testDir: "./e2e", testMatch: "**/*.spec.ts", globalSetup: "./e2e/utils/e2e-setup.ts", globalTeardown: "./e2e/utils/e2e-teardown.ts", fullyParallel: true, forbidOnly: isCI, workers, retries: isCI ? 2 : 0, reporter: isCI ? [["list"], ["html", { open: "never" }]] : "list", use: { baseURL, trace: "on-first-retry", }, projects: [ { name: "chromium", use: { ...devices["Desktop Chrome"], launchOptions: { // Allow WebGL (maplibre) to fall back to software rendering in headless. args: [ "--disable-gpu", "--enable-features=AllowSwiftShaderFallback,AllowSoftwareGLFallbackDueToCrashes", "--enable-unsafe-swiftshader", ], }, }, }, ], webServer: useExternalServer ? undefined : { command: "npm run start", url: "http://localhost:8888/maputnik/", reuseExistingServer: !isCI, timeout: 120000, }, });