#!/usr/bin/env bash # ── ss-tools E2E test runner ───────────────────────────────── # Usage: # ./e2e/run-e2e.sh # default: test against local stack # ./e2e/run-e2e.sh --ci # CI mode: build, start stack, test, teardown # ./e2e/run-e2e.sh --ui # open Playwright UI mode # ./e2e/run-e2e.sh --update-snapshots # update visual snapshots # # Prerequisites: # - Docker Compose stack running (or --ci to auto-start) # - Node 20+ # - Backend and frontend accessible on configured ports # ───────────────────────────────────────────────────────────── set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" FRONTEND_DIR="$PROJECT_ROOT/frontend" # Load .env.e2e if present if [ -f "$SCRIPT_DIR/.env.e2e" ]; then set -a source "$SCRIPT_DIR/.env.e2e" set +a fi # Defaults BACKEND_URL="${BACKEND_URL:-http://127.0.0.1:8101}" FRONTEND_URL="${FRONTEND_URL:-http://127.0.0.1:8102}" CI_MODE=false UI_MODE=false SNAPSHOT_MODE=false # Parse args for arg in "$@"; do case "$arg" in --ci) CI_MODE=true ;; --ui) UI_MODE=true ;; --update-snapshots) SNAPSHOT_MODE=true ;; esac done echo "═══════════════════════════════════════════════════════" echo " ss-tools E2E Test Runner" echo " Backend: $BACKEND_URL" echo " Frontend: $FRONTEND_URL" echo " CI mode: $CI_MODE" echo "═══════════════════════════════════════════════════════" # ── CI mode: build, start, test, teardown ────────────────── if [ "$CI_MODE" = true ]; then echo "[E2E] CI mode: building and starting stack..." cd "$PROJECT_ROOT" docker compose -p ss-tools-e2e --env-file .env.current up -d --build db backend echo "[E2E] Waiting for backend to be healthy..." for i in $(seq 1 30); do if curl -sf "$BACKEND_URL/api/health/summary" > /dev/null 2>&1; then echo "[E2E] Backend is healthy after ${i}s" break fi if [ "$i" -eq 30 ]; then echo "[E2E] Backend failed to start within 30s" docker compose -p ss-tools-e2e logs --tail=20 backend exit 1 fi sleep 1 done echo "[E2E] Starting frontend..." cd "$FRONTEND_DIR" npx vite --host 0.0.0.0 --port 8100 & VITE_PID=$! sleep 3 # Ensure cleanup on exit cleanup() { echo "[E2E] Cleaning up..." kill "$VITE_PID" 2>/dev/null || true docker compose -p ss-tools-e2e down -t 5 } trap cleanup EXIT fi # ── Pre-flight check ──────────────────────────────────────── echo "[E2E] Pre-flight: checking backend..." if ! curl -sf "$BACKEND_URL/api/health/summary" > /dev/null 2>&1; then echo "[E2E] ERROR: Backend unreachable at $BACKEND_URL" echo " Make sure the stack is running:" echo " docker compose -p ss-tools-current --env-file .env.current up -d" echo " Or use --ci to auto-start:" echo " ./e2e/run-e2e.sh --ci" exit 1 fi echo "[E2E] Pre-flight: checking frontend..." if ! curl -sf -o /dev/null "$FRONTEND_URL/login" 2>/dev/null; then echo "[E2E] WARNING: Frontend unreachable at $FRONTEND_URL, may fail later" fi # ── Run Playwright tests ──────────────────────────────────── cd "$FRONTEND_DIR" export BACKEND_URL export FRONTEND_URL PLAYWRIGHT_ARGS="" if [ "$UI_MODE" = true ]; then PLAYWRIGHT_ARGS="--ui" fi if [ "$SNAPSHOT_MODE" = true ]; then PLAYWRIGHT_ARGS="$PLAYWRIGHT_ARGS --update-snapshots" fi echo "[E2E] Running Playwright tests..." # shellcheck disable=SC2086 npx playwright test $PLAYWRIGHT_ARGS echo "[E2E] Done."