# ============================================================================== # OmniCard AI (CRMmp) - BTP-13 访客端微官网首屏与 Bento Grid 自适应视口测试 (P0) # ============================================================================== $session = "btp13" $evidenceDir = "docs/test-evidence/round-4" $screenshotPath = "$evidenceDir/btp-13-bento-viewport.png" function Clean-Val($str) { if ($null -eq $str) { return "" } return ($str -replace '^[\"\s]+|[\"\s]+$', '').Trim() } Write-Host "==================================================================" Write-Host "【BTP-13】访客端微官网首屏与 Bento Grid 自适应视口测试 (P0)" Write-Host "Session ID: $session" Write-Host "==================================================================" # ------------------------------------------------------------------------------ # 步骤一:移动端微官网视口验证 (390x844) # ------------------------------------------------------------------------------ Write-Host "`n[步骤 1/2] 移动端微官网视口 (390x844) 测试..." agent-browser --session $session set viewport 390 844 Start-Sleep -Milliseconds 500 $previewUrl = "http://localhost:9000/open/card/portal/preview-html/alex-morgan" agent-browser --session $session open $previewUrl Start-Sleep -Seconds 2 $step1Snapshot = agent-browser --session $session snapshot -i Write-Host "`n---------- 步骤一 DOM 关键结构快照 (Accessibility Tree) ----------" Write-Host $step1Snapshot Write-Host "--------------------------------------------------------------------" # 提取并验证步骤一的关键字段 $avatarRaw = agent-browser --session $session eval "document.querySelector('img.avatar')?.getAttribute('src')" $h1Raw = agent-browser --session $session eval "document.querySelector('h1.name')?.innerText?.trim()" $titleRaw = agent-browser --session $session eval "document.querySelector('div.title')?.innerText?.trim()" $companyRaw = agent-browser --session $session eval "document.querySelector('div.company')?.innerText?.trim()" $sloganRaw = agent-browser --session $session eval "document.querySelector('p.slogan')?.innerText?.trim()" $ctaTextRaw = agent-browser --session $session eval "document.querySelector('a.cta-button')?.innerText?.trim()" $ctaHrefRaw = agent-browser --session $session eval "document.querySelector('a.cta-button')?.getAttribute('href')" $viewportWRaw = agent-browser --session $session eval "window.innerWidth" $viewportHRaw = agent-browser --session $session eval "window.innerHeight" $avatarSrc = Clean-Val $avatarRaw $h1Name = Clean-Val $h1Raw $jobTitle = Clean-Val $titleRaw $company = Clean-Val $companyRaw $slogan = Clean-Val $sloganRaw $ctaText = Clean-Val $ctaTextRaw $ctaHref = Clean-Val $ctaHrefRaw $viewportW = [int](Clean-Val $viewportWRaw) $viewportH = [int](Clean-Val $viewportHRaw) $passVp = ($viewportW -eq 390 -and $viewportH -eq 844) $passAvatar = ($avatarSrc -like "*alex.jpg*") $passName = ($h1Name -eq "Alex Morgan") $passTitle = ($jobTitle -eq "VP of Global Business") $passCompany = ($company -eq "OmniCard AI Global Inc.") $passSlogan = ($slogan -like "*Empowering global trade*") $passCta = ($ctaText -eq "View Full Profile") Write-Host "`n移动端微官网首屏要素核验:" Write-Host " 1. 视口规格: ${viewportW}x${viewportH} (期望 390x844) -> $(if ($passVp) { '[PASS]' } else { '[FAIL]' })" Write-Host " 2. 头像 (img.avatar): $avatarSrc -> $(if ($passAvatar) { '[PASS]' } else { '[FAIL]' })" Write-Host " 3. 姓名 (h1.name): $h1Name -> $(if ($passName) { '[PASS]' } else { '[FAIL]' })" Write-Host " 4. 头衔 (div.title): $jobTitle -> $(if ($passTitle) { '[PASS]' } else { '[FAIL]' })" Write-Host " 5. 企业 (div.company): $company -> $(if ($passCompany) { '[PASS]' } else { '[FAIL]' })" Write-Host " 6. Slogan (p.slogan): $slogan -> $(if ($passSlogan) { '[PASS]' } else { '[FAIL]' })" Write-Host " 7. 主 CTA (a.cta-button): $ctaText ($ctaHref) -> $(if ($passCta) { '[PASS]' } else { '[FAIL]' })" $step1Pass = $passVp -and $passAvatar -and $passName -and $passTitle -and $passCompany -and $passSlogan -and $passCta Write-Host "`n步骤一移动端微官网视口验证结论: $(if ($step1Pass) { '[PASS]' } else { '[FAIL]' })" # ------------------------------------------------------------------------------ # 步骤二:管理端 Bento 画布与手机外框 (1280x800) # ------------------------------------------------------------------------------ Write-Host "`n[步骤 2/2] 管理端 Bento 构建器与手机模型画布测试..." agent-browser --session $session set viewport 1280 800 Start-Sleep -Milliseconds 500 Write-Host "导航至管理端登录页面并执行登录..." agent-browser --session $session open "http://localhost:5173/login" Start-Sleep -Seconds 1 agent-browser --session $session click "button.arco-btn-primary" Start-Sleep -Seconds 2 Write-Host "导航至 Bento 构建器 (http://localhost:5173/card/builder?id=1)..." agent-browser --session $session open "http://localhost:5173/card/builder?id=1" Start-Sleep -Seconds 2 # 确保手机外框中有 4 个卡片 (Hero, Case, Article, Social) $ensureBlocksJs = @' (() => { const phone = document.querySelector('[class*="phone"]'); if (!phone) return { ok: false, error: 'no phone' }; let cards = Array.from(phone.querySelectorAll('[class*="blockCard"]')); const typesNeeded = ['Hero', 'Case', 'Article', 'Social']; if (cards.length < 4) { const buttons = Array.from(document.querySelectorAll('.arco-btn')); for (const type of typesNeeded) { const btn = buttons.find(b => b.innerText.trim() === type); if (btn) { btn.click(); } } } return { ok: true }; })() '@ agent-browser --session $session eval $ensureBlocksJs Start-Sleep -Seconds 1 # 获取步骤二快照 $step2Snapshot = agent-browser --session $session snapshot -i Write-Host "`n---------- 步骤二 DOM 关键结构快照 (Accessibility Tree) ----------" Write-Host $step2Snapshot Write-Host "--------------------------------------------------------------------" # 深度校验手机模型画布、4个Bento卡片、colSpan、上移/下移按钮、属性表单 $checkBuilderJs = @' (() => { const phone = document.querySelector('[class*="phone"]'); if (!phone) return { hasPhone: false }; const cards = Array.from(phone.querySelectorAll('[class*="blockCard"]')); const cardData = cards.map((c, idx) => { const title = c.querySelector('[class*="blockTitle"]')?.innerText?.trim(); const meta = c.querySelector('[class*="blockMeta"]')?.innerText?.trim(); const actionButtons = Array.from(c.querySelectorAll('[class*="blockActions"] button')).map(b => ({ text: b.innerText.trim(), disabled: b.disabled || b.classList.contains('arco-btn-disabled') || b.getAttribute('disabled') !== null })); return { index: idx, title, meta, actionButtons }; }); const form = document.querySelector('form'); const formItems = form ? Array.from(form.querySelectorAll('.arco-form-item')).map(item => { const label = item.querySelector('label')?.innerText?.trim(); const input = item.querySelector('input, textarea'); const select = item.querySelector('.arco-select-view-value'); return { label, value: input ? input.value : (select ? select.innerText.trim() : '') }; }) : []; return { hasPhone: true, cardCount: cards.length, cardData, hasForm: Boolean(form), formItems }; })() '@ $builderResultRaw = agent-browser --session $session eval $checkBuilderJs Write-Host "`nBento 构建器模型与卡片数据核验:" Write-Host $builderResultRaw try { $builderResult = $builderResultRaw | ConvertFrom-Json $hasPhone = $builderResult.hasPhone $cardCount = $builderResult.cardCount $hasForm = $builderResult.hasForm $has4Cards = ($cardCount -ge 4) # 验证4个特定类型卡片 $hasHero = $builderResult.cardData | Where-Object { $_.meta -like "*hero*" } $hasCase = $builderResult.cardData | Where-Object { $_.meta -like "*case*" } $hasArticle = $builderResult.cardData | Where-Object { $_.meta -like "*article*" } $hasSocial = $builderResult.cardData | Where-Object { $_.meta -like "*social*" } $typesAllPresent = ($null -ne $hasHero) -and ($null -ne $hasCase) -and ($null -ne $hasArticle) -and ($null -ne $hasSocial) # 验证排序上移/下移按钮与disabled状态约束 (首项up禁用,末项down禁用) $firstCardUpDisabled = $builderResult.cardData[0].actionButtons[0].disabled $lastCardDownDisabled = $builderResult.cardData[-1].actionButtons[1].disabled $sortButtonsValid = $firstCardUpDisabled -and $lastCardDownDisabled Write-Host "`n核验详情:" Write-Host " 1. 手机模型画布 (.phone): $(if ($hasPhone) { '[PASS]' } else { '[FAIL]' })" Write-Host " 2. 卡片数量: $cardCount (期望 4) -> $(if ($has4Cards) { '[PASS]' } else { '[FAIL]' })" Write-Host " 3. 4类 Bento 卡片覆盖 (hero, case, article, social): $(if ($typesAllPresent) { '[PASS]' } else { '[FAIL]' })" Write-Host " 4. 排序按钮规范 (首卡上移禁用, 末卡下移禁用): $(if ($sortButtonsValid) { '[PASS]' } else { '[FAIL]' })" Write-Host " 5. 属性表单 (Properties Form): $(if ($hasForm) { '[PASS]' } else { '[FAIL]' })" $step2Pass = $hasPhone -and $has4Cards -and $typesAllPresent -and $sortButtonsValid -and $hasForm } catch { Write-Error "JSON 解析失败: $($_.Exception.Message)" $step2Pass = $false } Write-Host "`n步骤二管理端 Bento 画布核验结论: $(if ($step2Pass) { '[PASS]' } else { '[FAIL]' })" # ------------------------------------------------------------------------------ # 截图凭证 # ------------------------------------------------------------------------------ Write-Host "`n[截图] 正在保存完整证据截图到 $screenshotPath..." agent-browser --session $session screenshot $screenshotPath Start-Sleep -Seconds 1 $screenshotExists = Test-Path $screenshotPath Write-Host "截图文件是否存在: $(if ($screenshotExists) { '[PASS] ' + $screenshotPath } else { '[FAIL]' })" # ------------------------------------------------------------------------------ # 最终测试总结 # ------------------------------------------------------------------------------ $finalPass = $step1Pass -and $step2Pass -and $screenshotExists Write-Host "`n==================================================================" Write-Host "【BTP-13】测试总评: $(if ($finalPass) { '[PASS]' } else { '[FAIL]' })" Write-Host "=================================================================="