Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

[e2e] live 车道首次真跑即暴露:master-detail.spec.ts 的标题定位器命中两个 h1(strict mode violation),2/4 用例必红 #3434

Closed

Description

@yinlianghui

背景:这条 lane 刚刚第一次真正跑起来

.github/workflows/live-e2e.yml 因为一处 job 级 env: 里的 runner 上下文,自 #3325 落地起就一直是 workflow 级 startup failure(0 job / 0s),从未执行过任何一个用例。#3425 / PR #3432 修好该启动故障后,这条 lane 在 PR #3432 上跑出了历史第一个真实 run:

后端、控制台、登录都是好的([live-e2e] authenticated as admin@objectos.ai),action-modal 与 screen-flow 两条都过。失败集中在 master-detail.spec.ts 的两条,且是同一个根因,发生在 beforeEach 里。

现象

e2e/live/master-detail.spec.ts:33:

await expect(page.getByRole('heading', { name: 'New Project + Tasks' })).toBeVisible();

报:

Error: expect(locator).toBeVisible() failed
Locator: getByRole('heading', { name: 'New Project + Tasks' })
Expected: visible
Error: strict mode violation: getByRole('heading', { name: 'New Project + Tasks' })
       resolved to 2 elements:
    1) < h1 class="text-3xl font-bold tracking-tight text-foreground" >New Project + Tasks< /h1 >
       aka getByRole('heading', { name: 'New Project + Tasks' }).first()
    2) < h1 class="text-2xl font-semibold tracking-tight" >New Project + Tasks< /h1 >
       aka locator('header').filter({ hasText: 'New Project + TasksMaster-' }).getByRole('heading')

两条受影响用例(都卡在同一个 beforeEach,因此用例主体一行未跑):

  • master-detail.spec.ts:36 — Create submits the populated parent in one atomic batch
  • master-detail.spec.ts:58 — Create with a task line includes the child op referencing the parent

需要判断的是哪一侧的问题(我没有下结论)

同一段文案被渲染成两个 h1:一个是页面级大标题(text-3xl),一个在 header 里(text-2xl)。这有两种可能,请在三方定夺时一并判断:

  1. 测试侧:页面本来就有「页面标题 + 吸顶 header 标题」两处,属预期;那么 spec 的定位器过宽,应收窄(限定 scope,或改用更稳的语义锚点)。
  2. 应用侧:同一标题被重复渲染成两个 h1 本身就是缺陷 —— 一个文档里出现两个 h1 对 a11y / 文档大纲也不健康,读屏会读到重复标题。若如此,该修的是渲染侧,spec 反而是正确的探针。

倾向 2 值得先看一眼再决定:h1 重复是无障碍层面的真问题,而不只是选择器写窄一点就能了事的测试瑕疵。

影响

该 lane 是 continue-on-error: true 的 informational 车道,不阻塞合并(workflow run 结论为 success);但 PR checks 列表里 Live E2E (informational) 这一格会显示 failure。也就是说 #3425 消灭的是「假红」(startup failure),这条留下的是「真红」—— 有 Playwright 报告、截图、录像和 live-e2e-artifacts 制品可查,正是这条 lane 被设计出来要抓的东西。

复现:pnpm test:e2e:live:ci(需按 e2e/live/ci/backend.env 起真后端)。

发现于 #3425 的修复验证过程(PR #3432),按 Prime Directive #10 独立立单、不夹带修复。

Activity

  1. changed the title [-][e2e] live лейн 首次真跑即暴露:master-detail.spec.ts 的标题定位器命中两个 h1(strict mode violation),2/4 用例必红[/-] [+][e2e] live 车道首次真跑即暴露:master-detail.spec.ts 的标题定位器命中两个 h1(strict mode violation),2/4 用例必红[/+] on Aug 6, 2026
  2. yinlianghui commented on Aug 6, 2026

    @yinlianghui
    ContributorAuthor

    分诊:bug + pm:queue(objectui 分片 PM,会话 session_01GTRjn8xBqp75dk7kFupVRt)。

    判级理由:可复现的确定性失败(live-e2e 首次真实运行即红,两条 master-detail spec 同一 beforeEach,strict mode violation:getByRole('heading', { name: 'New Project + Tasks' }) 命中 2 个元素),且 #3425/PR #3432 落地后它是该 lane 唯一的红——不修则 lane 修好即被内容问题重新染红,信息量归零。

    派发前置(写给实现者,方向未预判):先回答「页面是否真的为同一上下文渲染了两个 h1」(page 级 text-3xl + header text-2xl):

    • 若是渲染缺陷(同一可访问树里双 h1 同名):修渲染侧,这是 a11y 层级问题,测试不动;
    • 若是测试定位器过宽(两个元素分属不同区域、各自合理):收窄定位器(byRole + level 或容器限定);
    • 若读码后发现这是刻意的设计形状(如响应式双标题),按 step 8 升级,不自行裁。
      用可访问树证据(getByRole 输出、DOM 层级)说话,不猜。

    文件面预告:e2e/live/master-detail.spec.ts 或对应渲染组件二选一(由上述判断决定),与在飞批 29–33(fields / collaboration+i18n / workflows / hooks / test 脚本)互不相交,可下批派发。


    Generated by Claude Code

  3. self-assigned this
    on Aug 6, 2026
  4. yinlianghui commented on Aug 6, 2026

    @yinlianghui
    ContributorAuthor

    认领:objectui 分片 PM 并行批第 34 单
    会话:session_01GTRjn8xBqp75dk7kFupVRt
    分支:claude/issue-3434-master-detail-dual-h1
    Worktree:objectui-issue-3434
    文件面:调查后二选一——渲染侧(渲染出重复 h1 的 app-shell 页面标题/吸顶 header 组件)或测试侧(e2e/live/master-detail.spec.ts),以可访问树证据定夺;两侧都不超出 app-shell 布局组件 + e2e/live + 各自测试 + changeset(若动渲染)。越界即停。
    与同批第 35 单(#3440,collaboration+语言包)、36 单(#3442,文档/skills)互不相交。


    Generated by Claude Code

  5. yinlianghui commented on Aug 6, 2026

    @yinlianghui
    ContributorAuthor

    验收:ACCEPT → PR #3444(并行批第 34 单,会话 session_01GTRjn8xBqp75dk7kFupVRt),16/17 检查绿(仅 Type Check 在跑,本地 tsc 已 clean),绿后转 ready + 入队。

    复核要点:

    1. 裁定路径走对了:以可访问树证据定夺——DOM 测试逐字节复现 Playwright 的双命中(page.tsx:613 的 text-3xl 页级标题 + containers.tsx:1359 的 header 标题,同文档同名同时渲染),且系统性命中 5 个示例页,非孤例。判渲染缺陷,spec 一字未动——它是诚实探针。
    2. 修法有出处:page.tsx 自己的注释早已写明 record 页「header 里的 page:header 接管标题」,本修复只是把该意图推广到所有页型;保守边界处理正确(空 title / 插值为空的 header 不接管——两个 h1 换零个 h1 是更糟的交换),负控四例两侧全绿钉住这一点。
    3. 验证是决定性的:PR 上的 live-e2e 实读 run 日志——4/4 通过,原两条红用例跑了完整主体(3.7s/5.0s),failure-only 步骤 SKIPPED 证明不是 continue-on-error 遮出来的绿。反向验证 4 红 4 绿与预测完全一致。该 lane 自 ci: 三条 live e2e 以 non-required lane 进 CI——真后端来自已发布的 rc.2 制品 (#2835) #3325 以来首次在 PR 上整体 success。
    4. 顺带发现 [finding] preview-samples 的 page 样例用了未注册的 heading 组件类型,designer 预览画廊里两行标题渲染成 fallback #3446(preview-samples 的 heading 非注册组件类型,dev-only)finding 留池;page.tsx:412 的 title ?? label 双读经核系跨仓命名桥(framework#1878 §3 有注),非 #0.1 目标形状,不动——认同 dev 判断。

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions