Files
SnapOtter/playwright.config.ts
T

149 lines
4.9 KiB
TypeScript
Raw Normal View History

import { randomBytes } from "node:crypto";
import path from "node:path";
import { defineConfig, devices } from "@playwright/test";
const authFile = path.join(__dirname, ".playwright", ".auth", "user.json");
const TEST_WEB_PORT = 2349;
// Fresh Postgres database per e2e run. The create-db script (chained before
// the API in the webServer command) CREATEs it and cleans up stale databases
// from previous runs. The API auto-migrates the empty database at boot.
const E2E_PG_BASE_URL =
process.env.E2E_PG_BASE_URL || "postgres://snapotter:snapotter@localhost:5432/snapotter";
const e2eDbName = `snapotter_e2e_${process.pid}_${randomBytes(4).toString("hex")}`;
const e2eDatabaseUrl = (() => {
const url = new URL(E2E_PG_BASE_URL);
url.pathname = `/${e2eDbName}`;
return url.toString();
})();
// Specs that mutate global server state (settings, users, roles, API keys)
// or assert on global lists/timing. These run in the chromium-serial project
// with --workers=1; everything else parallelizes safely.
const SERIAL_SPECS =
/gui-settings-|settings\.spec|rbac|security|people|api\.spec|state-bleed|full-session|gui-file-carry|i18n|theme|gui-performance/;
// Screenshot-comparison specs. Separate project because baselines are
// platform-specific: they run locally (darwin baselines) and via the
// update-visual-baselines workflow, but not in the nightly linux run until
// linux baselines are committed.
const VISUAL_SPECS = /visual-regression|gui-visual-/;
export default defineConfig({
testDir: "./tests/e2e",
timeout: 30_000,
expect: {
timeout: 10_000,
toHaveScreenshot: {
maxDiffPixelRatio: 0.01,
animations: "disabled",
caret: "hide",
},
},
// Platform-suffixed baselines: darwin baselines serve local runs on macOS,
// linux baselines (generated by the update-visual-baselines workflow) serve CI.
snapshotPathTemplate: "{testDir}/__screenshots__/{testFilePath}/{arg}-{platform}{ext}",
fullyParallel: false,
retries: process.env.CI ? 1 : 0,
// Files run across workers; tests within a file stay ordered. The serial
// bucket is pinned to --workers=1 by its run command. Default is 2: the
// dev-mode webServers saturate beyond that and 30s-timeout tests start
// flaking. Raise via PW_WORKERS on stronger setups.
workers: process.env.PW_WORKERS ? Number(process.env.PW_WORKERS) : 2,
reporter: "html",
use: {
baseURL: `http://localhost:${TEST_WEB_PORT}`,
screenshot: "only-on-failure",
trace: "retain-on-failure",
},
projects: [
{
name: "setup",
testMatch: /auth\.setup\.ts/,
},
{
name: "chromium",
use: {
...devices["Desktop Chrome"],
storageState: authFile,
},
testIgnore: [SERIAL_SPECS, VISUAL_SPECS],
dependencies: ["setup"],
},
{
name: "chromium-serial",
use: {
...devices["Desktop Chrome"],
storageState: authFile,
},
testMatch: SERIAL_SPECS,
dependencies: ["setup"],
},
{
name: "chromium-visual",
use: {
...devices["Desktop Chrome"],
storageState: authFile,
},
testMatch: VISUAL_SPECS,
dependencies: ["setup"],
},
{
name: "firefox",
use: {
...devices["Desktop Firefox"],
storageState: authFile,
},
testMatch: /gui-cross-browser\.spec\.ts/,
dependencies: ["setup"],
},
{
name: "webkit",
use: {
...devices["Desktop Safari"],
storageState: authFile,
},
testMatch: /gui-cross-browser\.spec\.ts/,
dependencies: ["setup"],
},
],
webServer: [
{
command: `node tests/e2e-pg-create-db.cjs ${e2eDbName} && pnpm --filter @snapotter/api dev`,
port: 13490,
reuseExistingServer: !process.env.CI,
env: {
AUTH_ENABLED: "true",
DEFAULT_USERNAME: "admin",
DEFAULT_PASSWORD: "admin",
RATE_LIMIT_PER_MIN: "50000",
SKIP_MUST_CHANGE_PASSWORD: "true",
ANALYTICS_ENABLED: "false",
DATABASE_URL: e2eDatabaseUrl,
REDIS_URL: process.env.REDIS_URL ?? "redis://localhost:6379",
BULLMQ_PREFIX: e2eDbName,
// The in-repo docker/feature-manifest.json makes the API think it is
// inside Docker and try to mkdir /data; point it somewhere writable.
DATA_DIR: path.join(__dirname, "test-results", ".e2e-data"),
},
timeout: 30_000,
},
{
// Production build + static preview: the dev server's on-demand
// transform saturates under parallel workers and flakes 30s-timeout
// tests. The build adds ~40s once per run and removes that whole class.
command: "pnpm --filter @snapotter/web build && pnpm --filter @snapotter/web preview",
port: TEST_WEB_PORT,
reuseExistingServer: !process.env.CI,
env: {
PORT: String(TEST_WEB_PORT),
VITE_API_URL: "http://localhost:13490",
},
timeout: 240_000,
},
],
});
export { authFile };