129 lines
5.5 KiB
Markdown
129 lines
5.5 KiB
Markdown
# Function 测试审计(2026-04-14)
|
||
|
||
补充更新:
|
||
|
||
- 本文记录的 2 个 bug 已在同日完成代码修复。
|
||
- 对应测试已经从“稳定复现旧行为”切换为“验证修复后行为”。
|
||
|
||
## 1. 本次新增测试
|
||
|
||
本轮新增了两组 function 相关测试:
|
||
|
||
- `src/data/stateFunctions.test.ts`
|
||
- 覆盖 state function 的运行时过滤、优先级、选项解析、排序逻辑。
|
||
- `src/data/functionCatalog/functionCatalog.test.ts`
|
||
- 覆盖 function 文档映射、flow helper、NPC helper modal 初始化逻辑。
|
||
|
||
这两组测试都直接挂在现有 `vitest` 体系里,没有新建独立测试框架。
|
||
|
||
## 2. 本次执行结果
|
||
|
||
本轮实际执行了以下测试:
|
||
|
||
```bash
|
||
npx vitest run src/data/stateFunctions.test.ts src/data/functionCatalog/functionCatalog.test.ts
|
||
npx vitest run src/data/npcInteractions.test.ts src/hooks/story/storyGenerationState.test.ts src/services/runtimeStoryService.test.ts
|
||
```
|
||
|
||
执行结果:
|
||
|
||
- 新增测试:`2` 个文件,`12` 条测试,全部通过。
|
||
- 复跑已有 function 相关测试:`3` 个文件,`17` 条测试,全部通过。
|
||
- 修复回归测试:`5` 个文件,`30` 条测试,全部通过。
|
||
- 编码检查:`1516` 个文件全部通过。
|
||
|
||
说明:
|
||
|
||
- 本轮不是“测试全绿就代表没有问题”。
|
||
- 最初定位出的 2 个问题,已经在后续修复回合里转成了回归测试。
|
||
|
||
## 3. 历史 bug 与修复结果
|
||
|
||
### 3.1 `battle_recover_breath`
|
||
|
||
- 所在位置:`src/data/stateFunctions.ts`
|
||
- 状态:已修复
|
||
- 原始问题表现:
|
||
- 当 `inBattle = true`,但当前没有存活敌人时,`battle_recover_breath` 仍会留在可执行 function 列表中。
|
||
- 直接原因:
|
||
- `matchesCategory` 对 `recovery` 分类只判断了是否处于战斗态,没有像 `battle` / `escape` 分类那样额外校验 `hasAliveMonsters(context.monsters)`。
|
||
- 修复方式:
|
||
- 已在 `matchesCategory` 的 `recovery` 分支中,为战斗恢复类 function 补上 `hasAliveMonsters(context.monsters)` 判断。
|
||
- 修复前影响:
|
||
- 在“敌人已死但战斗态尚未清理干净”的边界帧里,界面仍可能出现战斗恢复类选项。
|
||
- 这会让 function 池和真实战斗状态产生残留错位。
|
||
- 当前验证方式:
|
||
- `inBattle = true`
|
||
- `monsters = [{ hp: 0, ... }]`
|
||
- 调用 `getExecutableFunctions(context)`
|
||
- 现在返回结果应为空,不再包含 `battle_recover_breath`
|
||
- 对应用例:
|
||
- `src/data/stateFunctions.test.ts`
|
||
- 用例名:`removes battle_recover_breath when combat has no living monsters`
|
||
|
||
### 3.2 `npc_trade`
|
||
|
||
- 所在位置:`src/data/functionCatalog/npc/npcTrade.ts`
|
||
- 状态:已修复
|
||
- 原始问题表现:
|
||
- trade modal 初始化时,`selectedPlayerItemId` 直接取 `state.playerInventory[0]?.id`。
|
||
- 如果玩家背包第一项数量为 `0`,modal 默认会选中一件不可出售物品。
|
||
- 直接原因:
|
||
- `buildNpcTradeModalState` 没有过滤 `quantity <= 0` 的物品,也没有寻找第一个可交易物品。
|
||
- 修复方式:
|
||
- 已改为优先选择 `quantity > 0` 的可交易物品。
|
||
- 同时对 NPC 库存和玩家背包都使用同一条筛选规则,避免默认选中空物品。
|
||
- 修复前影响:
|
||
- 交易面板第一次打开时,默认状态可能就是不可确认的。
|
||
- 用户需要手动切换到第二件物品,才会进入可提交状态。
|
||
- 当前验证方式:
|
||
- `playerInventory[0].quantity = 0`
|
||
- `playerInventory[1].quantity > 0`
|
||
- 调用 `buildNpcTradeModalState(...)`
|
||
- 现在 `selectedPlayerItemId` 应该自动落到第一件可交易物品
|
||
- 对应用例:
|
||
- `src/data/functionCatalog/functionCatalog.test.ts`
|
||
- 用例名:`prefers the first tradable player item when zero-quantity items exist`
|
||
- `src/hooks/story/storyGenerationState.test.ts`
|
||
- 用例名:`skips zero-quantity player items when opening the trade modal`
|
||
|
||
## 4. 本轮已验证通过的 function 能力
|
||
|
||
以下内容本轮已通过测试验证,没有发现新的明显问题:
|
||
|
||
- state function runtime 构建:
|
||
- `idle_follow_clue` 已正确从运行时候选池移除。
|
||
- `idle_explore_forward` 的运行时文案覆盖仍然生效。
|
||
- state function 选项行为:
|
||
- 高压战斗下 `battle_recover_breath` 会被正确提权。
|
||
- 营地场景会正确隐藏 `idle_explore_forward`。
|
||
- `idle_travel_next_scene` 会强制使用运行时建议 actionText。
|
||
- `battle_all_in_crush` 会保留外部传入的自定义 actionText。
|
||
- story option 排序仍保持“前 2 个 model 锁定 + 后续按 priority 排序”。
|
||
- flow helper:
|
||
- `story_continue_adventure`
|
||
- `camp_travel_home_scene`
|
||
- NPC helper:
|
||
- `npc_preview_talk`
|
||
- `npc_gift`
|
||
- `npc_recruit`
|
||
- 文档映射:
|
||
- 当前 `SERVER_RUNTIME_FUNCTION_IDS` 全部都能在 function catalog 文档中找到对应条目。
|
||
- 本轮扫描到的 function `source` 路径全部存在,没有出现失效引用。
|
||
|
||
## 5. 本轮修复动作
|
||
|
||
- `battle_recover_breath`
|
||
- 已补充战斗恢复类 function 的存活敌人校验,避免战斗边界帧残留非法选项。
|
||
- `npc_trade`
|
||
- 已把 trade modal 默认选中逻辑改为优先寻找可交易物品,不再直接吃数组第一项。
|
||
- 回归测试
|
||
- 原先记录旧行为的测试已翻转为修复后预期,并额外补了一条 `storyGenerationState` 接入层测试。
|
||
|
||
## 6. 备注
|
||
|
||
这次测试资产的意义分两步:
|
||
|
||
- 第一步先把 bug 稳定复现出来,避免问题只停留在口头描述。
|
||
- 第二步在修复后把断言翻转成“正确行为”,让它们正式成为回归测试。
|