aether-shards/test/core/GameLoop/progression.test.js

205 lines
6.4 KiB
JavaScript
Raw Normal View History

import { expect } from "@esm-bundle/chai";
import sinon from "sinon";
import { GameLoop } from "../../../src/core/GameLoop.js";
import { Explorer } from "../../../src/units/Explorer.js";
import { UnitManager } from "../../../src/managers/UnitManager.js";
import {
createGameLoopSetup,
cleanupGameLoop,
} from "./helpers.js";
// Mock Class Definition
const CLASS_VANGUARD = {
id: "CLASS_VANGUARD",
base_stats: { health: 100, attack: 10, speed: 5 },
growth_rates: { health: 10, attack: 1 },
};
describe("Core: GameLoop - Explorer Progression", function () {
this.timeout(30000);
let gameLoop;
let container;
beforeEach(async () => {
const setup = createGameLoopSetup();
gameLoop = setup.gameLoop;
container = setup.container;
await gameLoop.init(container);
// Ensure unitManager is initialized (it's created during init)
// If it's not, create a minimal one for testing
if (!gameLoop.unitManager) {
gameLoop.unitManager = new UnitManager({});
}
});
afterEach(() => {
cleanupGameLoop(gameLoop, container);
});
it("CoA 1: _saveExplorerProgression should save classMastery to roster", () => {
// Setup: Create a mock gameStateManager with roster
const mockRosterUnit = {
id: "UNIT_1",
classId: "CLASS_VANGUARD",
name: "Test Explorer",
status: "READY",
};
const mockRosterManager = {
roster: [mockRosterUnit],
};
const mockGameStateManager = {
rosterManager: mockRosterManager,
_saveRoster: sinon.spy(),
};
gameLoop.gameStateManager = mockGameStateManager;
// Create an Explorer unit with progression
const explorer = new Explorer("UNIT_1", "Test Explorer", "CLASS_VANGUARD", CLASS_VANGUARD);
explorer.rosterId = "UNIT_1";
explorer.classMastery.CLASS_VANGUARD.level = 5;
explorer.classMastery.CLASS_VANGUARD.xp = 250;
explorer.classMastery.CLASS_VANGUARD.skillPoints = 3;
explorer.classMastery.CLASS_VANGUARD.unlockedNodes = ["ROOT", "NODE_1"];
explorer.activeClassId = "CLASS_VANGUARD";
// Add to unit manager
gameLoop.unitManager.activeUnits.set(explorer.id, explorer);
explorer.team = "PLAYER";
// Call the save method
gameLoop._saveExplorerProgression();
// Verify progression was saved to roster
expect(mockRosterUnit.classMastery).to.exist;
expect(mockRosterUnit.classMastery.CLASS_VANGUARD.level).to.equal(5);
expect(mockRosterUnit.classMastery.CLASS_VANGUARD.xp).to.equal(250);
expect(mockRosterUnit.classMastery.CLASS_VANGUARD.skillPoints).to.equal(3);
expect(mockRosterUnit.classMastery.CLASS_VANGUARD.unlockedNodes).to.include("ROOT");
expect(mockRosterUnit.classMastery.CLASS_VANGUARD.unlockedNodes).to.include("NODE_1");
expect(mockRosterUnit.activeClassId).to.equal("CLASS_VANGUARD");
// Verify roster was saved
expect(mockGameStateManager._saveRoster.called).to.be.true;
});
it("CoA 2: _saveExplorerProgression should handle multiple Explorers", () => {
const mockRosterUnit1 = {
id: "UNIT_1",
classId: "CLASS_VANGUARD",
name: "Explorer 1",
status: "READY",
};
const mockRosterUnit2 = {
id: "UNIT_2",
classId: "CLASS_TINKER",
name: "Explorer 2",
status: "READY",
};
const mockRosterManager = {
roster: [mockRosterUnit1, mockRosterUnit2],
};
const mockGameStateManager = {
rosterManager: mockRosterManager,
_saveRoster: sinon.spy(),
};
gameLoop.gameStateManager = mockGameStateManager;
// Create two Explorers with different progression
const explorer1 = new Explorer("UNIT_1", "Explorer 1", "CLASS_VANGUARD", CLASS_VANGUARD);
explorer1.rosterId = "UNIT_1";
explorer1.classMastery.CLASS_VANGUARD.level = 3;
explorer1.team = "PLAYER";
gameLoop.unitManager.activeUnits.set(explorer1.id, explorer1);
const explorer2 = new Explorer("UNIT_2", "Explorer 2", "CLASS_TINKER", {
id: "CLASS_TINKER",
base_stats: { health: 80, attack: 8 },
growth_rates: { health: 5, attack: 2 },
});
explorer2.rosterId = "UNIT_2";
explorer2.classMastery.CLASS_TINKER.level = 7;
explorer2.team = "PLAYER";
gameLoop.unitManager.activeUnits.set(explorer2.id, explorer2);
gameLoop._saveExplorerProgression();
// Verify both were saved
expect(mockRosterUnit1.classMastery.CLASS_VANGUARD.level).to.equal(3);
expect(mockRosterUnit2.classMastery.CLASS_TINKER.level).to.equal(7);
});
it("CoA 3: _saveExplorerProgression should not save if unit not in roster", () => {
const mockRosterManager = {
roster: [],
};
const mockGameStateManager = {
rosterManager: mockRosterManager,
_saveRoster: sinon.spy(),
};
gameLoop.gameStateManager = mockGameStateManager;
// Create an Explorer that's not in roster
const explorer = new Explorer("UNIT_UNKNOWN", "Unknown", "CLASS_VANGUARD", CLASS_VANGUARD);
explorer.rosterId = "UNIT_UNKNOWN";
explorer.classMastery.CLASS_VANGUARD.level = 5;
explorer.team = "PLAYER";
gameLoop.unitManager.activeUnits.set(explorer.id, explorer);
gameLoop._saveExplorerProgression();
// Should not crash, but roster should remain empty
expect(mockRosterManager.roster).to.be.empty;
// Should still call save (in case other units were updated)
expect(mockGameStateManager._saveRoster.called).to.be.true;
});
it("CoA 4: _handleMissionVictory should save progression", () => {
const mockRosterUnit = {
id: "UNIT_1",
classId: "CLASS_VANGUARD",
name: "Test Explorer",
status: "READY",
};
const mockRosterManager = {
roster: [mockRosterUnit],
};
const mockGameStateManager = {
rosterManager: mockRosterManager,
_saveRoster: sinon.spy(),
transitionTo: sinon.spy(),
};
gameLoop.gameStateManager = mockGameStateManager;
gameLoop.isPaused = false;
gameLoop.stop = sinon.spy();
// Create Explorer with progression
const explorer = new Explorer("UNIT_1", "Test Explorer", "CLASS_VANGUARD", CLASS_VANGUARD);
explorer.rosterId = "UNIT_1";
explorer.classMastery.CLASS_VANGUARD.level = 4;
explorer.team = "PLAYER";
gameLoop.unitManager.activeUnits.set(explorer.id, explorer);
// Call victory handler
gameLoop._handleMissionVictory({ missionId: "TEST_MISSION" });
// Verify progression was saved
expect(mockRosterUnit.classMastery.CLASS_VANGUARD.level).to.equal(4);
expect(mockGameStateManager._saveRoster.called).to.be.true;
});
});