138 lines
4.2 KiB
JavaScript
138 lines
4.2 KiB
JavaScript
|
|
import { expect } from "@esm-bundle/chai";
|
||
|
|
import { UnitManager } from "../../src/managers/UnitManager.js";
|
||
|
|
|
||
|
|
// Note: These tests rely on the existence of src/units/Explorer.js and src/units/Enemy.js
|
||
|
|
// If running in isolation without those files, mocks would be required.
|
||
|
|
|
||
|
|
describe("Manager: UnitManager", () => {
|
||
|
|
let manager;
|
||
|
|
let mockRegistry;
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
// Setup a mock registry to simulate loading definitions from JSON
|
||
|
|
mockRegistry = {
|
||
|
|
get: (id) => {
|
||
|
|
if (id === "CLASS_VANGUARD") {
|
||
|
|
return {
|
||
|
|
name: "Vanguard",
|
||
|
|
type: "EXPLORER",
|
||
|
|
stats: { health: 100, speed: 10 },
|
||
|
|
};
|
||
|
|
}
|
||
|
|
if (id === "ENEMY_GOBLIN") {
|
||
|
|
return {
|
||
|
|
name: "Goblin",
|
||
|
|
type: "ENEMY",
|
||
|
|
stats: { health: 30, attack: 5 },
|
||
|
|
ai_archetype: "BRUISER",
|
||
|
|
};
|
||
|
|
}
|
||
|
|
if (id === "STRUCT_WALL") {
|
||
|
|
return {
|
||
|
|
name: "Wall",
|
||
|
|
type: "STRUCTURE",
|
||
|
|
model: "wall.glb",
|
||
|
|
stats: { health: 50 },
|
||
|
|
};
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
manager = new UnitManager(mockRegistry);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("CoA 1: createUnit should instantiate an Explorer for CLASS_ IDs", () => {
|
||
|
|
const unit = manager.createUnit("CLASS_VANGUARD", "PLAYER");
|
||
|
|
|
||
|
|
expect(unit).to.exist;
|
||
|
|
// Verify it behaves like an Explorer (has class logic)
|
||
|
|
expect(unit.type).to.equal("EXPLORER");
|
||
|
|
expect(unit.team).to.equal("PLAYER");
|
||
|
|
expect(unit.name).to.equal("Vanguard");
|
||
|
|
|
||
|
|
// Verify it was added to the active list
|
||
|
|
expect(manager.getUnitById(unit.id)).to.equal(unit);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("CoA 2: createUnit should instantiate an Enemy for ENEMY_ IDs", () => {
|
||
|
|
const unit = manager.createUnit("ENEMY_GOBLIN", "ENEMY");
|
||
|
|
|
||
|
|
expect(unit).to.exist;
|
||
|
|
expect(unit.type).to.equal("ENEMY");
|
||
|
|
expect(unit.team).to.equal("ENEMY");
|
||
|
|
// Enemies should have AI props
|
||
|
|
expect(unit.archetypeId).to.equal("BRUISER");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("CoA 3: createUnit should handle generic structures", () => {
|
||
|
|
const unit = manager.createUnit("STRUCT_WALL", "NEUTRAL");
|
||
|
|
|
||
|
|
expect(unit).to.exist;
|
||
|
|
expect(unit.type).to.equal("STRUCTURE");
|
||
|
|
expect(unit.team).to.equal("NEUTRAL");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("CoA 4: removeUnit should remove the unit from the active map", () => {
|
||
|
|
const unit = manager.createUnit("CLASS_VANGUARD", "PLAYER");
|
||
|
|
const id = unit.id;
|
||
|
|
|
||
|
|
expect(manager.getUnitById(id)).to.exist;
|
||
|
|
|
||
|
|
const removed = manager.removeUnit(id);
|
||
|
|
|
||
|
|
expect(removed).to.be.true;
|
||
|
|
expect(manager.getUnitById(id)).to.be.undefined;
|
||
|
|
expect(manager.getAllUnits()).to.have.lengthOf(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("CoA 5: getUnitsInRange should return units within Manhattan distance", () => {
|
||
|
|
const u1 = manager.createUnit("CLASS_VANGUARD", "PLAYER");
|
||
|
|
// Manually set position since we aren't using the Grid's moveUnit here
|
||
|
|
u1.position = { x: 0, y: 0, z: 0 };
|
||
|
|
|
||
|
|
const u2 = manager.createUnit("ENEMY_GOBLIN", "ENEMY");
|
||
|
|
u2.position = { x: 2, y: 0, z: 0 }; // Distance 2
|
||
|
|
|
||
|
|
const u3 = manager.createUnit("ENEMY_GOBLIN", "ENEMY");
|
||
|
|
u3.position = { x: 5, y: 0, z: 0 }; // Distance 5
|
||
|
|
|
||
|
|
// Check range 3
|
||
|
|
const results = manager.getUnitsInRange({ x: 0, y: 0, z: 0 }, 3);
|
||
|
|
|
||
|
|
expect(results).to.include(u1); // Distance 0 (Self)
|
||
|
|
expect(results).to.include(u2); // Distance 2
|
||
|
|
expect(results).to.not.include(u3); // Distance 5
|
||
|
|
});
|
||
|
|
|
||
|
|
it("CoA 6: getUnitsInRange should filter by team if provided", () => {
|
||
|
|
const u1 = manager.createUnit("CLASS_VANGUARD", "PLAYER");
|
||
|
|
u1.position = { x: 0, y: 0, z: 0 };
|
||
|
|
|
||
|
|
const u2 = manager.createUnit("ENEMY_GOBLIN", "ENEMY");
|
||
|
|
u2.position = { x: 1, y: 0, z: 0 };
|
||
|
|
|
||
|
|
// Filter for ENEMY only
|
||
|
|
const results = manager.getUnitsInRange({ x: 0, y: 0, z: 0 }, 5, "ENEMY");
|
||
|
|
|
||
|
|
expect(results).to.include(u2);
|
||
|
|
expect(results).to.not.include(u1);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("CoA 7: tickAll should trigger cooldown updates on units", () => {
|
||
|
|
const unit = manager.createUnit("CLASS_VANGUARD", "PLAYER");
|
||
|
|
|
||
|
|
// Mock the skill manager on the unit instance
|
||
|
|
let ticked = false;
|
||
|
|
unit.skillManager = {
|
||
|
|
tickCooldowns: () => {
|
||
|
|
ticked = true;
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
manager.tickAll();
|
||
|
|
|
||
|
|
expect(ticked).to.be.true;
|
||
|
|
});
|
||
|
|
});
|