- Added visual-regression.sh for detecting UI changes - Created optimize-tests.sh to improve test performance - Added canary-deploy.sh for safer deployments with automatic rollback - Enhanced overall testing and deployment reliability 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			347 lines
		
	
	
		
			No EOL
		
	
	
		
			11 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			347 lines
		
	
	
		
			No EOL
		
	
	
		
			11 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
| #!/bin/bash
 | |
| # optimize-tests.sh - Script to optimize test execution and performance
 | |
| # Usage: ./bin/optimize-tests.sh [analyze|fix|profile] [--verbose]
 | |
| 
 | |
| 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=""
 | |
| VERBOSE=false
 | |
| CURRENT_DATE=$(date +"%Y-%m-%d")
 | |
| 
 | |
| # Parse arguments
 | |
| for arg in "$@"; do
 | |
|   case $arg in
 | |
|     analyze|fix|profile)
 | |
|       ACTION="$arg"
 | |
|       shift
 | |
|       ;;
 | |
|     --verbose)
 | |
|       VERBOSE=true
 | |
|       shift
 | |
|       ;;
 | |
|   esac
 | |
| done
 | |
| 
 | |
| # Check if action is provided
 | |
| if [ -z "$ACTION" ]; then
 | |
|   echo -e "${RED}Error: No action specified. Use: analyze, fix, or profile${NC}"
 | |
|   exit 1
 | |
| fi
 | |
| 
 | |
| echo -e "${GREEN}=== Test Optimization - ${ACTION} ===${NC}"
 | |
| 
 | |
| # 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/optimize
 | |
| LOG_FILE="logs/optimize/optimize-${ACTION}-${CURRENT_DATE}.log"
 | |
| 
 | |
| # Log function
 | |
| log() {
 | |
|   echo "[$(date +"%Y-%m-%d %H:%M:%S")] $1" >> "$LOG_FILE"
 | |
|   if [ "$VERBOSE" = true ] || [ -z "$2" ]; then
 | |
|     echo "$1"
 | |
|   else
 | |
|     echo "$2"
 | |
|   fi
 | |
| }
 | |
| 
 | |
| # Function to analyze test performance
 | |
| analyze_test_performance() {
 | |
|   log "Analyzing test performance..."
 | |
|   
 | |
|   # Check if we have test results
 | |
|   if [ ! -d "test-results" ]; then
 | |
|     log "No test results found. Please run tests first."
 | |
|     return 1
 | |
|   fi
 | |
|   
 | |
|   # Create analysis directory
 | |
|   mkdir -p "tests/e2e/analysis"
 | |
|   ANALYSIS_FILE="tests/e2e/analysis/performance-${CURRENT_DATE}.json"
 | |
|   
 | |
|   log "Analyzing test duration..."
 | |
|   
 | |
|   # Extract test durations from result files
 | |
|   echo "{" > "$ANALYSIS_FILE"
 | |
|   echo "  \"date\": \"${CURRENT_DATE}\"," >> "$ANALYSIS_FILE"
 | |
|   echo "  \"tests\": [" >> "$ANALYSIS_FILE"
 | |
|   
 | |
|   first=true
 | |
|   find test-results -name "*.json" | while read -r file; do
 | |
|     # Extract test name and duration
 | |
|     test_name=$(grep -o '"title":"[^"]*"' "$file" | head -1 | cut -d'"' -f4)
 | |
|     duration=$(grep -o '"duration":[0-9]*' "$file" | cut -d':' -f2)
 | |
|     
 | |
|     if [ -n "$test_name" ] && [ -n "$duration" ]; then
 | |
|       # Convert duration to seconds
 | |
|       duration_sec=$(echo "scale=2; $duration/1000" | bc)
 | |
|       
 | |
|       # Add to JSON
 | |
|       if [ "$first" = true ]; then
 | |
|         first=false
 | |
|       else
 | |
|         echo "," >> "$ANALYSIS_FILE"
 | |
|       fi
 | |
|       
 | |
|       echo "    {" >> "$ANALYSIS_FILE"
 | |
|       echo "      \"name\": \"${test_name}\"," >> "$ANALYSIS_FILE"
 | |
|       echo "      \"duration\": ${duration_sec}" >> "$ANALYSIS_FILE"
 | |
|       echo -n "    }" >> "$ANALYSIS_FILE"
 | |
|       
 | |
|       # Log slow tests
 | |
|       if (( $(echo "$duration_sec > 5" | bc -l) )); then
 | |
|         log "Slow test detected: ${test_name} (${duration_sec}s)" "  - Slow: ${test_name} (${duration_sec}s)"
 | |
|       fi
 | |
|     fi
 | |
|   done
 | |
|   
 | |
|   echo "" >> "$ANALYSIS_FILE"
 | |
|   echo "  ]" >> "$ANALYSIS_FILE"
 | |
|   echo "}" >> "$ANALYSIS_FILE"
 | |
|   
 | |
|   log "Performance analysis saved to ${ANALYSIS_FILE}" "Performance analysis complete."
 | |
|   
 | |
|   # Analyze wait operations in test files
 | |
|   log "Analyzing wait operations in test files..."
 | |
|   
 | |
|   WAIT_ANALYSIS="tests/e2e/analysis/waits-${CURRENT_DATE}.txt"
 | |
|   echo "Wait Operations Analysis - ${CURRENT_DATE}" > "$WAIT_ANALYSIS"
 | |
|   echo "=================================" >> "$WAIT_ANALYSIS"
 | |
|   echo "" >> "$WAIT_ANALYSIS"
 | |
|   
 | |
|   # Find all timeouts in test files
 | |
|   fixed_timeouts=$(grep -r "timeout:" --include="*.ts" tests/e2e | wc -l)
 | |
|   fixed_waits=$(grep -r "waitForTimeout" --include="*.ts" tests/e2e | wc -l)
 | |
|   
 | |
|   echo "Fixed Timeouts: ${fixed_timeouts}" >> "$WAIT_ANALYSIS"
 | |
|   echo "Fixed Waits: ${fixed_waits}" >> "$WAIT_ANALYSIS"
 | |
|   echo "" >> "$WAIT_ANALYSIS"
 | |
|   
 | |
|   # List files with the most timeouts
 | |
|   echo "Files with most timeouts:" >> "$WAIT_ANALYSIS"
 | |
|   grep -r "timeout:" --include="*.ts" tests/e2e | cut -d: -f1 | sort | uniq -c | sort -nr | head -5 >> "$WAIT_ANALYSIS"
 | |
|   echo "" >> "$WAIT_ANALYSIS"
 | |
|   
 | |
|   echo "Files with most waitForTimeout calls:" >> "$WAIT_ANALYSIS"
 | |
|   grep -r "waitForTimeout" --include="*.ts" tests/e2e | cut -d: -f1 | sort | uniq -c | sort -nr | head -5 >> "$WAIT_ANALYSIS"
 | |
|   
 | |
|   log "Wait analysis saved to ${WAIT_ANALYSIS}" "Wait analysis complete."
 | |
|   
 | |
|   # Analyze selector complexity
 | |
|   log "Analyzing selector complexity..."
 | |
|   
 | |
|   SELECTOR_ANALYSIS="tests/e2e/analysis/selectors-${CURRENT_DATE}.txt"
 | |
|   echo "Selector Complexity Analysis - ${CURRENT_DATE}" > "$SELECTOR_ANALYSIS"
 | |
|   echo "===================================" >> "$SELECTOR_ANALYSIS"
 | |
|   echo "" >> "$SELECTOR_ANALYSIS"
 | |
|   
 | |
|   # Find complex selectors
 | |
|   echo "Complex selectors:" >> "$SELECTOR_ANALYSIS"
 | |
|   grep -r "selector.*=" --include="*.ts" tests/e2e/pages | grep -v "import" | sort -u >> "$SELECTOR_ANALYSIS"
 | |
|   echo "" >> "$SELECTOR_ANALYSIS"
 | |
|   
 | |
|   # Count selector types
 | |
|   echo "Selector types:" >> "$SELECTOR_ANALYSIS"
 | |
|   echo "  ID selectors: $(grep -r "\('#" --include="*.ts" tests/e2e | wc -l)" >> "$SELECTOR_ANALYSIS"
 | |
|   echo "  Class selectors: $(grep -r "('\\." --include="*.ts" tests/e2e | wc -l)" >> "$SELECTOR_ANALYSIS"
 | |
|   echo "  Attribute selectors: $(grep -r "('\[" --include="*.ts" tests/e2e | wc -l)" >> "$SELECTOR_ANALYSIS"
 | |
|   
 | |
|   log "Selector analysis saved to ${SELECTOR_ANALYSIS}" "Selector analysis complete."
 | |
|   
 | |
|   # Summary
 | |
|   log "Analysis summary:"
 | |
|   log "  - Test performance analysis: ${ANALYSIS_FILE}"
 | |
|   log "  - Wait operations analysis: ${WAIT_ANALYSIS}"
 | |
|   log "  - Selector complexity analysis: ${SELECTOR_ANALYSIS}"
 | |
|   
 | |
|   return 0
 | |
| }
 | |
| 
 | |
| # Function to fix common performance issues
 | |
| fix_performance_issues() {
 | |
|   log "Fixing common performance issues..."
 | |
|   
 | |
|   # Fix waitForTimeout calls
 | |
|   log "Replacing fixed waitForTimeout calls with explicit waits..."
 | |
|   
 | |
|   FIXED_COUNT=0
 | |
|   
 | |
|   # Find all files with waitForTimeout
 | |
|   files_with_timeouts=$(grep -l "waitForTimeout" --include="*.ts" tests/e2e)
 | |
|   
 | |
|   for file in $files_with_timeouts; do
 | |
|     # Create backup
 | |
|     cp "$file" "${file}.bak"
 | |
|     
 | |
|     # Replace waitForTimeout with explicit waits
 | |
|     sed -i.tmp 's/await page.waitForTimeout(\([0-9]*\))/await page.waitForLoadState("networkidle")/' "$file"
 | |
|     
 | |
|     # Count replacements
 | |
|     replacements=$(diff "$file" "${file}.bak" | grep "waitForTimeout" | wc -l)
 | |
|     FIXED_COUNT=$((FIXED_COUNT + replacements))
 | |
|     
 | |
|     # Remove temporary files
 | |
|     rm -f "${file}.tmp"
 | |
|   done
 | |
|   
 | |
|   log "Replaced ${FIXED_COUNT} waitForTimeout calls with explicit waits" "Fixed ${FIXED_COUNT} waitForTimeout calls."
 | |
|   
 | |
|   # Optimize selectors in page objects
 | |
|   log "Optimizing selectors in page objects..."
 | |
|   
 | |
|   # Check LoginPage.ts specifically
 | |
|   if [ -f "tests/e2e/pages/LoginPage.ts" ]; then
 | |
|     # Check if it's already using the optimized selectors
 | |
|     if ! grep -q "input\[name=\"log\"\]" "tests/e2e/pages/LoginPage.ts"; then
 | |
|       log "Updating LoginPage.ts with optimized selectors..."
 | |
|       
 | |
|       # Create backup
 | |
|       cp "tests/e2e/pages/LoginPage.ts" "tests/e2e/pages/LoginPage.ts.bak"
 | |
|       
 | |
|       # Update selectors
 | |
|       sed -i.tmp 's/private readonly usernameInput = '\''#user_login'\'';/private readonly usernameInput = '\''input[name="log"]'\'';/' "tests/e2e/pages/LoginPage.ts"
 | |
|       sed -i.tmp 's/private readonly passwordInput = '\''#user_pass'\'';/private readonly passwordInput = '\''input[name="pwd"]'\'';/' "tests/e2e/pages/LoginPage.ts"
 | |
|       sed -i.tmp 's/private readonly loginButton = '\''#wp-submit'\'';/private readonly loginButton = '\''input[type="submit"]'\'';/' "tests/e2e/pages/LoginPage.ts"
 | |
|       
 | |
|       # Remove temporary files
 | |
|       rm -f "tests/e2e/pages/LoginPage.ts.tmp"
 | |
|       
 | |
|       log "LoginPage.ts updated with optimized selectors" "LoginPage.ts optimized."
 | |
|     else
 | |
|       log "LoginPage.ts already using optimized selectors" "LoginPage.ts already optimized."
 | |
|     fi
 | |
|   fi
 | |
|   
 | |
|   # Optimize playwright.config.ts
 | |
|   if [ -f "playwright.config.ts" ]; then
 | |
|     log "Optimizing Playwright configuration..."
 | |
|     
 | |
|     # Create backup
 | |
|     cp "playwright.config.ts" "playwright.config.ts.bak"
 | |
|     
 | |
|     # Check if already optimized
 | |
|     if ! grep -q "workers: 2" "playwright.config.ts"; then
 | |
|       # Add worker limit
 | |
|       sed -i.tmp 's/use: {/use: {\n    workers: 2,/' "playwright.config.ts"
 | |
|       log "Updated Playwright configuration with worker limit" "Added worker limit to config."
 | |
|     else
 | |
|       log "Playwright configuration already has worker limit" "Worker limit already set."
 | |
|     fi
 | |
|     
 | |
|     # Check for retry configuration
 | |
|     if ! grep -q "retries:" "playwright.config.ts"; then
 | |
|       # Add retry configuration
 | |
|       sed -i.tmp 's/projects: \[/retries: process.env.CI ? 2 : 0,\n  projects: \[/' "playwright.config.ts"
 | |
|       log "Added retry configuration to Playwright config" "Added retry configuration."
 | |
|     else
 | |
|       log "Playwright configuration already has retry settings" "Retry settings already configured."
 | |
|     fi
 | |
|     
 | |
|     # Remove temporary files
 | |
|     rm -f "playwright.config.ts.tmp"
 | |
|   fi
 | |
|   
 | |
|   log "Performance optimizations complete."
 | |
|   return 0
 | |
| }
 | |
| 
 | |
| # Function to profile test execution
 | |
| profile_test_execution() {
 | |
|   log "Profiling test execution..."
 | |
|   
 | |
|   # Create a profile test file
 | |
|   PROFILE_TEST="tests/e2e/profile-test.spec.ts"
 | |
|   
 | |
|   log "Creating profile test..."
 | |
|   cat > "$PROFILE_TEST" << 'EOF'
 | |
| import { test } from '@playwright/test';
 | |
| import { LoginPage } from './pages/LoginPage';
 | |
| import { TEST_USERS } from './data/test-users';
 | |
| 
 | |
| test('Profile test performance', async ({ page }) => {
 | |
|   console.time('Total');
 | |
|   
 | |
|   // Login page
 | |
|   const loginPage = new LoginPage(page);
 | |
|   
 | |
|   console.time('Navigate to login');
 | |
|   await loginPage.navigate();
 | |
|   console.timeEnd('Navigate to login');
 | |
|   
 | |
|   console.time('Login');
 | |
|   await loginPage.login(TEST_USERS.trainer.username, TEST_USERS.trainer.password);
 | |
|   console.timeEnd('Login');
 | |
|   
 | |
|   console.time('Load dashboard');
 | |
|   await page.waitForLoadState('networkidle');
 | |
|   console.timeEnd('Load dashboard');
 | |
|   
 | |
|   console.time('Screenshot');
 | |
|   await page.screenshot({ path: 'screenshots/profile-test.png' });
 | |
|   console.timeEnd('Screenshot');
 | |
|   
 | |
|   console.timeEnd('Total');
 | |
| });
 | |
| EOF
 | |
|   
 | |
|   log "Running profile test..."
 | |
|   
 | |
|   # Create profile output directory
 | |
|   mkdir -p "tests/e2e/profile"
 | |
|   PROFILE_OUTPUT="tests/e2e/profile/profile-${CURRENT_DATE}.txt"
 | |
|   
 | |
|   # Run the profile test with trace
 | |
|   npx playwright test "$PROFILE_TEST" --trace on > "$PROFILE_OUTPUT" 2>&1
 | |
|   
 | |
|   # Extract timing information
 | |
|   log "Extracting timing information..."
 | |
|   
 | |
|   echo "Performance Profile - ${CURRENT_DATE}" > "tests/e2e/profile/summary-${CURRENT_DATE}.txt"
 | |
|   echo "=================================" >> "tests/e2e/profile/summary-${CURRENT_DATE}.txt"
 | |
|   echo "" >> "tests/e2e/profile/summary-${CURRENT_DATE}.txt"
 | |
|   
 | |
|   # Extract console.time entries
 | |
|   grep -E "Navigate to login|Login|Load dashboard|Screenshot|Total" "$PROFILE_OUTPUT" | 
 | |
|     grep -v "console.time" >> "tests/e2e/profile/summary-${CURRENT_DATE}.txt"
 | |
|   
 | |
|   # Clean up
 | |
|   rm "$PROFILE_TEST"
 | |
|   
 | |
|   log "Profile results:"
 | |
|   cat "tests/e2e/profile/summary-${CURRENT_DATE}.txt"
 | |
|   
 | |
|   log "Profiling complete. Results saved to tests/e2e/profile/summary-${CURRENT_DATE}.txt"
 | |
|   return 0
 | |
| }
 | |
| 
 | |
| # Execute action
 | |
| case $ACTION in
 | |
|   "analyze")
 | |
|     analyze_test_performance
 | |
|     ;;
 | |
|   "fix")
 | |
|     fix_performance_issues
 | |
|     ;;
 | |
|   "profile")
 | |
|     profile_test_execution
 | |
|     ;;
 | |
|   *)
 | |
|     log "Invalid action: ${ACTION}"
 | |
|     exit 1
 | |
|     ;;
 | |
| esac
 | |
| 
 | |
| log "Test optimization ${ACTION} completed successfully."
 | |
| exit 0 |