From 27bd8b512c4fd6cd36a9c143d8f6112ec77dbf0b Mon Sep 17 00:00:00 2001 From: bengizmo Date: Wed, 21 May 2025 20:58:41 -0300 Subject: [PATCH] feat: Add comprehensive testing resilience and monitoring scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added test-monitor.sh for monitoring test execution metrics and generating reports - Created test-data-manager.sh for robust test data management - Added health-check.sh for comprehensive system health verification - Enhanced overall deployment safety and reliability 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- wordpress-dev/bin/health-check.sh | 655 +++++++++++++++++++++++++ wordpress-dev/bin/test-data-manager.sh | 526 ++++++++++++++++++++ wordpress-dev/bin/test-monitor.sh | 306 ++++++++++++ 3 files changed, 1487 insertions(+) create mode 100755 wordpress-dev/bin/health-check.sh create mode 100755 wordpress-dev/bin/test-data-manager.sh create mode 100755 wordpress-dev/bin/test-monitor.sh diff --git a/wordpress-dev/bin/health-check.sh b/wordpress-dev/bin/health-check.sh new file mode 100755 index 00000000..2db078e2 --- /dev/null +++ b/wordpress-dev/bin/health-check.sh @@ -0,0 +1,655 @@ +#!/bin/bash +# health-check.sh - Comprehensive health check for the testing and deployment environment +# Usage: ./bin/health-check.sh [--verbose] [--fix] [--ci] + +set -e + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Default settings +VERBOSE=false +FIX_ISSUES=false +CI_MODE=false +CURRENT_DATE=$(date +"%Y-%m-%d") + +# Parse arguments +for arg in "$@"; do + case $arg in + --verbose) + VERBOSE=true + shift + ;; + --fix) + FIX_ISSUES=true + shift + ;; + --ci) + CI_MODE=true + shift + ;; + esac +done + +echo -e "${GREEN}=== HVAC Community Events Health Check ===${NC}" +echo "Checking system health for testing and deployment..." + +# Check if we're in the right directory +if [ ! -d "tests/e2e" ]; then + echo -e "${RED}Error: Please run this script from the wordpress-dev directory${NC}" + exit 1 +fi + +# Create logs directory +mkdir -p logs/health +HEALTH_LOG="logs/health/health-check-${CURRENT_DATE}.log" + +# Log function +log() { + echo "[$(date +"%Y-%m-%d %H:%M:%S")] $1" >> "$HEALTH_LOG" + if [ "$VERBOSE" = true ]; then + echo "$1" + else + echo "$2" + fi +} + +# Function to check a component and report status +check_component() { + local component=$1 + local check_command=$2 + local fix_command=$3 + + echo -e "\n${YELLOW}Checking: ${component}${NC}" + log "Checking component: ${component}" "Checking: ${component}..." + + if eval "${check_command}"; then + echo -e "${GREEN}✓ ${component} check passed${NC}" + log "✓ ${component} check passed" + return 0 + else + echo -e "${RED}✗ ${component} check failed${NC}" + log "✗ ${component} check failed" + + if [ -n "$fix_command" ] && [ "$FIX_ISSUES" = true ]; then + echo -e "${YELLOW}Attempting to fix: ${component}${NC}" + log "Attempting to fix: ${component}" "Attempting to fix..." + + if eval "${fix_command}"; then + echo -e "${GREEN}✓ ${component} fixed successfully${NC}" + log "✓ ${component} fixed successfully" + return 0 + else + echo -e "${RED}✗ Failed to fix: ${component}${NC}" + log "✗ Failed to fix: ${component}" + return 1 + fi + fi + + return 1 + fi +} + +# Function to check npm dependencies +check_npm_dependencies() { + log "Checking npm dependencies" "Checking npm dependencies..." + + # Check if package.json exists + if [ ! -f "package.json" ]; then + log "package.json not found" "package.json not found" + return 1 + fi + + # Check if node_modules exists + if [ ! -d "node_modules" ]; then + log "node_modules not found" "node_modules not found" + return 1 + } + + # Check Playwright installation + if ! npm list @playwright/test > /dev/null 2>&1; then + log "Playwright not installed properly" "Playwright not installed properly" + return 1 + fi + + log "npm dependencies check passed" "npm dependencies ok" + return 0 +} + +# Function to fix npm dependencies +fix_npm_dependencies() { + log "Fixing npm dependencies" "Fixing npm dependencies..." + + # Install dependencies + npm install + + # Install Playwright browsers + npx playwright install + + log "npm dependencies fixed" "npm dependencies fixed" + return 0 +} + +# Function to check test configuration +check_test_config() { + log "Checking test configuration" "Checking test configuration..." + + # Check if playwright.config.ts exists + if [ ! -f "playwright.config.ts" ]; then + log "playwright.config.ts not found" "playwright.config.ts not found" + return 1 + fi + + # Check if config files exist + if [ ! -f "tests/e2e/config/staging-config.ts" ]; then + log "staging-config.ts not found" "staging-config.ts not found" + return 1 + fi + + log "Test configuration check passed" "Test configuration ok" + return 0 +} + +# Function to check test data +check_test_data() { + log "Checking test data" "Checking test data..." + + # Check if test data directory exists + if [ ! -d "tests/e2e/data" ]; then + log "tests/e2e/data directory not found" "tests/e2e/data directory not found" + return 1 + fi + + # Check if essential test data files exist + if [ ! -f "tests/e2e/data/test-users.ts" ] || [ ! -f "tests/e2e/data/test-events.ts" ]; then + log "Essential test data files missing" "Essential test data files missing" + return 1 + fi + + log "Test data check passed" "Test data ok" + return 0 +} + +# Function to fix test data +fix_test_data() { + log "Fixing test data" "Fixing test data..." + + # Generate test data + bash bin/test-data-manager.sh generate + + log "Test data fixed" "Test data fixed" + return 0 +} + +# Function to check page objects +check_page_objects() { + log "Checking page objects" "Checking page objects..." + + # Check if page object directory exists + if [ ! -d "tests/e2e/pages" ]; then + log "tests/e2e/pages directory not found" "tests/e2e/pages directory not found" + return 1 + fi + + # Check if essential page objects exist + if [ ! -f "tests/e2e/pages/BasePage.ts" ] || [ ! -f "tests/e2e/pages/LoginPage.ts" ]; then + log "Essential page objects missing" "Essential page objects missing" + return 1 + fi + + # Check selectors in LoginPage + if ! grep -q "input\[name=\"log\"\]" "tests/e2e/pages/LoginPage.ts"; then + log "LoginPage.ts missing updated selectors" "LoginPage.ts missing updated selectors" + return 1 + fi + + log "Page objects check passed" "Page objects ok" + return 0 +} + +# Function to fix page objects +fix_page_objects() { + log "Fixing page objects" "Fixing page objects..." + + # Create required directories + mkdir -p tests/e2e/pages + + # Fix LoginPage.ts with updated selectors + cat > "tests/e2e/pages/LoginPage.ts" << 'EOF' +import { Page, expect } from '@playwright/test'; +import { BasePage } from './BasePage'; +import { PATHS } from '../config/staging-config'; + +/** + * Page object representing the login page + */ +export class LoginPage extends BasePage { + // Login form elements based on debug analysis + private readonly usernameInput = 'input[name="log"]'; + private readonly passwordInput = 'input[name="pwd"]'; + private readonly loginButton = 'input[type="submit"]'; + private readonly rememberMeCheckbox = 'input[name="rememberme"]'; + private readonly loginError = '.login-error, .login_error, #login_error, .notice-error, .woocommerce-error, .wp-die-message'; + private readonly forgotPasswordLink = 'a:text("Lost your password?")'; + private readonly loginForm = 'form#hvac_community_loginform'; + + constructor(page: Page) { + super(page); + } + + /** + * Navigate to the login page + */ + async navigate(): Promise { + this.log('Navigating to login page'); + await this.page.goto(PATHS.login); + await this.page.waitForLoadState('networkidle'); + + // Make sure the form is visible before proceeding + await this.page.waitForSelector(this.loginForm, { timeout: 10000 }); + } + + /** + * Alternative name for navigate for backward compatibility + */ + async navigateToLogin(): Promise { + await this.navigate(); + } + + /** + * Login with provided credentials + * @param username Username or email + * @param password Password + */ + async login(username: string, password: string): Promise { + this.log(`Logging in as ${username}`); + + // Wait for form elements to be ready + await this.page.waitForSelector(this.usernameInput, { state: 'visible', timeout: 10000 }); + await this.page.waitForSelector(this.passwordInput, { state: 'visible', timeout: 5000 }); + await this.page.waitForSelector(this.loginButton, { state: 'visible', timeout: 5000 }); + + // Fill in the credentials + await this.page.fill(this.usernameInput, username); + await this.page.fill(this.passwordInput, password); + + // Click login and wait for navigation + await this.page.click(this.loginButton); + await this.page.waitForLoadState('networkidle'); + + this.log('Login form submitted'); + } + + /** + * Check if we're logged in + */ + async isLoggedIn(): Promise { + await this.page.waitForLoadState('networkidle'); + const url = await this.getUrl(); + return url.includes('hvac-dashboard'); + } + + /** + * Check if username field is visible + */ + async isUsernameFieldVisible(): Promise { + try { + await this.page.waitForSelector(this.usernameInput, { state: 'visible', timeout: 5000 }); + return true; + } catch (error) { + return false; + } + } + + /** + * Get error message if login failed + */ + async getErrorMessage(): Promise { + // Check all possible error selectors + const errorSelectors = this.loginError.split(', '); + + for (const selector of errorSelectors) { + if (await this.page.isVisible(selector)) { + return await this.page.textContent(selector); + } + } + + // Check for any text containing common error messages + const pageContent = await this.page.content(); + if (pageContent.includes('Invalid username') || + pageContent.includes('incorrect password') || + pageContent.includes('Unknown username') || + pageContent.includes('Error:')) { + + // Try to find error message in the page content + const errorText = await this.page.evaluate(() => { + const errorElements = Array.from(document.querySelectorAll('p, div, span')) + .filter(el => el.textContent && + (el.textContent.includes('Invalid') || + el.textContent.includes('Error') || + el.textContent.includes('incorrect') || + el.textContent.includes('Unknown'))); + + return errorElements.length > 0 ? errorElements[0].textContent : null; + }); + + return errorText; + } + + return null; + } + + /** + * Click on "forgot password" link + */ + async clickForgotPassword(): Promise { + await this.page.click(this.forgotPasswordLink); + await this.page.waitForLoadState('networkidle'); + } + + /** + * Toggle "remember me" checkbox + * @param check If true, check the box; if false, uncheck it + */ + async setRememberMe(check: boolean): Promise { + const isChecked = await this.page.isChecked(this.rememberMeCheckbox); + if (check !== isChecked) { + await this.page.click(this.rememberMeCheckbox); + } + } +} +EOF + + # Create BasePage.ts if missing + if [ ! -f "tests/e2e/pages/BasePage.ts" ]; then + cat > "tests/e2e/pages/BasePage.ts" << 'EOF' +import { Page } from '@playwright/test'; +import { STAGING_URL } from '../config/staging-config'; + +/** + * Base page object with common functionality for all pages + */ +export class BasePage { + protected page: Page; + + constructor(page: Page) { + this.page = page; + } + + /** + * Get the current URL + */ + async getUrl(): Promise { + return this.page.url(); + } + + /** + * Wait for page to load completely + */ + async waitForPageLoad(): Promise { + await this.page.waitForLoadState('networkidle'); + } + + /** + * Log a message with the page class name + */ + protected log(message: string): void { + console.log(`[${this.constructor.name}] ${message}`); + } + + /** + * Take a screenshot with a descriptive name + */ + async takeScreenshot(name: string): Promise { + const screenshotName = `${this.constructor.name}-${name}-${Date.now()}.png`; + await this.page.screenshot({ path: `screenshots/${screenshotName}` }); + this.log(`Screenshot saved: ${screenshotName}`); + } + + /** + * Check if an element is visible + */ + async isElementVisible(selector: string): Promise { + return await this.page.isVisible(selector); + } +} +EOF + fi + + log "Page objects fixed" "Page objects fixed" + return 0 +} + +# Function to check scripts +check_scripts() { + log "Checking scripts" "Checking scripts..." + + # Check if bin directory exists + if [ ! -d "bin" ]; then + log "bin directory not found" "bin directory not found" + return 1 + fi + + # Check if essential scripts exist and are executable + local missing_scripts=0 + + # Define essential scripts + essential_scripts=( + "verify-selectors.sh" + "pre-deploy-validation.sh" + "auto-recovery.sh" + "test-data-manager.sh" + ) + + for script in "${essential_scripts[@]}"; do + if [ ! -f "bin/$script" ] || [ ! -x "bin/$script" ]; then + log "Essential script missing or not executable: $script" "Missing script: $script" + missing_scripts=$((missing_scripts + 1)) + fi + done + + if [ $missing_scripts -gt 0 ]; then + log "$missing_scripts essential scripts missing" "$missing_scripts essential scripts missing" + return 1 + fi + + log "Scripts check passed" "Scripts ok" + return 0 +} + +# Function to check documentation +check_documentation() { + log "Checking documentation" "Checking documentation..." + + # Check if essential documentation exists + local missing_docs=0 + + # Define essential documentation + essential_docs=( + "TESTING.md" + "DEPLOYMENT-RESILIENCE.md" + "TROUBLESHOOTING.md" + "SELECTORS.md" + ) + + for doc in "${essential_docs[@]}"; do + if [ ! -f "$doc" ]; then + log "Essential documentation missing: $doc" "Missing doc: $doc" + missing_docs=$((missing_docs + 1)) + fi + done + + if [ $missing_docs -gt 0 ]; then + log "$missing_docs essential documentation files missing" "$missing_docs essential docs missing" + return 1 + fi + + log "Documentation check passed" "Documentation ok" + return 0 +} + +# Function to check test results +check_test_results() { + log "Checking test results" "Checking test results..." + + # Check if test results directory exists + if [ ! -d "test-results" ]; then + log "No test results found. Tests may not have been run yet." "No test results found" + return 0 # Not a failure, tests might not have been run yet + fi + + # Count recent test results + local recent_results=$(find test-results -type f -name "*.json" -mtime -1 | wc -l) + + if [ $recent_results -eq 0 ]; then + log "No recent test results found in the last 24 hours" "No recent test results" + return 0 # Not a failure, but worth noting + fi + + # Check pass rate if we have results + local total_tests=$(find test-results -name "*.json" | wc -l) + local passed_tests=$(grep -r '"status":"passed"' test-results | wc -l) + + if [ $total_tests -gt 0 ]; then + local pass_rate=$((passed_tests * 100 / total_tests)) + + log "Test pass rate: $pass_rate% ($passed_tests/$total_tests)" "Test pass rate: $pass_rate%" + + if [ $pass_rate -lt 80 ]; then + log "Warning: Test pass rate below 80%" "Warning: Low pass rate" + return 1 + fi + fi + + log "Test results check passed" "Test results ok" + return 0 +} + +# Function to check staging connectivity +check_staging_connectivity() { + log "Checking staging connectivity" "Checking staging connectivity..." + + # Ping the staging server (placeholder - update with actual staging URL) + if ping -c 1 wordpress-974670-5399585.cloudwaysapps.com &> /dev/null; then + log "Staging server is reachable" "Staging server reachable" + else + log "Warning: Cannot reach staging server" "Warning: Cannot reach staging" + return 1 + fi + + # Check if we can load the staging URL + if curl -s --head https://wordpress-974670-5399585.cloudwaysapps.com/ | grep "200 OK" > /dev/null; then + log "Staging URL returns 200 OK" "Staging URL OK" + else + log "Warning: Staging URL not returning 200 OK" "Warning: Staging URL not OK" + return 1 + fi + + log "Staging connectivity check passed" "Staging connectivity ok" + return 0 +} + +# Function to check for potential issues +check_potential_issues() { + log "Checking for potential issues" "Checking for potential issues..." + + # Check for uncommitted changes + if [ -n "$(git status --porcelain)" ]; then + log "Warning: Uncommitted changes detected" "Warning: Uncommitted changes" + fi + + # Check for large files in test results + local large_files=$(find test-results -type f -size +10M | wc -l) + if [ $large_files -gt 0 ]; then + log "Warning: $large_files large files (>10MB) found in test results" "Warning: Large test result files" + fi + + # Check disk space + local disk_usage=$(df -h . | awk 'NR==2 {print $5}' | tr -d '%') + if [ $disk_usage -gt 90 ]; then + log "Warning: Disk usage is high ($disk_usage%)" "Warning: High disk usage" + return 1 + fi + + log "Potential issues check passed" "No major issues found" + return 0 +} + +# Run all checks +echo -e "\n${GREEN}=== Running Health Checks ===${NC}" + +check_component "npm dependencies" check_npm_dependencies fix_npm_dependencies +NPM_STATUS=$? + +check_component "test configuration" check_test_config +CONFIG_STATUS=$? + +check_component "test data" check_test_data fix_test_data +DATA_STATUS=$? + +check_component "page objects" check_page_objects fix_page_objects +PAGES_STATUS=$? + +check_component "scripts" check_scripts +SCRIPTS_STATUS=$? + +check_component "documentation" check_documentation +DOCS_STATUS=$? + +check_component "test results" check_test_results +RESULTS_STATUS=$? + +check_component "staging connectivity" check_staging_connectivity +STAGING_STATUS=$? + +check_component "potential issues" check_potential_issues +ISSUES_STATUS=$? + +# Calculate overall health score +TOTAL_CHECKS=9 +PASSED_CHECKS=$(( + (NPM_STATUS == 0 ? 1 : 0) + + (CONFIG_STATUS == 0 ? 1 : 0) + + (DATA_STATUS == 0 ? 1 : 0) + + (PAGES_STATUS == 0 ? 1 : 0) + + (SCRIPTS_STATUS == 0 ? 1 : 0) + + (DOCS_STATUS == 0 ? 1 : 0) + + (RESULTS_STATUS == 0 ? 1 : 0) + + (STAGING_STATUS == 0 ? 1 : 0) + + (ISSUES_STATUS == 0 ? 1 : 0) +)) + +HEALTH_SCORE=$((PASSED_CHECKS * 100 / TOTAL_CHECKS)) + +# Summary +echo -e "\n${GREEN}=== Health Check Summary ===${NC}" +echo -e "Health Score: ${HEALTH_SCORE}% ($PASSED_CHECKS/$TOTAL_CHECKS)" + +if [ $HEALTH_SCORE -eq 100 ]; then + echo -e "${GREEN}✓ All health checks passed${NC}" + log "All health checks passed. Health Score: 100%" "All health checks passed" + exit 0 +elif [ $HEALTH_SCORE -ge 80 ]; then + echo -e "${YELLOW}⚠ Some minor issues detected${NC}" + log "Some minor issues detected. Health Score: $HEALTH_SCORE%" "Some minor issues detected" + + if [ "$CI_MODE" = true ]; then + echo -e "CI mode enabled, but passing due to acceptable health score" + exit 0 + fi + + exit 0 +else + echo -e "${RED}✗ Significant issues detected${NC}" + log "Significant issues detected. Health Score: $HEALTH_SCORE%" "Significant issues detected" + + if [ "$CI_MODE" = true ]; then + echo -e "CI mode enabled, failing build due to low health score" + exit 1 + fi + + exit 1 +fi \ No newline at end of file diff --git a/wordpress-dev/bin/test-data-manager.sh b/wordpress-dev/bin/test-data-manager.sh new file mode 100755 index 00000000..a22b6b53 --- /dev/null +++ b/wordpress-dev/bin/test-data-manager.sh @@ -0,0 +1,526 @@ +#!/bin/bash +# test-data-manager.sh - Script to manage test data for the HVAC Community Events plugin +# Usage: ./bin/test-data-manager.sh [generate|verify|cleanup|backup|restore] [--suite=name] + +set -e + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Default settings +ACTION="" +TEST_SUITE="default" +CURRENT_DATE=$(date +"%Y-%m-%d") + +# Parse arguments +for arg in "$@"; do + case $arg in + generate|verify|cleanup|backup|restore) + ACTION="$arg" + shift + ;; + --suite=*) + TEST_SUITE="${arg#*=}" + shift + ;; + esac +done + +# Check if action is provided +if [ -z "$ACTION" ]; then + echo -e "${RED}Error: No action specified. Use: generate, verify, cleanup, backup, or restore${NC}" + exit 1 +fi + +echo -e "${GREEN}=== Test Data Manager - ${ACTION} ===${NC}" +echo "Managing test data for suite: ${TEST_SUITE}" + +# Check if we're in the right directory +if [ ! -d "tests/e2e" ]; then + echo -e "${RED}Error: Please run this script from the wordpress-dev directory${NC}" + exit 1 +fi + +# Create test data directory structure +mkdir -p tests/e2e/data +mkdir -p tests/e2e/data/backups + +# Function to generate test data +generate_test_data() { + echo -e "\n${YELLOW}Generating test data for suite: ${TEST_SUITE}${NC}" + + # Create test users first + generate_test_users + + # Create test events based on the suite + case $TEST_SUITE in + "certificate") + generate_certificate_test_data + ;; + "dashboard") + generate_dashboard_test_data + ;; + "login") + # Login suite only needs users, which are already created + echo -e "${GREEN}Login test data created successfully${NC}" + ;; + *) + # Default suite includes all test data + generate_certificate_test_data + generate_dashboard_test_data + echo -e "${GREEN}Default test data created successfully${NC}" + ;; + esac +} + +# Function to generate test users +generate_test_users() { + echo -e "${YELLOW}Generating test users...${NC}" + + # Create test users TypeScript file + cat > "tests/e2e/data/test-users.ts" << 'EOF' +/** + * Test users for E2E testing + */ +export const TEST_USERS = { + trainer: { + username: 'test_trainer', + password: 'Test123!', + email: 'test_trainer@example.com', + role: 'trainer' + }, + admin: { + username: 'admin_trainer', + password: 'Admin123!', + email: 'admin_trainer@example.com', + role: 'administrator' + }, + pending: { + username: 'pending_trainer', + password: 'Pending123!', + email: 'pending_trainer@example.com', + role: 'pending' + } +}; +EOF + + echo -e "${GREEN}Test users created in tests/e2e/data/test-users.ts${NC}" + + # Create shell script to create these users on the server + cat > "bin/create-test-users.sh" << 'EOF' +#!/bin/bash +# Create test users for E2E testing + +# Create test_trainer user +ssh user@staging-server "cd /path/to/wordpress && wp user create test_trainer test_trainer@example.com --role=subscriber --user_pass=Test123! || wp user update test_trainer --role=subscriber --user_pass=Test123!" + +# Add trainer role +ssh user@staging-server "cd /path/to/wordpress && wp user meta update test_trainer wp_capabilities '{\"subscriber\":true,\"trainer\":true}'" + +# Create admin_trainer user +ssh user@staging-server "cd /path/to/wordpress && wp user create admin_trainer admin_trainer@example.com --role=administrator --user_pass=Admin123! || wp user update admin_trainer --role=administrator --user_pass=Admin123!" + +# Create pending_trainer user +ssh user@staging-server "cd /path/to/wordpress && wp user create pending_trainer pending_trainer@example.com --role=subscriber --user_pass=Pending123! || wp user update pending_trainer --role=subscriber --user_pass=Pending123!" + +# Add pending role +ssh user@staging-server "cd /path/to/wordpress && wp user meta update pending_trainer wp_capabilities '{\"subscriber\":true,\"pending_trainer\":true}'" + +echo "Test users created/updated successfully" +EOF + + chmod +x bin/create-test-users.sh + echo -e "${YELLOW}Created bin/create-test-users.sh - Update SSH credentials before using${NC}" +} + +# Function to generate certificate test data +generate_certificate_test_data() { + echo -e "${YELLOW}Generating certificate test data...${NC}" + + # Create test events TypeScript file with attendees for certificate testing + cat > "tests/e2e/data/test-events.ts" << 'EOF' +/** + * Test events for E2E testing + * Includes event data specifically designed for certificate testing + */ +export const TEST_EVENTS = { + basicEvent: { + title: 'Basic HVAC Training', + description: 'A basic training event for HVAC technicians.', + venue: 'Test Venue', + organizer: 'Test Organizer', + startDate: getTomorrowDate(), + endDate: getTomorrowDate(), + startTime: '09:00', + endTime: '17:00', + cost: '99.99', + capacity: '25' + }, + certificateEvent: { + title: 'Certificate Training Course', + description: 'A training event that issues certificates upon completion.', + venue: 'Certificate Test Venue', + organizer: 'Certificate Test Organizer', + startDate: getYesterdayDate(), // Past event for certificate generation + endDate: getYesterdayDate(), + startTime: '08:00', + endTime: '16:00', + cost: '149.99', + capacity: '20', + issueCertificates: true + }, + multiDayEvent: { + title: 'Advanced HVAC Workshop', + description: 'A multi-day workshop covering advanced HVAC topics.', + venue: 'Advanced Test Venue', + organizer: 'Advanced Test Organizer', + startDate: getTomorrowDate(), + endDate: getFutureDateDays(3), // 3 days in the future + startTime: '09:00', + endTime: '17:00', + cost: '299.99', + capacity: '15' + } +}; + +// Test attendees for certificate testing +export const TEST_ATTENDEES = { + complete: { + firstName: 'John', + lastName: 'Smith', + email: 'john.smith@example.com', + company: 'HVAC Testing Inc.', + checkedIn: true + }, + notCheckedIn: { + firstName: 'Jane', + lastName: 'Doe', + email: 'jane.doe@example.com', + company: 'HVAC Services', + checkedIn: false + }, + specialChars: { + firstName: 'Jörg', + lastName: "O'Neill-Müller", + email: 'jorg.oneill@example.com', + company: 'Special HVAC & Co.', + checkedIn: true + } +}; + +// Helper functions for dates +function getTomorrowDate() { + const tomorrow = new Date(); + tomorrow.setDate(tomorrow.getDate() + 1); + return formatDate(tomorrow); +} + +function getYesterdayDate() { + const yesterday = new Date(); + yesterday.setDate(yesterday.getDate() - 1); + return formatDate(yesterday); +} + +function getFutureDateDays(days) { + const future = new Date(); + future.setDate(future.getDate() + days); + return formatDate(future); +} + +function formatDate(date) { + return date.toISOString().split('T')[0]; // YYYY-MM-DD format +} +EOF + + echo -e "${GREEN}Certificate test data created in tests/e2e/data/test-events.ts${NC}" + + # Create shell script to create these events on the server + cat > "bin/create-test-data-with-checkins.sh" << 'EOF' +#!/bin/bash +# Create test events and attendees for certificate testing + +# Create the certificate test event +ssh user@staging-server "cd /path/to/wordpress && wp post create --post_type=tribe_events --post_title='Certificate Training Course' --post_content='A training event that issues certificates upon completion.' --post_status=publish --meta_input='{\"_EventStartDate\":\"$(date -d \"yesterday\" +\"%Y-%m-%d 08:00:00\")\",\"_EventEndDate\":\"$(date -d \"yesterday\" +\"%Y-%m-%d 16:00:00\")\",\"_EventVenue\":\"Certificate Test Venue\",\"_EventCost\":\"149.99\",\"_tribe_events_issue_certificates\":\"1\"}' --porcelain" + +# Get the event ID +EVENT_ID=$(ssh user@staging-server "cd /path/to/wordpress && wp post list --post_type=tribe_events --post_status=publish --posts_per_page=1 --post_title='Certificate Training Course' --field=ID") + +# Create attendees +ATTENDEE1_ID=$(ssh user@staging-server "cd /path/to/wordpress && wp post create --post_type=tribe_attendee --post_title='John Smith' --post_status=publish --meta_input='{\"_tribe_tickets_first_name\":\"John\",\"_tribe_tickets_last_name\":\"Smith\",\"_tribe_tickets_email\":\"john.smith@example.com\",\"_tribe_tickets_checkin\":\"1\",\"_tribe_rsvp_event\":\"$EVENT_ID\",\"_tribe_tickets_attendee_company\":\"HVAC Testing Inc.\"}' --porcelain") + +ATTENDEE2_ID=$(ssh user@staging-server "cd /path/to/wordpress && wp post create --post_type=tribe_attendee --post_title='Jane Doe' --post_status=publish --meta_input='{\"_tribe_tickets_first_name\":\"Jane\",\"_tribe_tickets_last_name\":\"Doe\",\"_tribe_tickets_email\":\"jane.doe@example.com\",\"_tribe_tickets_checkin\":\"0\",\"_tribe_rsvp_event\":\"$EVENT_ID\",\"_tribe_tickets_attendee_company\":\"HVAC Services\"}' --porcelain") + +ATTENDEE3_ID=$(ssh user@staging-server "cd /path/to/wordpress && wp post create --post_type=tribe_attendee --post_title='Jörg O'Neill-Müller' --post_status=publish --meta_input='{\"_tribe_tickets_first_name\":\"Jörg\",\"_tribe_tickets_last_name\":\"O'Neill-Müller\",\"_tribe_tickets_email\":\"jorg.oneill@example.com\",\"_tribe_tickets_checkin\":\"1\",\"_tribe_rsvp_event\":\"$EVENT_ID\",\"_tribe_tickets_attendee_company\":\"Special HVAC & Co.\"}' --porcelain") + +echo "Certificate test data created successfully" +echo "Event ID: $EVENT_ID" +echo "Attendees: $ATTENDEE1_ID, $ATTENDEE2_ID, $ATTENDEE3_ID" +EOF + + chmod +x bin/create-test-data-with-checkins.sh + echo -e "${YELLOW}Created bin/create-test-data-with-checkins.sh - Update SSH credentials before using${NC}" +} + +# Function to generate dashboard test data +generate_dashboard_test_data() { + echo -e "${YELLOW}Generating dashboard test data...${NC}" + + # Create additional test events for dashboard testing + cat > "bin/create-test-events-admin.sh" << 'EOF' +#!/bin/bash +# Create test events for dashboard testing + +# Create multiple events with different statuses +ssh user@staging-server "cd /path/to/wordpress && wp post create --post_type=tribe_events --post_title='Published HVAC Training' --post_content='A published training event for dashboard testing.' --post_status=publish --meta_input='{\"_EventStartDate\":\"$(date -d \"+5 days\" +\"%Y-%m-%d 09:00:00\")\",\"_EventEndDate\":\"$(date -d \"+5 days\" +\"%Y-%m-%d 17:00:00\")\",\"_EventVenue\":\"Dashboard Test Venue\",\"_EventCost\":\"99.99\"}' --porcelain" + +ssh user@staging-server "cd /path/to/wordpress && wp post create --post_type=tribe_events --post_title='Draft HVAC Training' --post_content='A draft training event for dashboard testing.' --post_status=draft --meta_input='{\"_EventStartDate\":\"$(date -d \"+7 days\" +\"%Y-%m-%d 09:00:00\")\",\"_EventEndDate\":\"$(date -d \"+7 days\" +\"%Y-%m-%d 17:00:00\")\",\"_EventVenue\":\"Dashboard Test Venue\",\"_EventCost\":\"79.99\"}' --porcelain" + +ssh user@staging-server "cd /path/to/wordpress && wp post create --post_type=tribe_events --post_title='Private HVAC Training' --post_content='A private training event for dashboard testing.' --post_status=private --meta_input='{\"_EventStartDate\":\"$(date -d \"+10 days\" +\"%Y-%m-%d 09:00:00\")\",\"_EventEndDate\":\"$(date -d \"+10 days\" +\"%Y-%m-%d 17:00:00\")\",\"_EventVenue\":\"Dashboard Test Venue\",\"_EventCost\":\"129.99\"}' --porcelain" + +ssh user@staging-server "cd /path/to/wordpress && wp post create --post_type=tribe_events --post_title='Pending HVAC Training' --post_content='A pending training event for dashboard testing.' --post_status=pending --meta_input='{\"_EventStartDate\":\"$(date -d \"+15 days\" +\"%Y-%m-%d 09:00:00\")\",\"_EventEndDate\":\"$(date -d \"+15 days\" +\"%Y-%m-%d 17:00:00\")\",\"_EventVenue\":\"Dashboard Test Venue\",\"_EventCost\":\"149.99\"}' --porcelain" + +# Create a past event +ssh user@staging-server "cd /path/to/wordpress && wp post create --post_type=tribe_events --post_title='Past HVAC Training' --post_content='A past training event for dashboard testing.' --post_status=publish --meta_input='{\"_EventStartDate\":\"$(date -d \"-3 days\" +\"%Y-%m-%d 09:00:00\")\",\"_EventEndDate\":\"$(date -d \"-3 days\" +\"%Y-%m-%d 17:00:00\")\",\"_EventVenue\":\"Dashboard Test Venue\",\"_EventCost\":\"99.99\"}' --porcelain" + +echo "Dashboard test events created successfully" +EOF + + chmod +x bin/create-test-events-admin.sh + echo -e "${YELLOW}Created bin/create-test-events-admin.sh - Update SSH credentials before using${NC}" +} + +# Function to verify test data +verify_test_data() { + echo -e "\n${YELLOW}Verifying test data for suite: ${TEST_SUITE}${NC}" + + # Verify test user files exist + if [ -f "tests/e2e/data/test-users.ts" ]; then + echo -e "${GREEN}✓ Test users file exists${NC}" + else + echo -e "${RED}✗ Test users file missing${NC}" + fi + + # Verify test events files exist + if [ -f "tests/e2e/data/test-events.ts" ]; then + echo -e "${GREEN}✓ Test events file exists${NC}" + else + echo -e "${RED}✗ Test events file missing${NC}" + fi + + # Verify test data on server (if scripts exist) + if [ -f "bin/verify-test-data.sh" ]; then + echo -e "${YELLOW}Running server-side test data verification...${NC}" + bash bin/verify-test-data.sh + else + echo -e "${YELLOW}Creating server-side verification script...${NC}" + + # Create verification script + cat > "bin/verify-test-data.sh" << 'EOF' +#!/bin/bash +# Verify test data exists on the server + +# Check test users +echo "Verifying test users..." +TEST_TRAINER=$(ssh user@staging-server "cd /path/to/wordpress && wp user get test_trainer --field=ID 2>/dev/null || echo 'missing'") +ADMIN_TRAINER=$(ssh user@staging-server "cd /path/to/wordpress && wp user get admin_trainer --field=ID 2>/dev/null || echo 'missing'") +PENDING_TRAINER=$(ssh user@staging-server "cd /path/to/wordpress && wp user get pending_trainer --field=ID 2>/dev/null || echo 'missing'") + +if [ "$TEST_TRAINER" != "missing" ] && [ "$ADMIN_TRAINER" != "missing" ]; then + echo "✓ Test users verified" +else + echo "✗ Test users missing" + echo " - test_trainer: ${TEST_TRAINER}" + echo " - admin_trainer: ${ADMIN_TRAINER}" + echo " - pending_trainer: ${PENDING_TRAINER}" +fi + +# Check test events +echo "Verifying test events..." +CERTIFICATE_EVENT=$(ssh user@staging-server "cd /path/to/wordpress && wp post list --post_type=tribe_events --post_status=publish --posts_per_page=1 --post_title='Certificate Training Course' --field=ID 2>/dev/null || echo 'missing'") +DASHBOARD_EVENTS=$(ssh user@staging-server "cd /path/to/wordpress && wp post list --post_type=tribe_events --field=ID | wc -l 2>/dev/null || echo '0'") + +if [ "$CERTIFICATE_EVENT" != "missing" ] && [ "$DASHBOARD_EVENTS" -gt 0 ]; then + echo "✓ Test events verified" + echo " - Certificate event: ${CERTIFICATE_EVENT}" + echo " - Total events: ${DASHBOARD_EVENTS}" +else + echo "✗ Test events missing" + echo " - Certificate event: ${CERTIFICATE_EVENT}" + echo " - Total events: ${DASHBOARD_EVENTS}" +fi + +# Check attendees +echo "Verifying test attendees..." +if [ "$CERTIFICATE_EVENT" != "missing" ]; then + ATTENDEES=$(ssh user@staging-server "cd /path/to/wordpress && wp post list --post_type=tribe_attendee --meta_key=_tribe_rsvp_event --meta_value=${CERTIFICATE_EVENT} --field=ID 2>/dev/null | wc -l || echo '0'") + + if [ "$ATTENDEES" -gt 0 ]; then + echo "✓ Test attendees verified: ${ATTENDEES} attendees found" + else + echo "✗ Test attendees missing for certificate event" + fi +fi + +echo "Test data verification complete" +EOF + + chmod +x bin/verify-test-data.sh + echo -e "${YELLOW}Created bin/verify-test-data.sh - Update SSH credentials before using${NC}" + fi +} + +# Function to cleanup test data +cleanup_test_data() { + echo -e "\n${YELLOW}Cleaning up test data for suite: ${TEST_SUITE}${NC}" + + # Check if cleanup script exists + if [ -f "bin/cleanup-test-data.sh" ]; then + echo -e "${YELLOW}Running test data cleanup...${NC}" + bash bin/cleanup-test-data.sh + else + echo -e "${YELLOW}Creating cleanup script...${NC}" + + # Create cleanup script + cat > "bin/cleanup-test-data.sh" << 'EOF' +#!/bin/bash +# Clean up test data from the server + +echo "Cleaning up test data..." + +# Clean up test events +echo "Removing test events..." +ssh user@staging-server "cd /path/to/wordpress && wp post delete \$(wp post list --post_type=tribe_events --post_title='Certificate Training Course' --field=ID) --force 2>/dev/null || echo 'No certificate event to remove'" +ssh user@staging-server "cd /path/to/wordpress && wp post delete \$(wp post list --post_type=tribe_events --post_title='Published HVAC Training' --field=ID) --force 2>/dev/null || echo 'No published event to remove'" +ssh user@staging-server "cd /path/to/wordpress && wp post delete \$(wp post list --post_type=tribe_events --post_title='Draft HVAC Training' --field=ID) --force 2>/dev/null || echo 'No draft event to remove'" +ssh user@staging-server "cd /path/to/wordpress && wp post delete \$(wp post list --post_type=tribe_events --post_title='Private HVAC Training' --field=ID) --force 2>/dev/null || echo 'No private event to remove'" +ssh user@staging-server "cd /path/to/wordpress && wp post delete \$(wp post list --post_type=tribe_events --post_title='Pending HVAC Training' --field=ID) --force 2>/dev/null || echo 'No pending event to remove'" +ssh user@staging-server "cd /path/to/wordpress && wp post delete \$(wp post list --post_type=tribe_events --post_title='Past HVAC Training' --field=ID) --force 2>/dev/null || echo 'No past event to remove'" + +# Clean up attendees - remove all test attendees +echo "Removing test attendees..." +ssh user@staging-server "cd /path/to/wordpress && wp post delete \$(wp post list --post_type=tribe_attendee --meta_key=_tribe_tickets_email --meta_value='john.smith@example.com' --field=ID) --force 2>/dev/null || echo 'No John Smith attendee to remove'" +ssh user@staging-server "cd /path/to/wordpress && wp post delete \$(wp post list --post_type=tribe_attendee --meta_key=_tribe_tickets_email --meta_value='jane.doe@example.com' --field=ID) --force 2>/dev/null || echo 'No Jane Doe attendee to remove'" +ssh user@staging-server "cd /path/to/wordpress && wp post delete \$(wp post list --post_type=tribe_attendee --meta_key=_tribe_tickets_email --meta_value='jorg.oneill@example.com' --field=ID) --force 2>/dev/null || echo 'No Jorg attendee to remove'" + +# Keep test users (just reset their data) +echo "Resetting test users..." +ssh user@staging-server "cd /path/to/wordpress && wp user meta delete test_trainer hvac_test_data 2>/dev/null || echo 'No test data to remove for test_trainer'" +ssh user@staging-server "cd /path/to/wordpress && wp user meta delete admin_trainer hvac_test_data 2>/dev/null || echo 'No test data to remove for admin_trainer'" +ssh user@staging-server "cd /path/to/wordpress && wp user meta delete pending_trainer hvac_test_data 2>/dev/null || echo 'No test data to remove for pending_trainer'" + +echo "Test data cleanup complete" +EOF + + chmod +x bin/cleanup-test-data.sh + echo -e "${YELLOW}Created bin/cleanup-test-data.sh - Update SSH credentials before using${NC}" + fi +} + +# Function to backup test data +backup_test_data() { + echo -e "\n${YELLOW}Backing up test data for suite: ${TEST_SUITE}${NC}" + + # Create backup directory + BACKUP_DIR="tests/e2e/data/backups/${CURRENT_DATE}_${TEST_SUITE}" + mkdir -p "$BACKUP_DIR" + + # Backup test user data + if [ -f "tests/e2e/data/test-users.ts" ]; then + cp "tests/e2e/data/test-users.ts" "$BACKUP_DIR/" + echo -e "${GREEN}✓ Test users backed up${NC}" + fi + + # Backup test event data + if [ -f "tests/e2e/data/test-events.ts" ]; then + cp "tests/e2e/data/test-events.ts" "$BACKUP_DIR/" + echo -e "${GREEN}✓ Test events backed up${NC}" + fi + + # Backup any other test data files + if [ -f "tests/e2e/data/test-config.ts" ]; then + cp "tests/e2e/data/test-config.ts" "$BACKUP_DIR/" + echo -e "${GREEN}✓ Test config backed up${NC}" + fi + + # Compress backup + tar -czf "$BACKUP_DIR.tar.gz" "$BACKUP_DIR" + echo -e "${GREEN}Backup created: ${BACKUP_DIR}.tar.gz${NC}" + + # Remove uncompressed backup + rm -rf "$BACKUP_DIR" +} + +# Function to restore test data +restore_test_data() { + echo -e "\n${YELLOW}Restoring test data for suite: ${TEST_SUITE}${NC}" + + # Find most recent backup for the suite + LATEST_BACKUP=$(ls -t tests/e2e/data/backups/*_${TEST_SUITE}.tar.gz 2>/dev/null | head -1) + + if [ -z "$LATEST_BACKUP" ]; then + echo -e "${RED}No backup found for suite: ${TEST_SUITE}${NC}" + return 1 + fi + + echo -e "${YELLOW}Restoring from backup: ${LATEST_BACKUP}${NC}" + + # Create temp directory + TEMP_DIR="tests/e2e/data/temp_restore" + mkdir -p "$TEMP_DIR" + + # Extract backup + tar -xzf "$LATEST_BACKUP" -C "$TEMP_DIR" + + # Find extracted directory + EXTRACTED_DIR=$(find "$TEMP_DIR" -type d -depth 1) + + # Restore files + if [ -f "$EXTRACTED_DIR/test-users.ts" ]; then + cp "$EXTRACTED_DIR/test-users.ts" "tests/e2e/data/" + echo -e "${GREEN}✓ Test users restored${NC}" + fi + + if [ -f "$EXTRACTED_DIR/test-events.ts" ]; then + cp "$EXTRACTED_DIR/test-events.ts" "tests/e2e/data/" + echo -e "${GREEN}✓ Test events restored${NC}" + fi + + if [ -f "$EXTRACTED_DIR/test-config.ts" ]; then + cp "$EXTRACTED_DIR/test-config.ts" "tests/e2e/data/" + echo -e "${GREEN}✓ Test config restored${NC}" + fi + + # Clean up + rm -rf "$TEMP_DIR" + echo -e "${GREEN}Restore completed from: ${LATEST_BACKUP}${NC}" +} + +# Execute action +case $ACTION in + "generate") + generate_test_data + ;; + "verify") + verify_test_data + ;; + "cleanup") + cleanup_test_data + ;; + "backup") + backup_test_data + ;; + "restore") + restore_test_data + ;; + *) + echo -e "${RED}Invalid action: ${ACTION}${NC}" + exit 1 + ;; +esac + +echo -e "\n${GREEN}=== Test Data Manager Complete ===${NC}" +echo "Action '${ACTION}' completed for suite: ${TEST_SUITE}" +exit 0 \ No newline at end of file diff --git a/wordpress-dev/bin/test-monitor.sh b/wordpress-dev/bin/test-monitor.sh new file mode 100755 index 00000000..6c8e39ad --- /dev/null +++ b/wordpress-dev/bin/test-monitor.sh @@ -0,0 +1,306 @@ +#!/bin/bash +# test-monitor.sh - Script to monitor test execution and generate reports +# Usage: ./bin/test-monitor.sh [--store] [--notify] [--threshold=80] + +set -e + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Default settings +STORE_RESULTS=false +SEND_NOTIFICATIONS=false +SUCCESS_THRESHOLD=80 +CURRENT_DATE=$(date +"%Y-%m-%d") + +# Parse arguments +for arg in "$@"; do + case $arg in + --store) + STORE_RESULTS=true + shift + ;; + --notify) + SEND_NOTIFICATIONS=true + shift + ;; + --threshold=*) + SUCCESS_THRESHOLD="${arg#*=}" + shift + ;; + esac +done + +echo -e "${GREEN}=== Test Monitoring Dashboard ===${NC}" +echo "Analyzing test results and performance metrics..." + +# Check if we're in the right directory +if [ ! -d "tests/e2e" ]; then + echo -e "${RED}Error: Please run this script from the wordpress-dev directory${NC}" + exit 1 +fi + +# Create monitoring directory structure +mkdir -p monitoring/data +mkdir -p monitoring/reports +mkdir -p monitoring/alerts + +# Generate a unique run ID +RUN_ID=$(date +"%Y%m%d%H%M%S") +REPORT_FILE="monitoring/reports/test-report-${RUN_ID}.md" +DATA_FILE="monitoring/data/test-data-${RUN_ID}.json" + +# Function to analyze Playwright test results +analyze_test_results() { + echo -e "\n${YELLOW}Analyzing test results...${NC}" + + # Check if test results directory exists + if [ ! -d "test-results" ]; then + echo -e "${RED}No test results found.${NC}" + return 1 + fi + + # Count passed and failed tests + TOTAL_TESTS=$(find test-results -name "*.json" | wc -l) + PASSED_TESTS=$(grep -r '"status":"passed"' test-results | wc -l) + FAILED_TESTS=$(grep -r '"status":"failed"' test-results | wc -l) + SKIPPED_TESTS=$(grep -r '"status":"skipped"' test-results | wc -l) + + # Calculate success rate + if [ $TOTAL_TESTS -gt 0 ]; then + SUCCESS_RATE=$((PASSED_TESTS * 100 / TOTAL_TESTS)) + else + SUCCESS_RATE=0 + fi + + # Analyze test duration + AVERAGE_DURATION=$(grep -r '"duration":' test-results | awk -F'"duration":' '{sum+=$2; count++} END {print sum/count/1000}') + + # Find slowest tests + SLOWEST_TESTS=$(grep -r '"duration":' test-results | sort -nr -k2 | head -5) + + # Find most frequent failures + FAILURE_PATTERNS=$(grep -r "Error:" test-results | sort | uniq -c | sort -nr | head -5) + + # Output results + echo -e "\n${GREEN}Test Results Summary:${NC}" + echo -e "Total Tests: ${TOTAL_TESTS}" + echo -e "Passed: ${PASSED_TESTS}" + echo -e "Failed: ${FAILED_TESTS}" + echo -e "Skipped: ${SKIPPED_TESTS}" + echo -e "Success Rate: ${SUCCESS_RATE}%" + echo -e "Average Duration: ${AVERAGE_DURATION} seconds" + + # Store results if enabled + if [ "$STORE_RESULTS" = true ]; then + # Create JSON data + cat > "$DATA_FILE" << EOF +{ + "runId": "${RUN_ID}", + "date": "${CURRENT_DATE}", + "totalTests": ${TOTAL_TESTS}, + "passedTests": ${PASSED_TESTS}, + "failedTests": ${FAILED_TESTS}, + "skippedTests": ${SKIPPED_TESTS}, + "successRate": ${SUCCESS_RATE}, + "averageDuration": ${AVERAGE_DURATION} +} +EOF + echo -e "${GREEN}Test data stored in ${DATA_FILE}${NC}" + + # Create markdown report + cat > "$REPORT_FILE" << EOF +# Test Execution Report - ${CURRENT_DATE} + +## Summary + +- **Run ID**: ${RUN_ID} +- **Date**: ${CURRENT_DATE} +- **Total Tests**: ${TOTAL_TESTS} +- **Passed**: ${PASSED_TESTS} +- **Failed**: ${FAILED_TESTS} +- **Skipped**: ${SKIPPED_TESTS} +- **Success Rate**: ${SUCCESS_RATE}% +- **Average Duration**: ${AVERAGE_DURATION} seconds + +## Slowest Tests + +\`\`\` +${SLOWEST_TESTS} +\`\`\` + +## Common Failure Patterns + +\`\`\` +${FAILURE_PATTERNS} +\`\`\` + +## Recommendations + +EOF + + # Add recommendations based on results + if [ $SUCCESS_RATE -lt $SUCCESS_THRESHOLD ]; then + cat >> "$REPORT_FILE" << EOF +- **Critical Issue**: Success rate below threshold (${SUCCESS_THRESHOLD}%) +- Run the auto-recovery script: \`./bin/auto-recovery.sh\` +- Check recent code changes that might have affected tests +- Verify selector stability with \`./bin/verify-selectors.sh\` +EOF + else + cat >> "$REPORT_FILE" << EOF +- Success rate above threshold (${SUCCESS_THRESHOLD}%) +- Continue monitoring test performance +- Consider optimizing slow tests +EOF + fi + + echo -e "${GREEN}Test report generated: ${REPORT_FILE}${NC}" + fi + + # Send notifications if enabled and below threshold + if [ "$SEND_NOTIFICATIONS" = true ] && [ $SUCCESS_RATE -lt $SUCCESS_THRESHOLD ]; then + generate_alert "${SUCCESS_RATE}" "${FAILED_TESTS}" + fi + + # Return success/failure based on threshold + if [ $SUCCESS_RATE -ge $SUCCESS_THRESHOLD ]; then + return 0 + else + return 1 + fi +} + +# Function to generate historical trends +generate_trends() { + echo -e "\n${YELLOW}Generating historical trends...${NC}" + + # Check if we have historical data + if [ $(find monitoring/data -name "test-data-*.json" | wc -l) -lt 2 ]; then + echo -e "${YELLOW}Not enough historical data for trend analysis.${NC}" + return 0 + fi + + # Extract success rates from historical data + SUCCESS_TREND=$(grep -r '"successRate":' monitoring/data | sort | tail -10 | awk -F'"successRate":' '{print $2}' | tr -d ',' | tr '\n' ',') + + # Extract dates from historical data + DATE_TREND=$(grep -r '"date":' monitoring/data | sort | tail -10 | awk -F'"date":"' '{print $2}' | tr -d '",' | tr '\n' ',') + + echo -e "\n${GREEN}Historical Trend:${NC}" + echo -e "Recent Success Rates: ${SUCCESS_TREND}" + echo -e "Dates: ${DATE_TREND}" + + # Determine trend direction + LATEST_RATE=$(echo $SUCCESS_TREND | awk -F',' '{print $(NF-1)}') + PREVIOUS_RATE=$(echo $SUCCESS_TREND | awk -F',' '{print $(NF-2)}') + + if [ -n "$LATEST_RATE" ] && [ -n "$PREVIOUS_RATE" ]; then + if [ $LATEST_RATE -gt $PREVIOUS_RATE ]; then + echo -e "${GREEN}Trend: Improving ↑${NC}" + elif [ $LATEST_RATE -lt $PREVIOUS_RATE ]; then + echo -e "${RED}Trend: Declining ↓${NC}" + else + echo -e "${YELLOW}Trend: Stable →${NC}" + fi + fi +} + +# Function to generate alerts +generate_alert() { + local success_rate=$1 + local failed_tests=$2 + + echo -e "\n${YELLOW}Generating alert...${NC}" + + # Create alert file + ALERT_FILE="monitoring/alerts/alert-${RUN_ID}.md" + + cat > "$ALERT_FILE" << EOF +# Test Alert - ${CURRENT_DATE} + +## Alert Details + +- **Run ID**: ${RUN_ID} +- **Date**: ${CURRENT_DATE} +- **Success Rate**: ${success_rate}% (below threshold of ${SUCCESS_THRESHOLD}%) +- **Failed Tests**: ${failed_tests} + +## Recommended Actions + +1. Run the auto-recovery script: \`./bin/auto-recovery.sh\` +2. Check recent code changes that might have affected tests +3. Verify selector stability with \`./bin/verify-selectors.sh\` +4. Review the full report: \`${REPORT_FILE}\` + +## Next Steps + +- Fix failing tests before proceeding with deployment +- Update selectors if necessary +- Run tests again to verify fixes +EOF + + echo -e "${RED}Alert generated: ${ALERT_FILE}${NC}" + echo -e "Would send notification email/Slack message in a production environment" +} + +# Function to generate recommendations +generate_recommendations() { + echo -e "\n${YELLOW}Generating recommendations...${NC}" + + # Analyze test execution times + if [ -n "$AVERAGE_DURATION" ] && [ $(echo "$AVERAGE_DURATION > 10" | bc) -eq 1 ]; then + echo -e "${YELLOW}Performance Recommendation: Tests are taking longer than 10 seconds on average.${NC}" + echo -e "- Consider optimizing test execution" + echo -e "- Review the slowest tests identified above" + echo -e "- Use more efficient selectors" + fi + + # Analyze failure patterns + if [ $FAILED_TESTS -gt 0 ]; then + echo -e "${YELLOW}Stability Recommendation: ${FAILED_TESTS} tests are failing.${NC}" + echo -e "- Run the auto-recovery script: ./bin/auto-recovery.sh" + echo -e "- Check selector stability with: ./bin/verify-selectors.sh" + echo -e "- Review the common failure patterns above" + fi + + # Check for missing test data + if ! [ -f "tests/e2e/data/test-users.ts" ] || ! [ -f "tests/e2e/data/test-events.ts" ]; then + echo -e "${YELLOW}Test Data Recommendation: Missing test data files.${NC}" + echo -e "- Create or restore test data files" + echo -e "- Run test data generation scripts" + fi +} + +# Main execution +echo -e "\n${GREEN}=== Test Monitoring Dashboard - ${CURRENT_DATE} ===${NC}" + +# Analyze test results +analyze_test_results +ANALYSIS_STATUS=$? + +# Generate historical trends +generate_trends + +# Generate recommendations +generate_recommendations + +# Summary +echo -e "\n${GREEN}=== Monitoring Summary ===${NC}" +if [ $ANALYSIS_STATUS -eq 0 ]; then + echo -e "${GREEN}✓ Tests are performing above threshold (${SUCCESS_THRESHOLD}%)${NC}" + echo -e "Continue monitoring for performance trends" +else + echo -e "${RED}✗ Tests are performing below threshold (${SUCCESS_THRESHOLD}%)${NC}" + echo -e "Review recommendations and take action before deployment" +fi + +# Generate ASCII chart for visualization +if [ "$STORE_RESULTS" = true ]; then + echo -e "\nRun test-report-generator.js to create visual charts and reports" +fi + +exit $ANALYSIS_STATUS \ No newline at end of file