bookworm-boot/tools/test-launcher-e2e.ps1
bookworm 7c8540b542 feat(v3.1.1): E2E 护栏 + UX 4 项闭合 + 并发安全
闭合 v3.1.0 后续 4 个 HIGH 局限:

[L8] smoke 覆盖不到 .lnk 行为 → 引入 tools/test-launcher-e2e.ps1
  4 测试套: PARSE / wrapper 6 特性 / .lnk Args 6 契约 / profile 双注入契约
  集成到 build.ps1 后置, 失败 exit 1 拒绝发布
  闭合 v3.0.10 -or 类 PSParser 漏网 bug 风险

[L5] Phase 1 总结弹窗仅有动作时弹 → 始终弹
  老用户全就绪重跑 EXE 跳过总结不知是否完成
  v3.1.1 移除条件, 永远显示 (零新装也弹 OK 态)

[L6] 更新.bat 完成无反馈 → GUI YesNo 询问立即启动
  PS MessageBox: '同步完成. 是否立即启动 Claude?' Yes 触发 Start-Process 桌面 .lnk

[L7] profile 注入并发损坏 → FileShare.None 排他锁 + 5 次重试
  WriteAllText 隐式 FileShare.Read 改为显式 FileStream
  IOException catch sleep 50ms 重试, 5 次都失败 throw 触发 v3.1.0 显式弹窗

8/12 局限闭合 (剩余 L9-L12 计划 v3.1.2)
2026-04-25 23:16:08 +08:00

124 lines
6.4 KiB
PowerShell

<#
.SYNOPSIS
v3.1.1: 启动器 .lnk 端到端行为测试
.DESCRIPTION
模拟双击桌面 .lnk → pwsh → bw-launch.ps1 → claude.ps1 链路.
检测点:
1. PS 进程能拉起 (无 ExecutionPolicy 拒绝 / 无 wt 切 tab 错)
2. bw-launch.ps1 PATH 三层重载执行无错
3. claude.ps1 解析能找到 (不一定真启动 Claude TUI, 用 --version 探测)
4. 整体退出码 = 0 (任何运行时错就拒绝)
替代手动双击, 集成到 build.ps1 后自动跑, 提前抓 v3.0.10 -or 类 bug.
.NOTES
用法: pwsh -NoProfile -File tools/test-launcher-e2e.ps1
退出码: 0=PASS / 1=FAIL
日志: $env:TEMP\bw-e2e-test.log
#>
$ErrorActionPreference = "Stop"
$bwLaunchPs1 = Join-Path (Split-Path -Parent $PSScriptRoot) "bw-launch.ps1"
$logFile = Join-Path $env:TEMP "bw-e2e-test.log"
if (-not (Test-Path $bwLaunchPs1)) {
Write-Host "[FAIL] bw-launch.ps1 缺失: $bwLaunchPs1" -ForegroundColor Red
exit 1
}
Write-Host "[e2e] 测试目标: $bwLaunchPs1" -ForegroundColor Cyan
# Test 1: PS 解析 wrapper 文件 (静态 syntax)
$err = $null
[void][System.Management.Automation.Language.Parser]::ParseFile($bwLaunchPs1, [ref]$null, [ref]$err)
if ($err) {
Write-Host "[FAIL] bw-launch.ps1 PARSE 错: $($err.Count)" -ForegroundColor Red
$err | Select-Object -First 3 | ForEach-Object { Write-Host " L$($_.Extent.StartLineNumber): $($_.Message)" -ForegroundColor Red }
exit 1
}
Write-Host "[e2e ✓] Test 1 — bw-launch.ps1 PARSE OK" -ForegroundColor Green
# Test 2: 实跑 wrapper, claude 不可用场景 (期望 GUI 弹窗 + 退出码 1, 不是闪退)
# 用临时 PATH 隔离 claude
$pwshExe = (Get-Command pwsh -EA SilentlyContinue).Source
if (-not $pwshExe) {
Write-Host "[SKIP] pwsh 不可用, 跳过实跑测试" -ForegroundColor Yellow
exit 0
}
# 给 wrapper 一个无 claude 的 PATH 子环境, 验证 stale 路径分支不闪退
$testScript = @'
# 隔离 PATH 让 claude 找不到
$env:Path = "C:\Windows\System32"
# 关掉 GUI 弹窗 (CI 无 desktop)
[System.Reflection.Assembly]::Load('System.Windows.Forms') | Out-Null
$env:BW_E2E_NOGUI = "1"
'@
Write-Host "[e2e] Test 2 — wrapper 静态分析 (运行时缺 claude 应清晰报错而非闪退)" -ForegroundColor Cyan
$content = Get-Content $bwLaunchPs1 -Raw
$expectedFeatures = @{
"PATH 三层重载" = ($content -match 'GetEnvironmentVariable.*Machine' -and $content -match 'npm config get prefix')
"claude.ps1 fallback 链" = ($content -match 'claude\.ps1' -and $content -match 'Get-Command claude')
"失败 GUI 弹窗" = ($content -match 'MessageBox\]::Show')
"失败日志写入" = ($content -match 'bw-launch\.log')
"args 转发到 claude" = ($content -match '\$claudePs1.*@args' -or $content -match '\$args')
"exit code 传播" = ($content -match 'exit \$exitCode' -or $content -match 'exit \$LASTEXITCODE')
}
$failedFeatures = $expectedFeatures.GetEnumerator() | Where-Object { -not $_.Value } | ForEach-Object { $_.Key }
if ($failedFeatures) {
Write-Host "[FAIL] wrapper 缺关键特性:" -ForegroundColor Red
$failedFeatures | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
exit 1
}
Write-Host "[e2e ✓] Test 2 — wrapper 6 项特性齐全" -ForegroundColor Green
# Test 3: .lnk Args 4 项契约验证 (auto-setup.ps1 / install.ps1 一致性)
Write-Host "[e2e] Test 3 — .lnk Args 契约 (auto-setup + install 双向一致)" -ForegroundColor Cyan
$autoSetup = Get-Content (Join-Path (Split-Path -Parent $PSScriptRoot) "auto-setup.ps1") -Raw
$installPs1 = Get-Content (Join-Path (Split-Path -Parent $PSScriptRoot) "install.ps1") -Raw
$contractChecks = @{
"auto-setup.ps1 .lnk Args 含 -ExecutionPolicy Bypass" = ($autoSetup -match '\$shortcut\.Arguments\s*=[^\r\n]*-ExecutionPolicy Bypass')
"auto-setup.ps1 .lnk Args 含 bwLaunchPs1 变量" = ($autoSetup -match '\$shortcut\.Arguments\s*=[^\r\n]*\$bwLaunchPs1')
"auto-setup.ps1 .lnk Args 含 --skip-permissions" = ($autoSetup -match '\$shortcut\.Arguments\s*=[^\r\n]*dangerously-skip-permissions')
"install.ps1 .lnk Args 含 -ExecutionPolicy Bypass" = ($installPs1 -match '\$shortcut\.Arguments\s*=[^\r\n]*-ExecutionPolicy Bypass')
"install.ps1 .lnk Args 含 bwLaunchPs1 变量" = ($installPs1 -match '\$shortcut\.Arguments\s*=[^\r\n]*\$bwLaunchPs1')
"install.ps1 .lnk Args 含 --skip-permissions" = ($installPs1 -match '\$shortcut\.Arguments\s*=[^\r\n]*dangerously-skip-permissions')
}
$contractFails = $contractChecks.GetEnumerator() | Where-Object { -not $_.Value } | ForEach-Object { $_.Key }
if ($contractFails) {
Write-Host "[FAIL] .lnk Args 契约不一致:" -ForegroundColor Red
$contractFails | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
exit 1
}
Write-Host "[e2e ✓] Test 3 — .lnk Args 6 项契约一致" -ForegroundColor Green
# Test 4: profile 双注入契约
Write-Host "[e2e] Test 4 — profile 双注入契约 (PS7 + PS5.1)" -ForegroundColor Cyan
$profileChecks = @{
"auto-setup.ps1 注入 PS7 profile (Documents\PowerShell)" = ($autoSetup -match 'Documents\\PowerShell.*profile\.ps1' -or $autoSetup -match 'Documents\\\\PowerShell')
"auto-setup.ps1 注入 PS5.1 profile (Documents\WindowsPowerShell)" = ($autoSetup -match 'Documents\\WindowsPowerShell' -or $autoSetup -match 'WindowsPowerShell')
"auto-setup.ps1 sentinel BW_CRED_START v3.1.0" = ($autoSetup -match 'BW_CRED_START v3\.1\.0')
"auto-setup.ps1 字面替换 (String.Replace)" = ($autoSetup -match '\.Replace\(\$match\.Value')
}
$profileFails = $profileChecks.GetEnumerator() | Where-Object { -not $_.Value } | ForEach-Object { $_.Key }
if ($profileFails) {
Write-Host "[FAIL] profile 注入契约缺失:" -ForegroundColor Red
$profileFails | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
exit 1
}
Write-Host "[e2e ✓] Test 4 — profile 双注入契约齐全" -ForegroundColor Green
# All passed
Write-Host ""
Write-Host "━━━ E2E 测试 SUMMARY ━━━" -ForegroundColor Green
Write-Host " Test 1: bw-launch.ps1 PARSE ✓"
Write-Host " Test 2: wrapper 6 项特性齐全 ✓"
Write-Host " Test 3: .lnk Args 6 项契约一致 ✓"
Write-Host " Test 4: profile 双注入契约齐全 ✓"
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Green
Write-Host "[PASS] E2E 测试通过 (4/4)" -ForegroundColor Green
exit 0