205 lines
6.4 KiB
JavaScript
205 lines
6.4 KiB
JavaScript
|
|
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;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|