Skip to content

✅ 加固 UI 异步断言与 E2E 保存结果观察 - #1727

Merged
CodFrm merged 6 commits into
scriptscat:mainfrom
cyfung1031:codex/stabilize-ui-test-timeouts
Sep 7, 2026
Merged

✅ 加固 UI 异步断言与 E2E 保存结果观察#1727
CodFrm merged 6 commits into
scriptscat:mainfrom
cyfung1031:codex/stabilize-ui-test-timeouts

Conversation

@cyfung1031

@cyfung1031 cyfung1031 commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

目的

修正 PR #1727 中两层测试在 #1532 合并后出现的异步观察偏差,并把可重复执行的约束写入 agent 文档和 ESLint 配置。

实际改动

  • 为 Testing Library 的 waitFor 交互、重复包装查询和固定休眠增加三个边界明确的 ESLint 规则及规则测试;交互/查询规则按真实导入绑定识别本地别名并尊重词法遮蔽,同名普通函数或对象不会误报;timer Promise 规则覆盖直接 resolver 回调,不提供自动修复。
  • 清理现有 UI 测试中的重复交互、waitFor(getBy*) 和无条件 timer,保留请求完成、拖拽监听器注册及有限负向观察窗口等真实契约。
  • 调整 E2E helper:保存成功只接受本次新增、与保存语义匹配的 success toast;执行前观察同类旧通知归零,避免自动卸载造成计数竞争;保存失败用例显式传入 { saveOutcome: "failure" },等待对应的 error toast。旧通知、任意 toast 和列表外壳都不能完成断言。
  • 补充 E2E 和测试文档,明确请求开始与操作完成、正向与负向结果、计时契约与任意休眠的区别;AGENTS.md 要求修改测试、helper 或 runner 前走测试规范路由并建模成功/失败两种结果。
  • 为 WebSocket action 的有限观察窗口保留逐处 timer 豁免,并记录其清理监听器、传播超时失败的契约。
  • 修正测试运行文档中与实际配置不符的 worker 描述。

CI 失败修正

CI shard 2 的 user-config-yaml.spec.ts 失败原因是恶意 __proto__ 配置本应触发保存失败,但 helper 无条件等待成功通知。当前用例显式等待失败信号,并在重建后的本地完整 E2E 与 CI 中通过。

验证

  • ESLint 规则 harness:33 tests passed。
  • 相关 UI 定向测试:84 tests passed;完整 UI project:196 files / 1484 tests passed。
  • coverage 分片 1:182 files / 2212 tests passed;分片 2 passed。
  • pnpm run typecheck、Prettier、完整 ESLint、i18n/issue-template checks、pnpm run build passed。
  • 目标 E2E:user-config-yaml.spec.ts 2/2 passed。
  • 完整本地 Playwright:64 tests 首次 63 passed;唯一 GM_xhr 的 138 项内嵌测试中有一次 abort onloadend 观察窗口波动。隔离重跑该用例(含一次 retry)通过,138/138。
  • 提交 6e064871 的 CI:Lint、Vitest 两分片、E2E 四分片、Run tests、Codecov、FOSSA 全部通过。

@cyfung1031 cyfung1031 changed the title test: stabilize heavy network rules UI cases test: isolate UI files and await observable state Sep 4, 2026
@cyfung1031 cyfung1031 changed the title test: isolate UI files and await observable state ✅ 使用可观察状态同步网络规则 UI 测试 Sep 5, 2026
@cyfung1031 cyfung1031 changed the title ✅ 使用可观察状态同步网络规则 UI 测试 ✅ 加固 UI 异步断言与 E2E 保存结果观察 Sep 5, 2026
@cyfung1031
cyfung1031 marked this pull request as draft September 5, 2026 02:39
@cyfung1031

Copy link
Copy Markdown
Collaborator Author

astra 烧了整个上午的token. 下午做最终审查后改回正式PR

@cyfung1031
cyfung1031 marked this pull request as ready for review September 5, 2026 05:17
@cyfung1031 cyfung1031 added the P1 🔥 重要但是不紧急的内容 label Sep 5, 2026
@CodFrm
CodFrm merged commit eae267e into scriptscat:main Sep 7, 2026
10 checks passed
CodFrm added a commit that referenced this pull request Sep 7, 2026
* 🐛 restore ScriptCat registration health checks (#1724)

* 🐛 修复 @run-at context-menu:设置覆写不生效、菜单注册不上、脚本体自己的菜单被屏蔽 (#1718)

* 🐛 修复设置面板覆写运行时机在重新注册后失效

restoreJSCodeFromCompiledResource 用脚本自带 metadata 选择编译分支,
而设置面板改运行时机/early-start 只写 selfMetadata,导致全量重新注册
(扩展更新、切换启用脚本、改黑名单等)后覆写被丢弃:context-menu 脚本
恢复自动执行且不注册菜单项,early-start 退化为普通注入。

pushValueUpdate 判断 early-start 时同样只看自带 metadata,覆写而来的
early-start 脚本在 GM 值变更后不会重新编译,预注入代码里的值会过期。

close #1649

* 🐛 修复 GM API 权限校验忽略用户覆写的运行时机

GMApi.parseRequest 直接把 scriptDAO 里的原始 Script 放进 GMApiRequest,
metadata 没有合并 selfMetadata。PermissionVerify 对 context-menu 脚本的
GM_registerMenuCommand 免 @grant 豁免因此判不出来,浏览器里表现为
verify error {"api":"GM_registerMenuCommand","error":"permission not requested"},
菜单项注册不上 —— 即 #1649 里「上下文菜单中没有出现执行选项」。

真实浏览器验证记录见 e2e/scratch/run-at-override/report.md(未入库)。

* 🐛 context-menu 包装不再屏蔽脚本体自己的 GM_registerMenuCommand

@run-at context-menu 的包装把脚本体塞进菜单回调时,回调开头把
GM_registerMenuCommand 连同 window./GM. 上的引用一起置为 undefined。
于是任何在脚本体里注册菜单的脚本,点菜单执行就会
TypeError: GM_registerMenuCommand is not a function 当场中断,
它自己的菜单项也永远注册不上——用户看到的是「GM_registerMenu 的菜单显示不出来」。
该置空还会污染页面 window 与该脚本的 GM 物件,且是持久的。

去掉这行,脚本体里的菜单注册照常工作。代价是脚本体每次被点执行都会重新注册
一次,内部条目累积(显示层按 groupKey 去重,不会出现重复菜单项,但同名项的
回调会被触发多次)。

真实浏览器验证记录见 e2e/scratch/ctx-menu-{display,fix}/(未入库)。

* ✨ 统一 example/tests 测试结果与人工验证反馈 (#1717)

* ✨ 统一 example/tests 测试结果与人工验证反馈

* 🔒 固定 sctest CDN 引用到框架提交

* 🎨 统一 userscript 诊断面板与测试描述

* 🔒 固定 sctest CDN 引用到最新框架提交

* Update sctest.js

* 🔒 固定 sctest CDN 引用到最新框架提交

* ✨ 增强统一测试诊断与面板反馈

* 🔒 固定 sctest CDN 引用到最终框架提交

* ✨ 优化 sctest 诊断面板与 frame 反馈

* 🔒 固定 sctest CDN 依赖版本

* ♿ 优化 sctest 面板可访问性反馈

* 🔒 重新固定 sctest CDN 引用

* 🎨 优化 sctest 面板指标与布局

* 🔒 固定指标优化后的 sctest CDN 引用

* 🐛 固定 sctest 耗时显示宽度

* ✅ 加固 UI 异步断言与 E2E 保存结果观察 (#1727)

* test: stabilize heavy network rules UI cases

* test: isolate UI files and await observable state

* ✅ 保留 UI 测试原有隔离配置

* ✅ harden async test observations

* 🐛 align E2E save expectations with failure cases

* 🔍 tighten test guard binding and toast observation

* 📄 补充 Agent 自主操作边界、指令冲突裁决与人类可读写作规范 (#1728)

现有 agent 文档规定了改动的质量门槛,但缺三层:agent 在两次人工决策之间可以自行做什么、
指令冲突如何裁决、以及写给人看的东西该怎么写。静态审查的依据:
整套文档没有一处把 agent 写成决策者(`decide` 的主语全是分类表或原则),因而产出「建议生成器」;
`material` 作为门槛术语被引用九次却从未定义,且在 pull-request.md 内有两种含义;
测试失败例外在 AGENTS.md 概括成两条而 owner 定义了六种;路由表是一次性分类;
人工指令能覆盖什么没有成文;以及全套文档没有任何一条关于行文的规范,
而 pull-request.md 提供的九级标题骨架会被当成表格来填。

本次补齐:范围内自行决策、交还决定须指名归属与阻塞点、不写可查证却不查的保留意见、
指令冲突裁决与人工指令覆盖边界、连续路由、`material` 定义、测试失败例外改交 owner 裁决、
自主操作边界、不稳定结果报告口径、面向人类读者的写作原则、文档集自身的指令预算。
PR 模板补一条不渲染注释;pull-request.md 明确其结构是待考虑项而非待填表格。

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* 🐛 批量更新页打开更新详情复用检查缓存并挡住重复点击 (#1719)

* 🐛 批量更新页打开更新详情复用检查缓存并挡住重复点击

点击脚本名查看更新时,openUpdatePageByUUID 会重新 fetch 一次脚本代码,
而这份新版代码在检查更新阶段已经存进 scriptUpdateCheck 的记录缓存里
(行内「更新」按钮装的就是它)。用户因此要为每次点击白等一次网络往返,
期间页面又没有任何反馈,连点几下就会开出多个安装页。

- SW: 拆出 prepareUpdateOrInstallPage,openUpdatePage 命中缓存代码时
  跳过 fetchScriptBody;openUpdatePageByUUID 改为回报 boolean
- 页面: 打开期间行内转圈并同步挡住重复点击,失败弹 toast,
  点击脚本名同样取消自动关闭倒计时

* 🐛 更新页与安装页补齐骨架屏与异步中间态,失败不再被渲染成成功 (#1721)

* 🐛 打开更新详情区分静默更新,忽略动作补齐逐条回执

页面此前无从判断服务端到底做了什么:openUpdatePageByUUID 在命中静默更新时
不开安装页却同样返回 true,用户点完脚本名只看到转一圈、什么都没发生;
IGNORE 分支根本没有返回值,页面只能 fire-and-forget。

- openUpdatePageByUUID / openUpdatePage 返回 "opened" | "silent" | "failed"
- IGNORE 逐条回报结果。忽略写的是脚本自身的 ignoreVersion,与检查缓存无关,
  因此缓存随 Service Worker 回收后忽略照样生效,这里如实回报而不是谎报失效
- checkScriptUpdate 的结果收敛成 TCheckScriptUpdateResult 并用 reason 区分
  「已有检查在跑」与真正的失败,页面才能分别提示

* 🐛 安装页补齐加载分档、代码骨架与提交忙态

从批量更新页点脚本名进来的必然是「更新」,加载屏却把上下文 chip 写死成
「脚本安装」,几百毫秒后再闪成「脚本更新」;描述写着「正在从来源下载」,
但这条入口的代码 Service Worker 早已备好,根本不下载。

- 状态屏按来路分档,未确知场景不渲染 chip(不猜),并补一条与就绪态操作栏
  等高的底部占位,避免就绪瞬间内容区高度再跳一次
- 暂存代码被定时清理回收时落到专属终态,出口换成「重新检查更新」——
  原来的「重试」在这个最常见的失败原因下重试多少次都是同一结果
- Monaco 实例就绪前渲染代码骨架,替代此前 340px 的纯空白
- toggleWatch / rejectExternalAccess 补忙态,install 加重入守卫:
  这两个动作全程不置忙态,连点会发出两次安装/两次决定

* 🐛 批量更新页补齐取数失败、检查空窗期与忽略/批量的中间态

取数失败时记录仍是空的,页面直接走到空态,把一次加载失败渲染成
「所有脚本均为最新(已检查 0 个脚本)」这条与事实相反的成功终态;
点「检查更新」到服务端广播回来之间页面完全静止,期间可以连点。

- 取数失败落错误终态:等宽 detail 框 + 重试 / 脚本列表出口
- 主动检查由本地 pending 立刻接管忙态,并把服务端的「正忙」「结果够新已跳过」
  「通道异常」三条回执分别说出来;跳过时就地清掉待反馈标记,
  否则会在下一次后台检查完成时冒出一条用户没点过的 toast
- 忽略复用与更新相同的行级阶段(working → success → 退场),不再 fire-and-forget
- 批量进行中互斥(行内勾选、两个批量按钮、全部恢复),避免两条进度互相覆盖;
  被「结果失效」中断时保留已完成条数,不把汇总抹掉
- 骨架补齐工具条(桌面)与顶部选择栏/底部操作栏(移动)占位,消除数据到达时的
  布局跳动,并加 role="status" / aria-busy;空态下重新检查不再整页闪回骨架
- 脚本名改用 aria-disabled + onClick 早退:disabled 会让浏览器不派发指针事件,
  正好在名字被截断、最需要看全名时把 tooltip 一起关掉,键盘触发后焦点还会掉到 body

---------

Co-authored-by: wangyizhi <yz@ggnb.top>
Co-authored-by: cyfung1031 <44498510+cyfung1031@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P1 🔥 重要但是不紧急的内容

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants