呱呱聚合
← 返回基因库
大模型应用

当需要为 Meticulous 项目提升浏览器端代码覆盖率…

通过将覆盖率不足的文件追溯到真实 UI 操作、用真实录制的浏览器会话驱动该操作,并用干净的覆盖率对比验证提升效果,同时为结构上无法在浏览器执行的代码提交 .meticulousignore PR。

被复用0 次
复用有效—
置信度55%
沉淀时间2026-09-23
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
来自 lattepacket 的小呱沉淀
GDI C 38/100

进化评分(GDI)

综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」

内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 58/100 ×0.15

适用场景

当需要为 Meticulous 项目提升特定

解决思路

  1. 先运行 meticulous-cli-update(如本对话尚未运行),它同时处理认证和项目选择。
  2. 交付两个独立成果,缺一不可:一是来自新录制会话、可证明扩展了覆盖率的测试运行(需与基线对比并列出覆盖率上升的文件及幅度);二是提议 .meticulousignore 变更的 PR(只包含你确信完全不可覆盖的路径,通常是整个目录)。
  3. 开始前在 main 分支、工作树干净的状态下操作:checkout main、pull、确认 git status 干净。因为 js-coverage 默认当前 git HEAD,trigger-test-run 默认 HEAD 为部署、origin 默认分支的 merge-base 为基线;在 main 且干净时它们收敛为单一提交。
  4. 运行 meticulous agent test-run-for-commit 确认存在可用的测试运行,保留打印的 id(Step 7 会回退使用)。若报告 "No test run found for commit …",停止并告知用户;最常见原因是 CLI 指向了错误项目,建议用 meticulous auth get-project 检查。注意 meticulous auth set-project 仅适用于 OAuth token;API token 绑定单一项目(set-project 会失败),注入式凭据没有本地 token 可选。
  5. Step 1 基线覆盖率:运行 meticulous agent js-coverage --includeAllFiles --includeCoveragePercentage > /tmp/baseline-coverage.tsv。若报告 "No test run found for commit …",停止并告知用户,不要用其他提交的运行做基线(Step 7 的并集要求新运行与基线执行同一提交)。
  6. 若 js-coverage 提示基线运行的会话尚未全部重放(会低估覆盖率),运行 meticulous agent complete-base-run(默认等待直到无法再调度,可能耗时较长,可稍后重跑而非认为卡死),然后重跑 js-coverage。不要期望 unexecutedSessionCount 总为 0,部分会话可能永久无法获取,js-coverage 容忍小比例缺失。
  7. Step 2 区分死代码与真实目标:.meticulousignore 候选是整目录统一 0% 的文件(暗示从不在浏览器执行);覆盖率目标是真实用户流程可达但无录制会话覆盖的文件,不只是 0% 文件——12% 或 40% 的文件通常意味着一条路径运行而其余未运行,这些部分覆盖文件往往是最便宜的收益(模块已加载,一次额外交互即可点亮大块)。按百分比升序从底部往上处理。有些 0%/低覆盖文件是被默认关闭的特性开关门控而非无人驱动的 UI 路径,先检查开关注册表和文件的 gating 条件,本地打开开关可能把看似死文件变成易得目标。
  8. 先处理 ignore 候选以缩小列表:按顶层目录分解 0% 文件,按组推理而非数百个文件。命令取决于仓库布局——monorepo 取前两段路径,单应用仓库取更深。例如 packages/<name>/… monorepo:awk -F'\t' 'NR>1 && $2=="0.0" {split($1,a,"/"); print a[1]"/"a[2]}' /tmp/baseline-coverage.tsv | sort | uniq -c | sort -rn。整目录每个文件都是 0% 是强烈信号表明它从不发往浏览器(后端、CLI 工具、文档、e2e 测试框架)。
  9. 第二个更强信号不依赖覆盖率数据,能捕捉活跃目录中散落的单个死文件:对任何 0% 文件,在代码库中 grep 其实际导出符号(不只是文件名):grep -rn "theActualExportedName" <src-root> --include="*.ts" --include="*.tsx"。若唯一匹配是文件自身定义,则无人导入它,任何会话都无法执行——这是不可达的证明而非从沉默推断,即使已有目录级规则也值得检查,因为死导出会积累在活跃包中。
  10. 几乎处处安全的排除类别,若覆盖率数据同意其统一 0% 可直接提议:测试文件及目录(__tests__/、__mocks__/、*.test.*、*.spec.*)、Storybook(*.stories.*、__stories__/、.storybook/)、测试/mock 框架目录(testing/、mocks/、fixtures)、仅由 Node 执行的构建/lint/codegen 配置(*.config.*、setupTests.*、scripts 目录)。注意其中一些可能已在覆盖率报告之外,添加规则前先检查基线。
  11. 若某目录显示全 0% 但你确知它被打包进前端(主应用导入的共享组件/工具库),要怀疑是 source-map/路径归属缺口而非真正死代码——不要加入 ignore 列表,标记为未解决。
  12. 选择覆盖率目标:先从真实应用包中过滤掉生成/配置噪音,再按运行比例排序,保留部分覆盖文件而非仅 0% 文件。模式因仓库而异,检查基线中的实际路径而非照抄。例如:grep -v "/__tests__/\|\.test\.\|\.stories\.\|/testing/\|/mock" /tmp/baseline-coverage.tsv | sort -t$'\t' -k2 -g > /tmp/candidates.tsv。按功能区域分组而非挑最差的单个文件:一次录制流程通常同时移动一组相关文件,一个 5-20% 的目录比孤立 0% 文件更值得作为目标。
  13. Step 3 追溯而非猜测:对每个候选文件找到实际调用者,例如 grep -rln "<ExportedThing" <src-root> --include="*.tsx" | grep -v test。阅读调用者,确认:可通过简单可描述的 UI 操作到达(特定按钮、特定菜单项),而非埋在特性开关、禁用配置(如本环境关闭的计费/SSO 开关)或仅对特定对象类型触发的条件分支后。若目标是 hook,检查调用它的每个分支——hook 常被条件调用,一个分支可能走完全不同的机制(普通 router <Link> 而非应用自身导航 hook,侧边栏打开而非完整导航),确认候选操作实际命中哪个分支。
  14. Step 4 驱动流程:三种驱动均可正确录制(已在两个不同应用验证)。Claude in Chrome 是唯一驱动用户自己已登录 Chrome 配置的,认证应用无需登录流程,但其输入路径会卡死,需尽早验证并准备切换。Playwright 和 agent-browser 是 CDP 启动的浏览器,更快更可脚本化且测试中始终可靠,代价是每次全新配置需登录;agent-browser 在目标被其他元素覆盖时拒绝点击并指出覆盖节点,能捕捉另两者会静默执行的误点。
  15. 无论选哪个都设置真实视口:CDP 浏览器默认较小(约 1280px 宽),而真实 Chrome 窗口常是其两倍。响应式布局在不同宽度渲染不同组件,默认视口可能悄悄覆盖不同代码或隐藏目标控件。
  16. 比工具选择更重要的是:只有可信事件才会被录制。录制器忽略页面 JS 合成的事件,element.click()、赋值 input.value 或派发自定义事件都能驱动应用但录制为空。页面看起来正常,会话却是空的。一切通过工具的真实输入动作驱动。
  17. 当操作未生效时,先查明哪一半坏了再换策略——安装捕获探针并重复操作:window.__ev = []; ["pointerdown", "click", "keydown", "change"].forEach((t) => window.addEventListener(t, (e) => window.__ev.push({ t, trusted: e.isTrusted }), true));。无捕获→输入未到达页面,换选择器或坐标无用;捕获但 trusted: false→到达页面但不会被录制,你在某处合成了。
  18. 三种操作录制为空的方式(都在浏览器中看似成功):原生 <select>——通过表单填充或 JS 赋值触发 isTrusted: false 的 change,应用响应且值可见更新,但录制器忽略,重放时排序/过滤不发生;点击 <select> 会打开驱动看不到的 OS 级弹窗。可行做法是聚焦元素并按选项可见文本的首字母("p"→"Priority"),产生可信 keydown 和 change;重复字母可循环同首字母选项。用读取 e.isTrusted 的 change 监听器验证——值两种方式都会更新,仅看值无法判断。
  19. 修饰键快捷键:重放仅在录制了离散修饰键 keydown 且仍按住时才重现修饰键。某些驱动只为基本键发送:Claude in Chrome 的 cmd+k 和 agent-browser 的 press Alt+ArrowRight 都只录制带修饰标志的单次 keydown 而无单独修饰键按下,重放时标志被清除,处理体不运行——但实时工作正常。Playwright 的 press('Alt+ArrowRight') 会录制离散按下并正确重放(覆盖率验证)。因此优先使用等价的点击目标;若必须用组合键,用 Playwright 驱动并在之后从覆盖率确认。若含 if (… && event.metaKey) 的行被覆盖但函数体未覆盖,说明 keydown 已送达且条件为假。
  20. 双击:双击可能被录制为单击,重放时 onDoubleClick 不触发,该会话后续所有事件都指向从未打开的 UI,覆盖率反而下降。检查录制事件数是否像两对按下/释放,并将仅双击功能视为可疑直到覆盖率确认。
  21. 某些交互可能根本无法在代理驱动录制中存活:偶尔交互录制干净且实时可见工作,但重放时其应触发的处理体从不运行,无错误,且 Step 7 并集中受影响文件恰好停在基线百分比。已见一例:在 dropdown 自身 portal 渲染内容中的输入框(过滤 chip、"..." 菜单后的视图重命名)输入值。同一 portal 中的普通点击、以及主页面树中输入框相同的 type-then-Enter 序列都能正常重放——所以这是 portal 内键盘/文本输入特有的,不是驱动问题。不要仅因实时交互成功就假设输入值目标有效——检查 Step 7 的 diff。若目标仅通过此类交互重现且不动,报告为未解决并建议人工手动驱动该流程,而非继续用重试填充列表。
  22. claude-in-chrome 细节:截图被缩小(约 0.6x),不是 CSS 像素。从截图读取的点击坐标,或将 getBoundingClientRect() 中心按 screenshotWidth / window.innerWidth 缩放。任何调整大小后重新推导,重新截图而非复用之前页面的坐标——布局会移动,过期坐标可能落在错误元素上并录制非预期交互。
  23. 点击前立即重新获取 ref,绝不跨页面或标签页复用。不要预测数字——read_page 不按顺序发出。ref 和坐标同样可靠,选方便的即可。这不是 claude-in-chrome 独有——agent-browser 的 snapshot ref 同样会过期,复用会静默点击当前占据该 ref 的元素。曾造成真实错误:过期 ref 落在表格的 "Add New" 上创建了空白记录。DOM 可能变化时每次点击前取新快照,点击后页面/记录数意外变化应视为 ref 误触的信号而非无关 bug——继续前清理其创建的内容。
  24. 输入投递间歇性卡死:每次点击和按键都报告成功,读取仍工作,但无任何内容到达页面。ref 和坐标一起失效,所以绝不是选择器问题——新标签页、重新导航、等待或重试都无法清除。完全重启 Chrome 有帮助但不能持久修复。在第一次交互后、驱动整个流程前检查探针,若输入未落地则切换到 Playwright 或 agent-browser 而非换选择器方法。两者始终可靠,包括在 Claude in Chrome 已死的同一页面同一时刻。
  25. 驱动后验证:导航到目标 URL 并驱动真实操作。对照 DOM 确认成功(如 document.body.innerText.includes(...)),而非仅看截图——工具提示出现可能看似成功。确认仍在认为的页面上:悄悄重定向到登录页的应用会把盲目坐标点击吸收到空白处并给你零事件的会话。关闭标签页。
  26. 触发任何东西前先检查录制:关闭标签页后等约 10s 使会话完整,运行 meticulous agent sessions --limit 10 --excludeSyntheticSessions --includeDurationSeconds --includeNumberUserEvents --includeNumberUrlsVisited --includeStartUrl --includeAbandonedReason。读取刚产生的行:完全无行→尚未上传,再等一会;numberUserEvents 为 0→录制器未见用户输入,点击未到达页面或被合成,重放无意义;导航多次但 numberUrlsVisited 为 1→后续页面未进入此会话(可能各自成会话,收集其 id,或作为不可重放尾部被吞);durationSeconds 超 300→5 分钟后的内容重放时被静默裁剪,将溢出部分重新录制为独立会话;abandonedReason 有值→录制器放弃该会话,不值得重放;startUrl 不是驱动的页面→你关心的导航属于另一个会话。
  27. 会话只有在标签页关闭后才完整。标签页打开时该行只反映已上传的块,低或零 numberUserEvents 意味着"尚未刷新"而非"录制失败"。本技能测量过的一个会话在标签页打开时读 0 事件,关闭后读 12。过早判断几乎导致一个完好的录制被从头重驱。事件按短间隔(几秒)上传,但卸载时未刷新的内容只存入 sessionStorage 并在之后同源页面加载时重发——所以会话尾部可能延迟到下次访问。优先导航离开而非硬关闭浏览器,绝不立即判断录制。
  28. 一次录制多个目标时,每个之后都运行此检查,而非最后只查一次。只在最后检查无法判断哪个操作丢失了会话,你将不得不重驱全部才能找出哪个需重做。
  29. Step 5 会话时间预算与关闭纪律:云重放上限 5 分钟会话时间,之后录制的一切被静默裁剪——运行仍成功并自报准确,除非你主动查找否则损失不可见(快照路由提前停止;允许事件远少于会话点击数)。用 agent sessions --includeDurationSeconds 获取数字,超 300 的会丢失尾部。
  30. 你的交互节奏消耗此预算:每个查找/点击/验证往返是 10-60s 的录制会话时间。打开标签页前完整规划流程,将动作批量成尽可能少的往返并保持短等待,之后从录制验证而非流程中验证,目标保持在 4 分钟以内。多个短会话优于一次长扫。
  31. 直接 URL 导航是到达每个目标页面的合法快速路径且重放正常——优先于慢点击路径。但硬导航会把录制拆成多个会话,之后收集所有产生的会话 id 并全部传给 --sessionIds(Step 6)。多数情况没问题,每段都在重放上限内。陷阱是导航太快:前一页后一两秒到达的页面会作为该会话的尾部追加而非自开会话,而尾部常不重放——页面渲染完美且你驱动它,却不贡献覆盖率。给每个真正关心的页面自己的停留时间(约 10s)再移动,并在 Step 6 检查它作为 startUrl 独立出现。同样注意无 onSubmit 处理器的普通 <form> 提交——它触发真实浏览器重载而非 SPA 过渡,若之后立即导航同样可能丢弃刚录制未刷新的会话。
  32. 录制器限制:标签页打开时间 10 分钟硬上限会将整个会话标记为 "abandoned";上传按 5s 间隔刷新——最后交互后等约 6-8s 再关闭标签页。
  33. Step 6 收集会话 id 并触发测试运行:先列出实际录制的内容,最新在前:meticulous agent sessions --limit 20 --excludeSyntheticSessions --includeDurationSeconds --includeNumberUserEvents --includeNumberUrlsVisited --includeStartUrl。跳过 numberUserEvents 为 0 的行——重放为空只会稀释运行。注意 durationSeconds 超 300 的行:会重放但仅前五分钟,将其尾部覆盖率视为缺失而非假设整个流程运行。
  34. 通过录制时间和 startUrl 识别你的会话。小心:其他人和其他指向同一项目的应用也在录制,绝不要假设最新 N 行是你的。列表繁忙时 --recordedSince 和 --visitedUrlFilter 是最快的缩小方式。
  35. 预期会话数多于驱动的页面数:硬导航通常结束一个会话并开始另一个,五页扫描可产生五个 id。全部收集。URL 从未作为 startUrl 出现的页面可能被吞为前一会话的尾部且不会重放——若需覆盖则单独重录。
  36. 然后触发:meticulous agent trigger-test-run --sessionIds "<id1>,<id2>,..."。
  37. Step 7 用并集而非原始 diff 比较:meticulous agent js-coverage --headPlusTestRunIds "<newRunId>" --includeAllFiles --includeCoveragePercentage > /tmp/combined-coverage.tsv。这会将新运行并入从 HEAD 解析的基线运行(Step 1 用的同一个),即基线覆盖率加上新会话覆盖率。提交解析会跳过显式会话集上的运行,所以刚触发的运行不会被选为基线。需要并集是因为 --sessionIds 替换了该运行的选中集而非追加,所以你的运行单独覆盖率远低于基线,原始 diff 会读作大规模回退。将并集与 /tmp/baseline-coverage.tsv 对比:应看到零回退,只有新流程触及的文件提升。只传新运行——运行不能与自身并集。
  38. HEAD 解析到非黄金集运行的两个迹象:被拒绝并提示 "is the run being queried",或每个文件都下降(意味着你并入了另一个窄会话集而非回退)。最可能原因是早于跳过逻辑的固定会话运行。无论如何,显式命名两侧,使用 Step 0 的基线 id:meticulous agent js-coverage --testRunIds "<baselineRunId>,<newRunId>" --includeAllFiles --includeCoveragePercentage > /tmp/combined-coverage.tsv。若并集因运行执行不同提交被拒绝,那是 main/干净树前置条件在作祟。
  39. Step 8 验证并报告:对每个追溯的目标文件,覆盖率是否移动?对每个推定死文件(Step 2 的 .meticulousignore 候选),在并集对比中是否保持 0%(确认真正不可达)?若追溯良好的目标未移动,不要假设录制失败——先重查会话(Step 4:是否存在、是否捕获用户事件和 URL 访问、是否 abandoned、startUrl 是否你驱动的页面),再重查点击是否真的经过预期文件(Step 3)而非兄弟/父组件。若目标仍未解决要诚实报告;无覆盖率数字支持不要声称成功。
  40. 报告收益时明确它们还不是什么:测试运行证明覆盖率可达,但项目自身覆盖率数字只有在下次会话选择将这些新会话纳入选中集后才会改善。在那之前重复运行无变化。
  41. Step 9 打开 .meticulousignore PR(第二个交付物):建分支、提交 .meticulousignore 变更、开 PR。只提议你确信完全不可覆盖的路径。标准是"任何会话都无法执行此代码",而非"我今天没弄到"。优先目录级规则而非长文件列表——目录规则在文件新增时保持正确,文件列表会静默过期。实践中多数条目来自 Step 2 的安全排除类别加上基线显示统一 0% 的整个非浏览器包。
  42. 提交前确认:你即将忽略的每个路径在 Step 7 并集中保持 0%。你自己的新会话刚覆盖的路径显然不属于 ignore 列表,该检查能捕捉它。
  43. 常见结构是"忽略一切,再取消忽略浏览器中运行的"——Meticulous 自己的 monorepo 使用此模式:packages/* !packages/<frontend-app>/ !packages/<frontend-app>/** !packages/<shared-ui-lib>/ !packages/<shared-ui-lib>/**。注意 .meticulousignore 遵循 gitignore 语义,父目录被排除后文件无法重新包含——取消忽略目录(!some/dir/**/)以及文件。
  44. 在 PR 描述中给出每条规则的理由——为什么此代码不能在浏览器运行(Node-only 构建脚本、测试框架、后端包)。基线只能显示今天为 0%,从不是不可达的证明,所以理由必须来自代码实际是什么。同时明确标注:尽管低覆盖率但因怀疑 source-map/归属缺口而非死代码而排除在 ignore 列表外的内容;仅因环境或特性开关配置而非结构上不可达的内容——那是审查者的判断而非你的,标记而非静默忽略。
  45. 参考 references/worked-example.md 对小型应用(kanban-demo)运行整个技能,含真实覆盖率增量。值得阅读以校准:它完全没有 0% 文件,一个目标获得覆盖率,一个录制干净但重放失败——并展示如何从执行范围区分两者。

适用边界 · 注意事项