fix(test): disambiguate pending reply from live announcements - #4251
Conversation
Signed-off-by: huangruiteng <huangrt01@163.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
评审绑定 exact head:e7d1d161c48ea7d02211a1f08c91e2afa645fbe5。
动机
这个 PR 修复的是现有 Personal Workspace reload/reconnect acceptance 的 locator 歧义,不是产品运行时缺陷。页面会同时保留 pending placeholder 正在整理… 和 aria-live announcement Claude Code:正在整理…;基线使用 Playwright 的 substring text matching,strict mode 因而解析到两个节点,在真正检查 placeholder 是否消失之前就失败。历史 CI 日志明确列出了这两个元素。
改动思路
修复留在正确 owner:由 browser smoke 的 locator 精确选择 pending placeholder,不修改产品 copy,也不删除给读屏器/实时状态使用的 live announcement。exact: true 是现有断言上最小且可逆的修复;它让测试语义与“等待 pending 节点隐藏”一致,同时继续通过后续 terminal-event replay 与 assistant-answer deduplication 验证真实 reload 路径。
具体改动
关键内容讲解
- reload 后的
getByText("正在整理…")改为 exact text locator,只绑定 pending span,不再把带 agent 前缀的 live announcement 算作候选。 - 代码注释解释了两个节点并存的产品原因,避免维护者以后把 exact selector 当成冗余而删除。
- testing guide 记录 strict locator 的选择原则和失败形态;没有新增平行 smoke,也没有改变 UI 或 Chat 生命周期。
我在本 head 运行完整 development-mode Personal Workspace browser smoke,结果为 ok;node --check 与 git diff --check 也通过。托管 checks job 中同一 browser smoke 同样通过。
对主干的风险
剩余风险很小:如果 pending placeholder 的精确 copy 将来变化,这个断言会明确失败,维护者需要同步 locator;相比 substring matcher 的误匹配,这种失败更可诊断。当前 aggregate pytest gate 仍为红色,但直接日志显示唯一原因是 current main 的 loopx/control_plane/todos/decision_scope.py 七个 mypy no-any-return 错误;本 PR 在该文件没有 diff,同样错误也可在本 head 独立复现,因此不是这个 selector patch 引入的回归。
durable-smoke pass 也已完成:这是对既有 CI acceptance 的精确修复,保护真实 reload/replay/deduplication 行为;没有新增一次性脚手架、重复测试或同作者批量同形 PR。
我的整体评价
未发现阻塞项。改动最小、边界正确,并且历史反例、真实浏览器路径和 hosted log 三者相互印证。技术结论是 APPROVE;由于这是 author-owned PR,GitHub 不允许正式 self-approval,所以以 COMMENTED 记录批准结论。future-facing pass 无需再引入 test id 或 locator helper;当前 exact text 是最窄且最容易回滚的实现。
English verdict: APPROVE — exact head e7d1d161c48ea7d02211a1f08c91e2afa645fbe5 fixes the demonstrated strict-locator ambiguity at the existing browser-smoke boundary; the full Personal Workspace smoke passes locally and in the hosted checks job, while the remaining aggregate failure is an unrelated current-main mypy regression in decision_scope.py.
Summary
Fix the remaining Dashboard CI recovery failure after #4241 and #4250. The detailed log from main qualification shows a Playwright strict-mode violation, not an elapsed recovery timeout: the substring locator matches both the accessibility live announcement and the pending message.
Use exact pending-message text matching. Keep the live region, the ten-second completion bound, and the session/completion-replay assertions introduced by #4250. Record the locator lesson in the existing testing guide.
Scope and product judgment
Only the existing browser acceptance fixture and developer testing guidance change. No product frontend/backend, packaged assets, settings, runtime state, coverage threshold or CI exemption changes. No UI preview or companion configuration work is needed because the product surface is unchanged. The owning boundary is browser qualification, not a new capability or abstraction.
The timing dependence explains why local/packaged runs passed: if completion removes the message first, the broad locator no longer matches two elements. Increasing the timeout cannot fix a strict-mode error.
Validation