- 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 |