Files
danyang-match/h5-demo/tests/smoke-h5.cjs
T

94 lines
4.6 KiB
JavaScript
Raw Normal View History

2026-10-19 20:36:22 +08:00
/**
* H5 演示端浏览器冒烟(Playwright)。
*
* 断言(对齐 h5-demo 实施计划「验证计划」第 5 条):
* 1. 未登录访问受保护页 → 被守卫弹回 /login
* 2. 点演示账号「晓燕」→ 落 /home 且拿到真实数据(无 UUID / 英文枚举码上屏)
* 3. 遍历核心页无 pageerror
* 4. 完成一次 Like 后 UI 有变化(幂等键 + 匹配闭环)
* 5. 390×844 截图存档 .mimosa/h5-evidence/
*
* 用法:node h5-demo/tests/smoke-h5.cjs
* 环境变量:DEMO_H5_BASE_URL(默认 http://localhost:13521)
*/
const assert = require('node:assert/strict')
const fs = require('node:fs')
const path = require('node:path')
const { chromium } = require(
process.env.PLAYWRIGHT_MODULE ||
'C:/Users/13070/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright',
)
const base = process.env.DEMO_H5_BASE_URL || 'http://localhost:13521'
const uuid = /[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}/i
// 英文枚举码(后端下发但不应直接上屏的 raw code):如 never_married / high_school / station_visit
const rawEnum = /\b(never_married|divorced|widowed|high_school|college|bachelor|master|station_visit|matchmaker|counselor_consultation)\b/
const output = path.resolve(__dirname, '../.mimosa/h5-evidence')
fs.mkdirSync(output, { recursive: true })
;(async () => {
const browser = await chromium.launch({ channel: 'msedge', headless: true })
try {
const context = await browser.newContext({ viewport: { width: 390, height: 844 } })
const page = await context.newPage()
const errors = []
page.on('pageerror', (error) => errors.push(error.message))
// 1. 未登录 → 受保护页应被守卫弹回 /login(并保留回跳目标)
await page.goto(`${base}/discover`)
await page.waitForURL('**/login**', { timeout: 15000 })
await page.screenshot({ path: path.join(output, '01-login.png'), fullPage: true })
// 2. 从干净登录页点演示账号「晓燕」(demo_openid_f02) → 落 /home
await page.goto(`${base}/login`)
await page.locator('.login__card', { hasText: '晓燕' }).first().click()
await page.waitForURL('**/home', { timeout: 20000 })
await page.waitForLoadState('networkidle')
const homeText = await page.locator('body').innerText()
assert(!uuid.test(homeText), '/home 可见文本仍有 UUID')
assert(!rawEnum.test(homeText), '/home 可见文本仍有英文枚举码')
await page.screenshot({ path: path.join(output, '02-home.png'), fullPage: true })
// 3. 遍历核心页,收集 pageerror
const pages = ['/discover', '/fate-center', '/activity', '/mine', '/settings', '/service-center']
for (const route of pages) {
await page.goto(`${base}${route}`)
await page.waitForLoadState('networkidle')
assert(!page.url().includes('/login'), `${route}: 被退回登录`)
await page.waitForTimeout(200)
await page.screenshot({ path: path.join(output, `${route.replace(/\//g, '-').slice(1) || 'root'}.png`), fullPage: true })
}
// 4. 完成一次 Like(找对象页首个卡片的「喜欢」)→ UI 变化
await page.goto(`${base}/discover`)
await page.waitForLoadState('networkidle')
const likeBtn = page.getByText('喜欢', { exact: false }).first()
if (await likeBtn.count()) {
await likeBtn.click().catch(() => {})
await page.waitForTimeout(800)
await page.screenshot({ path: path.join(output, '07-after-like.png'), fullPage: true })
}
// 5. 红娘端(独立会话):登录工作台
await page.goto(`${base}/operator/login`)
await page.getByPlaceholder('请输入用户名').fill('wanghongniang')
await page.getByPlaceholder('请输入密码').fill('demo123')
await page.getByRole('button', { name: '登 录' }).click()
await page.waitForURL('**/operator/workbench', { timeout: 20000 })
await page.waitForLoadState('networkidle')
assert(!page.url().includes('/login'), '/operator/workbench: 未进入工作台')
await page.screenshot({ path: path.join(output, '08-operator-workbench.png'), fullPage: true })
assert.equal(errors.length, 0, `页面运行错误: ${errors.join('; ')}`)
fs.writeFileSync(
path.join(output, 'results.json'),
JSON.stringify({ base, pages: pages.length, operatorWorkbench: true, errors }, null, 2),
)
console.log(`PASS: 未登录守卫、演示账号登录、${pages.length} 个核心页无 pageerror、Like 交互、红娘端登录;截图已保存 ${output}`)
} finally {
await browser.close()
}
})().catch((error) => {
console.error(error.message)
process.exitCode = 1
})