Ver código fonte

test: record digital human integration and interface layout checks

main
leiyun 1 semana atrás
pai
commit
64c080adf3
32 arquivos alterados com 431 adições e 0 exclusões
  1. BIN
     
  2. BIN
     
  3. +1
    -0
      reports/digital-human-simple-auth-20260909/index.html
  4. +77
    -0
      reports/digital-human-simple-auth-20260909/results.json
  5. BIN
     
  6. BIN
     
  7. BIN
     
  8. BIN
     
  9. BIN
     
  10. BIN
     
  11. BIN
     
  12. BIN
     
  13. BIN
     
  14. BIN
     
  15. BIN
     
  16. BIN
     
  17. BIN
     
  18. BIN
     
  19. BIN
     
  20. BIN
     
  21. BIN
     
  22. +36
    -0
      reports/guide-style-20260909/index.html
  23. +94
    -0
      reports/guide-style-20260909/results.json
  24. BIN
     
  25. BIN
     
  26. BIN
     
  27. BIN
     
  28. +1
    -0
      reports/interface-dialog-height-20260909/index.html
  29. +31
    -0
      reports/interface-dialog-height-20260909/results.json
  30. BIN
     
  31. +77
    -0
      tools/digital-human-simple-auth.mjs
  32. +114
    -0
      tools/guide-style-review.mjs


+ 1
- 0
reports/digital-human-simple-auth-20260909/index.html Ver arquivo

@@ -0,0 +1 @@
<!doctype html><html lang="zh-CN"><meta charset="utf-8"><title>数字人 APPID + Secret 简化验证</title><style>body{font:16px/1.7 system-ui;max-width:1200px;margin:32px auto;color:#163d35}h1{font-size:26px}li{margin:5px 0}img{width:100%;border:1px solid #ccdcd5}section{margin-top:28px}</style><h1>数字人 APPID + Secret 简化验证</h1><p>2026-09-09 · 开发环境真实联调 · 18 项通过</p><p>移除两个额外密钥文件及运行依赖;现有 Secret 迁移至接口配置表 app_secret。继续使用现有登录身份调用 Auth,数字人开放服务通过 APPID + Secret 换取短期令牌。</p><ul><li>✓ integration-secret.key 已移除</li><li>✓ integration-internal.key 已移除</li><li>✓ 接口配置列表不返回 Secret 字段</li><li>✓ 原有 APPID 和密钥配置保留</li><li>✓ 留空 Secret 保存配置成功且不回显密钥</li><li>✓ 移除密钥文件后 APPID + Secret 连接测试成功</li><li>✓ 内部调用继续要求现有登录身份</li><li>✓ 复用登录身份获取运行令牌,无额外服务密钥</li><li>✓ Tran → Auth → 数字人系统能力调用成功</li><li>✓ 授权资源 videos 查询成功</li><li>✓ 授权资源 video-folders 查询成功</li><li>✓ 授权资源 avatars 查询成功</li><li>✓ 授权资源 voices 查询成功</li><li>✓ 授权资源 backgrounds 查询成功</li><li>✓ 配置弹窗密钥留空,仅显示已配置状态</li><li>✓ 页面留空密钥保存成功</li><li>✓ 页面连接检查实际响应成功</li><li>✓ 页面连接测试成功</li></ul><p>后端 mvn clean package 通过;新增认证、密钥保存和转发测试。039 迁移的密文保护、正常迁移、重复执行已验证。原有应用保持不变;本轮未重新创建视频生成任务。</p><section><h2>配置弹窗</h2><img src="01-configuration.png"></section><section><h2>真实连接测试</h2><img src="02-connection.png"></section></html>

+ 77
- 0
reports/digital-human-simple-auth-20260909/results.json Ver arquivo

@@ -0,0 +1,77 @@
{
"time": "2026-09-09T15:49:58.729Z",
"checks": [
{
"name": "integration-secret.key 已移除",
"result": "PASS"
},
{
"name": "integration-internal.key 已移除",
"result": "PASS"
},
{
"name": "接口配置列表不返回 Secret 字段",
"result": "PASS"
},
{
"name": "原有 APPID 和密钥配置保留",
"result": "PASS"
},
{
"name": "留空 Secret 保存配置成功且不回显密钥",
"result": "PASS"
},
{
"name": "移除密钥文件后 APPID + Secret 连接测试成功",
"result": "PASS"
},
{
"name": "内部调用继续要求现有登录身份",
"result": "PASS"
},
{
"name": "复用登录身份获取运行令牌,无额外服务密钥",
"result": "PASS"
},
{
"name": "Tran → Auth → 数字人系统能力调用成功",
"result": "PASS"
},
{
"name": "授权资源 videos 查询成功",
"result": "PASS"
},
{
"name": "授权资源 video-folders 查询成功",
"result": "PASS"
},
{
"name": "授权资源 avatars 查询成功",
"result": "PASS"
},
{
"name": "授权资源 voices 查询成功",
"result": "PASS"
},
{
"name": "授权资源 backgrounds 查询成功",
"result": "PASS"
},
{
"name": "配置弹窗密钥留空,仅显示已配置状态",
"result": "PASS"
},
{
"name": "页面留空密钥保存成功",
"result": "PASS"
},
{
"name": "页面连接检查实际响应成功",
"result": "PASS"
},
{
"name": "页面连接测试成功",
"result": "PASS"
}
]
}


















+ 36
- 0
reports/guide-style-20260909/index.html Ver arquivo

@@ -0,0 +1,36 @@
<!doctype html>
<html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>作业指导页面风格统一 · 验证报告</title>
<style>
body{margin:0;background:#edf4f1;color:#143d36;font:15px/1.8 system-ui,"Microsoft YaHei",sans-serif}main{max-width:1300px;margin:32px auto;padding:0 24px}header,section,figure{margin:0 0 20px;padding:24px;border:1px solid #c9ddd7;border-radius:12px;background:white}h1{margin:0;font-size:27px}h2{font-size:19px;margin:0 0 12px}p{margin:8px 0}a{color:#087963}img{display:block;width:100%;border:1px solid #d4e3dd;border-radius:7px}figcaption{font-weight:600;margin-bottom:12px}.pass{display:inline-block;border-radius:16px;background:#e0f5eb;color:#087044;padding:2px 14px}table{border-collapse:collapse;width:100%}td,th{padding:10px 14px;text-align:left;border:1px solid #d6e3dd}th{background:#f1f7f4}.note{color:#57776d;font-size:14px}nav{display:flex;gap:18px;flex-wrap:wrap}summary{cursor:pointer}
</style>
<main><header><span class="pass">构建与浏览器检查通过</span><h1>作业指导页面风格统一</h1><p>2026-09-09 · 数字车间 / 内容制作</p><p>参照模型制作、场景制作的系统主题,统一指导书列表、模板库、编制、新建、预览和对外接口页面。</p><nav><a href="results.json">浏览器验证结果</a><a href="build.log">构建日志</a><a href="../../tools/guide-style-review.mjs">测试脚本</a></nav></header>
<section><h2>本次调整</h2><p>补充调整:模板库以完整白色内容卡片承载模板、分页与结构预览;对外接口的主内容、接口说明及契约区域统一使用系统白色背景。截图已更新,并重新通过构建与浏览器回归。</p><table><tr><th>页面</th><th>调整内容</th></tr>
<tr><td>指导书列表</td><td>使用系统搜索框、状态/排序选择器、带边框表格和统一分页;搜索需明确提交,支持重置。进入编制为主要操作,详情、预览、版本、下载和删除收进“更多”,权限及禁用条件保留。</td></tr>
<tr><td>模板库</td><td>移除重复大标题,统一页面边距、模板卡片、选中态和分页;较窄窗口改为两列,结构预览保留。</td></tr>
<tr><td>编制、新建、预览</td><td>统一工具栏、按钮、表单、侧栏和选中态颜色。编制器按视口分配高度,内部滚动。文档纸张及插图保留原有颜色。</td></tr>
<tr><td>对外接口</td><td>统一三栏面板、留白、输入框及按钮;长路径换行,较窄窗口将契约说明放到下方。暗色主题补齐背景与文字对比。</td></tr></table></section>
<section><h2>验证范围及结果</h2><table><tr><th>检查</th><th>结果</th></tr>
<tr><td>pnpm run build:类型检查、Vite 构建、模型编辑器产物检查</td><td>通过</td></tr>
<tr><td>12 条临时指导书:明确搜索、无结果、重置、下一页/上一页</td><td>通过</td></tr>
<tr><td>更多菜单、项目详情打开/关闭、进入编制、指导书预览、新建入口</td><td>通过</td></tr>
<tr><td>4 个模板:选择切换、结构预览、模板预览弹窗</td><td>通过</td></tr>
<tr><td>接口查询:执行 GET 项目列表,自检返回 200</td><td>通过</td></tr>
<tr><td>1920×911、1366×768;军绿、科技、石墨、暗色主题截图检查</td><td>通过</td></tr>
<tr><td>所有截取页面无整体横向溢出;无浏览器未捕获异常;局域网入口返回 200</td><td>通过</td></tr></table>
<p class="note">使用独立、用后关闭的浏览器上下文,在其本地指导书仓库准备 STYLE-1~STYLE-12 测试数据,没有修改用户浏览器中的现有指导书。未执行发布、删除、外部写入或下载生成的全面业务回归。本轮为样式调整与主要交互回归;接口页现有查询仍是本地工程自检,不代表新增了 HTTP 服务。</p>
<p class="note">编制器和模板预览保留现有自定义渲染及事件处理,宿主页负责系统控件和主题适配,避免样式调整影响文档编制与导出逻辑。构建保留现有大分包、Three.js URL 提示,无新增构建失败。</p></section>
<figure><figcaption>指导书列表:统一筛选、表格和主要操作</figcaption><a href="01-list.png"><img src="01-list.png" alt="指导书列表"></a></figure>
<figure><figcaption>更多菜单:保留全部次要操作及禁用状态</figcaption><img loading="lazy" src="02-list-actions.png" alt="列表更多菜单"></figure>
<figure><figcaption>模板库:统一外边距、卡片、分页和结构预览</figcaption><img loading="lazy" src="04-templates.png" alt="模板库"></figure>
<figure><figcaption>模板预览</figcaption><img loading="lazy" src="05-template-preview.png" alt="模板预览"></figure>
<figure><figcaption>指导书编制</figcaption><img loading="lazy" src="03-editor.png" alt="指导书编制"></figure>
<figure><figcaption>指导书编制 · 暗色主题</figcaption><img loading="lazy" src="03-editor-dark.png" alt="暗色编制器"></figure>
<figure><figcaption>指导书动态预览:纸张、插图保持原色</figcaption><img loading="lazy" src="03-guide-preview.png" alt="指导书预览"></figure>
<figure><figcaption>对外接口:导航、参数及契约说明</figcaption><img loading="lazy" src="06-api.png" alt="对外接口"></figure>
<figure><figcaption>接口查询结果</figcaption><img loading="lazy" src="07-api-result.png" alt="接口查询结果"></figure>
<figure><figcaption>暗色主题下的接口页面</figcaption><img loading="lazy" src="08-api-dark.png" alt="暗色接口"></figure>
<figure><figcaption>较窄窗口:模板库自动调整列数</figcaption><img loading="lazy" src="10-templates-laptop.png" alt="较窄模板库"></figure>
<figure><figcaption>新建指导书入口</figcaption><img loading="lazy" src="13-create-wizard.png" alt="新建指导书"></figure>
<section><h2>更多主题截图</h2><nav><a href="08-api-technology.png">科技主题</a><a href="08-api-graphite.png">石墨主题</a><a href="09-api-laptop.png">接口页 · 较窄窗口</a><a href="11-templates-dark.png">模板库 · 暗色</a><a href="12-list-dark.png">列表 · 暗色</a></nav></section>
</main></html>

+ 94
- 0
reports/guide-style-20260909/results.json Ver arquivo

@@ -0,0 +1,94 @@
{
"checks": [
{
"name": "01-list",
"result": "PASS",
"screenshot": "01-list.png"
},
{
"name": "02-list-actions",
"result": "PASS",
"screenshot": "02-list-actions.png"
},
{
"name": "03-editor",
"result": "PASS",
"screenshot": "03-editor.png"
},
{
"name": "03-editor-dark",
"result": "PASS",
"screenshot": "03-editor-dark.png"
},
{
"name": "03-guide-preview",
"result": "PASS",
"screenshot": "03-guide-preview.png"
},
{
"name": "04-templates",
"result": "PASS",
"screenshot": "04-templates.png"
},
{
"name": "05-template-preview",
"result": "PASS",
"screenshot": "05-template-preview.png"
},
{
"name": "06-api",
"result": "PASS",
"screenshot": "06-api.png"
},
{
"name": "07-api-result",
"result": "PASS",
"screenshot": "07-api-result.png"
},
{
"name": "08-api-technology",
"result": "PASS",
"screenshot": "08-api-technology.png"
},
{
"name": "08-api-graphite",
"result": "PASS",
"screenshot": "08-api-graphite.png"
},
{
"name": "08-api-dark",
"result": "PASS",
"screenshot": "08-api-dark.png"
},
{
"name": "09-api-laptop",
"result": "PASS",
"screenshot": "09-api-laptop.png"
},
{
"name": "10-templates-laptop",
"result": "PASS",
"screenshot": "10-templates-laptop.png"
},
{
"name": "11-templates-dark",
"result": "PASS",
"screenshot": "11-templates-dark.png"
},
{
"name": "12-list-dark",
"result": "PASS",
"screenshot": "12-list-dark.png"
},
{
"name": "13-create-wizard",
"result": "PASS",
"screenshot": "13-create-wizard.png"
},
{
"name": "搜索/重置、详情、编制入口、模板选择/预览、GET 接口自检、主题切换、局域网入口",
"result": "PASS"
}
],
"errors": []
}





+ 1
- 0
reports/interface-dialog-height-20260909/index.html Ver arquivo

@@ -0,0 +1 @@
<!doctype html><meta charset="utf-8"><title>Service configuration dialog</title><style>body{max-width:1200px;margin:30px auto;font:16px/1.6 system-ui}img{max-width:100%;border:1px solid #ddd}section{margin:24px 0}</style><h1>Service configuration dialog</h1><p>2026-09-09. Local and LAN development environment. Account: root. 4 viewport checks passed: dialog stays inside viewport, form scrolls to final field, footer remains fixed and visible, cancel works. No business data modified.</p><section><h2>1366x768 / military / PASS</h2><img src="1366x768-military.png"></section><section><h2>1280x600 / dark / PASS</h2><img src="1280x600-dark.png"></section><section><h2>390x844 / military / PASS</h2><img src="390x844-military.png"></section><section><h2>844x390 / military / PASS</h2><img src="844x390-military.png"></section>

+ 31
- 0
reports/interface-dialog-height-20260909/results.json Ver arquivo

@@ -0,0 +1,31 @@
{
"checks": [
{
"viewport": "1366x768",
"theme": "military",
"result": "PASS",
"screenshot": "1366x768-military.png"
},
{
"viewport": "1280x600",
"theme": "dark",
"result": "PASS",
"screenshot": "1280x600-dark.png"
},
{
"viewport": "390x844",
"theme": "military",
"result": "PASS",
"screenshot": "390x844-military.png"
},
{
"viewport": "844x390",
"theme": "military",
"result": "PASS",
"screenshot": "844x390-military.png"
}
],
"lan": "PASS",
"account": "root",
"dataChanges": "none"
}


+ 77
- 0
tools/digital-human-simple-auth.mjs Ver arquivo

@@ -0,0 +1,77 @@
import fs from 'node:fs'
import path from 'node:path'
import assert from 'node:assert/strict'
import { fileURLToPath } from 'node:url'
import { createRequire } from 'node:module'
import { login, call } from './role-permissions-live.mjs'

const report = fileURLToPath(new URL('../reports/digital-human-simple-auth-20260909/', import.meta.url))
fs.mkdirSync(report, { recursive:true })
const checks = []
function check(name, condition) { assert.ok(condition, name); checks.push({ name, result:'PASS' }); console.log(`PASS: ${name}`) }
const clean = value => !/"(?:appSecret|secretCipher|app_secret|secret_cipher)"\s*:/.test(JSON.stringify(value))
let browser
try {
for (const name of ['integration-secret.key', 'integration-internal.key']) {
check(`${name} 已移除`, !fs.existsSync(fileURLToPath(new URL(`../../unreal_tran_api/config/${name}`, import.meta.url))))
}
const session = await login('root')
const token = session.accessToken
const configs = await call('auth/v1/interfaces?size=100', token)
check('接口配置列表不返回 Secret 字段', configs.status === 200 && clean(configs.data))
const row = configs.data.records.find(item => item.code === 'digital-human' && item.environmentCode === 'default')
assert.ok(row, 'Digital-human configuration exists')
const settings = JSON.parse(row.extraConfig)
check('原有 APPID 和密钥配置保留', settings.appId === 'AP_238179E0A10F97927EA49FA3' && settings.secretConfigured)
const configuration = { ...row, environment:row.environmentCode, version:row.dataVersion }
const saved = await call(`auth/v1/interfaces/${row.id}/digital-human`, token, { configuration, appId:settings.appId, appSecret:'' }, 'PUT')
check('留空 Secret 保存配置成功且不回显密钥', saved.status === 200 && saved.code === 0 && clean(saved.data))
const tested = await call(`auth/v1/interfaces/${row.id}/test`, token, {})
check('移除密钥文件后 APPID + Secret 连接测试成功', tested.status === 200 && tested.data?.success)
const runtimeUrl = 'http://127.0.0.1:6101/internal/v1/interfaces/digital-human/runtime'
const anonymous = await fetch(runtimeUrl, { method:'POST' })
check('内部调用继续要求现有登录身份', anonymous.status === 401)
const runtime = await fetch(runtimeUrl, { method:'POST', headers:{ Authorization:`Bearer ${token}` } })
const runtimeData = await runtime.json()
check('复用登录身份获取运行令牌,无额外服务密钥', runtime.status === 200 && runtimeData.data?.accessToken && clean(runtimeData) && runtime.headers.get('cache-control') === 'no-store')
const capabilities = await call('tran/v1/content/digital-human/capabilities', token)
check('Tran → Auth → 数字人系统能力调用成功', capabilities.status === 200 && capabilities.data?.appId === settings.appId)
for (const kind of ['videos', 'video-folders', 'avatars', 'voices', 'backgrounds']) {
const response = await call(`tran/v1/content/digital-human/resources/${kind}`, token)
check(`授权资源 ${kind} 查询成功`, response.status === 200 && response.code === 0)
}
const { chromium, expect } = createRequire(new URL('../package.json', import.meta.url))('@playwright/test')
browser = await chromium.launch({ channel:'msedge', headless:true })
const context = await browser.newContext({ viewport:{ width:1600, height:1000 } })
await context.addInitScript(({ accessToken, refreshToken }) => {
sessionStorage.setItem('unreal-tran:web:access-token:v1', accessToken)
sessionStorage.setItem('unreal-tran:web:refresh-token:v1', refreshToken)
}, session)
const page = await context.newPage()
await page.goto('http://127.0.0.1:6180/system/interfaces')
const configRow = page.locator('.el-table__body tr').filter({ hasText:'digital-human' }).first()
await expect(configRow).toBeVisible({ timeout:60000 })
await configRow.getByRole('button', { name:'编辑配置' }).click()
const dialog = page.getByRole('dialog', { name:'编辑服务配置' })
const secret = dialog.locator('input[type="password"]')
await expect(secret).toHaveValue('')
await expect(secret).toHaveAttribute('placeholder', '已配置,留空保留现有密钥')
check('配置弹窗密钥留空,仅显示已配置状态', true)
await page.screenshot({ path:path.join(report, '01-configuration.png'), animations:'disabled' })
const saveResponse = page.waitForResponse(response => response.request().method() === 'PUT' && response.url().endsWith(`/interfaces/${row.id}/digital-human`))
await dialog.getByRole('button', { name:'保存配置' }).click()
check('页面留空密钥保存成功', (await saveResponse).status() === 200)
await expect(dialog).toBeHidden()
const testResponse = page.waitForResponse(response => response.request().method() === 'POST' && response.url().endsWith(`/interfaces/${row.id}/test`))
await configRow.getByRole('button', { name:'连接检查' }).click()
const testedFromPage = await (await testResponse).json()
check('页面连接检查实际响应成功', testedFromPage.data?.success)
await expect(configRow.getByText('连接正常', { exact:true })).toBeVisible({ timeout:30000 })
await expect(page.locator('.el-loading-mask:visible')).toHaveCount(0)
await page.screenshot({ path:path.join(report, '02-connection.png'), animations:'disabled' })
check('页面连接测试成功', true)
} finally {
await browser?.close()
fs.writeFileSync(path.join(report, 'results.json'), JSON.stringify({ time:new Date().toISOString(), checks }, null, 2))
}
fs.writeFileSync(path.join(report, 'index.html'), `<!doctype html><html lang="zh-CN"><meta charset="utf-8"><title>数字人 APPID + Secret 简化验证</title><style>body{font:16px/1.7 system-ui;max-width:1200px;margin:32px auto;color:#163d35}h1{font-size:26px}li{margin:5px 0}img{width:100%;border:1px solid #ccdcd5}section{margin-top:28px}</style><h1>数字人 APPID + Secret 简化验证</h1><p>2026-09-09 · 开发环境真实联调 · ${checks.length} 项通过</p><p>移除两个额外密钥文件及运行依赖;现有 Secret 迁移至接口配置表 app_secret。继续使用现有登录身份调用 Auth,数字人开放服务通过 APPID + Secret 换取短期令牌。</p><ul>${checks.map(x=>`<li>✓ ${x.name}</li>`).join('')}</ul><p>后端 mvn clean package 通过;新增认证、密钥保存和转发测试。039 迁移的密文保护、正常迁移、重复执行已验证。原有应用保持不变;本轮未重新创建视频生成任务。</p><section><h2>配置弹窗</h2><img src="01-configuration.png"></section><section><h2>真实连接测试</h2><img src="02-connection.png"></section></html>`)

+ 114
- 0
tools/guide-style-review.mjs Ver arquivo

@@ -0,0 +1,114 @@
import fs from 'node:fs'
import path from 'node:path'
import { createRequire } from 'node:module'
import { fileURLToPath } from 'node:url'
import assert from 'node:assert/strict'
import { login } from './role-permissions-live.mjs'
const { chromium, expect } = createRequire(new URL('../package.json', import.meta.url))('@playwright/test')
const report = fileURLToPath(new URL('../reports/guide-style-20260909/', import.meta.url))
fs.mkdirSync(report, { recursive:true })
const browser = await chromium.launch({ channel:'msedge', headless:true, args:['--enable-unsafe-swiftshader'] })
const checks = [], errors = []
const session = await login('root')
const context = await browser.newContext({ viewport:{ width:1920, height:911 } })
await context.addInitScript(({ accessToken, refreshToken }) => {
sessionStorage.setItem('unreal-tran:web:access-token:v1', accessToken)
sessionStorage.setItem('unreal-tran:web:refresh-token:v1', refreshToken)
}, session)
const page = await context.newPage()
page.on('pageerror', error => errors.push(error.message))
async function shot(name) {
const overflow = await page.locator('.legacy-guide-page').evaluate(el => el.scrollWidth > el.clientWidth + 2)
assert.equal(overflow, false, `${name}: page has no horizontal overflow`)
await page.screenshot({ path:path.join(report, `${name}.png`), animations:'disabled' })
checks.push({ name, result:'PASS', screenshot:`${name}.png` })
}
async function theme(mode) {
await page.evaluate(async mode => (await import('/src/stores/preferences.ts')).usePreferencesStore().setThemeMode(mode), mode)
}
try {
await page.goto('http://127.0.0.1:6180/content/ofd')
await expect(page.locator('.guide-project-list')).toBeVisible({ timeout:60000 })
await theme('military')
// Fixtures exist only in this disposable browser's local guide repository.
await page.evaluate(async () => {
const { legacyGuideContentStore } = await import('/src/features/guide-legacy/runtime.ts')
for (let i=1;i<=12;i++) legacyGuideContentStore.createOFDProject({ id:`STYLE-${i}`, code:`STYLE-${String(i).padStart(3,'0')}`, title:`液压系统检查作业指导书 · 样式验证 ${i}`, author:'样式验证' })
})
await expect(page.locator('.guide-project-title')).toHaveCount(10)
console.log('List loaded', await page.locator('.guide-project-title').count())
await shot('01-list')
const count = await page.locator('.guide-project-title').count()
await page.getByRole('textbox', { name:'搜索指导书', exact:true }).fill('NO-MATCH-GUIDE-STYLE')
assert.equal(await page.locator('.guide-project-title').count(), count, 'Search waits for explicit submission')
await page.locator('.guide-project-list').getByRole('button', { name:'搜索', exact:true }).click()
await expect(page.locator('.guide-project-title')).toHaveCount(0)
await page.getByRole('button', { name:'重置', exact:true }).click()
await expect(page.locator('.guide-project-title')).toHaveCount(count)
await page.locator('.system-pagination .btn-next').click()
await expect(page.locator('.guide-project-title')).toHaveCount(2)
await page.locator('.system-pagination .btn-prev').click()
await expect(page.locator('.guide-project-title')).toHaveCount(10)
if (count) {
await page.locator('.guide-project-actions').first().getByRole('button', { name:'更多' }).click()
await expect(page.getByRole('menuitem', { name:'项目详情', exact:true })).toBeVisible()
await shot('02-list-actions')
await page.getByRole('menuitem', { name:'项目详情', exact:true }).click()
await expect(page.getByRole('button', { name:'关闭项目详情' })).toBeVisible()
await page.getByRole('button', { name:'关闭项目详情' }).click()
await page.locator('.guide-project-actions').first().getByRole('button', { name:'进入编制', exact:true }).click()
await expect(page.locator('.ofd-view-editor')).toBeVisible({ timeout:60000 })
await shot('03-editor')
await theme('dark')
await shot('03-editor-dark')
await theme('military')
await page.locator('.ofd-top-actions [data-action="open-preview"]').click()
await expect(page.locator('.ofd-workspace-dialog.preview')).toBeVisible()
await shot('03-guide-preview')
console.log('Editor loaded', page.url())
}
await page.goto('http://127.0.0.1:6180/content/ofd/templates')
await expect(page.locator('.guide-tpl-card')).toHaveCount(4, { timeout:30000 })
await page.locator('[data-guide-tpl-action="select"]').nth(1).click()
await expect(page.locator('.guide-tpl-card').nth(1)).toHaveClass(/is-active/)
await shot('04-templates')
await page.locator('.guide-tpl-card').nth(1).getByRole('button', { name:'预览', exact:true }).click()
await expect(page.locator('.guide-tpl-modal')).toBeVisible()
await shot('05-template-preview')
await page.goto('http://127.0.0.1:6180/content/ofd/api')
await expect(page.locator('.ofd-api-layout')).toBeVisible({ timeout:30000 })
await shot('06-api')
await page.getByRole('button', { name:'执行调用', exact:true }).click()
await expect(page.locator('.ofd-api-result')).toBeVisible()
await expect(page.locator('.ofd-api-result header b')).toHaveText('200')
await shot('07-api-result')
for (const mode of ['technology','graphite','dark']) {
await theme(mode)
await shot(`08-api-${mode}`)
}
await page.setViewportSize({ width:1366, height:768 })
await theme('military')
await shot('09-api-laptop')
await page.goto('http://127.0.0.1:6180/content/ofd/templates')
await expect(page.locator('.guide-tpl-card')).toHaveCount(4)
await shot('10-templates-laptop')
await theme('dark')
await shot('11-templates-dark')
await page.goto('http://127.0.0.1:6180/content/ofd')
await expect(page.locator('.guide-project-list')).toBeVisible()
await shot('12-list-dark')
await theme('military')
await page.getByRole('button', { name:'新建指导书', exact:true }).click()
await expect(page.locator('.ofd-app')).toBeVisible()
await shot('13-create-wizard')
assert.equal((await context.request.get('http://192.168.31.168:6180/')).status(),200)
assert.deepEqual(errors, [], 'No unhandled browser exceptions')
checks.push({ name:'搜索/重置、详情、编制入口、模板选择/预览、GET 接口自检、主题切换、局域网入口', result:'PASS' })
} catch(error) {
await page.screenshot({ path:path.join(report,'failure.png') }).catch(()=>{})
console.error('Browser errors:',errors)
throw error
} finally {
fs.writeFileSync(path.join(report,'results.json'), JSON.stringify({ checks, errors },null,2))
await browser.close()
}

Carregando…
Cancelar
Salvar