|
|
2 nedēļas atpakaļ | |
|---|---|---|
| .. | ||
| README.md | 2 nedēļas atpakaļ | |
| amount-floor-harness.mjs | 2 nedēļas atpakaļ | |
操作员在收银台输入
0.5,按下「收款」——那一枪会不会发出去?
「源码里写了 if (fen < MIN_FEN) return;」不是答案。这页有 8 个场景,
答案是数出来的:createCashierQr 被调了几次。
cd .claude/plan/2026-09-29-lsy-amount-floor-harness
node amount-floor-harness.mjs # 默认拿本仓的 cashier/index.vue
node amount-floor-harness.mjs <另一份 SFC 路径>
不带参数、不联网、不碰库、不写任何东西。只认最后那行 SUMMARY ——
失败也 exit 0(与同目录各台一致),别拿 exit code 当判据。
| 环节 | 真的还是假的 |
|---|---|
| SFC | 真:@vue/compiler-sfc 解析 + compileScript 编译本仓那个 index.vue |
| vue | 真:frontend/node_modules 里那份 vue(createRenderer 挂载) |
| 被驱动的函数 | 真:start() 是 setup 返回的那袋绑定里的那一个,本台直接调它 |
| 金额换算 | 真:页面的 Math.round(Number(text) * 100) 原样跑 |
| DOM | 假:createRenderer 接一套哑节点,模板不渲染(inlineTemplate: false) |
| 接口 | 假:@/api/module_payment/collection 换成记账桩(记下每次调用) |
| element-plus / qrcode | 假:可调用、可无限取属性的 Proxy |
「假」的那三样与要证的那句话无关:本台问的是有没有发那一枪,不是页面长什么样。
副作用一则:模板不渲染 ⇒ amountEl.value 是 undefined ⇒ 页面里的
amountEl.value?.focus() 是空操作。
| # | 输入(元) | 期望 | 它挡的是什么 |
|---|---|---|---|
| A | 0.5 |
不下单,提示「收款金额最低 1 元」 | 门槛外侧 |
| B | 0.99 |
不下单,同上 | 门槛内侧最后一格 |
| C | 1 |
下单 amount=100 |
门槛本身(放行侧正对照) |
| D | 1.01 |
下单 amount=101 |
门槛之上 |
| E | 0 |
不下单,提示「请先填一个大于 0 的金额」 | 旧的 fen <= 0 分支没被新闸顶掉 |
| F | "" |
不下单,同上 | 空串(Number("") 是 0,不是 NaN) |
| G | abc |
不下单,同上 | 非数字 |
| H | 0.999 |
下单 amount=100 |
四舍五入到分正好 1 元 ⇒ 放行(读数,不是缺陷) |
A/B/E/F/G 是拦下侧,C/D/H 是放行侧 —— 两侧都必须有。
只有拦下侧的话,把 start() 改成第一行 return 也能全绿。
logs/_mutate-fe-floor.txt)| 变异 | 期望 | 实读 |
|---|---|---|
MIN_FEN 100 → 0(把闸拆掉) |
必须红 | SUMMARY FAIL 场景=8 不符=2,A 变成「下单 50」、B 变成「下单 99」 |
| 只改一行注释 | 必须仍绿 | SUMMARY PASS 场景=8 不符=0 |
两条变异还原后复量 sha256,与变异前逐字节一致(e1e495e8ad5c…)。
PAYING ⇒ start() 成功后 poll() 每 3 秒自己
重排一次定时器(schedulePoll),startTicking 另有一个 1 秒 interval。8 条读数
全对、SUMMARY 也打了,进程却一直挂着。修法是每个场景后 b.stopTimers?.(),
末尾再 process.exit(0) 兜底。
★ 挂着那次是靠 Get-CimInstance Win32_Process 按命令行认出 amount-floor-harness.mjs
那个 PID 才只杀掉自己的(同机另有 codegraph / MCP / IDE 的十几个 node)。process.exit(0) 不设 exitCode。 与同目录各台一致:判据是 SUMMARY 那行,
不是退出码 —— 否则「台子崩了」与「场景不符」在 CI 里分不开。后端 LsyAmountFloor.MIN = 100(四个下单入口的 @Min)是真的闸:
开放 API 的调用方根本不经过这一页。这一页拦的是体验 ——
不拦的话操作员收到的是一句报文措辞(amount: amount 不能低于 1 元(100 分)),
而屏幕上正站着顾客。
两处的数值是同一件事写了两遍:frontend/.../cashier/index.vue 的 MIN_FEN
与 java/.../util/LsyAmountFloor.java 的 MIN。改一处必须改另一处,
两边各有测试/台子钉着(后端 LsyAmountFloorTest,前端本台)。