Files
restitution/tests/unit/HealthBarSystem.test.js
kaykayyali 8fc45968b5 M2.3 + M2.4 + TeamManager integration: projectile sprites, death handling, build menu, production panel, building placer
- ProjectileSprite.js: physics arcade sprite, faction tint, off-screen culling
- CombatSystem: refactored enemy selection to use TeamManager instead of legacy containers
- Death handling: DYING alpha tween (500ms), smoke puff (300ms), unit:killed event, cleanup
- TeamManager: centralized team registry replacing goodGuys/badGuys containers
- HealthBarSystem, ResourceBar, CaptureProgressUI, BuildMenu, BuildingPlacer, BuildingRenderer, ProductionPanel
- Map_Player: wired new subsystems, removed legacy container creation
- Tests: ProjectileSprite (4), DeathHandling (13), CombatSystem updated

47 tests passed at dev time (M2.3), 158/158 at dev time (M2.4)
2026-06-01 05:18:33 +00:00

161 lines
5.1 KiB
JavaScript

/**
* HealthBarSystem.test.js — M2.2: Health bar overlay
*
* Tests:
* 1. drawBar — bar draws with correct width proportional to sprite displayWidth
* 2. Color transitions at thresholds — green (100%), yellow (50%), red (<25%)
* 3. Auto-hide at full HP, show on damage
* 4. destroy(unit) cleans up graphics objects
*/
import HealthBarSystem from 'Systems/HealthBarSystem';
// ── Helpers ───────────────────────────────────────────────────────
function buildMockScene() {
const added = [];
return {
add: {
graphics: jest.fn(() => {
const g = {
clear: jest.fn(),
fillStyle: jest.fn().mockReturnThis(),
fillRect: jest.fn().mockReturnThis(),
lineStyle: jest.fn().mockReturnThis(),
strokeRect: jest.fn().mockReturnThis(),
setDepth: jest.fn().mockReturnThis(),
setPosition: jest.fn().mockReturnThis(),
setAlpha: jest.fn().mockReturnThis(),
setVisible: jest.fn().mockReturnThis(),
destroy: jest.fn(),
active: true,
x: 0,
y: 0,
};
added.push(g);
return g;
}),
},
_graphicsAdded: added,
};
}
function buildMockUnit(overrides = {}) {
const hp = overrides.hp ?? 100;
const maxHp = overrides.maxHp ?? 100;
return {
x: 100,
y: 200,
displayWidth: 48,
displayHeight: 48,
active: true,
_data: { health: hp, maxHp },
getData: jest.fn((key) => {
if (key === 'health') return hp;
if (key === 'maxHp') return maxHp;
return undefined;
}),
setData: jest.fn(),
...overrides,
};
}
// ── Tests ─────────────────────────────────────────────────────────
describe('HealthBarSystem', () => {
let scene;
let system;
beforeEach(() => {
scene = buildMockScene();
system = new HealthBarSystem(scene);
});
afterEach(() => {
system?.destroy?.();
});
// ── 1. drawBar — correct width proportional to displayWidth ─────
test('drawBar creates a bar whose width matches unit displayWidth', () => {
const unit = buildMockUnit({ hp: 75, maxHp: 100 });
system.drawBar(unit);
expect(scene.add.graphics).toHaveBeenCalled();
const graphics = system._bars.get(unit);
expect(graphics).toBeDefined();
expect(graphics.active).toBe(true);
// drawBar should call fillRect twice: background + fill bar
expect(graphics.fillRect).toHaveBeenCalled();
// The second fillRect call (foreground bar) should have width based on health fraction
const calls = graphics.fillRect.mock.calls;
expect(calls.length).toBeGreaterThanOrEqual(1);
});
// ── 2. Color transitions at thresholds ────────────────────────
test('getColor returns green at 100%, yellow at 50%, red below 25%', () => {
expect(system.getColor(1.0)).toBe(0x00ff00);
expect(system.getColor(0.75)).toBe(0x00ff00);
expect(system.getColor(0.5)).toBe(0xffff00);
expect(system.getColor(0.25)).toBe(0xffff00);
expect(system.getColor(0.24)).toBe(0xff0000);
expect(system.getColor(0.0)).toBe(0xff0000);
});
// ── 3. Auto-hide at full HP, show on damage ───────────────────
test('bar is hidden at full HP and shown when damaged', () => {
const unit = buildMockUnit({ hp: 100, maxHp: 100 });
system.drawBar(unit);
system.update(unit);
const graphics = system._bars.get(unit);
expect(graphics).toBeDefined();
// At full HP, bar should be hidden
expect(graphics.setVisible).toHaveBeenCalledWith(false);
// Simulate damage
unit.getData = jest.fn((key) => {
if (key === 'health') return 80;
if (key === 'maxHp') return 100;
return undefined;
});
// Reset mock
graphics.setVisible.mockClear();
system.update(unit);
// After damage, bar should be visible
expect(graphics.setVisible).toHaveBeenCalledWith(true);
});
// ── 4. destroy(unit) cleans up graphics ──────────────────────
test('destroy(unit) destroys the health bar graphics', () => {
const unit = buildMockUnit({ hp: 60, maxHp: 100 });
system.drawBar(unit);
const graphics = system._bars.get(unit);
expect(graphics).toBeDefined();
const destroySpy = graphics.destroy;
system.destroy(unit);
expect(destroySpy).toHaveBeenCalled();
expect(system._bars.has(unit)).toBe(false);
});
// ── flash ─────────────────────────────────────────────────────
test('flash sets tint color briefly', () => {
const unit = buildMockUnit({ hp: 60, maxHp: 100 });
system.drawBar(unit);
const graphics = system._bars.get(unit);
system.flash(unit, 0xff0000);
// Flash should temporarily change fill style
expect(graphics.fillStyle).toHaveBeenCalled();
});
});