79 lines
3.6 KiB
JavaScript
Executable File
79 lines
3.6 KiB
JavaScript
Executable File
const test = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
const data = require("../assets/scripts/pages/princess-lima-data.js");
|
|
const state = require("../assets/scripts/pages/princess-lima-state.js");
|
|
|
|
test("fresh save uses the Princess Lima schema and safe village start", () => {
|
|
const fresh = state.fresh(" Rowan ", "pine");
|
|
assert.equal(fresh.version, 1);
|
|
assert.equal(state.STORAGE_KEY, "zxh_princess_lima_rpg_v1");
|
|
assert.equal(fresh.player.name, "Rowan");
|
|
assert.equal(fresh.player.appearance, "pine");
|
|
assert.equal(fresh.region, "village");
|
|
assert.deepEqual({ x: fresh.position.x, y: fresh.position.y }, data.MAPS.village.spawns.start);
|
|
assert.equal(fresh.settings.soundEnabled, false);
|
|
assert.equal(fresh.introSeen, false);
|
|
assert.equal(fresh.settings.subtitles, true);
|
|
assert.equal(fresh.settings.narrationEnabled, true);
|
|
});
|
|
|
|
test("old v1 saves continue without unexpectedly replaying the new introduction", () => {
|
|
const candidate = state.fresh("Legacy", "azure");
|
|
delete candidate.introSeen;
|
|
delete candidate.settings.voice;
|
|
delete candidate.settings.subtitles;
|
|
delete candidate.settings.narrationEnabled;
|
|
const restored = state.normalize(candidate);
|
|
assert.equal(restored.introSeen, true);
|
|
assert.equal(restored.settings.voice, 0.85);
|
|
assert.equal(restored.settings.subtitles, true);
|
|
assert.equal(restored.settings.narrationEnabled, true);
|
|
});
|
|
|
|
test("names and appearances validate", () => {
|
|
assert.equal(state.validName(" A Traveller "), "A Traveller");
|
|
assert.equal(state.validName(""), null);
|
|
assert.equal(state.validName("x".repeat(21)), null);
|
|
assert.equal(state.normalize({ ...state.fresh("A", "azure"), player: { name: "A", appearance: "bad" } }), null);
|
|
});
|
|
|
|
test("valid saves restore bounded state and derived equipment", () => {
|
|
const candidate = state.fresh("Mira", "azure");
|
|
candidate.health = 999;
|
|
candidate.inventory = [
|
|
{ id: "tempered_sword", quantity: 1 },
|
|
{ id: "healing_tonic", quantity: 99 },
|
|
{ id: "bad", quantity: 4 }
|
|
];
|
|
candidate.solvedPuzzles = ["forest_stones", "forest_stones", "bad"];
|
|
candidate.defeatedBosses = ["captain", "captain", "bad"];
|
|
const restored = state.normalize(candidate);
|
|
assert.equal(restored.health, restored.maxHealth);
|
|
assert.equal(restored.attack, 2);
|
|
assert.equal(restored.inventory.find((item) => item.id === "healing_tonic").quantity, 9);
|
|
assert.deepEqual(restored.solvedPuzzles, ["forest_stones"]);
|
|
assert.deepEqual(restored.defeatedBosses, ["captain"]);
|
|
});
|
|
|
|
test("invalid and unsupported saves recover without throwing", () => {
|
|
assert.equal(state.parse("{"), null);
|
|
assert.equal(state.parse(JSON.stringify({ version: 99 })), null);
|
|
assert.equal(state.parse(JSON.stringify({ version: 1 })), null);
|
|
});
|
|
|
|
test("quest, route, puzzle, boss and settings restoration filters malformed data", () => {
|
|
const candidate = state.fresh("Mira", "ember");
|
|
candidate.quests.aftermath = { status: "active", count: 999, rewarded: true };
|
|
candidate.quests.village_defence = { status: "nonsense", count: -10 };
|
|
candidate.unlockedRoutes = ["guide_found", "guide_found", "fake"];
|
|
candidate.settings = { master: 4, music: -2, effects: "bad", textSpeed: "instant", highContrast: true };
|
|
const restored = state.normalize(candidate);
|
|
assert.equal(restored.quests.aftermath.count, 99);
|
|
assert.equal(restored.quests.village_defence.status, "locked");
|
|
assert.deepEqual(restored.unlockedRoutes, ["guide_found"]);
|
|
assert.equal(restored.settings.master, 1);
|
|
assert.equal(restored.settings.music, 0);
|
|
assert.equal(restored.settings.effects, 0.7);
|
|
assert.equal(restored.settings.textSpeed, "instant");
|
|
});
|