Skip to content

♻️ 重构本地验证流程:常驻会话 + 命令驱动,替代一次性 spec - #1674

Merged
CodFrm merged 8 commits into
mainfrom
refactor/local-verification-session
Aug 17, 2026
Merged

♻️ 重构本地验证流程:常驻会话 + 命令驱动,替代一次性 spec#1674
CodFrm merged 8 commits into
mainfrom
refactor/local-verification-session

Conversation

@CodFrm

@CodFrm CodFrm commented Aug 13, 2026

Copy link
Copy Markdown
Member

Checklist / 检查清单

  • Fixes mentioned issues / 修复已提及的问题
  • Code reviewed by human / 代码通过人工检查
  • Changes tested / 已完成测试

N/A — 无关联 issue,本次是本地验证流程的自发重构。

Description / 描述

背景

本地验证一直是「写一个 spec → 整体跑一遍 → 看输出 → 想换个角度看 → 再改再跑」。
代价在仓库里是可量化的:e2e/scratch/ 里累计了 20 个一次性 spec、6871 行,
是 committed 套件(3251 行)的 2.1 倍,而它们几乎都只被跑过一次。

根因是没有可附着的浏览器:全仓 grep -rn "remote-debugging\|connectOverCDP" 零命中,
每次观察都必须从头启动一个 spec。

本次改动

  • e2e/session.mjs:启动一个常驻的、加载 dist/ext 的浏览器并保持存活。
    start / status / stop --all
  • e2e/drive.mjs:每次调用是一个短命进程,附着到会话做一件事。
    open / goto / click / fill / press / wait / snapshot / text /
    shot / eval / sw / storage / install / pages / use / close / console
  • 全上下文 console 采集:脚本自测与后台脚本的断言打在 Service Worker、
    Offscreen 文档、Sandbox iframe 里,它们各自是独立的 CDP target,Playwright 只暴露
    页面的 console 事件。改为连浏览器级 CDP 端点并递归 setAutoAttach,四类上下文
    统一落到一个 console.log 并标注来源。
  • E2E_HEADED:原先 9 处把 "--headless=new" 写死在 args 里,覆盖了
    Playwright 的 headless 选项 —— 也就是说 headless: false--debug 一直
    开不出窗口。现在统一走 headlessArgs()
  • 文档docs/verification.md 改以驱动会话为默认形式;e2e/README.md 新增
    §8 会话手册;驱动方法拆到 docs/references/verification-methods.md

实现考虑

  • 默认无头:验证不该抢占桌面焦点,--headed 只为人工旁观保留。
  • 并发:唯一全局争用的资源是 CDP 端口,因此向内核申请(listen(0))而不写死;
    profile 走 mkdtemp,证据落各自的 scenario 目录。多个 worktree 可同时验证。
    已实测两个会话互不串扰(一个装了脚本读到 1,另一个读到 0)。
  • 两阶段启动updateExtensionConfiguration 授权 userScripts 会重载扩展,
    重载期间扩展自己的页面返回 ERR_BLOCKED_BY_CLIENT。所以授权放在一次性启动里,
    再从同一 profile 重启接管 —— 与既有 fixture 已验证过的两阶段模式同源。
  • console 采集的三个坑(均已实测并修正):每个 target 只能 Runtime.enable
    一次,重复 enable 会重放该上下文的 console 历史造成成倍重复;不开
    setDiscoverTargets 就收不到 targetInfoChanged,页面导航后来源会一直停在
    附着那一刻的 about:blank;对象参数不带 value,必须按 preview 渲染,
    否则断言里的 {passed, failed} 只会记成 Object
  • 当前页按 URL 而非下标跟踪:扩展会自己开引导页,下标随时错位。
  • snapshot 的选择器优先级:testid > 稳定 id > 可见文本。Radix 生成的
    radix-_r_0_ 每次渲染都会变,明确排除。

已知限制

  • 采集器会在每个 target 上常驻一个 debugger 会话。这正是采集完整的原因,但也意味着
    会话不适合验证 Service Worker 的驱逐 / 空闲终止行为,那条线仍走
    keep-alive.spec.ts
  • 会话不提供协议 mock 与 .test 域名映射,需要 mock server 的验证仍走 scratch spec。
  • snapshot 不进 iframe。
  • e2e/scratch/ 下清掉了 21 个一次性文件;发版配图工具
    mobile-shots.spec.ts / promo-render.spec.ts / _assets/)保留,它们仍是平铺的,
    未纳入 <scenario>/ 约定。

建议审查重点

  • e2e/fixtures.tsheadlessArgs() 被另外三个 fixture 引入,确认 CI 仍为无头。
  • attachConsoleCollector()waitForDebuggerOnStart 要求每个 target 都必须收到
    runIfWaitingForDebugger,否则新 target 会被永久挂起 —— 这条路径值得重点看。
  • session.mjs 的 SIGTERM/context.on("close") 清理路径,是否会残留 profile 或进程。
  • drive.mjswrapEvalSource():带 return 当函数体、否则当表达式。

验证

pnpm run lint                                                                        exit 0
pnpm exec playwright test options.spec.ts script-management.spec.ts popup.spec.ts    12 passed
pnpm exec playwright test resource-update.spec.ts agent-navigation.spec.ts            6 passed
pnpm exec playwright test gm-api.spec.ts                                              9 passed
pnpm exec playwright test options.spec.ts popup.spec.ts gm-api.spec.ts               18 passed(采集器改动后复跑)

覆盖了全部 4 个被改动的 fixture 文件(fixtures / server-fixtures / agent-fixtures /
gm-api 内联 fixture)。

会话本身的实测(非推断):

  • 装脚本 → SW 确认 → options 列表出现 → 截图,全链路通过
  • 四类上下文的 console 均实测捕获:(src/service_worker.js)(src/sandbox.html)
    (装一个 @background 脚本并启用后打出的行)、(src/options.html);对象渲染为
    {passed: 29, failed: 0} 而非 Object
  • 两个会话并发且状态隔离;stop --all 后无残留 profile 与进程
  • E2E_HEADED=1session.mjs --headed 均确认开出真实窗口(UA 无 Headless
  • dist/ext/manifest.json 缺失时 start 拒绝启动,退出码 1
  • snapshotclick [data-testid="theme-toggle"]documentElement.className
    变为 darklightMode=dark

文档检查:6 个文档的 69 条相对链接与锚点全部解析通过;文中每条命令均已实跑。

CodFrm and others added 7 commits August 13, 2026 13:33
启动一次浏览器常驻,之后逐条命令附着驱动,验证一件事不再需要
先写一个 spec 再整体重跑。

- session.mjs:start/status/stop,默认无头,--headed 供人工旁观
- drive.mjs:open/goto/click/fill/snapshot/shot/eval/sw/storage/install 等
- 端口向内核申请(listen(0))、profile 走 mkdtemp、证据落各自的
  scenario 目录,多个 worktree 可并发验证
- 会话全程记录 console/pageerror 与操作,报告直接引用
原先 9 处把 "--headless=new" 写死在 args 里,而启动参数会覆盖
Playwright 的 headless 选项,所以 headless: false(含 --debug/PWDEBUG)
其实一直开不出窗口。统一走 headlessArgs(),E2E_HEADED=1 才可见。
verification.md 以驱动会话为默认形式,写 spec 收敛为「顺序/时序即契约」
时的例外;驱动方法拆到 references/verification-methods.md;e2e/README.md
新增 §8 会话手册(命令表、证据目录、并发、能力边界)。
Playwright 只暴露页面的 console 事件,但脚本自测与后台脚本的断言打在
Service Worker、Offscreen 文档和 Sandbox iframe 里 —— 这些各自是独立
的 CDP target。改为连浏览器级 CDP 端点并递归 setAutoAttach。

- waitForDebuggerOnStart 保证 document-start 的输出不漏
- 每个 target 只 Runtime.enable 一次:重复 enable 会重放 console 历史
- 开 setDiscoverTargets,否则导航后 URL 停在附着那一刻
- 对象参数按 preview 渲染,不再是无信息的 Object

Copy link
Copy Markdown
Collaborator

针对原 PR「♻️ 重构本地验证流程:常驻会话 + 命令驱动,替代一次性 spec」,我在原分支追加了 3 个修正 commits(未 force-push,未修改 PR 标题和描述):

  • c0dd9abd:为同一 scenario 增加原子启动锁;补齐启动失败、异常退出、正常停止和 stop --all 的 stale session/profile 清理;限制 scenario 路径边界,并避免停止超时后删除仍在使用的 profile。
  • 16523627:用 CDP targetId 追踪活动页面,修复重复 URL 页面在 use <i> 后可能操作错误 target 的问题;同时让页面管理和 console 命令写入 actions 记录。
  • 17aad4ce:将 E2E_HEADED 明确为 1/true/yes 才启用 headed,补充分支测试,并修正验证文档中未定义 tabId/url 的示例。

本地验证证据:

  • 新增的 9 条窄测试通过;
  • pnpm run lint 通过(含 typecheck、i18n、issue-template、ESLint 和 Prettier);
  • 相关 Playwright 回归 27/27 通过:options、script-management、popup、resource-update、agent-navigation、gm-api;
  • 常驻会话实测通过:drive 后会话仍存活、重复 URL target 选择正确、同 scenario 并发只保留一个会话、杀死 daemon 后 stop --all 清理 session/profile;
  • 发布后的分支 head:17aad4cec51f06c0128eaa04d00f8373c2886f8d

@CodFrm
CodFrm merged commit 9e31780 into main Aug 17, 2026
9 of 10 checks passed
@CodFrm
CodFrm deleted the refactor/local-verification-session branch August 17, 2026 02:13
CodFrm added a commit that referenced this pull request Aug 17, 2026
- docs/verification.md:采用 #1674 重写后的“常驻会话驱动”结构,
  将 PR 的 in-page self-test 说明作为子节并入 “Driving the session”,
  并注明 gm_download/gm_menu(已回退)与 gm_value 不输出统一汇总。
- e2e/gm-api.spec.ts:合并 main 的 headlessArgs 重构(保留 type Page
  与 mock server 的 http 类型导入),去除 gm_download E2E 后共享设施不变。
- 回退后的 gm_download_test.js / gm_menu_test.js 与 main 完全一致
  (自包含实现 + main 的 httpbingo 更新)。

验证:tsc/lint/build 通过;sctest 单测 66/66;gm-api E2E 12/12(gm_xhr 138、
gm_xhr_redirect 12、gm_api_sync 29、gm_api_async 29、inject_content 11、
window_message 5、sandbox 32、unwrap 3,failed 全 0)。
CodFrm added a commit that referenced this pull request Aug 17, 2026
合并 #1674 时只有 docs/verification.md 被 git 标成冲突,但 #1674 已把
in-page self-test 这一节拆去新建的 references/verification-methods.md,
拆出去的那份没跟着改,留下了本 PR 已推翻的描述:

- "the line varies by script" —— 12/15 脚本共用 sctest,输出一致;
- 代码块里的「总计: N | 通过: N」「Total/Passed」两种格式全树 grep 零命中;
- "matches all three layouts" —— 只剩一种;
- 缺 跳过 行、itManual、GM_log 后台通道。

docs/README.md 指明这一节归 verification-methods.md 所有,因此把内容
移过去替换过期段落(保留该文件「会话 + spec 两写」的体例),
verification.md 只留指向它的链接 —— 顺带补上 #1674 漏写的反向链接。

同时修正 gm-api.spec.ts 两处随本 PR 失效的注释:
- beforeCollect 的「B 类文件 / 真实下载副作用」——「B 类」全树无定义,
  且 GM_download E2E 已在 a6bad63 回退,现存唯一消费者是 gm_xhr_test.js;
  该套件 auto:false 的理由在脚本自身已写明,此处不复述。
- 「三行汇总里的最后一行」—— 汇总现为四行,且末行是「跳过:」。

验证:tsc/eslint/prettier 通过;vitest 78/78(sctest 66 + verification-tools 12)。
CodFrm added a commit that referenced this pull request Aug 18, 2026
* ✅ 新增 example/tests 共用测试框架内核与 Console reporter

* 🐛 修复 sctest toEqual 的 JSON 序列化误判并补测试

toEqual 原先用 stringify(actual) !== stringify(expected) 做深比较,导致
NaN 与 null 被误判相等、显式 undefined 键与缺失键被误判相等、对象键顺序
影响比较结果。改为手写的递归结构比较(Object.is 语义 + hasOwnProperty
探测键存在性 + 数组/对象类型互斥 + 循环引用防护),并补齐 toBeTruthy 的
真值/假值用例。

ConsoleReporter 的 MANUAL 分支此前丢弃了 c.hint,console-only 场景下
用户看不到人工确认需要做什么,现追加 hint 到既有 (待人工确认) 文案后。

* ✅ 测试框架新增 Shadow DOM 面板 reporter

* ✅ 测试框架新增 GM_log reporter 供后台/定时脚本使用

* 🐛 移除 emitLog 中吞异常的 try/catch,补全跳过/开始日志断言

typeof GM_log === "function" 的判断已完整覆盖未 @grant GM_log 的降级场景,
外层 try/catch 实际只是把已授权 GM_log 抛出的真实异常静默吞掉。移除
try/catch,让已授权 GM_log 的异常正常抛出。

同时为开始日志(sctest:"run")与跳过/人工用例日志(sctest:"case",
status:"skip")补上内容校验断言 —— 此前只有 key 数量断言,不会在
level/label 内容错误时失败。

* ✅ 测试框架补齐手动 suite 重跑通路与用法文档

* 🐛 修复面板失败详情在手动 suite 重跑时不渲染的问题

onCase 的更新分支此前只更新图标/耗时/统计,从不生成 .sc-detail,
而 auto:false 的 suite 每个用例首次真正执行时都会先被预渲染成 skip、
从而永远走这条分支——失败用例因此从不展示期望/实际/错误详情。
新增 renderDetail 统一由两条分支调用,重跑时先移除旧详情再按需重建,
避免重复追加;更新分支同时改用既有的 applyStatus 消掉重复表达式。
强化重跑用例的断言,校验行数不翻倍、跳过数清零,并补充详情展示与
失败转通过后详情清除的覆盖。

* ✅ e2e 支持把测试框架 @require 重写到本地 mock server

* ✅ gm_api_sync_test 迁移到共用测试框架

* 🐛 恢复 gm_api_sync_test 断言前的过程日志

GM_addValueChangeListener/GM_addElement 迁移时被误删的三条+两条日志,
均在断言之前/之间无条件执行,超时或挂起时仍会打印,是排查这两个
用例卡住位置的唯一线索,应予保留。

* ✅ gm_api_async_test 迁移到共用测试框架

* ✅ inject_content 与 early_inject 系列迁移到共用测试框架

迁移前后计数(全部一致):
- inject_content_test.js:      e2e passed=11 failed=0 → passed=11 failed=0
- early_inject_content_test.js: 总计 14 通过 14 失败 0 → 总测试数 14 通过 14 失败 0
- early_inject_page_test.js:    总计 14 通过 14 失败 0 → 总测试数 14 通过 14 失败 0

后两个文件无 e2e 覆盖,用一次性 Playwright scratch 脚本核对。

两个 early_inject 文件显式指定 reporter: "console":它们断言 document-start 时
DOM 保持原始态,而面板会往 document.documentElement 挂 #sctest-panel-host,
正好破坏 expect(firstElement.innerHTML).toBe("") 这条断言。这两个文件因此
不显示页面面板——注入型 DOM 面板与 DOM 纯净断言无法共存。

* ✅ sandbox_test 迁移到共用测试框架

e2e gate (e2e/gm-api.spec.ts -g "Sandbox Test"): passed=32, failed=0
before migration; passed=32, failed=0 after migration. N unchanged.

* ✅ window_message 与 unwrap 系列迁移到共用测试框架

e2e gate (e2e/gm-api.spec.ts -g "WindowMessage Transport Test"): passed=5, failed=0
before migration; passed=5, failed=0 after migration. N unchanged.

e2e gate (e2e/gm-api.spec.ts -g "Unwrap scriptlet tests"): passed=3, failed=0
before migration; passed=3, failed=0 after migration. N unchanged.

unwrap_test.js has no e2e coverage; verified with a throwaway Playwright scratch
script (e2e/scratch/verify-unwrap-test.spec.ts, git-ignored) that installs the
migrated script and confirms it injects and reports passed=3/failed=0 on
https://example.com/?test_unwrap_123, and does not inject at all (no panel, no
console output) on https://example.com/?test_unwrap_excluded per its @exclude.

* ✅ gm_xhr_redirect_test 迁移到共用框架并接入 e2e

首个 B 类文件迁移:删除手写面板 + assertEq,接入 SCTest 框架,首次获得
可解析的汇总行与 e2e 覆盖。tests 数组(basicTests + useFetch 变体)保持
数据驱动,映射为 it(),未手动展开。

e2e 新增用例需要:
- patchTargetMatchCode 正则备选组加 GM_XHR_REDIRECT_TEST_SC token
- patchGMApiTestCode 新增 HB 常量重写规则(该文件及未迁移的
  gm_download_test.js/gm_xhr_test.js 都用 `const HB = "https://httpbun.com"`
  拼 URL,走模板字符串后原有的字面量 URL 替换规则匹配不到)
- mock server 补 /redirect-to 路由(302 + Location)
- mock server /get 路由补上查询串回显(该文件断言 response.url 带 query)

用例数:迁移前(原手写面板,真实 httpbun.com,一次性 scratch 脚本量得)
passed=12 failed=0;迁移后(新 e2e,走 mock server)passed=12 failed=0,
完全对齐。

* ✅ gm_download_test 迁移到共用测试框架

纯机械改写:删除手写面板与 logLine/setCounts/setStatus/setQueue 及本地
assertEq/assertTrue,26 个用例按 manual 标志拆成「自动套件」与「手动用例」
两个 auto:false suite(沿用 runAuto 原本 filter((t) => !t.manual) 的区分),
prefix 从 suite params 读取。

assertEq(a, b) 是实际在前,转成 expect(a).toBe(b) 不换位。断言语义逐条保持
不变——包括 test 18「empty URL」这条迁移前就在失败的用例,本提交不碰它的
判定,只做形式转换。

e2e 接入放在后续提交:本提交后该文件对真实 httpbun 仍是 19 通过 / 2 失败,
与迁移前基线一致。

* 🐛 修正 gm_download empty URL 用例一开始就写错的断言

该用例断言空 url 必须触发 onerror 或抛异常,但 ScriptCat 从未如此表现:
src/app/service/content/gm_api/gm_xhr.ts:230 对 url 统一做
new URL(urlResolved, window.location.href),GM_download 在同一函数的 :265-269
分支复用这条解析,空串按 RFC 3986 解析为当前页地址,下载因此正常成功。

不是迁移引入的回归——迁移前打真实 httpbun.com 就是失败的,对 e2e mock server
与解析源码三处一致且确定。属于 docs/references/develop-testing.md 里
「一开始就写错的断言」这条例外,单独提交以便独立复核或回退。

若日后判定「空 url 应当被拒绝」是正确的产品行为,改的是实现,本用例随之
翻回原判定即可。

* ✅ gm_download_test 接入 e2e

@match token GM_DOWNLOAD_TEST_SC 加进 patchTargetMatchCode;两个 suite 都是
auto:false,页面加载不会自动跑,给 runTestScript 加 beforeCollect 钩子在
page.goto 之后点一次「GM_download 自动套件」的运行按钮,手动用例保持不跑。

* 🐛 修复手动 suite 跑完后不重新发出 onEnd 的问题

runManualSuites 只逐条调用 onCase,从不调用 onEnd。后果是对**全部 auto:false 的
文件**,ConsoleReporter 的三行汇总永远停在页面加载时打的 "通过: 0 / 失败: 0"
(那时这些用例都被预置为 skip),LogReporter 的汇总日志同样永不出现。
面板因为靠 onCase 实时累加,看起来正常,把这个缺陷掩盖了。

三行汇总是 e2e 的解析契约,所以这等于 B 类文件根本无法用标准路径接入 e2e。
Task 12 当时是在 e2e 侧绕过去的——加了个 runSuiteAndCollectFromPanel 去爬面板
Shadow DOM 读结果。现在根因修好,这段绕行代码一并删除,B 类文件回到与其余文件
相同的 console 汇总路径。

- sctest.js: runManualSuites 结束时 buildSummary + 广播 onEnd,并返回 summary
- gm-api.spec.ts: beforeCollect 简化为「只点按钮」,返回 void;
  轮询改为「先等首次汇总 → 快照计数 → 点击 → 等下一组汇总」,
  避免快照取早了被首次的 0/0 立即满足

验证:sctest 单测 45/45(新增 3 条覆盖 Console/Log/返回值三条契约);
gm-api.spec.ts 全部 9 个用例通过,计数与各自基线一致
(inject_content 11、sandbox 32、gm_api_sync 29、gm_xhr_redirect 12、
unwrap_e2e 3、window_message 5、gm_api_async 29、gm_download 21,failed 均为 0)

* ✅ 测试框架新增用例内主动跳过通道 SCTest.skip

迁移前 gm_download_test 的 runOne 特判错误消息的 "SKIP:" 前缀来区分跳过,
迁移到共用框架后这个通道没了,5 个手动用例超时或人工点 Skip 全部记为失败。

改用独立的 SkipSignal 类型而非消息前缀嗅探:前缀嗅探会把消息碰巧同名的
真实错误一并吞成跳过。STATUS.SKIP、summary.skipped、面板 sc-chip-skip 与
LogReporter 的 ○ 分支本来就在,这里补的是从用例体内产生 skip 的入口。

顺带修一个真实浏览器里复现的遮挡:verdict bar 原本 fixed 在右上角,与
右下角最高 80vh 的 sctest 面板重叠 2px,两者 z-index 同为最大值而面板挂载
更晚,Skip/Pass/Fail 按钮被吃掉点击。改到左上角。

* ✅ gm_xhr_test 迁移到共用框架并接入 e2e

* ✅ gm_menu_test 迁移到共用框架,契约检查升级为断言

8 处 GM_registerMenuCommand 返回值契约检查从软打印 console.log(x === y) 升级为真断言 expect(x).toBe(y),放进 it() 用例;scratch 自动核过全部通过(总20 通过11 失败0 跳过9)。菜单点击观察点转 itManual() 按注册顺序交错;保留三个调试开关与全部注册/注销调用及回调内 console.log 面包屑,仅删除 waitActions/myResolve/waitNext 等待机制。gm_value_test.js 按决定不在本次范围,保持原样。

* ✅ gm_xhr_cookie_test 迁移到共用测试框架

12 个 test() → 12 个 it(),归入 3 个 describe。assert(expected,actual) 是期望在前,
转成 expect(actual).toBe(expected) 逐条换位;assertTrue → toBeTruthy。领域 helper
assertCookieValues 保签名与 slice().sort() 集合语义不变,内部 assert 改写为
expect(JSON.stringify(actual)).toBe(JSON.stringify(expected))。

矩阵段的 9 个依赖用例:原文用 `if (matrixRequestPassed && lastCookieMap)` 门控
(请求失败则这 9 个 test 不注册)。声明式框架无法条件注册,故引入 matrixOk 标志 +
每个依赖用例开头 `if (!matrixOk) SCTest.skip(...)`,复刻「前置请求失败则跳过依赖用例
而非各自级联失败」的原语义。

对真实 mockhttp.org 各跑 2 次稳定:迁移前基线 12/12/0,迁移后 12/12/0(含 skip 守卫,
happy path 无跳过)。

* 📝 更新 verification 文档以匹配统一后的测试框架输出

example/tests 下 14 个脚本迁移到 sctest.js 后,in-page self-test 只剩一种汇总格式,
不再有原来三种方言。改写「self-test pattern」小节:统一为框架的三行汇总,说明
background/crontab 走 GM_log、人工用例走 itManual,并标注 gm_value_test.js 是刻意
不迁移的交互式演示(无可判定断言、不打印汇总)。正则示例保留,注释从「三种布局」改为
「框架汇总行」。

* 📝 记录 sctest deepEqual 对 Date/Map/Set 的已知限制

终审建议(Minor ①): deepEqual 把 Date/RegExp/Map/Set 当普通对象比较,两个不同 Date
会相等。当前迁移用例的 toEqual 均未触及这些类型,仅补注释说明契约边界,行为不变。

* 🐛 修复 SCTest 面板 CSP 注入与设计对齐

* 🐛 修复 SCTest 面板交互功能

* 🐛 固定 SCTest 的提交引用

* fix: 修正 sctest 异常判定与重跑详情清理

* 🐛 修正 GM_download 空 url 测试契约

* 🐛 include manual cases in skip filter

* 🐛 install E2E permission watcher before scripts

* 🐛 wait for permission confirmation navigation

* 📝 clarify E2E dependency scope

* 🐛 watch existing permission pages

* 🐛 avoid abort race in DNS error tests

* 🐛 make blocked download test local

* ♻️ 回退 gm_download_test / gm_menu_test 至迁移前

8/8 审查指出的两个行为回归仍未修复:
- gm_download 人工用例经 itManual 注册但从不执行动作(fn:null),
  面板可点通过/失败造成假阳性;
- gm_menu 丢失了 waitActions 的时间屏障,后续用例会改写待检查的菜单状态。

按 PR 讨论的回退方案,恢复这两个脚本迁移前的自包含实现:
- 恢复 example/tests/gm_download_test.js / gm_menu_test.js(无 @require、自带
  运行器与人工确认流程);
- 移除 e2e/gm-api.spec.ts 中依赖 sctest 面板/统一输出的 GM_download E2E 用例
  及其 @match 重写条目;共享的 sctest 本地重写与 mock server 保留(gm_xhr /
  gm_xhr_redirect 等仍在使用)。

* 📝 把 in-page self-test 一节归位到 verification-methods 并修正过期注释

合并 #1674 时只有 docs/verification.md 被 git 标成冲突,但 #1674 已把
in-page self-test 这一节拆去新建的 references/verification-methods.md,
拆出去的那份没跟着改,留下了本 PR 已推翻的描述:

- "the line varies by script" —— 12/15 脚本共用 sctest,输出一致;
- 代码块里的「总计: N | 通过: N」「Total/Passed」两种格式全树 grep 零命中;
- "matches all three layouts" —— 只剩一种;
- 缺 跳过 行、itManual、GM_log 后台通道。

docs/README.md 指明这一节归 verification-methods.md 所有,因此把内容
移过去替换过期段落(保留该文件「会话 + spec 两写」的体例),
verification.md 只留指向它的链接 —— 顺带补上 #1674 漏写的反向链接。

同时修正 gm-api.spec.ts 两处随本 PR 失效的注释:
- beforeCollect 的「B 类文件 / 真实下载副作用」——「B 类」全树无定义,
  且 GM_download E2E 已在 a6bad63 回退,现存唯一消费者是 gm_xhr_test.js;
  该套件 auto:false 的理由在脚本自身已写明,此处不复述。
- 「三行汇总里的最后一行」—— 汇总现为四行,且末行是「跳过:」。

验证:tsc/eslint/prettier 通过;vitest 78/78(sctest 66 + verification-tools 12)。

---------

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants