|
|
2 тижнів тому | |
|---|---|---|
| .. | ||
| README.md | 2 тижнів тому | |
| fe-task3-mutate.mjs | 3 тижнів тому | |
| fe-update-harness.mjs | 3 тижнів тому | |
| fe-update-keycheck.mjs | 3 тижнів тому | |
| fe-update-mutate.mjs | 3 тижнів тому | |
| lsy-keepalive-harness.mjs | 2 тижнів тому | |
| task-9-fix1-harness.mjs | 3 тижнів тому | |
这五支是验收用的:不连库、不连上游、不发任何网络请求,也不需要登录凭据。
它们直接编译真的 Vue SFC、跑 frontend/ 里那份真的 vue、驱动页面的真 setup(),
只把 @/api 与上传子组件桩掉。
来源与搬迁经过见 .claude/plan/2026-09-23-lsy-onboarding-B-交付说明.md §四 4。
本 README 的每一条命令与读数都是 2026-09-23 实跑取的,不是转述,但取自两个时点:
fe-update-harness.mjs 之外的读数,取自交付提交 20a222b;fe-update-harness.mjs 与第 3 节的 fe-task3-mutate.mjs,是在「乐收赢全流程傻瓜化」Task 3
(进件页重写成「我的商户」列表,计划见 .claude/plan/2026-09-23-lsy-simple-flow.md)里
扩写 / 新增的,读数取自该任务尚未提交的工作区:页面
frontend/src/views/module_payment/collection/onboarding/index.vue
= 58650 字节 / sha256 ef04f76615739c3712f38e874223e0fc3e0d13df76ac75afea3aca0e684d6356(LF 形态,
git ls-files --eol 实测 i/lf w/lf;CRLF 形态 60041 字节,见第 4 节)。v22.22.3。D:/project2/payment-platform 为 cwd 写。
台子内部用的是绝对路径,换 cwd 不影响结果(已实测:从 D:\ 跑同样通过)。frontend/node_modules:台子用 createRequire 指到 frontend/package.json 来加载 vue
与 @vue/compiler-sfc ⇒ 那个目录不存在时加载这一关就过不去,先 pnpm i。git status -- frontend/ 应当是干净的。第 1、2 节那三支只读,跑完仍干净;
第 3 节两台变异驱动会临时改生产文件(3a 自己还原,3b 要手动 restore)——
所以「跑完还干净」这句只对前三支成立。这两支把目标页面当命令行参数读(process.argv[2]):
PG="D:/project2/payment-platform/frontend/src/views/module_payment/collection/onboarding/index.vue"
node .claude/plan/2026-09-23-lsy-onboarding-B-harness/task-9-fix1-harness.mjs "$PG"
node .claude/plan/2026-09-23-lsy-onboarding-B-harness/fe-update-harness.mjs "$PG"
忘了传参数会怎样:立刻崩,TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string ... Received undefined
(栈顶是 compileSfc 里的 readFileSync),退出码 1。看到这个就是漏了页面路径,不是台子坏了。
SUMMARY 行两支都会在最后打一行汇总。不要看退出码:台子故意不设 process.exitCode
(fe-update-harness.mjs 第 14 行的注释就是这么写的),所以有 FAIL 也退 0;
唯一会给出非 0 退出码的情况是上面那种「参数没传」的崩溃。
所以判据是这两行里的 fail=:
SUMMARY <页面路径>: pass=25 fail=0 ← task-9-fix1-harness.mjs
SUMMARY <页面路径>: pass=89 fail=0 ← fe-update-harness.mjs(Task 3 之前是 43)
有失败时同一行会追加失败用例名:... fail=2 -> <用例名> | <用例名>。
上面两个读数都是 2026-09-23 实跑的(各 1 次,exit=0):pass=25 取自交付提交 20a222b;
pass=89 取自「傻瓜化」Task 3 的工作区(页面指纹见文首)。
★ 顺手可以把 stderr 丢掉,屏幕只剩 PASS 与 SUMMARY(实测:fe-update-harness 加 2>/dev/null 后
stdout 91 行、grep -c "Vue warn" = 0;这个行数随用例数走,43 条那会儿是 27 行)
—— 台子的告警与桩报错都在 stderr,stdout 是干净的判据流。
task-9-fix1-harness.mjs(25 条):进件页 Task 9 那处修复(商户号回显 / 警示)的判定逻辑,
含两条正对照(G4「正常商户号 ⇒ 显示出来」、G5「正常商户号 ⇒ 不置警示」)
—— 没有正对照的话「一律不显示」也会全绿。fe-update-harness.mjs(89 条):同一支台子,两批被测逻辑。原 43 条是 R-7c 的
「建号 / 更新」两个模式的报文形状 —— U. 更新腿键白名单(U1/U1b:不含 merchant_name_business)、
V. 建号腿正对照(一个都没被改坏)、W. 渲染投影、Y. 更新腿的失败与形状、
Z. 键集(Z5/Z6:更新集与建号集里都没有 category / tenant_id / rate_code)。
Task 3 新增的五段钉的是重写后新出现的判定:| 段 | 钉什么 |
|---|---|
| X. | 打开两张表单的入口 —— 新建从干净表单起步;「改资料」模式与商户号预填,但不把建号表单的值带过去 |
| P. | 进度列:四个 review_status 逐字映射,表外的值一律不猜(正对照:未知值 ⇒ 空) |
| A. | 每行恰好一个主按钮 + 至多一个文字按钮;A7 是正对照(APPROVED 没有提交审核入口)、A5 是基数闸(五档各恰好一个主按钮) |
| C. | 提交审核报文:6 个业务字段 + mch_no,空白整个省掉;12 个资质码表;大写 L 那个坑 |
| S. | 409 当成「已提交」而不是失败(S2 关弹窗、S4 常驻警示);另配一个 400 正对照,证明它认的是那个码值而不是「任何失败都当 409」 |
| L. | 列表读法要解两层 .data(响应拦截器不解包);L5 是正对照 —— 只解一层时读不到行 |
★ 台子里有一处已删的空断言(原 S3)和一处已改的脆弱写法(L2 原用 [0].mch_no),
两处的理由都写在代码注释里,别当漏做补回去。详见
.claude/plan/2026-09-23-lsy-simple-flow.md Task 3 的「变异暴露出的两条我自己的问题」。
[Vue warn]: onMounted is called when there is no active component instance...
—— 这是桩环境没有组件实例导致的,预期内,不是失败。级联数据加载失败: Error: 网络挂了),
那是故意注入的网络失败用例在走错误分支,同样不是失败。
(这两条都实测过只在 stderr:2>/dev/null 之后 stdout 里一个都没有。)node .claude/plan/2026-09-23-lsy-onboarding-B-harness/fe-update-keycheck.mjs
退出码 0 + 末行 SUMMARY keycheck: 全绿。它比对前后端两侧的字段键名集合,
确认没有拼错的键(跨端键名拼错在运行时只会表现为「字段悄悄没发出去」)。
★ 这支是五支里唯一搬过家时改过内容的一支:原先写死了兄弟台子的工作区绝对路径,
搬完就成了一个已删除的文件 ⇒ 改成按自身位置相对定位
(fileURLToPath(new URL("./fe-update-harness.mjs", import.meta.url)))。
所以它必须与 fe-update-harness.mjs 待在同一个目录里。
两台驱动形状不同,别互相套用:fe-update-mutate.mjs 是「一次一个变异 + 手动 restore」,
fe-task3-mutate.mjs 是「四轮一口气跑完 + 每轮自己还原」。
fe-task3-mutate.mjs —— Task 3 的两向变异,一条命令跑完node .claude/plan/2026-09-23-lsy-onboarding-B-harness/fe-task3-mutate.mjs
不需要参数,也不需要事后 restore:它每一轮都在 finally 里按字节还原,
还原后再复核 sha256 是否回到基线,末行还会再打一次「基线复核 sha …(未被留脏)」。
判据是最后那行:MUTATE-SUMMARY: 全绿。四个变异各自预期红的用例:
| 变异 | 打的是 | 预期该红 |
|---|---|---|
M-APPROVED-ALSO-SUBMIT |
APPROVED 那档也挂提交审核入口 | A7、A8 |
M-409-CODE-CHANGED |
把 409 换成一个表外的码值 | S2、S4 |
M-LIST-ONE-LAYER |
列表只解一层 .data |
L1、L2、L5(正对照自己也红) |
H-REORDER-DECLS |
无害:换个声明顺序 | (无,必须仍 89/0) |
最后一行那格是这台子存在的理由:没有它,「该红的都红了」也可能只是台子对任何改动都敏感。
几个会让读数作废、但驱动器自己会拦下来的情况(都会打印出来并计入非 0 退出码):
锚点命中次数 ≠ 1(说明变异打偏了,不会去改文件)、还原后 sha ≠ 基线、台子没跑完
(spawnSync ⇒ 变异把台子打崩时驱动器不跟着死,这一档单独判,不会被读成「没红 ⇒ 通过」)。
fe-update-mutate.mjs —— R-7c 的变异,需要手动还原node .claude/plan/2026-09-23-lsy-onboarding-B-harness/fe-update-mutate.mjs restore
restore:把备份 .mut-bak 还原回生产文件。没有备份时什么都不做,退出码 0。M-U1 / M-U2 / M-U3 / M-U5 / M-T1 / M-T2):会真的改生产前端文件
(frontend/src/views/module_payment/collection/onboarding/index.vue 与
frontend/src/api/module_payment/onboarding.ts),并在同目录留 .mut-bak。
跑完必须用 restore 还原,再用 git status -- frontend/ 确认干净。验收不需要跑变异。
MUTATE-SUMMARY,不用再 restore,末行会自己报「未被留脏」。git status 干净 → 变异 → 跑第 1 节的两支台子看读数变化 → restore → 再 git status 干净」的顺序。git status 该与跑前逐行相同。
(跑 3a 实测过:跑前跑后 git status --porcelain diff 无差异、git diff --cached --stat 空。)本仓 core.autocrlf = true 且没有 .gitattributes ⇒ 重新 checkout 会把工作区文件抹成 CRLF。
两种形态都实测过,不是按行数推算的(LF 即当前工作区形态):
| 文件 | LF 字节 | LF sha256 | CRLF 字节 | CRLF sha256 |
|---|---|---|---|---|
task-9-fix1-harness.mjs |
10796 | 7f07de4099c96a23c56c1238aeb002857ed8bc10c83458feab5b979cac5bc095 |
11049 | 81271e98d40456c3a594669e796ff3d49681eee9b2491bf8ba1766f09e4a362f |
fe-update-harness.mjs |
24707 | a93e0f8e4dd86340f8db29766ecc6336335e00a9b3e190e219135bb296805150 |
25189 | 17e1bd83b73123bd1a941c0f0f1cdc6396e0c513638cad47753ef86baa1ef81d |
fe-update-keycheck.mjs |
6874 | 3d4033167ed8950cda71c3396d77fe4968f70aafef915f2616193a675eba1767 |
7002 | 2e1eb43d829ea7e4aabc330c77d4a5605c4b4672a580d21ace255fbfa26325e4 |
fe-update-mutate.mjs |
4197 | a3e68dff6d58fd86a6b219c2de50f98493434bc929c544d9f77bb1af9565a330 |
4294 | fafacc0c8e41091a870054098c2de20dc46f90670890983dcd5101f9d8d65621 |
fe-task3-mutate.mjs |
6575 | 4003028451629bcbef57cf40bfc99c67e7879084640cfdf4b5cd8cfa7abb42dc |
6706 | 6640b0083e02066ebccc85d34c99064d7d2ec9af5ae85cedf9eff77228c87ddf |
被测页面(Task 3 那两行的读数钉在它的这个版本上):
| 文件 | LF 字节 | LF sha256 | CRLF 字节 | CRLF sha256 |
|---|---|---|---|---|
collection/onboarding/index.vue |
58650 | ef04f76615739c3712f38e874223e0fc3e0d13df76ac75afea3aca0e684d6356 |
60041 | 34e3cb98fd44c8835e26f79d7e3805d3a7a9b42be65fc01e5510dd12d90dfea8 |
核出 CRLF 那组数不是文件被改过,是行尾。
(上面两张表共 12 个读数,是用同一个换算脚本一次跑出来的:把读入的字节按 \r\n ↔ \n 互转后各自 sha256。
该脚本对 task-9-fix1-harness.mjs 复现出的 CRLF 值 81271e98… 与早先独立量到的一致 ⇒ 换算方式没跑偏。)
lsy-keepalive-harness.mjs —— keep-alive 组件名匹配(2026-09-28 新增)要证的一句话:<keep-alive :include> 匹配的是组件名,而 cachedViews 里放的是
路由名(= sys_menu.route_name)⇒ 两者不逐字相同时,那页的 keep_alive=true
静默失效(vue 不报错,只是不缓存;症状是「切走再切回来,筛选条件/分页/正在等的二维码全没了」)。
链路三跳(全部从源码量过,不是推的):
sys_menu.route_name → permission.store.ts 造路由时 name: item.route_name
→ tags-view.store.ts 的 addCachedView 把路由名推进 cachedViews
→ layouts/components/AppMain/index.vue:6 的 <keep-alive :include="cachedViews"> 拿它去比组件名。
node .claude/plan/2026-09-23-lsy-onboarding-B-harness/lsy-keepalive-harness.mjs \
"D:/project2/payment-platform/frontend/src/views/module_payment/collection/order/index.vue" order \
[可选的 include 覆盖值]
编真 SFC(@vue/compiler-sfc)、用 frontend/node_modules 里那份真 vue 挂进真
<keep-alive>,数 setup() 跑了几次 —— 缓存命中后再激活不会重跑 setup。
一次跑给两向读数:include=[本页真名] 期望 1;include=[必然不匹配的串] 期望 2(正对照,
没有它,setups=1 也可能只是计数器没在工作)。
五个页面各自自比,5/5 PASS(hit=1 miss=2):
| 页面 | 组件名(修后) | 活库 route_name |
|---|---|---|
collection/order |
CollectionOrder |
CollectionOrder(id=269) |
collection/refund |
CollectionRefund |
CollectionRefund(id=270) |
collection/merchant |
CollectionMerchant |
CollectionMerchant(id=271) |
collection/cashier |
CollectionCashier |
CollectionCashier |
collection/onboarding |
CollectionOnboarding |
CollectionOnboarding(id=272) |
活库那一列取自 lsy-cashier-menu.sql 头部记的 2026-09-23 只读实测(id 269–272)。
★ 前三个页面在 2026-09-28 之前写的是 Leshouying*(lsy-menu-rename.sql 把库从
Leshouying* 改成 Collection* 时,SFC 的 name 没跟着改)—— 即三个页面的 keep_alive 一直是失效的。
lsy-cashier-menu.sql:32-40 早记过这条,当时按「不相关的不动」留下未修。
变异(两向的另一半):把 order 页的 name 改回 LeshouyingOrder,include 仍喂
CollectionOrder ⇒ SUMMARY FAIL hit=2 miss=2(不缓存)。这证明上面那些 PASS 是
行为差别,不是文字差别。还原后 git status -- frontend/ 只剩那三个待提交文件。
inlineTemplate: false)⇒ 它证明的是缓存语义,不是浏览器里长什么样。createRenderer 接一套哑节点操作,不引 jsdom。有的页面 onMounted 会碰 window
(如 cashier 页),台子里有一行 globalThis.window = globalThis 的垫片 ——
★ 那是台子的垫片,不是页面的缺陷,别去改页面。@/api/* 与 element-plus 都换成「取什么都是可调用、返回 Promise」的代理)
⇒ 它验不到任何接口契约。残留 import 会被一句兜底断言当场炸掉,不会悄悄跑出假绿
(实测:qrcode 与 SingleImageUpload 两条就是这么被发现并补上的)。process.exitCode(与同目录各台一致)⇒ 失败也退 0,只认最后那行 SUMMARY。| 文件 | LF 字节 | LF sha256 | CRLF 字节 | CRLF sha256 |
|---|---|---|---|---|
lsy-keepalive-harness.mjs |
7718 | 2d5a9c9a677dafd1d57d84eae6e0afc8d11ce7526d0aae2e66dffa15327c7571 |
7888 | cd97a29a36877aeb88656b2271d232e960850f7cc3c94329b256ed009a04d1fe |
collection/order/index.vue |
10531 | 66b144354bb612081aeca65ef54b002c194f29ec2eab5d840fea7fa6ea7b9700 |
10789 | 1559fbb99ad173c7995f5491dfdd96def53b8b894dfc38fcb41ea30e73ef315a |
collection/refund/index.vue |
4720 | 0a6c782061522baad7a97a794f51f78b214bcf960141aed6546e8a8291322b2b |
4860 | 1c00b8b0f89f46adaf8d0a64999817415c16194bf2e5fe8218d3a72493df5ea7 |
collection/merchant/index.vue |
11178 | 2df3a00d5440b08487cd409d9923b72dd76fa5659fc75a436e4e900ebcb449b6 |
11431 | bebaac71b14e2c331d32c96d7d55d83fbc255b8a9b4233307891bf1a3ab60942 |
三个 .vue 的 git ls-files --eol 实测 i/lf w/crlf(工作区即 CRLF 形态);
.mjs 是 2026-09-28 新写的,工作区当前是 LF(CR 数 0)—— 提交后随 core.autocrlf=true 会变 CRLF。