aether-shards/test/core/GameLoop/deployment.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

160 lines
5.4 KiB
JavaScript

import { expect } from "@esm-bundle/chai";
import sinon from "sinon";
import { GameLoop } from "../../../src/core/GameLoop.js";
import {
createGameLoopSetup,
cleanupGameLoop,
createRunData,
createMockGameStateManagerForDeployment,
createMockMissionManager,
} from "./helpers.js";
describe("Core: GameLoop - Deployment", function () {
this.timeout(30000);
let gameLoop;
let container;
beforeEach(() => {
const setup = createGameLoopSetup();
gameLoop = setup.gameLoop;
container = setup.container;
gameLoop.init(container);
});
afterEach(() => {
cleanupGameLoop(gameLoop, container);
});
it("CoA 3: Deployment Phase should separate zones and allow manual placement", async () => {
const runData = createRunData({
squad: [{ id: "u1", classId: "CLASS_VANGUARD" }],
});
// Mock gameStateManager for deployment phase
gameLoop.gameStateManager = createMockGameStateManagerForDeployment();
// startLevel should now prepare the map but NOT spawn units immediately
await gameLoop.startLevel(runData, { startAnimation: false });
// 1. Verify Spawn Zones Generated
// The generator/loop should identify valid tiles for player start and enemy start
expect(gameLoop.playerSpawnZone).to.be.an("array").that.is.not.empty;
expect(gameLoop.enemySpawnZone).to.be.an("array").that.is.not.empty;
// 2. Verify Zone Separation
// Create copies to ensure we don't test against mutated arrays later
const pZone = [...gameLoop.playerSpawnZone];
const eZone = [...gameLoop.enemySpawnZone];
const overlap = pZone.some((pTile) =>
eZone.some((eTile) => eTile.x === pTile.x && eTile.z === pTile.z)
);
expect(overlap).to.be.false;
// 3. Test Manual Deployment (User Selection)
const unitDef = runData.squad[0];
const validTile = pZone[0]; // Pick first valid tile from player zone
// Expect a method to manually place a unit from the roster onto a specific tile
const unit = gameLoop.deployUnit(unitDef, validTile);
expect(unit).to.exist;
expect(unit.position.x).to.equal(validTile.x);
expect(unit.position.z).to.equal(validTile.z);
// Verify visual mesh created
const mesh = gameLoop.unitMeshes.get(unit.id);
expect(mesh).to.exist;
expect(mesh.position.x).to.equal(validTile.x);
// 4. Test Enemy Spawning (Finalize Deployment)
// This triggers the actual start of combat/AI
gameLoop.finalizeDeployment();
const enemies = gameLoop.unitManager.getUnitsByTeam("ENEMY");
expect(enemies.length).to.be.greaterThan(0);
// Verify enemies are in their zone
// Note: finalizeDeployment removes used spots from gameLoop.enemySpawnZone,
// so we check against our copy `eZone`.
const enemyPos = enemies[0].position;
const isInZone = eZone.some(
(t) => t.x === enemyPos.x && t.z === enemyPos.z
);
expect(
isInZone,
`Enemy spawned at ${enemyPos.x},${enemyPos.z} which is not in enemy zone`
).to.be.true;
});
it("CoA 5: finalizeDeployment should spawn enemies from mission enemy_spawns", async () => {
const runData = createRunData({
squad: [{ id: "u1", classId: "CLASS_VANGUARD" }],
});
// Mock gameStateManager for deployment phase
gameLoop.gameStateManager = createMockGameStateManagerForDeployment();
// Mock MissionManager with enemy_spawns
// Use ENEMY_DEFAULT which exists in the test environment
gameLoop.missionManager = createMockMissionManager([
{ enemy_def_id: "ENEMY_DEFAULT", count: 2 },
]);
await gameLoop.startLevel(runData, { startAnimation: false });
// Copy enemy spawn zone before finalizeDeployment modifies it
const eZone = [...gameLoop.enemySpawnZone];
// Finalize deployment should spawn enemies from mission definition
gameLoop.finalizeDeployment();
const enemies = gameLoop.unitManager.getUnitsByTeam("ENEMY");
// Should have spawned 2 enemies (or as many as possible given spawn zone size)
expect(enemies.length).to.be.greaterThan(0);
expect(enemies.length).to.be.at.most(2);
// Verify enemies are in their zone
enemies.forEach((enemy) => {
const enemyPos = enemy.position;
const isInZone = eZone.some(
(t) => t.x === enemyPos.x && t.z === enemyPos.z
);
expect(
isInZone,
`Enemy spawned at ${enemyPos.x},${enemyPos.z} which is not in enemy zone`
).to.be.true;
});
});
it("CoA 6: finalizeDeployment should fall back to default if no enemy_spawns", async () => {
const runData = createRunData({
squad: [{ id: "u1", classId: "CLASS_VANGUARD" }],
});
// Mock gameStateManager for deployment phase
gameLoop.gameStateManager = createMockGameStateManagerForDeployment();
// Mock MissionManager with no enemy_spawns
gameLoop.missionManager = createMockMissionManager([]);
await gameLoop.startLevel(runData, { startAnimation: false });
// Finalize deployment should fall back to default behavior
const consoleWarnSpy = sinon.spy(console, "warn");
gameLoop.finalizeDeployment();
// Should have warned about missing enemy_spawns
expect(consoleWarnSpy.calledWith(sinon.match(/No enemy_spawns defined/))).to
.be.true;
const enemies = gameLoop.unitManager.getUnitsByTeam("ENEMY");
// Should still spawn at least one enemy (default behavior)
expect(enemies.length).to.be.greaterThan(0);
consoleWarnSpy.restore();
});
});