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.
149 lines
4.7 KiB
JavaScript
149 lines
4.7 KiB
JavaScript
import { expect } from "@esm-bundle/chai";
|
|
import sinon from "sinon";
|
|
// Import the singleton instance AND the class for constants
|
|
import {
|
|
gameStateManager,
|
|
GameStateManager,
|
|
} from "../../src/core/GameStateManager.js";
|
|
|
|
describe("Core: GameStateManager (Singleton)", () => {
|
|
let mockPersistence;
|
|
let mockGameLoop;
|
|
|
|
beforeEach(() => {
|
|
// 1. Reset Singleton State
|
|
gameStateManager.reset();
|
|
|
|
// 2. Mock Persistence
|
|
mockPersistence = {
|
|
init: sinon.stub().resolves(),
|
|
saveRun: sinon.stub().resolves(),
|
|
loadRun: sinon.stub().resolves(null),
|
|
loadRoster: sinon.stub().resolves(null),
|
|
saveRoster: sinon.stub().resolves(),
|
|
};
|
|
// Inject Mock (replacing the real Persistence instance)
|
|
gameStateManager.persistence = mockPersistence;
|
|
|
|
// 3. Mock GameLoop
|
|
mockGameLoop = {
|
|
init: sinon.spy(),
|
|
startLevel: sinon.spy(),
|
|
stop: sinon.spy(),
|
|
};
|
|
|
|
// 4. Mock MissionManager
|
|
gameStateManager.missionManager = {
|
|
setupActiveMission: sinon.stub(),
|
|
getActiveMission: sinon.stub().returns({
|
|
id: "MISSION_TUTORIAL_01",
|
|
config: { title: "Test Mission" },
|
|
biome: {
|
|
generator_config: {
|
|
seed_type: "RANDOM",
|
|
seed: 12345,
|
|
},
|
|
},
|
|
objectives: [],
|
|
}),
|
|
playIntro: sinon.stub().resolves(),
|
|
};
|
|
});
|
|
|
|
it("CoA 1: Should initialize and transition to MAIN_MENU", async () => {
|
|
const eventSpy = sinon.spy();
|
|
window.addEventListener("gamestate-changed", eventSpy);
|
|
|
|
await gameStateManager.init();
|
|
|
|
expect(mockPersistence.init.calledOnce).to.be.true;
|
|
expect(gameStateManager.currentState).to.equal(
|
|
GameStateManager.STATES.MAIN_MENU
|
|
);
|
|
|
|
expect(eventSpy.called).to.be.true;
|
|
});
|
|
|
|
it("CoA 2: startNewGame should transition to TEAM_BUILDER", async () => {
|
|
await gameStateManager.init();
|
|
gameStateManager.startNewGame();
|
|
|
|
expect(gameStateManager.currentState).to.equal(
|
|
GameStateManager.STATES.TEAM_BUILDER
|
|
);
|
|
});
|
|
|
|
it("CoA 3: handleEmbark should initialize run, save, and start engine", async () => {
|
|
// Mock RosterManager.recruitUnit to return async unit with generated name
|
|
const mockRecruitedUnit = {
|
|
id: "UNIT_123",
|
|
name: "Valerius", // Generated character name
|
|
className: "Vanguard", // Class name
|
|
classId: "CLASS_VANGUARD",
|
|
};
|
|
gameStateManager.rosterManager.recruitUnit = sinon.stub().resolves(mockRecruitedUnit);
|
|
gameStateManager.setGameLoop(mockGameLoop);
|
|
await gameStateManager.init();
|
|
|
|
const mockSquad = [{ id: "u1", isNew: false }]; // Existing unit, not new
|
|
|
|
// Mock startLevel to resolve immediately
|
|
mockGameLoop.startLevel = sinon.stub().resolves();
|
|
|
|
// Await the full async chain
|
|
await gameStateManager.handleEmbark({ detail: { squad: mockSquad, mode: "SELECT" } });
|
|
|
|
expect(gameStateManager.currentState).to.equal(
|
|
GameStateManager.STATES.DEPLOYMENT
|
|
);
|
|
expect(mockPersistence.saveRun.calledWith(gameStateManager.activeRunData))
|
|
.to.be.true;
|
|
expect(mockGameLoop.startLevel.calledWith(gameStateManager.activeRunData))
|
|
.to.be.true;
|
|
});
|
|
|
|
it("CoA 3b: handleEmbark should dispatch run-data-updated event", async () => {
|
|
// Mock RosterManager.recruitUnit
|
|
const mockRecruitedUnit = {
|
|
id: "UNIT_123",
|
|
name: "Valerius",
|
|
className: "Vanguard",
|
|
classId: "CLASS_VANGUARD",
|
|
};
|
|
gameStateManager.rosterManager.recruitUnit = sinon.stub().resolves(mockRecruitedUnit);
|
|
gameStateManager.setGameLoop(mockGameLoop);
|
|
await gameStateManager.init();
|
|
|
|
const mockSquad = [{ id: "u1", isNew: true, name: "Vanguard", classId: "CLASS_VANGUARD" }];
|
|
mockGameLoop.startLevel = sinon.stub().resolves();
|
|
|
|
let eventDispatched = false;
|
|
let eventData = null;
|
|
window.addEventListener("run-data-updated", (e) => {
|
|
eventDispatched = true;
|
|
eventData = e.detail.runData;
|
|
});
|
|
|
|
await gameStateManager.handleEmbark({ detail: { squad: mockSquad, mode: "DRAFT" } });
|
|
|
|
expect(eventDispatched).to.be.true;
|
|
expect(eventData).to.exist;
|
|
expect(eventData.squad).to.exist;
|
|
expect(eventData.squad[0].name).to.equal("Valerius");
|
|
expect(eventData.squad[0].className).to.equal("Vanguard");
|
|
});
|
|
|
|
it("CoA 4: continueGame should load save and resume engine", async () => {
|
|
gameStateManager.setGameLoop(mockGameLoop);
|
|
|
|
const savedData = { seed: 999, depth: 5, squad: [] };
|
|
mockPersistence.loadRun.resolves(savedData);
|
|
|
|
await gameStateManager.init();
|
|
await gameStateManager.continueGame();
|
|
|
|
expect(mockPersistence.loadRun.called).to.be.true;
|
|
expect(gameStateManager.activeRunData).to.deep.equal(savedData);
|
|
expect(mockGameLoop.startLevel.calledWith(savedData)).to.be.true;
|
|
});
|
|
});
|