Add keyword integration tests
Exercises exhaust, ethereal, retain, poison, unplayable, and ironclad heal-on-victory in a single test file using manual state construction to control hand contents without relying on random draws.
This commit is contained in:
parent
ac45cb8758
commit
4f91396e3a
1 changed files with 168 additions and 0 deletions
168
src/keywords.test.js
Normal file
168
src/keywords.test.js
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
import { beforeAll, describe, expect, test } from "bun:test";
|
||||
import { initCards } from "./cards.js";
|
||||
import { checkCombatEnd, resolveEnemyTurn, startTurn } from "./combat.js";
|
||||
import { initEnemies } from "./enemies.js";
|
||||
import { createRunState, endCombat } from "./run.js";
|
||||
import { createCombatFromRun, drawCards, endTurn, playCard } from "./state.js";
|
||||
|
||||
beforeAll(async () => {
|
||||
await Promise.all([initCards(), initEnemies()]);
|
||||
});
|
||||
|
||||
describe("keyword integration", () => {
|
||||
test("exhaust card removed from cycle after play", () => {
|
||||
const run = createRunState("ironclad");
|
||||
let state = createCombatFromRun(run, "jaw_worm");
|
||||
state = drawCards(state, 5);
|
||||
|
||||
// force true_grit into hand at index 0
|
||||
const player = {
|
||||
...state.players[0],
|
||||
hand: ["true_grit", ...state.players[0].hand.slice(1)],
|
||||
};
|
||||
state = { ...state, players: [player], player };
|
||||
|
||||
state = playCard(state, 0);
|
||||
expect(state.players[0].exhaustPile).toContain("true_grit");
|
||||
|
||||
state = endTurn(state);
|
||||
state = { ...state, combat: { ...state.combat, dieResult: 3 } };
|
||||
state = resolveEnemyTurn(state);
|
||||
state = startTurn(state);
|
||||
|
||||
expect(state.players[0].hand).not.toContain("true_grit");
|
||||
expect(state.players[0].drawPile).not.toContain("true_grit");
|
||||
expect(state.players[0].discardPile).not.toContain("true_grit");
|
||||
expect(state.players[0].exhaustPile).toContain("true_grit");
|
||||
});
|
||||
|
||||
test("ethereal card exhausts if not played by end of turn", () => {
|
||||
const run = createRunState("ironclad");
|
||||
let state = createCombatFromRun(run, "jaw_worm");
|
||||
|
||||
const player = { ...state.players[0], hand: ["carnage", "strike_r"] };
|
||||
state = { ...state, players: [player], player };
|
||||
|
||||
state = endTurn(state);
|
||||
|
||||
expect(state.players[0].exhaustPile).toContain("carnage");
|
||||
expect(state.players[0].discardPile).not.toContain("carnage");
|
||||
expect(state.players[0].discardPile).toContain("strike_r");
|
||||
expect(state.players[0].exhaustPile).not.toContain("strike_r");
|
||||
});
|
||||
|
||||
test("retained card stays through turn cycle", () => {
|
||||
const run = createRunState("ironclad");
|
||||
let state = createCombatFromRun(run, "jaw_worm");
|
||||
|
||||
const player = { ...state.players[0], hand: ["equilibrium", "strike_r"] };
|
||||
state = { ...state, players: [player], player };
|
||||
|
||||
state = endTurn(state);
|
||||
|
||||
expect(state.players[0].hand).toContain("equilibrium");
|
||||
expect(state.players[0].discardPile).toContain("strike_r");
|
||||
|
||||
state = { ...state, combat: { ...state.combat, dieResult: 3 } };
|
||||
state = resolveEnemyTurn(state);
|
||||
state = startTurn(state);
|
||||
|
||||
// equilibrium was retained, startTurn draws 5 more on top of it
|
||||
expect(state.players[0].hand).toContain("equilibrium");
|
||||
expect(state.players[0].hand).toHaveLength(6);
|
||||
});
|
||||
|
||||
test("poison ticks down and kills enemy", () => {
|
||||
const run = createRunState("ironclad");
|
||||
let state = createCombatFromRun(run, "jaw_worm");
|
||||
|
||||
const enemy = { ...state.enemies[0], poison: 3, hp: 5 };
|
||||
state = {
|
||||
...state,
|
||||
enemies: [enemy],
|
||||
enemy,
|
||||
combat: { ...state.combat, dieResult: 3 },
|
||||
};
|
||||
|
||||
state = resolveEnemyTurn(state);
|
||||
expect(state.enemies[0].hp).toBe(2);
|
||||
expect(state.enemies[0].poison).toBe(2);
|
||||
|
||||
const dying = { ...state.enemies[0], poison: 5, hp: 3 };
|
||||
state = {
|
||||
...state,
|
||||
enemies: [dying],
|
||||
enemy: dying,
|
||||
combat: { ...state.combat, dieResult: 3 },
|
||||
};
|
||||
|
||||
state = resolveEnemyTurn(state);
|
||||
expect(state.enemies[0].hp).toBe(0);
|
||||
expect(checkCombatEnd(state)).toBe("victory");
|
||||
});
|
||||
|
||||
test("unplayable card blocks play", () => {
|
||||
const run = createRunState("ironclad");
|
||||
let state = createCombatFromRun(run, "jaw_worm");
|
||||
|
||||
const player = { ...state.players[0], hand: ["tactician", "strike_r"] };
|
||||
state = { ...state, players: [player], player };
|
||||
|
||||
const result = playCard(state, 0);
|
||||
expect(result).toBeNull();
|
||||
expect(state.players[0].hand).toEqual(["tactician", "strike_r"]);
|
||||
});
|
||||
|
||||
test("ironclad heals after victory", () => {
|
||||
let run = createRunState("ironclad");
|
||||
run = { ...run, hp: 8 };
|
||||
|
||||
const updated = endCombat(run, 8);
|
||||
expect(updated.hp).toBe(9);
|
||||
expect(updated.combatCount).toBe(1);
|
||||
});
|
||||
|
||||
test("full combat: exhaust + poison + victory heal", () => {
|
||||
let run = createRunState("ironclad");
|
||||
run = { ...run, hp: 10 };
|
||||
|
||||
let state = createCombatFromRun(run, "jaw_worm");
|
||||
state = startTurn(state);
|
||||
|
||||
// inject true_grit into hand and set enemy poison
|
||||
const player = {
|
||||
...state.players[0],
|
||||
hand: ["true_grit", ...state.players[0].hand.slice(1)],
|
||||
};
|
||||
const enemy = { ...state.enemies[0], poison: 5 };
|
||||
state = {
|
||||
...state,
|
||||
players: [player],
|
||||
player,
|
||||
enemies: [enemy],
|
||||
enemy,
|
||||
};
|
||||
|
||||
state = playCard(state, 0);
|
||||
expect(state.players[0].exhaustPile).toContain("true_grit");
|
||||
|
||||
// set enemy hp below poison so it dies from the tick
|
||||
const dying = { ...state.enemies[0], hp: 4 };
|
||||
state = {
|
||||
...state,
|
||||
enemies: [dying],
|
||||
enemy: dying,
|
||||
combat: { ...state.combat, dieResult: 3 },
|
||||
};
|
||||
|
||||
state = endTurn(state);
|
||||
state = resolveEnemyTurn(state);
|
||||
|
||||
expect(checkCombatEnd(state)).toBe("victory");
|
||||
|
||||
const finalHp = state.players[0].hp;
|
||||
const afterRun = endCombat(run, finalHp);
|
||||
expect(afterRun.hp).toBe(finalHp + 1);
|
||||
expect(afterRun.combatCount).toBe(1);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue