diff --git a/src/integration.test.js b/src/integration.test.js new file mode 100644 index 0000000..ea3190d --- /dev/null +++ b/src/integration.test.js @@ -0,0 +1,106 @@ +import { beforeAll, describe, expect, test } from "bun:test"; +import { initCards } from "./cards.js"; +import { getEnemy, initEnemies } from "./enemies.js"; +import { + campfireRest, + campfireSmith, + createRunState, + endCombat, + pickReward, + revealRewards, + skipRewards, +} from "./run.js"; +import { createCombatFromRun } from "./state.js"; + +beforeAll(async () => { + await Promise.all([initCards(), initEnemies()]); +}); + +describe("skip all rewards → deck stays at 10", () => { + test("3 combats with skipped rewards leave deck unchanged", () => { + let run = createRunState("ironclad"); + expect(run.deck).toHaveLength(10); + + for (let i = 0; i < 3; i++) { + const { revealed, run: afterReveal } = revealRewards(run); + run = skipRewards(afterReveal, revealed); + expect(run.deck).toHaveLength(10); + } + }); +}); + +describe("take every reward → deck grows", () => { + test("3 combats with picked rewards add 3 cards to deck", () => { + let run = createRunState("ironclad"); + expect(run.deck).toHaveLength(10); + + for (let i = 0; i < 3; i++) { + const { revealed, run: afterReveal } = revealRewards(run); + run = pickReward(afterReveal, revealed, 0); + } + + expect(run.deck).toHaveLength(13); + }); +}); + +describe("rest at campfires → HP carries into combat", () => { + test("healed HP is reflected in combat player state", () => { + let run = { ...createRunState("ironclad"), hp: 5 }; + run = campfireRest(run); + expect(run.hp).toBe(8); + + const combat = createCombatFromRun(run, "jaw_worm"); + expect(combat.players[0].hp).toBe(8); + }); + + test("campfireRest caps at maxHp and combat reflects the cap", () => { + let run = { ...createRunState("ironclad"), hp: 10 }; + run = campfireRest(run); + expect(run.hp).toBe(11); + + const combat = createCombatFromRun(run, "jaw_worm"); + expect(combat.players[0].hp).toBe(11); + }); +}); + +describe("smith upgrades change cards in combat", () => { + test("smithed card appears in draw pile when combat is created", () => { + let run = createRunState("ironclad"); + run = campfireSmith(run, "strike_r"); + expect(run.deck).toContain("strike_r+"); + + const combat = createCombatFromRun(run, "jaw_worm"); + const drawPile = combat.players[0].drawPile; + expect(drawPile).toContain("strike_r+"); + }); +}); + +describe("fresh run after death resets everything", () => { + test("death leaves hp 0, new run restores full HP and original deck", () => { + let run = createRunState("ironclad"); + + // simulate dying: endCombat with 0 HP + // ironclad gets +1 from burning blood, so post-combat hp is 1 + run = endCombat(run, 0); + expect(run.hp).toBe(1); + + // fresh run represents starting over + const fresh = createRunState("ironclad"); + expect(fresh.hp).toBe(11); + expect(fresh.maxHp).toBe(11); + expect(fresh.deck).toHaveLength(10); + expect(fresh.combatCount).toBe(0); + }); +}); + +describe("boss enemies are harder than encounter enemies", () => { + test("all bosses have higher HP than all encounter enemies", () => { + const bosses = ["slime_boss", "the_guardian"].map((id) => getEnemy(id)); + const encounters = ["jaw_worm", "cultist"].map((id) => getEnemy(id)); + + const minBossHp = Math.min(...bosses.map((e) => e.hp)); + const maxEncounterHp = Math.max(...encounters.map((e) => e.hp)); + + expect(minBossHp).toBeGreaterThan(maxEncounterHp); + }); +});