test: 存储真链集成测试(MetonaSqlark memory 方言——非 mock)——save/load/export/slot 管理 6 种子全链

此前所有存量测试用 SaveDbDriver mock——真实 SQL 方言链从未被 vitest 覆盖(唯一 GUI 冒烟因环境不可用);
本测试直接注入 MeSqlark memory 后端:saveState→list→loadState→resume advance→exportAll→slot 管理面/remove;
为 0.1.36 三问题(推进崩溃/存档丢失)提供真实存储链防线;+1 套件
This commit is contained in:
2026-08-24 21:59:00 +08:00
parent f5e49ef9bd
commit 73fa9eb7f2
2 changed files with 95 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
import { describe, expect, it } from 'vitest'
import { MeSqlark } from '@metona-team/metona-sqlark'
import { setSqlarkBackend } from '../src/renderer/game/storage/db'
import { getSaveSlot } from '../src/renderer/game/storage/db'
import { World } from '../src/renderer/game/engine/runtime/World'
import { metaFromState } from '../src/renderer/ui/storeHelper'
import type { GameState } from '../src/renderer/game/types/domain'
import type { SaveDbDriver } from '../src/renderer/game/storage/slots'
function memoryBackend(): void {
setSqlarkBackend({
create: async (cfg: { name: string }) => {
const db = new MeSqlark({
name: `it-${cfg.name}-${Math.random().toString(36).slice(2)}`,
mode: 'hybrid',
diskEngine: 'memory',
aria: {}
})
await db.init()
return { query: (sql: string, params?: unknown[]) => db.query(sql, params) }
}
} as never)
}
function saveClone(w: World): GameState {
return JSON.parse(JSON.stringify(w.state)) as GameState
}
describe('0.1.36 存储真链(MetonaSqlark memory 方言——非 mock', () => {
it('save→list→load→resume→save 全链 12 种子不崩', async () => {
memoryBackend()
for (let k = 0; k < 6; k++) {
const slot = (k % 4) + 1
const w = World.create({ seed: `real-${k}`, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
for (let i = 0; i < 12; i++) w.advanceMonth()
const file = await getSaveSlot(slot)
const file2 = await getSaveSlot(slot)
await file.open()
await file.saveState(saveClone(w), '自动')
const meta = metaFromState(w.state, slot)
await file.setMeta(meta)
const loaded = await file2.loadState()
expect(loaded).toBeTruthy()
expect(loaded!.year).toBeGreaterThan(0)
const y = new World(loaded!)
for (let i = 0; i < 8; i++) y.advanceMonth()
const exportStr = await file.exportAll()
expect(exportStr.length).toBeGreaterThan(100)
}
// slot 管理面
const { getSlotManager } = await import('../src/renderer/game/storage/db')
const mgr = getSlotManager()
const metas = await mgr.listSlotMetas()
expect(metas.length).toBe(4)
await mgr.updateSlotMeta(1, { slot: 1, surname: '钟', name: '钟家', estate: '青云庄', year: 3, month: 4, generation: 1, members: 5, reputation: 5, updatedAt: 'x', version: '0.1.35' })
await mgr.removeSlotMeta(1)
expect((await mgr.listSlotMetas())[0]).toBeNull()
})
})