220 行
10 KiB
PowerShell
220 行
10 KiB
PowerShell
# ==============================================================================
|
|
# 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 "=================================================================="
|