aether-shards/test/units/Explorer.test.js
Matthew Mone ac0f3cc396 Enhance testing and integration of inventory and character management systems
Add comprehensive tests for the InventoryManager and InventoryContainer to validate item management functionalities. Implement integration tests for the CharacterSheet component, ensuring proper interaction with the inventory system. Update the Explorer class to support new inventory features and maintain backward compatibility. Refactor related components for improved clarity and performance.
2025-12-27 16:54:03 -08:00

240 lines
7.4 KiB
JavaScript

import { expect } from "@esm-bundle/chai";
import { Explorer } from "../../src/units/Explorer.js";
// Mock Class Definitions
const CLASS_VANGUARD = {
id: "CLASS_VANGUARD",
base_stats: { health: 100, attack: 10, speed: 5 },
growth_rates: { health: 10, attack: 1 },
};
const CLASS_TINKER = {
id: "CLASS_TINKER",
base_stats: { health: 80, attack: 8, speed: 7 },
growth_rates: { health: 5, attack: 2 },
};
describe("Unit: Explorer Class Logic", () => {
it("CoA 1: Should initialize with base stats from definition", () => {
const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
expect(hero.baseStats.health).to.equal(100);
expect(hero.baseStats.attack).to.equal(10);
expect(hero.classMastery["CLASS_VANGUARD"]).to.exist;
expect(hero.classMastery["CLASS_VANGUARD"].level).to.equal(1);
});
it("CoA 2: Should calculate stats based on Level Growth", () => {
const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
// Manually level up to 3
hero.classMastery["CLASS_VANGUARD"].level = 3;
hero.recalculateBaseStats(CLASS_VANGUARD);
// Level 3 means 2 level-ups.
// Health: 100 + (10 * 2) = 120
// Attack: 10 + (1 * 2) = 12
expect(hero.baseStats.health).to.equal(120);
expect(hero.baseStats.attack).to.equal(12);
});
it("CoA 3: changeClass should switch stats and persist old progress", () => {
const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
// Level up Vanguard
hero.classMastery["CLASS_VANGUARD"].level = 5;
hero.recalculateBaseStats(CLASS_VANGUARD);
expect(hero.baseStats.health).to.equal(140); // 100 + 40
// Switch to Tinker (New Job)
hero.changeClass("CLASS_TINKER", CLASS_TINKER);
// Should have Level 1 Tinker Stats
expect(hero.activeClassId).to.equal("CLASS_TINKER");
expect(hero.baseStats.health).to.equal(80); // Base Tinker
// Verify Vanguard history is saved
expect(hero.classMastery["CLASS_VANGUARD"].level).to.equal(5);
});
it("CoA 4: Switching BACK to old class should restore high stats", () => {
const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
hero.classMastery["CLASS_VANGUARD"].level = 5;
// Switch Away
hero.changeClass("CLASS_TINKER", CLASS_TINKER);
// Switch Back
hero.changeClass("CLASS_VANGUARD", CLASS_VANGUARD);
// Should be back to Level 5 Stats
expect(hero.baseStats.health).to.equal(140);
});
describe("recalculateStats with Skill Tree", () => {
it("should apply skill tree stat boosts to maxHealth", () => {
const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
hero.recalculateBaseStats(CLASS_VANGUARD);
hero.maxHealth = hero.baseStats.health;
hero.currentHealth = hero.maxHealth;
// Initial health should be 100
expect(hero.maxHealth).to.equal(100);
// Create skill tree with health boost
const treeDef = {
nodes: {
ROOT: {
id: "ROOT",
type: "STAT_BOOST",
data: { stat: "health", value: 10 },
},
},
};
// Unlock the node
hero.classMastery["CLASS_VANGUARD"].unlockedNodes = ["ROOT"];
// Recalculate stats with tree definition
hero.recalculateStats(null, treeDef);
// Health should be increased by 10
expect(hero.maxHealth).to.equal(110);
});
it("should apply multiple skill tree stat boosts", () => {
const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
hero.recalculateBaseStats(CLASS_VANGUARD);
hero.maxHealth = hero.baseStats.health;
hero.currentHealth = hero.maxHealth;
const treeDef = {
nodes: {
ROOT: {
id: "ROOT",
type: "STAT_BOOST",
data: { stat: "health", value: 10 },
},
NODE_2: {
id: "NODE_2",
type: "STAT_BOOST",
data: { stat: "health", value: 5 },
},
},
};
// Unlock both nodes
hero.classMastery["CLASS_VANGUARD"].unlockedNodes = ["ROOT", "NODE_2"];
hero.recalculateStats(null, treeDef);
// Health should be increased by 15 (10 + 5)
expect(hero.maxHealth).to.equal(115);
});
it("should only apply stat boosts from unlocked nodes", () => {
const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
hero.recalculateBaseStats(CLASS_VANGUARD);
hero.maxHealth = hero.baseStats.health;
hero.currentHealth = hero.maxHealth;
const treeDef = {
nodes: {
ROOT: {
id: "ROOT",
type: "STAT_BOOST",
data: { stat: "health", value: 10 },
},
LOCKED_NODE: {
id: "LOCKED_NODE",
type: "STAT_BOOST",
data: { stat: "health", value: 20 },
},
},
};
// Only unlock ROOT, not LOCKED_NODE
hero.classMastery["CLASS_VANGUARD"].unlockedNodes = ["ROOT"];
hero.recalculateStats(null, treeDef);
// Should only get boost from ROOT (10), not LOCKED_NODE (20)
expect(hero.maxHealth).to.equal(110);
});
it("should apply stat boosts to non-health stats", () => {
const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
hero.recalculateBaseStats(CLASS_VANGUARD);
const treeDef = {
nodes: {
ATTACK_BOOST: {
id: "ATTACK_BOOST",
type: "STAT_BOOST",
data: { stat: "attack", value: 5 },
},
},
};
hero.classMastery["CLASS_VANGUARD"].unlockedNodes = ["ATTACK_BOOST"];
// Note: recalculateStats doesn't return stats, but we can verify it was called
// The actual stat application is tested through CharacterSheet UI tests
hero.recalculateStats(null, treeDef);
// Verify the method completed without error
expect(hero.maxHealth).to.exist;
});
it("should update currentHealth proportionally when maxHealth changes", () => {
const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
hero.recalculateBaseStats(CLASS_VANGUARD);
hero.maxHealth = 100;
hero.currentHealth = 50; // 50% health
const treeDef = {
nodes: {
ROOT: {
id: "ROOT",
type: "STAT_BOOST",
data: { stat: "health", value: 20 },
},
},
};
hero.classMastery["CLASS_VANGUARD"].unlockedNodes = ["ROOT"];
hero.recalculateStats(null, treeDef);
// maxHealth should be 120 (100 + 20)
expect(hero.maxHealth).to.equal(120);
// currentHealth should be proportionally adjusted (50% of 120 = 60)
expect(hero.currentHealth).to.equal(60);
});
it("should handle treeDef with no unlocked nodes", () => {
const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
hero.recalculateBaseStats(CLASS_VANGUARD);
hero.maxHealth = hero.baseStats.health;
hero.currentHealth = hero.maxHealth;
const treeDef = {
nodes: {
ROOT: {
id: "ROOT",
type: "STAT_BOOST",
data: { stat: "health", value: 10 },
},
},
};
// No unlocked nodes
hero.classMastery["CLASS_VANGUARD"].unlockedNodes = [];
hero.recalculateStats(null, treeDef);
// Health should remain unchanged
expect(hero.maxHealth).to.equal(100);
});
});
});