Files
gym-manage/run-all-tests.ps1

282 lines
8.9 KiB
PowerShell

# Gym Manage - 全量测试编排脚本
# 用法: .\run-all-tests.ps1 [-Backend] [-Admin] [-Member] [-Coach] [-All] [-ReportOnly] [-SkipBuild]
# 默认: -All
param(
[switch]$Backend,
[switch]$Admin,
[switch]$Member,
[switch]$Coach,
[switch]$All,
[switch]$ReportOnly,
[switch]$SkipBuild
)
$ErrorActionPreference = "Stop"
$RootDir = Split-Path -Parent $MyInvocation.MyCommand.Path
# 颜色输出
function Write-Step { Write-Host "`n========================================" -ForegroundColor Cyan; Write-Host " $args" -ForegroundColor Cyan; Write-Host "========================================" -ForegroundColor Cyan }
function Write-Success { Write-Host " [OK] $args" -ForegroundColor Green }
function Write-Fail { Write-Host " [FAIL] $args" -ForegroundColor Red }
function Write-Warn { Write-Host " [WARN] $args" -ForegroundColor Yellow }
function Write-Info { Write-Host " [INFO] $args" -ForegroundColor Gray }
# 结果收集
$Results = @{}
$StartTime = Get-Date
# =============================================
# 阶段0: 环境检查
# =============================================
Write-Step "阶段0: 环境检查"
# 检查 Java
try {
$javaVer = java -version 2>&1 | Select-Object -First 1
Write-Success "Java available: $javaVer"
} catch {
Write-Fail "Java not found. Please install JDK 21."
exit 1
}
# 检查 Node
try {
$nodeVer = node -v
Write-Success "Node available: $nodeVer"
} catch {
Write-Fail "Node not found. Please install Node.js."
exit 1
}
# 检查 Maven Wrapper
$MvnCmd = if (Test-Path "$RootDir\gym-manage-api\mvnw.cmd") { "$RootDir\gym-manage-api\mvnw.cmd" } else { "mvn" }
# 检查微信开发者工具CLI(端口45869)
$wcCliPort = 45869
try {
$wcCheck = Invoke-WebRequest -Uri "http://127.0.0.1:$wcCliPort" -TimeoutSec 3 -ErrorAction SilentlyContinue
if ($wcCheck.StatusCode -eq 200 -or $wcCheck.StatusCode -eq 404) {
Write-Success "WeChat DevTools CLI available on port $wcCliPort"
}
} catch {
Write-Warn "WeChat DevTools CLI not detected on port $wcCliPort. MiniTest tests will be skipped."
}
# =============================================
# 阶段1: 启动后端服务
# =============================================
Write-Step "阶段1: 启动后端服务"
$BackendPort = 8084
$BackendHealthUrl = "http://localhost:$BackendPort/actuator/health"
function Test-BackendHealth {
try {
$r = Invoke-WebRequest -Uri $BackendHealthUrl -TimeoutSec 5 -ErrorAction SilentlyContinue
return ($r.StatusCode -eq 200)
} catch { return $false }
}
$backendWasRunning = Test-BackendHealth
if ($backendWasRunning) {
Write-Success "Backend already running on port $BackendPort"
} else {
Write-Info "Starting backend with Maven..."
$backendJob = Start-Job -ScriptBlock {
param($mvnCmd, $apiDir)
Set-Location $apiDir
& $mvnCmd spring-boot:run -Dspring-boot.run.profiles=test 2>&1
} -ArgumentList $MvnCmd, "$RootDir\gym-manage-api\manage-app"
# 等待后端就绪 (最多90秒)
$retries = 0
while (-not (Test-BackendHealth) -and $retries -lt 90) {
$retries++
Write-Progress -Activity "Waiting for backend..." -PercentComplete (($retries / 90) * 100) -Status "$retries/90s"
Start-Sleep -Seconds 1
}
Write-Progress -Activity "Waiting for backend..." -Completed
if (Test-BackendHealth) {
Write-Success "Backend started successfully ($retries seconds)"
} else {
Write-Fail "Backend failed to start within 90 seconds"
Stop-Job $backendJob
Remove-Job $backendJob
exit 1
}
}
# =============================================
# 阶段2: 执行测试套件
# =============================================
function Invoke-TestStage {
param(
[string]$Name,
[string]$WorkingDir,
[string]$Command,
[bool]$Enabled = $true
)
if (-not $Enabled) {
Write-Warn "Skipping $Name (not requested)"
$Results[$Name] = "SKIPPED"
return
}
Write-Step "Running: $Name"
Write-Info "Working directory: $WorkingDir"
Write-Info "Command: $Command"
try {
Push-Location $WorkingDir
$sw = [System.Diagnostics.Stopwatch]::StartNew()
Invoke-Expression $Command
$sw.Stop()
Write-Success "$Name completed in $([math]::Round($sw.Elapsed.TotalSeconds, 1))s"
$Results[$Name] = "PASS ($([math]::Round($sw.Elapsed.TotalSeconds, 1))s)"
Pop-Location
} catch {
Write-Fail "$Name failed: $_"
$Results[$Name] = "FAIL"
Pop-Location
}
}
# 决定执行哪些测试
$runBackend = $All -or $Backend
$runAdmin = $All -or $Admin
$runMember = $All -or $Member
$runCoach = $All -or $Coach
if (-not ($Backend -or $Admin -or $Member -or $Coach)) { $runBackend = $runAdmin = $runMember = $runCoach = $true }
# 后端 API 契约测试
Invoke-TestStage -Name "Backend-API-Contract" `
-WorkingDir "$RootDir\gym-manage-api" `
-Command "$MvnCmd test -pl manage-app -Dtest='cn.novalon.gym.manage.app.contract.*Test' -DfailIfNoTests=false" `
-Enabled $runBackend
# Admin E2E: Smoke
Invoke-TestStage -Name "Admin-E2E-Smoke" `
-WorkingDir "$RootDir\gym-manage-web" `
-Command "npx playwright test --project=smoke --reporter=list" `
-Enabled $runAdmin
# Admin E2E: Journeys (需等待smoke完成)
if ($runAdmin) {
Invoke-TestStage -Name "Admin-E2E-Journeys" `
-WorkingDir "$RootDir\gym-manage-web" `
-Command "npx playwright test --project=journeys --reporter=list" `
-Enabled $true
}
# UniApp 会员端 MiniTest
if ($runMember) {
$memberTestDir = "$RootDir\gym-manage-uniapp"
if (Test-Path "$memberTestDir\jest.e2e.config.js") {
Invoke-TestStage -Name "UniApp-Member-MiniTest" `
-WorkingDir $memberTestDir `
-Command "npx jest --config jest.e2e.config.js --forceExit" `
-Enabled $true
} else {
Write-Warn "Member MiniTest config not found, skipping"
$Results["UniApp-Member-MiniTest"] = "SKIPPED (no config)"
}
}
# UniApp 教练端 MiniTest
if ($runCoach) {
$coachTestDir = "$RootDir\gym-manage-coach-uniapp"
if (Test-Path "$coachTestDir\jest.e2e.config.js") {
Invoke-TestStage -Name "UniApp-Coach-MiniTest" `
-WorkingDir $coachTestDir `
-Command "npx jest --config jest.e2e.config.js --forceExit" `
-Enabled $true
} else {
Write-Warn "Coach MiniTest config not found, skipping"
$Results["UniApp-Coach-MiniTest"] = "SKIPPED (no config)"
}
}
# =============================================
# 阶段3: 汇总报告
# =============================================
Write-Step "阶段3: 测试汇总报告"
$EndTime = Get-Date
$TotalTime = [math]::Round(($EndTime - $StartTime).TotalSeconds, 1)
$totalPass = 0
$totalFail = 0
$totalSkip = 0
Write-Host ""
Write-Host " Test Results Summary" -ForegroundColor White
Write-Host " $(('=' * 60))" -ForegroundColor DarkGray
foreach ($key in $Results.Keys | Sort-Object) {
$val = $Results[$key]
if ($val -like "PASS*") {
Write-Host " [PASS] " -NoNewline -ForegroundColor Green
Write-Host "$key : $val"
$totalPass++
} elseif ($val -like "FAIL*") {
Write-Host " [FAIL] " -NoNewline -ForegroundColor Red
Write-Host "$key : $val"
$totalFail++
} else {
Write-Host " [SKIP] " -NoNewline -ForegroundColor Yellow
Write-Host "$key : $val"
$totalSkip++
}
}
Write-Host " $(('=' * 60))" -ForegroundColor DarkGray
Write-Host (" Total: {0} | Pass: {1} | Fail: {2} | Skip: {3} | Time: {4}s" -f ($totalPass + $totalFail + $totalSkip), $totalPass, $totalFail, $totalSkip, $TotalTime) -ForegroundColor White
Write-Host ""
# 生成JSON报告
$ReportPath = "$RootDir\test-results\summary-$(Get-Date -Format 'yyyyMMdd-HHmmss').json"
$ReportDir = Split-Path $ReportPath -Parent
if (-not (Test-Path $ReportDir)) { New-Item -ItemType Directory -Path $ReportDir -Force | Out-Null }
$Report = @{
timestamp = (Get-Date -Format "yyyy-MM-ddTHH:mm:ss")
totalTimeSeconds = $TotalTime
results = $Results
summary = @{
total = $totalPass + $totalFail + $totalSkip
pass = $totalPass
fail = $totalFail
skip = $totalSkip
}
}
$Report | ConvertTo-Json -Depth 3 | Out-File -FilePath $ReportPath -Encoding UTF8
Write-Success "Report saved to: $ReportPath"
# =============================================
# 阶段4: 清理
# =============================================
Write-Step "阶段4: 清理"
# 如果后端是我们启动的,停止它
if (-not $backendWasRunning -and $backendJob) {
Write-Info "Stopping backend..."
Stop-Job $backendJob -ErrorAction SilentlyContinue
Remove-Job $backendJob -ErrorAction SilentlyContinue
Write-Success "Backend stopped"
}
if ($totalFail -gt 0) {
Write-Host "`n Some tests FAILED. Check reports for details." -ForegroundColor Red
exit 1
} else {
Write-Host "`n All tests PASSED!" -ForegroundColor Green
exit 0
}