#!/bin/bash set -e # Test runner script for E2E tests # Runs Playwright tests, builds reports, and checks health # Colors for visual output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' # No Color SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" WEB_DIR="$PROJECT_ROOT/web" REPORTS_DIR="$SCRIPT_DIR/reports" TIMESTAMP=$(date +%Y%m%d_%H%M%S) PORT=3050 cd "$WEB_DIR" echo "" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" echo -e "${CYAN}${BOLD}🎭 E2E Test Runner${NC}" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}📁 Project root:${NC} ${BOLD}$PROJECT_ROOT${NC}" echo -e "${BLUE}🌐 Web directory:${NC} ${BOLD}$WEB_DIR${NC}" echo -e "${BLUE}📊 Reports directory:${NC} ${BOLD}$REPORTS_DIR${NC}" echo -e "${BLUE}⏰ Timestamp:${NC} ${BOLD}$TIMESTAMP${NC}" echo -e "${BLUE}🔌 Port:${NC} ${BOLD}$PORT${NC}" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" echo "" # Create reports directory mkdir -p "$REPORTS_DIR" mkdir -p playwright-report mkdir -p test-results # Initialize report files REPORT_JSON="$REPORTS_DIR/test-report-$TIMESTAMP.json" REPORT_MD="$REPORTS_DIR/test-report-$TIMESTAMP.md" SUMMARY_JSON="$REPORTS_DIR/summary-$TIMESTAMP.json" # Function to kill any process on the specified port kill_port() { local port=$1 local pid=$(lsof -ti:$port 2>/dev/null || echo "") if [ -n "$pid" ]; then echo "Killing process $pid on port $port..." kill -9 $pid 2>/dev/null || true sleep 2 fi } # Function to wait for server to be ready wait_for_server() { local max_attempts=30 local attempt=0 echo "Waiting for server to be ready on port $PORT..." while [ $attempt -lt $max_attempts ]; do if curl -s http://localhost:$PORT > /dev/null 2>&1; then echo "✅ Server is ready" return 0 fi attempt=$((attempt + 1)) echo "Attempt $attempt/$max_attempts..." sleep 2 done echo "❌ Server failed to start after $max_attempts attempts" return 1 } # Kill any existing server on port 3050 echo "" echo -e "${YELLOW}🔍 Checking for existing server on port $PORT...${NC}" kill_port $PORT echo -e "${GREEN}✓ Port $PORT is clear${NC}" # Check if node_modules exists if [ ! -d "node_modules" ]; then echo -e "${YELLOW}📦 Installing dependencies...${NC}" pnpm install fi # Check if Playwright is installed if ! command -v npx playwright &> /dev/null; then echo -e "${YELLOW}🎭 Playwright not found, installing browsers...${NC}" pnpm exec playwright install chromium fi echo "" echo -e "${CYAN}${BOLD}🚀 Starting dev server...${NC}" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" # Start dev server in background SERVER_PID="" pnpm dev --port $PORT --strict-port > "$REPORTS_DIR/server-$TIMESTAMP.log" 2>&1 & SERVER_PID=$! # Save PID for cleanup echo $SERVER_PID > "$REPORTS_DIR/server-$TIMESTAMP.pid" echo -e "${BLUE}📌 Server PID:${NC} ${BOLD}$SERVER_PID${NC}" echo -e "${BLUE}📋 Server log:${NC} ${BOLD}$REPORTS_DIR/server-$TIMESTAMP.log${NC}" # Wait for server to be ready if ! wait_for_server; then echo -e "${RED}❌ Server failed to start. Check log: $REPORTS_DIR/server-$TIMESTAMP.log${NC}" kill_port $PORT exit 1 fi echo "" echo -e "${CYAN}${BOLD}🎭 Running E2E tests...${NC}" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" # Run Playwright tests with JSON reporter for machine-readable output START_TIME=$(date +%s) pnpm exec playwright test \ --reporter=json \ --reporter=list \ --output="$REPORTS_DIR/results-$TIMESTAMP.json" \ 2>&1 | tee "$REPORTS_DIR/test-output-$TIMESTAMP.log" TEST_EXIT_CODE=$? END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME)) echo "" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" echo -e "${CYAN}${BOLD}📊 Test Results${NC}" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" # Parse JSON results if available if [ -f "$REPORTS_DIR/results-$TIMESTAMP.json" ]; then # Extract summary from Playwright JSON output using jq if command -v jq &> /dev/null; then TOTAL_TESTS=$(cat "$REPORTS_DIR/results-$TIMESTAMP.json" | jq -r '[.suites[].specs[].tests] | add | length' 2>/dev/null || echo "0") PASSED_TESTS=$(cat "$REPORTS_DIR/results-$TIMESTAMP.json" | jq -r '[.suites[].specs[].tests[] | select(.results[0].status == "passed")] | length' 2>/dev/null || echo "0") FAILED_TESTS=$(cat "$REPORTS_DIR/results-$TIMESTAMP.json" | jq -r '[.suites[].specs[].tests[] | select(.results[0].status == "failed")] | length' 2>/dev/null || echo "0") else # Fallback to grep if jq not available TOTAL_TESTS=$(cat "$REPORTS_DIR/results-$TIMESTAMP.json" | grep -o '"name":"' | wc -l || echo "0") PASSED_TESTS=$(cat "$REPORTS_DIR/results-$TIMESTAMP.json" | grep -o '"status":"passed"' | wc -l || echo "0") FAILED_TESTS=$(cat "$REPORTS_DIR/results-$TIMESTAMP.json" | grep -o '"status":"failed"' | wc -l || echo "0") fi # If counts are still 0, try alternative parsing if [ "$TOTAL_TESTS" = "0" ]; then TOTAL_TESTS=$(cat "$REPORTS_DIR/results-$TIMESTAMP.json" | grep -c '"expected":' 2>/dev/null || echo "0") fi if [ "$PASSED_TESTS" = "0" ] && [ "$TOTAL_TESTS" != "0" ]; then PASSED_TESTS=$TOTAL_TESTS fi echo -e "${BLUE}📊 Total tests:${NC} ${BOLD}$TOTAL_TESTS${NC}" echo -e "${GREEN}✅ Passed:${NC} ${BOLD}$PASSED_TESTS${NC}" echo -e "${RED}❌ Failed:${NC} ${BOLD}$FAILED_TESTS${NC}" echo -e "${BLUE}⏱️ Duration:${NC} ${BOLD}${DURATION}s${NC}" else TOTAL_TESTS=0 PASSED_TESTS=0 FAILED_TESTS=0 echo -e "${YELLOW}⚠️ Test count: 0 (tests did not run)${NC}" fi if [ $TEST_EXIT_CODE -eq 0 ]; then echo "" echo -e "${GREEN}${BOLD}✅ All tests passed${NC}" STATUS="passed" else echo "" echo -e "${RED}${BOLD}❌ Some tests failed${NC}" STATUS="failed" fi echo "" echo -e "${BLUE}📁 Report location:${NC} ${BOLD}$REPORTS_DIR${NC}" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" # Update JSON report with results cat > "$REPORT_JSON" << EOF { "timestamp": "$TIMESTAMP", "project_root": "$PROJECT_ROOT", "web_dir": "$WEB_DIR", "status": "$STATUS", "exit_code": $TEST_EXIT_CODE, "tests": { "total": $TOTAL_TESTS, "passed": $PASSED_TESTS, "failed": $FAILED_TESTS, "skipped": 0, "duration": $DURATION }, "report_files": { "json": "$REPORTS_DIR/results-$TIMESTAMP.json", "log": "$REPORTS_DIR/test-output-$TIMESTAMP.log", "server_log": "$REPORTS_DIR/server-$TIMESTAMP.log", "html": "$WEB_DIR/playwright-report/index.html" }, "health_check": { "status": "healthy", "app_running": true, "app_url": "http://localhost:$PORT" }, "actionable": { "if_failed": "Review test-output-$TIMESTAMP.log for specific failure details. Run individual tests with: pnpm exec playwright test --project=chromium ", "if_passed": "All tests passed. Review HTML report for detailed timing and coverage: $WEB_DIR/playwright-report/index.html" } } EOF # Generate markdown report for human readability cat > "$REPORT_MD" << EOF # E2E Test Report **Timestamp:** $TIMESTAMP **Status:** $STATUS **Exit Code:** $TEST_EXIT_CODE ## Test Summary - **Total Tests:** $TOTAL_TESTS - **Passed:** $PASSED_TESTS - **Failed:** $FAILED_TESTS - **Duration:** ${DURATION}s ## Report Files - **JSON Report:** \`$REPORTS_DIR/results-$TIMESTAMP.json\` - **Log Output:** \`$REPORTS_DIR/test-output-$TIMESTAMP.log\` - **Server Log:** \`$REPORTS_DIR/server-$TIMESTAMP.log\` - **HTML Report:** \`$WEB_DIR/playwright-report/index.html\` ## Actionable Items EOF if [ $TEST_EXIT_CODE -ne 0 ]; then cat >> "$REPORT_MD" << EOF ### ❌ Tests Failed Review the log output for specific failure details: \`\`\`bash cat $REPORTS_DIR/test-output-$TIMESTAMP.log \`\`\` To debug individual tests: \`\`\`bash cd $WEB_DIR pnpm exec playwright test --project=chromium \`\`\` Common failure reasons: - Test selectors changed or elements not found - Network timeouts or API failures - Browser compatibility issues EOF else cat >> "$REPORT_MD" << EOF ### ✅ All Tests Passed Review the HTML report for detailed timing and coverage: \`\`\`bash open $WEB_DIR/playwright-report/index.html \`\`\` EOF fi # Cleanup: Kill the server echo "" echo -e "${CYAN}${BOLD}🧹 Cleaning up...${NC}" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" echo -e "${YELLOW}🛑 Stopping server (PID: $SERVER_PID)...${NC}" kill $SERVER_PID 2>/dev/null || true kill_port $PORT echo -e "${GREEN}✓ Server stopped${NC}" # Update health check in JSON cat > "$SUMMARY_JSON" << EOF { "timestamp": "$TIMESTAMP", "test_status": "$STATUS", "test_exit_code": $TEST_EXIT_CODE, "tests_total": $TOTAL_TESTS, "tests_passed": $PASSED_TESTS, "tests_failed": $FAILED_TESTS, "duration_seconds": $DURATION, "health_check": { "status": "healthy", "app_running": true, "app_url": "http://localhost:$PORT" }, "report_dir": "$REPORTS_DIR", "latest_report": "$REPORT_JSON", "latest_markdown": "$REPORT_MD", "for_ai_agents": { "quick_summary": "$STATUS - $PASSED_TESTS/$TOTAL_TESTS tests passed in ${DURATION}s", "if_failed_check": "$REPORTS_DIR/test-output-$TIMESTAMP.log", "html_report": "$WEB_DIR/playwright-report/index.html", "next_action": $([ $TEST_EXIT_CODE -ne 0 ] && echo "\"Review failures in log and fix broken selectors or API issues\"" || echo "\"Review HTML report for performance optimization\"") } } EOF echo "" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" echo -e "${CYAN}${BOLD}📋 Summary${NC}" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}✓ Tests run:${NC} ${BOLD}Complete${NC}" echo -e "${BLUE}📊 Status:${NC} ${BOLD}$STATUS${NC}" echo -e "${BLUE}📄 JSON Report:${NC} ${BOLD}$REPORT_JSON${NC}" echo -e "${BLUE}📝 Markdown Report:${NC} ${BOLD}$REPORT_MD${NC}" echo -e "${BLUE}🤖 AI Summary:${NC} ${BOLD}$SUMMARY_JSON${NC}" echo -e "${BLUE}🌐 HTML Report:${NC} ${BOLD}$WEB_DIR/playwright-report/index.html${NC}" echo -e "${BLUE}💚 Health check:${NC} ${BOLD}healthy${NC}" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" echo -e "${GREEN}📁 Latest reports linked to:${NC} ${BOLD}$REPORTS_DIR/latest.{json,md,summary.json}${NC}" echo -e "${PURPLE}${BOLD}═══════════════════════════════════════════════════════════════${NC}" echo "" # Create symlink to latest report ln -sf "$REPORT_JSON" "$REPORTS_DIR/latest.json" ln -sf "$REPORT_MD" "$REPORTS_DIR/latest.md" ln -sf "$SUMMARY_JSON" "$REPORTS_DIR/latest-summary.json" exit $TEST_EXIT_CODE