test(fe): 添加部分平仓比例刷新守卫 + 历史对账骨架(离线无DB) — closePercentInterestRefresh 守卫全部→部分平仓比例刷新链; historicalReconciliation 独立规格vs落库值差分; 全部18套件276测试通过

This commit is contained in:
hjhan
2026-08-08 14:16:54 +08:00
parent 096d2609eb
commit fc01b766cd
5 changed files with 687 additions and 0 deletions
@@ -0,0 +1,72 @@
# 历史对账 + 基准差分测试骨架
## 一句话结论
**这套骨架在测试运行时不需要任何数据库连接。** 唯一触碰数据库的地方是
`tools/exportHistoricalSwapEvents.js`——一个**开发期一次性导出脚本**(把真实
`swap_event.data` 灌进 fixture),它**文件名非 `*.test.js`jest 不会执行它**
因此 CI 跑 `npm test` 时零 DB 依赖。
## 文件清单
| 文件 | 运行时是否要 DB | 说明 |
|------|----------------|------|
| `historicalReconciliation.test.js` | **否** | 离线对账:独立规格 vs fixture 中记录的落库值 |
| `fixtures/historical_swap_events.json` | **否** | 历史数据夹具(当前为手搓代表性样本,可由导出脚本替换为真实数据) |
| `swapCalc.test.js`(既有) | **否** | `swapCalc.js` 参考实现 vs C# 金标准 `FC_001~009` 差分 |
| `tools/exportHistoricalSwapEvents.js` | **是(仅此一处,开发期)** | 一次性导出真实历史,不属于测试路径 |
## 设计原则(回应"重构怕引入新 Bug"的顾虑)
1. **先冻后改**:用特征测试把"当前(可能含历史 bug 的)行为"钉死。任何重构只要改变了
金额产出,测试立即变红,**逼你查根因,绝不自动 re-baseline**(避免 `01d7f0c5` 式静默掩盖)。
2. **已知差异显式冻结**`swapLongShort.js``SwapMarginAmount` 用裸 `InterestPrincipal`
(无符号),而 `unwindSwapTrade.js``InterestDirection` 求符号——这是真实的代码不一致。
它在 fixture 里以 `knownDiscrepancies.SwapMarginAmount` 记录"差异量",测试只在该**差异量变化**
时报红,既不掩盖也不误报。
3. **独立规格不信任任何既有实现**`referenceOracle` 是按 `unwindSwapTrade.js:329` 独立重写的
纯函数,作为"应然"基准。若生产代码与独立规格分叉,说明要么生产错了、要么规格写错了——必须人工裁决。
## 如何扩展到"4 个生产 calcCloseAmount 的差分"
当前骨架用的是**独立重写的规格**,并未直接驱动那 4 个组件里的 `calcCloseAmount`
原因是这 4 个文件在模块顶层就访问 `window.otcformat` / `model` / `swapPricePrecision`
等全局(见 `unwindSwapTrade.js:1-2`),在 jest 的 `node` 环境下直接 `require` 会在加载期抛错。
要把它们纳入差分,**唯一的代码改动**是"提取纯函数"(行为不变,非统一):
```js
// 在组件文件里,把 calcCloseAmount 的金额聚合核心抽成导出纯函数
function calcUnwindCloseAmountCore(deal, floatPosition, interestList, marginList) {
// ...原 :329-367 的金额聚合逻辑搬过来,去掉 this / formatSwapAmount 展示归一...
}
// 原方法改为 2 行包装,保持行为完全一致:
calcCloseAmount() {
const r = calcUnwindCloseAmountCore(this.deal, this.floatPosition, this.interestList, this.marginList);
Object.assign(this.deal, r);
}
module.exports = { calcUnwindCloseAmountCore }; // 仅新增导出,不改逻辑
```
提取后 jest 即可 `require` 并差分,且**不连 DB、不碰业务逻辑**。这一步务必配合一条
"提取前后产出一致"的快照测试,确保提取本身没改行为。
> 注意:`swapCalc.js` 目前**未接入生产**(其 `calcUnwind/calcIncome` 注释明写"未接入"),
> 且它**不计算 `SwapMarginAmount`**(利息腿 `InterestPrincipal` 那一项),因此不能直接拿它
> 替换 4 个生产函数。它目前只作为"参考金标准"被 `swapCalc.test.js` 的 `FC_*` 用例校验。
## 运行
```bash
cd YLErpWeb/fe-tests
npm i # 安装 jest / mysql2(可选,仅导出脚本用)
npx jest historicalReconciliation.test.js
```
要注入真实历史(可选,需 DB):
```bash
MYSQL_HOST=... MYSQL_USER=... MYSQL_PASS=... MYSQL_DB=... \
node tools/exportHistoricalSwapEvents.js --from 2026-01-01 --limit 200
npx jest historicalReconciliation.test.js # 此时跑的是真实历史对账
```