import { describe, expect, it } from "vitest"; import { applyMigrations, CURRENT_SAVE_VERSION, migrateSave, saveDocumentSchema, type SaveMigration, } from "../src/index"; import { fullSave } from "./save-fixture"; describe("save document (Step 14.2)", () => { it("validates a fully populated save", () => { expect(saveDocumentSchema.safeParse(fullSave()).success).toBe(true); expect(CURRENT_SAVE_VERSION).toBe(1); }); it("rejects an invalid save with a readable error naming the field", () => { const broken = fullSave() as unknown as { company: { credits: unknown } }; broken.company.credits = "lots"; const result = migrateSave(broken); expect(result.ok).toBe(false); if (!result.ok) { expect(result.error).toContain("The save is damaged"); expect(result.error).toContain("company.credits"); } }); it("rejects things that aren't saves, and saves from a newer build", () => { expect(migrateSave("hello")).toEqual({ ok: false, error: "The save isn't a save document." }); expect(migrateSave({ company: {} })).toEqual({ ok: false, error: "The save has no valid saveVersion.", }); const future = migrateSave({ ...fullSave(), saveVersion: CURRENT_SAVE_VERSION + 1 }); expect(future.ok).toBe(false); if (!future.ok) expect(future.error).toContain("newer version"); }); it("migrates a version-1 save to a valid current save", () => { const result = migrateSave(JSON.parse(JSON.stringify(fullSave()))); expect(result).toEqual({ ok: true, save: fullSave() }); }); it("chains migrations in order, one version at a time", () => { const seen: number[] = []; const migrations: SaveMigration[] = [ { from: 2, migrate: (s) => (seen.push(2), { ...s, extra: [...(s.extra as number[]), 2] }) }, { from: 1, migrate: (s) => (seen.push(1), { ...s, extra: [1] }) }, ]; const result = applyMigrations({ saveVersion: 1 }, migrations, 3); expect(result).toEqual({ ok: true, save: { saveVersion: 3, extra: [1, 2] } }); expect(seen).toEqual([1, 2]); expect(applyMigrations({ saveVersion: 1 }, [], 2)).toEqual({ ok: false, error: "No migration from save version 1.", }); }); });