Appearance
修复购物车负金额:先复现,再改代码
商品总额 10 元,优惠券 15 元,购物车却显示应付 -5 元。问题不大,却很适合做第一次 AI 修复练习:结果对不对,你不用读懂整个项目就能判断。
如果你还没有完成安装登录,先读完整入门实战。本页是同一题的精简配方,适合已有环境的读者,不必两篇重复做。
这次你会先看见两项测试失败,再让 Codex 修改计算逻辑,最后亲自检查五项测试全部通过。重点不是记住一行修复代码,而是知道怎样判断“修好了”。
1. 先看修好后应该是什么样
适合已经能打开 Codex 工作目录、能运行 Node.js 命令的读者。重点是检查 AI 修复是否真的有效。
输入是一段虚构的购物车代码:金额以整数分计价,优惠不能让应付金额小于零。输出是修复后的 cart.mjs、未被改动的测试,以及可解释的 diff。
- ① 复现错误应付 −5 元
3 通过 / 2 失败 - ② 只改计算逻辑应付最低为零
测试文件保持不变 - ③ 重新运行测试应付 0 元
5 通过 / 0 失败
这是教学练习,不是可直接接入支付系统的金额库。输入限定为合法非负整数,不覆盖校验、退款、税费与运费。
2. 下载代码,重现失败
命令以 macOS 终端为例,需要 Node.js 和可用的 Codex 登录。不要求安装 MCP 或全局 Skill。
创建一个空目录,将以下三个链接的文件保存进去,保持文件名:
若浏览器直接显示文本,使用“另存为”保存为对应文件名,不要保存成网页。已安装 Node.js 的读者可先检查环境,再在该目录执行:
bash
node --version
node --test cart.test.mjs预期是 3 个通过、2 个失败。先别急着修环境:这里报错才说明你重现了题目中的 Bug。 找到下面两条失败记录;不同 Node.js 版本的符号和排版可能不同。
| 失败测试 | 实际值(actual) | 预期值(expected) |
|---|---|---|
| 优惠超过小计时不能出现负数 | -500 | 0 |
| 空购物车使用优惠后仍为零 | -100 | 0 |
两项失败都指向一个规则:减完优惠后没有守住零下限。如果一开始全部通过,确认下载的是原始文件,而不是参考答案。
现在就保存修改前的基线,不要等修复后再做。 在 Finder 中复制整个练习文件夹,作为原始副本。完成后用编辑器比较两个目录的 cart.mjs 与 cart.test.mjs。
已经会用 Git?可用提交代替文件夹副本
在这个专门的新目录执行以下命令;不要在已有生产仓库重新初始化,不要把私人文件一起加入:
bash
git init
git add cart.mjs cart.test.mjs TASK.md
git commit -m "保存练习原始输入"提交若提示缺少身份,先按 Git 提示配置自己的身份,或改用文件夹副本。本练习不要求修改全局 Git 配置。
3. 确认工作目录
不需要额外配置,也不需要 package.json。使用 Node.js 自带测试运行器;三个输入文件应位于同一目录。不要把参考答案替换进输入后再让 Codex“寻找问题”。
text
你的练习目录/
├── cart.mjs ← 允许修改的计算逻辑
├── cart.test.mjs ← 保持不变的测试
└── TASK.md ← 本题业务规则4. 让 Codex 修复计算逻辑
如果上一课使用了只读会话,不要在其中继续要求修改。另开系统终端,进入新的购物车练习目录,用 pwd 和 ls 确认文件,再启动允许工作区写入的会话:
bash
codex --sandbox workspace-write --ask-for-approval on-request只授权这个教学目录;审批时检查具体请求,不选择全盘访问或绕过审批。然后在 Codex 对话中发送:
text
请读取 TASK.md 和购物车源码,先运行 node --test cart.test.mjs 复现问题。
解释失败原因,仅修改 cart.mjs 修复优惠导致负金额的问题,不修改测试。
重新运行全部测试,输出实际测试结果、修复 diff 和没有覆盖的边界。看执行过程,不只等最后一句“完成”
留意它是否读取了题目文件、运行了测试,然后才修改 cart.mjs。如果出现命令审批,检查是否仍在练习目录、是否与测试和修复有关;不要批准无关安装或全盘访问。
如果它只给出一段建议代码,没有修改文件,继续说:
text
请把修复应用到当前目录的 cart.mjs,不修改 cart.test.mjs。
完成后运行 node --test cart.test.mjs,给出实际结果。
若受权限限制无法执行,请指出卡在哪一步。如果它同时重写测试或添加新依赖,先要求停止扩展,查看差异,保留自己需要的改动,再恢复本题固定测试。不要用“测试变绿”掩盖题目已经被换掉。
先做完下一步检查,再展开参考修复。
参考修复:为什么限制在零以上
关键修复为:
diff
- return items.reduce((sum, item) => sum + item.priceCents * item.quantity, 0) - discountCents;
+ const subtotal = items.reduce((sum, item) => sum + item.priceCents * item.quantity, 0);
+ return Math.max(0, subtotal - discountCents);这项修复对应题目明确规定的金额下限。真实业务若有负余额、退款等需求,需要另行定义规则,不能机械套用。
5. 检查测试和代码差异
回到另一个系统终端,进入同一练习目录,再运行:
bash
node --test cart.test.mjs你应该看到 5 个通过、0 个失败。五项测试分别检查:普通汇总、正常扣优惠、优惠等于小计、优惠超过小计、空购物车。后两项由失败变为通过,前三项仍然通过,才是这道题想要的结果。
接着用编辑器比较原始副本和当前文件。diff 就是修改前后的差异。你需要看到金额计算变了,cart.test.mjs 完全没变,也没有新引入支付接口或依赖。
为什么两件事都要做?测试说明既定行为符合要求;diff 帮你发现“为了过测试,偷偷改了题目”或不必要的额外修改。
选做:用 Git 看差异,再做一次代码审查
若之前建立了 Git 基线,在系统终端检查:
bash
git diff -- cart.mjs cart.test.mjs
node --test cart.test.mjscart.test.mjs 应没有差异。金额下限应在 cart.mjs 修复;不能把期望结果改成负数让测试“变绿”。
review(选做) 是额外代码审查,不是测试替代品。已建立 Git 基线的读者,可在 CLI 对话中输入 /review,选择未提交变更;这不是终端 shell 命令。其他审查方式见文末官方说明。即使审查说没有发现问题,也不等于生产安全保证。
可以要求审查聚焦:“检查这次修改是否改变普通优惠行为、是否遗漏空购物车、是否改动测试掩盖问题。”每条发现仍需你回到代码和测试核实。
结果不对时,从这里查
- 找不到文件:先确认终端当前目录和文件扩展名,避免保存成
.txt。 - 运行器不支持:核对 Node.js 版本;本文没有验证所有历史版本。
- Codex 修改测试让它通过:拒绝这次结果,恢复下载的固定测试后重新修复源码。
- 全部通过仍不代表生产可用:本题未覆盖非法输入、整数溢出、多币种、并发或支付状态。
换成你自己的 Bug,保留这四样东西
把示例中的文件和命令换成实际项目的:复现输入、实际与预期结果、允许修改范围、回归检查方式。没有现成测试时,先要求把复现步骤固定下来;别一开始就说“帮我全面优化”。
例如“点击保存后刷新,内容丢失”,应先固定保存与刷新步骤,再查写入逻辑,最后用同样步骤复查。金额题中的 Math.max 用不上了,但这条修复顺序仍然适用。
6. 参考代码与资料
- 修复后参考实现:与原始输入区分保存;需要运行时将其命名为
cart.mjs。 - Node.js 测试运行器
- Codex Best practices
- CLI Code review
