test(游戏共创): 截图工具断言跟进终稿语义(封面主视觉/选中路径/面包屑)
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled

This commit is contained in:
2026-10-06 15:23:27 +08:00
parent 6dc314562e
commit ce4a50532b
+74 -10
View File
@@ -727,14 +727,19 @@ async function main() {
.then((text) => text.includes('当前作品'))),
`anchorCount=${await anchor.count()}`,
);
const focusable = await nodeCards.evaluateAll((nodes) =>
nodes.every(
(node) =>
node.getAttribute('tabindex') === '0' &&
(node.getAttribute('aria-label') ?? '').length > 0,
),
const accessibleNames = await nodeCards.evaluateAll((nodes) =>
nodes.every((node) => (node.getAttribute('aria-label') ?? '').length > 0),
);
check(
'DOM 断言:每个节点卡片都有可访问名称(aria-label)',
accessibleNames,
);
const openButtons = await page.locator('.game-lineage-node__open').count();
check(
'DOM 断言:每个可交互节点都有可聚焦的「打开《…》详情」主行动作(占位节点除外)',
openButtons >= 6,
`openButtons=${openButtons}`,
);
check('DOM 断言:每个节点都可聚焦且有可访问名称', focusable);
const b1Node = nodeCards.filter({ hasText: b1.title }).first();
const c1Node = nodeCards.filter({ hasText: c1.title }).first();
@@ -758,7 +763,7 @@ async function main() {
`cardText=${cardText.replace(/\n/gu, ' / ').slice(0, 70)}`,
);
const coverImages = await page
.locator('.game-lineage-node__main img')
.locator('.game-lineage-node__cover img')
.count();
check(
'DOM 断言:节点卡片渲染真实封面缩略图(coverObjectKey 有值才渲染)',
@@ -929,15 +934,73 @@ async function main() {
{ timeout: 120_000 },
);
await page.waitForTimeout(800);
await nodeCards.filter({ hasText: e.title }).first().focus();
// 关键字可达:主行动作(打开《…》详情)聚焦后按 Enter 应跳转(卡片主体现在=选中,不再跳详情)。
const openE = page.locator(
`.game-lineage-node__open[aria-label="打开《${e.title}》详情"]`,
);
await openE.first().focus();
await page.keyboard.press('Enter');
await page.waitForTimeout(800);
check(
'DOM 断言:键盘 Enter 也能跳转(可聚焦 + 键盘可达)',
'DOM 断言:键盘 Enter(在「打开详情」主行动作上)能跳转',
page.url().includes(nodeIds.E),
`url=${page.url()}`,
);
// 本轮终稿的核心:卡片主体点击 = 选中并保持路径高亮 + 面包屑(不跳详情)
await page.goto(richUrl, { waitUntil: 'commit', timeout: 120_000 });
await page.waitForFunction(
() => document.querySelectorAll('.game-lineage-node').length >= 6,
undefined,
{ timeout: 120_000 },
);
await page.waitForTimeout(900);
const b1CardForSelect = page
.locator('.game-lineage-node')
.filter({ hasText: b1.title })
.first();
await b1CardForSelect.click({ position: { x: 6, y: 6 } });
await page.waitForTimeout(700);
const breadcrumb = page.locator('.game-lineage-breadcrumb');
const crumbText = await breadcrumb
.first()
.innerText()
.catch(() => '');
const selectedDimmed = await page
.locator('.game-lineage-node--dimmed')
.count();
const selectedActiveEdges = await page
.locator('.game-lineage-edge--active')
.count();
check(
'DOM 断言(新):点击卡片主体 → 出现面包屑「已选中的路径」且包含根与当前节点',
(await breadcrumb.count()) >= 1 &&
crumbText.includes(root.title) &&
crumbText.includes(b1.title),
`crumb=${crumbText.replace(/\n+/gu, ' › ').slice(0, 70)}`,
);
check(
'DOM 断言(新):点击后路径持续高亮(--active 边 ≥1 且其余节点降透明度)',
selectedActiveEdges >= 1 && selectedDimmed >= 1,
`activeEdges=${selectedActiveEdges} dimmed=${selectedDimmed}`,
);
await page.mouse.move(5, 5);
await page.waitForTimeout(500);
const dimmedAfterHoverOut = await page
.locator('.game-lineage-node--dimmed')
.count();
check(
'DOM 断言(新):鼠标移开后选中路径仍保持(不是 hover 一次性效果)',
dimmedAfterHoverOut >= 1,
`dimmed=${dimmedAfterHoverOut}`,
);
check(
'DOM 断言(新):卡片主体点击不会跳走详情页',
page.url().includes('/games/lineage'),
`url=${page.url()}`,
);
await takeShot(page, 'lineage-08-selected-path.png');
// ---------- 移动端窄屏 ----------
// 只给窄视口宽度(不模拟触摸设备):验证窄屏布局不溢出 + 画布内部可横向平移。
const mobile = await browser.newContext({
@@ -1136,6 +1199,7 @@ async function main() {
'⑦ lineage-07-hover-edge-path.png(新增,核心)—— 在放大状态下 hover 1 代 B1:B1→根的**祖先路径连线被强化**(--active),其余连线变淡(--dimmed),同时节点侧兄弟卡降透明度。这是「可视化路径」需求的直接证据。',
'⑥ lineage-06-fit-window.png(新增)—— 点「适应窗口」后:全树真正完整落在画布框内(6 个节点都在框内)、右侧大片空白消失(内容水平居中)、第 3 代不再贴底被裁。',
'③ lineage-03-hover-ancestor.png:默认视野 hover B1 —— 自身与祖先不降透明度,同代兄弟 C1/F1(及 D/E)降透明度。',
'⑧ lineage-08-selected-path.png(新增)—— 点击 1 代卡片主体(非标题/按钮)后:路径被「选中」并**保持**高亮(祖先连线加粗、其余节点降透明度),鼠标移开也不消失,顶部出现面包屑「已选中的路径」(含根 → 当前节点);页面不跳转。',
'④ lineage-04-mobile-narrow.png:390×844 窄屏 —— 控件折行、**页面本身不横向溢出**、底部 tab 正常;初访不再是 35%(按可读下限 + 提示),画布内可拖拽横向平移(这张是平移后的画面)。',
'⑤ lineage-05-parent-unavailable.png:父作品下架后 —— 缺失父作品处是占位卡「原作品已不可用/标题与作者名不对外展示」,顶部有「母版已不可用…」notice,标题回退为「创作族谱」,全文不出现被下架父作品的标题与作者名。',
];