test: verify database migration and scheduled operations
This commit is contained in:
1 parent
86c6daf695
commit
932a864ed6
5 files changed
+96
-5
No files matched your search
@@ -151,7 +151,7 @@ test('borrow/lend/collect/repay pair balances atomically and survive concurrency
|
||||
200,
|
||||
);
|
||||
const backup = (await call(a.token, '/backup')).data;
|
||||
assert.equal(JSON.parse(packBackup(backup)['manifest.json']).version, 6);
|
||||
assert.equal(JSON.parse(packBackup(backup)['manifest.json']).version, 7);
|
||||
assert.equal(backup.transfers.length, 5);
|
||||
assert.ok(backup.transfers.some((p: any) => p.operation === 'lend' && p.fee === '-2'));
|
||||
assert.equal(
|
||||
|
||||
@@ -129,8 +129,62 @@ test('real MySQL: groups, scheduled atomic execution, calendar, privacy and ZIP
|
||||
assert.equal(day.expense, '5.50');
|
||||
assert.equal(day.income, '0.00');
|
||||
assert.equal((await call('/calendar/day?date=' + today(), a.cookie)).data.items.length, 4);
|
||||
const transferPlan = await call('/schedules', a.cookie, 'POST', {
|
||||
...input,
|
||||
name: 'Scheduled transfer',
|
||||
operation: 'transfer',
|
||||
targetId,
|
||||
amount: '3',
|
||||
received: '3',
|
||||
});
|
||||
assert.equal(transferPlan.status, 201);
|
||||
const transferRace = await Promise.all([
|
||||
call('/schedules/run', a.cookie, 'POST', {}),
|
||||
call('/schedules/run', a.cookie, 'POST', {}),
|
||||
]);
|
||||
assert.equal(
|
||||
transferRace.reduce((sum, v) => sum + v.data.executed, 0),
|
||||
1,
|
||||
);
|
||||
const afterTransfer = (await call('/positions', a.cookie)).data;
|
||||
assert.equal(afterTransfer.find((p: any) => p.id === sourceId).amount, '-23.5');
|
||||
assert.equal(afterTransfer.find((p: any) => p.id === targetId).amount, '28');
|
||||
assert.equal((await call('/calendar/day?date=' + today(), a.cookie)).data.items.length, 4);
|
||||
const failedPlan = await call('/schedules', a.cookie, 'POST', {
|
||||
...input,
|
||||
name: 'Archived account',
|
||||
});
|
||||
assert.equal(failedPlan.status, 201);
|
||||
const beforeFailure = (await call('/schedules', a.cookie)).data.find(
|
||||
(p: any) => p.id === failedPlan.data.id,
|
||||
);
|
||||
await call('/positions/' + sourceId, a.cookie, 'PATCH', {
|
||||
name: 'Daily',
|
||||
category: 'bank',
|
||||
groupName: '日常',
|
||||
archived: true,
|
||||
});
|
||||
const failure = await call('/schedules/run', a.cookie, 'POST', {});
|
||||
assert.equal(failure.data.executed, 0);
|
||||
assert.equal(failure.data.errors.length, 1);
|
||||
assert.equal(
|
||||
(await call('/schedules', a.cookie)).data.find((p: any) => p.id === failedPlan.data.id)
|
||||
.nextAt,
|
||||
beforeFailure.nextAt,
|
||||
);
|
||||
assert.equal(
|
||||
(await call('/positions', a.cookie)).data.find((p: any) => p.id === sourceId).amount,
|
||||
'-23.5',
|
||||
);
|
||||
await call('/positions/' + sourceId, a.cookie, 'PATCH', {
|
||||
name: 'Daily',
|
||||
category: 'bank',
|
||||
groupName: '日常',
|
||||
archived: false,
|
||||
});
|
||||
assert.equal((await call('/schedules/' + failedPlan.data.id, a.cookie, 'DELETE')).status, 200);
|
||||
const backup = (await call('/backup', a.cookie)).data;
|
||||
assert.equal(backup.schedules.length, 2);
|
||||
assert.equal(backup.schedules.length, 3);
|
||||
assert.equal(
|
||||
(await call('/backup/import', b.cookie, 'POST', { confirmed: true, backup })).status,
|
||||
201,
|
||||
@@ -141,7 +195,32 @@ test('real MySQL: groups, scheduled atomic execution, calendar, privacy and ZIP
|
||||
['日常', '理财'].sort(),
|
||||
);
|
||||
const restored = (await call('/backup', b.cookie)).data;
|
||||
assert.equal(restored.schedules.filter((p: any) => p.completed).length, 1);
|
||||
assert.equal(restored.schedules.filter((p: any) => p.completed).length, 2);
|
||||
await db.schedule.createMany({
|
||||
data: Array.from({ length: 21 }, (_, i) => ({
|
||||
id: randomUUID(),
|
||||
userId: a.id,
|
||||
name: 'Batch ' + i,
|
||||
operation: 'expense',
|
||||
sourceId,
|
||||
amount: '1',
|
||||
received: '0',
|
||||
nextAt: new Date(Date.now() - 60000),
|
||||
intervalDays: 0,
|
||||
enabled: true,
|
||||
notes: '',
|
||||
})),
|
||||
});
|
||||
const firstBatch = await call('/schedules/run', a.cookie, 'POST', {});
|
||||
assert.equal(firstBatch.data.executed, 20);
|
||||
assert.equal(firstBatch.data.hasMore, true);
|
||||
const secondBatch = await call('/schedules/run', a.cookie, 'POST', {});
|
||||
assert.equal(secondBatch.data.executed, 1);
|
||||
assert.equal(secondBatch.data.hasMore, false);
|
||||
assert.equal(
|
||||
(await call('/positions', a.cookie)).data.find((p: any) => p.id === sourceId).amount,
|
||||
'-44.5',
|
||||
);
|
||||
await call('/positions/' + sourceId, a.cookie, 'PATCH', {
|
||||
name: 'Daily',
|
||||
category: 'bank',
|
||||
|
||||
+1
-1
@@ -55,4 +55,4 @@
|
||||
|
||||
## 2026-10-02 账户分组、计划与日历
|
||||
|
||||
本轮 28 项单元测试、类型检查和生产构建通过。浏览器模拟数据验证与实际数据库未验证部分详见 [本轮验收](update-2026-10-02.md)。连接数据库发生 PROTOCOL_CONNECTION_LOST,迁移、图库初始化及真实 MySQL 并发集成仍需在可连接环境执行;前文并发余额不足的旧断言已随允许透支需求调整。
|
||||
本轮 28 项单元测试、类型检查和生产构建通过。浏览器模拟数据验证与实际数据库未验证部分详见 [本轮验收](update-2026-10-02.md)。首轮连接数据库发生 PROTOCOL_CONNECTION_LOST;2026-10-02 17:54 补充验收已完成迁移、31 个图库图标初始化及全部 9 项真实 MySQL 集成检查。前文并发余额不足的旧断言已随允许透支需求调整。
|
||||
@@ -49,4 +49,14 @@ pnpm test:integration
|
||||
- `pnpm test` 28 项通过:透支/负转入余额、债务超额还款拒绝、请求去重、金额范围、债务符号/币种、轨迹裁剪、计划完成/重复/失败推进、日历口径/小数汇总/缺汇率、ZIP v7 分组计划往返及旧版兼容。
|
||||
- 浏览器使用明确的模拟数据检查分组弹窗切换、转账选择和月历默认今天/日期切换/上下布局及红色支出,未操作真实用户财务数据。
|
||||
- 新增 `test/update-integration.test.ts`,覆盖真实 MySQL 中计划并发执行一次、透支、补记、分组恢复、隐藏账户与日历隔离,纳入 `pnpm test:integration`。
|
||||
- 本环境尝试连接现有数据库时发生 `PROTOCOL_CONNECTION_LOST`,因此本轮未应用数据库迁移、未向实际数据库导入新图标、未运行真实数据库集成测试。上述命令需在数据库可连接后完成;历史验收文档的旧测试结果不代表本轮已通过。
|
||||
- 首轮连接数据库发生 `PROTOCOL_CONNECTION_LOST` 时,数据库验收暂未执行;该阻塞已在下面的补充验收中解决。
|
||||
|
||||
## 数据库恢复后的补充验收(2026-10-02 17:54,香港时间)
|
||||
|
||||
- 已确认 MySQL 连接恢复并通过 SELECT 1;增量应用 `20261002000400_groups_schedules` 成功,`pnpm db:status` 确认全部 12 个迁移完成,schema 最新。
|
||||
- 已生成 Prisma 客户端并编译后端,运行图库初始化;数据库检查确认 31 个固定内置图标 ID 均有图片数据且为共享图标。
|
||||
- 在独立端口 3101 启动当前工作树后端,`pnpm test:integration` 9 项全部通过。测试使用随机验收账号,测试结束按对应 ID/用户名清理自己的数据,未使用真实用户账号执行记账或清空。
|
||||
- 新增专项进一步验证:定时支出/转账并发只记一次、透支后的精确余额、归档账户执行失败保留到期时间和余额、21 项到期计划按 20 + 1 分批处理、内部转账不计日历收支、ZIP 分组/计划状态恢复及隐藏账户隔离。
|
||||
- 修复债务集成测试中仍断言 manifest v6 的旧预期,当前应为 v7。连续重跑触发临时服务的正常登录限流后,重启本次临时测试服务再执行,未修改限流规则。
|
||||
- 本轮 `pnpm test` 28 项通过,`pnpm typecheck` 通过;后端编译通过,前端生产构建在此前实现验收已通过,本轮未修改前端代码。
|
||||
- 上一轮遗留的数据库迁移、图标初始化及真实 MySQL 集成验收现已完成。浏览器布局验收仍沿用此前模拟数据结果,没有新增真实浏览器端到端验收。
|
||||
Reference in new issue
Block a user