96 lines
3.7 KiB
TypeScript
96 lines
3.7 KiB
TypeScript
import { defineConfig, devices } from '@playwright/test';
|
||
import { fileURLToPath } from 'node:url';
|
||
import { dirname, resolve } from 'node:path';
|
||
import { tmpdir } from 'node:os';
|
||
import { mkdirSync } from 'node:fs';
|
||
import { join } from 'node:path';
|
||
|
||
// __dirname under ESM.
|
||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||
// Repo root is one level up from ui/.
|
||
const repoRoot = resolve(__dirname, '..');
|
||
|
||
// Separate port from the auth-OFF harness (8788) so both configs can coexist.
|
||
const PORT = Number(process.env.E2E_AUTH_PORT ?? 8790);
|
||
const BASE_URL = `http://127.0.0.1:${PORT}`;
|
||
|
||
// Isolated throwaway data + workspace dirs — never touches real ./data/maestro.db.
|
||
//
|
||
// DETERMINISTIC path (NOT mkdtemp): Playwright imports this config in the main
|
||
// runner process AND re-imports it in each spec worker process. A random
|
||
// mkdtemp would yield a DIFFERENT DB_PATH per import — the webServer (started
|
||
// from the main-process value) and the spec's seeding code would then open
|
||
// DIFFERENT databases, so seeded members would never appear. A fixed path makes
|
||
// every import agree on one DB. The spec computes the SAME path independently
|
||
// (see DB_PATH in the spec) and seeds into it. We do NOT delete it at import
|
||
// time (a worker import would nuke the live DB); the server rebuilds its schema
|
||
// on boot and seeding is idempotent, so a stale file from a prior run is benign.
|
||
const e2eTmp = join(tmpdir(), 'maestro-e2e-auth');
|
||
mkdirSync(e2eTmp, { recursive: true });
|
||
const DB_PATH = join(e2eTmp, 'e2e-auth.db');
|
||
const WORKTREE_DIR = join(e2eTmp, 'workspaces');
|
||
|
||
// Absolute path to the local-auth config YAML (enables POST /auth/local login).
|
||
const AAO_CONFIG = resolve(repoRoot, 'ui/e2e-auth/config.e2e-auth.yaml');
|
||
|
||
export default defineConfig({
|
||
testDir: resolve(__dirname, 'e2e-auth'),
|
||
testMatch: '**/*.spec.ts',
|
||
// Build+boot can be slow; roomy per-test budget.
|
||
timeout: 60_000,
|
||
expect: { timeout: 15_000 },
|
||
fullyParallel: false,
|
||
workers: 1,
|
||
retries: 0,
|
||
reporter: [['list']],
|
||
|
||
use: {
|
||
baseURL: BASE_URL,
|
||
headless: true,
|
||
// NOTE: the wide viewport that keeps the desktop nav (data-testid="nav-*")
|
||
// out of the hamburger drawer is set on the chromium project below, AFTER
|
||
// the Desktop Chrome device spread (which would otherwise pin 1280×720).
|
||
// Under LOCAL AUTH the TopBar carries extra right-side chrome (user chip,
|
||
// change-password, logout) that collapses it to compact mode at 1280 — and
|
||
// the drawer nav exposes no nav-* testids.
|
||
// This sandbox disables the Chromium sandbox (bwrap/userns off). Launch
|
||
// with --no-sandbox or every browser launch fails to spawn.
|
||
launchOptions: {
|
||
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
|
||
},
|
||
trace: 'retain-on-failure',
|
||
},
|
||
|
||
projects: [
|
||
{
|
||
name: 'chromium',
|
||
// Device spread sets 1280×720; override AFTER it so the wide viewport wins.
|
||
use: { ...devices['Desktop Chrome'], viewport: { width: 1600, height: 900 } },
|
||
},
|
||
],
|
||
|
||
// Boot the real orchestrator (worker mode) with LOCAL AUTH ON (AAO_CONFIG
|
||
// points at the local-auth YAML). The bootstrap admin is seeded at startup;
|
||
// member users are seeded by the spec's beforeAll into the same temp DB.
|
||
// dist/ must exist (npm run build:all).
|
||
webServer: {
|
||
command: 'node dist/main.js',
|
||
cwd: repoRoot,
|
||
url: `${BASE_URL}/ui`,
|
||
reuseExistingServer: false,
|
||
timeout: 120_000,
|
||
stdout: 'pipe',
|
||
stderr: 'pipe',
|
||
env: {
|
||
...process.env,
|
||
PORT: String(PORT),
|
||
DB_PATH,
|
||
WORKTREE_DIR,
|
||
AAO_CONFIG,
|
||
AAO_MODE: 'worker',
|
||
LOG_LEVEL: 'warn',
|
||
MCP_ENCRYPTION_KEY: '00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff',
|
||
},
|
||
},
|
||
});
|