2026-07-27 15:37:30 +08:00
|
|
|
import path from "node:path";
|
2026-05-07 09:29:01 +08:00
|
|
|
import { defineConfig, devices } from "@playwright/test";
|
2026-07-27 15:37:30 +08:00
|
|
|
import { resolvePlaywrightBackingState } from "./tests/playwright-backing-state.mjs";
|
|
|
|
|
import { resolvePlaywrightEndpoint, resolvePlaywrightRun } from "./tests/playwright-run.js";
|
|
|
|
|
|
|
|
|
|
const { runId, runRoot } = resolvePlaywrightRun(__dirname, "editor");
|
|
|
|
|
if (!process.env.PLAYWRIGHT_EDITOR_WEB_PORT && process.env.EDITOR_TEST_PORT) {
|
|
|
|
|
process.env.PLAYWRIGHT_EDITOR_WEB_PORT = process.env.EDITOR_TEST_PORT;
|
|
|
|
|
}
|
|
|
|
|
const apiEndpoint = resolvePlaywrightEndpoint(
|
|
|
|
|
"PLAYWRIGHT_EDITOR_API_PORT",
|
|
|
|
|
"PLAYWRIGHT_EDITOR_API_URL",
|
|
|
|
|
30_000,
|
|
|
|
|
);
|
|
|
|
|
const webEndpoint = resolvePlaywrightEndpoint(
|
|
|
|
|
"PLAYWRIGHT_EDITOR_WEB_PORT",
|
|
|
|
|
"PLAYWRIGHT_EDITOR_WEB_URL",
|
|
|
|
|
50_000,
|
|
|
|
|
);
|
|
|
|
|
process.env.EDITOR_TEST_PORT = String(webEndpoint.port);
|
|
|
|
|
process.env.API_URL = apiEndpoint.url;
|
|
|
|
|
const webDistDir = path.join(runRoot, "web-dist");
|
|
|
|
|
|
|
|
|
|
const postgresBaseUrl =
|
|
|
|
|
process.env.E2E_PG_BASE_URL || "postgres://snapotter:snapotter@localhost:5432/snapotter";
|
|
|
|
|
const backingState = resolvePlaywrightBackingState({
|
|
|
|
|
postgresBaseUrl,
|
|
|
|
|
redisUrl: process.env.REDIS_URL ?? "redis://localhost:6379",
|
|
|
|
|
runId,
|
|
|
|
|
scope: "editor",
|
|
|
|
|
});
|
2026-05-07 09:29:01 +08:00
|
|
|
|
|
|
|
|
export default defineConfig({
|
|
|
|
|
testDir: "./tests/e2e-editor",
|
|
|
|
|
timeout: 60_000,
|
|
|
|
|
expect: { timeout: 15_000 },
|
|
|
|
|
fullyParallel: false,
|
|
|
|
|
workers: 1,
|
|
|
|
|
retries: 0,
|
2026-07-27 15:37:30 +08:00
|
|
|
outputDir: path.join(runRoot, "playwright-output"),
|
|
|
|
|
reporter: [["html", { open: "never", outputFolder: path.join(runRoot, "playwright-report") }]],
|
2026-05-07 09:29:01 +08:00
|
|
|
use: {
|
2026-07-27 15:37:30 +08:00
|
|
|
baseURL: webEndpoint.url,
|
2026-05-07 09:29:01 +08:00
|
|
|
trace: "retain-on-failure",
|
|
|
|
|
screenshot: "only-on-failure",
|
|
|
|
|
viewport: { width: 1440, height: 900 },
|
|
|
|
|
},
|
|
|
|
|
projects: [
|
|
|
|
|
{
|
|
|
|
|
name: "chromium",
|
|
|
|
|
use: { ...devices["Desktop Chrome"] },
|
|
|
|
|
},
|
|
|
|
|
],
|
2026-07-27 15:37:30 +08:00
|
|
|
webServer: [
|
|
|
|
|
{
|
|
|
|
|
command: `node tests/playwright-api-lifecycle.mjs ${runId} editor -- pnpm --filter @snapotter/api start`,
|
|
|
|
|
url: `${apiEndpoint.url}/api/v1/health`,
|
|
|
|
|
reuseExistingServer: false,
|
|
|
|
|
gracefulShutdown: { signal: "SIGTERM", timeout: 30_000 },
|
|
|
|
|
env: {
|
|
|
|
|
PORT: String(apiEndpoint.port),
|
|
|
|
|
AUTH_ENABLED: "true",
|
|
|
|
|
DEFAULT_USERNAME: "admin",
|
|
|
|
|
DEFAULT_PASSWORD: "admin",
|
|
|
|
|
RATE_LIMIT_PER_MIN: "50000",
|
|
|
|
|
LOGIN_ATTEMPT_LIMIT: "100000",
|
|
|
|
|
SKIP_MUST_CHANGE_PASSWORD: "true",
|
|
|
|
|
ANALYTICS_ENABLED: "false",
|
|
|
|
|
DATABASE_URL: backingState.databaseUrl,
|
|
|
|
|
E2E_PG_BASE_URL: backingState.postgresBaseUrl,
|
|
|
|
|
REDIS_URL: backingState.redisUrl,
|
|
|
|
|
BULLMQ_PREFIX: backingState.bullmqPrefix,
|
|
|
|
|
DATA_DIR: path.join(runRoot, "data"),
|
|
|
|
|
FILES_STORAGE_PATH: path.join(runRoot, "files"),
|
|
|
|
|
WORKSPACE_PATH: path.join(runRoot, "workspace"),
|
|
|
|
|
FEATURE_MANIFEST_PATH: path.join(runRoot, ".no-feature-manifest.json"),
|
|
|
|
|
},
|
|
|
|
|
timeout: 30_000,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Run-scoped output directory: vite empties it before writing, so sharing
|
|
|
|
|
// the default apps/web/dist lets a concurrent run delete the assets this
|
|
|
|
|
// run's preview server is still serving.
|
|
|
|
|
command: `pnpm --filter @snapotter/web exec tsc -b && pnpm --filter @snapotter/web exec vite build --outDir ${webDistDir} --emptyOutDir && exec pnpm --filter @snapotter/web exec vite preview --outDir ${webDistDir} --host ${webEndpoint.host} --port ${webEndpoint.port} --strictPort`,
|
|
|
|
|
url: webEndpoint.url,
|
|
|
|
|
reuseExistingServer: false,
|
|
|
|
|
env: {
|
|
|
|
|
PORT: String(webEndpoint.port),
|
|
|
|
|
VITE_API_URL: apiEndpoint.url,
|
|
|
|
|
},
|
|
|
|
|
timeout: 240_000,
|
|
|
|
|
},
|
|
|
|
|
],
|
2026-05-07 09:29:01 +08:00
|
|
|
});
|