- 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)
137 lines
4.1 KiB
JavaScript
137 lines
4.1 KiB
JavaScript
/**
|
|
* CaptureProgressUI.test.js -- S4.2: Capture progress world-space HUD
|
|
*
|
|
* Tests:
|
|
* 1. drawBar -- lazily creates Graphics for a CP on first update
|
|
* 2. update -- refreshes fill based on getCaptureProgress()
|
|
* 3. Color by state: neutral grey, contested yellow, captured green/red
|
|
* 4. destroy(cp) cleans up graphics
|
|
* 5. shutdown clears all
|
|
*/
|
|
|
|
import CaptureProgressUI from 'Systems/CaptureProgressUI';
|
|
|
|
function buildMockScene() {
|
|
const added = [];
|
|
return {
|
|
add: {
|
|
graphics: jest.fn(() => {
|
|
const g = {
|
|
clear: jest.fn(),
|
|
fillStyle: jest.fn().mockReturnThis(),
|
|
fillRect: jest.fn().mockReturnThis(),
|
|
fillCircle: jest.fn().mockReturnThis(),
|
|
strokeCircle: jest.fn().mockReturnThis(),
|
|
lineStyle: jest.fn().mockReturnThis(),
|
|
setDepth: jest.fn().mockReturnThis(),
|
|
setPosition: jest.fn().mockReturnThis(),
|
|
setVisible: jest.fn().mockReturnThis(),
|
|
setAlpha: jest.fn().mockReturnThis(),
|
|
destroy: jest.fn(),
|
|
active: true,
|
|
x: 0, y: 0,
|
|
};
|
|
added.push(g);
|
|
return g;
|
|
}),
|
|
},
|
|
_graphicsAdded: added,
|
|
};
|
|
}
|
|
|
|
function buildMockCP(state = 'NEUTRAL', progress = 0, owner = null, overrides = {}) {
|
|
return {
|
|
id: 'cp_test_01',
|
|
x: 400,
|
|
y: 300,
|
|
radiusPx: 80,
|
|
active: true,
|
|
getCaptureProgress: jest.fn(() => progress),
|
|
getState: jest.fn(() => state),
|
|
getOwner: jest.fn(() => owner),
|
|
zone: { active: true },
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe('CaptureProgressUI', () => {
|
|
let scene;
|
|
let ui;
|
|
|
|
beforeEach(() => {
|
|
scene = buildMockScene();
|
|
ui = new CaptureProgressUI(scene);
|
|
});
|
|
|
|
afterEach(() => {
|
|
ui?.shutdown?.();
|
|
});
|
|
|
|
// -- 1. drawBar lazily creates Graphics --------------------------------
|
|
test('update lazily draws a bar for a new CP', () => {
|
|
const cp = buildMockCP('NEUTRAL', 0, null);
|
|
ui.update(cp);
|
|
expect(scene.add.graphics).toHaveBeenCalledTimes(1);
|
|
const g = ui._bars.get(cp);
|
|
expect(g).toBeDefined();
|
|
expect(g.setDepth).toHaveBeenCalled();
|
|
});
|
|
|
|
// -- 2. update refreshes fill based on progress --------------------------
|
|
test('bar fill reflects capture progress at 50%', () => {
|
|
const cp = buildMockCP('CONTESTED', 50, null);
|
|
ui.update(cp);
|
|
const g = ui._bars.get(cp);
|
|
expect(g.fillStyle).toHaveBeenCalled();
|
|
expect(g.fillRect).toHaveBeenCalled();
|
|
});
|
|
|
|
test('bar fill width scales with progress fraction', () => {
|
|
const cp = buildMockCP('CONTESTED', 75, null, { radiusPx: 100 });
|
|
ui.update(cp);
|
|
const g = ui._bars.get(cp);
|
|
// Should call fillRect for background + foreground + possibly border
|
|
expect(g.fillRect.mock.calls.length).toBeGreaterThanOrEqual(1);
|
|
});
|
|
|
|
// -- 3. Colors by state ------------------------------------------------
|
|
test('getColor returns grey for NEUTRAL', () => {
|
|
expect(ui.getColor('NEUTRAL')).toBe(0xaaaaaa);
|
|
});
|
|
|
|
test('getColor returns yellow for CONTESTED', () => {
|
|
expect(ui.getColor('CONTESTED')).toBe(0xffcc00);
|
|
});
|
|
|
|
test('getColor returns green when captured by player', () => {
|
|
expect(ui.getColor('CAPTURED', 'player')).toBe(0x00ff00);
|
|
});
|
|
|
|
test('getColor returns red when captured by enemy', () => {
|
|
expect(ui.getColor('CAPTURED', 'enemy')).toBe(0xff3333);
|
|
});
|
|
|
|
// -- 4. destroy(cp) cleans up graphics ---------------------------------
|
|
test('destroy(cp) removes bar from Map and destroys graphics', () => {
|
|
const cp = buildMockCP('CAPTURED', 100, 'player');
|
|
ui.update(cp);
|
|
const g = ui._bars.get(cp);
|
|
const destroySpy = g.destroy;
|
|
ui.destroy(cp);
|
|
expect(destroySpy).toHaveBeenCalled();
|
|
expect(ui._bars.has(cp)).toBe(false);
|
|
});
|
|
|
|
// -- 5. shutdown clears all --------------------------------------------
|
|
test('shutdown destroys all bars and clears Map', () => {
|
|
const cp1 = buildMockCP('NEUTRAL', 0);
|
|
const cp2 = buildMockCP('CAPTURED', 100, 'player');
|
|
ui.update(cp1);
|
|
ui.update(cp2);
|
|
expect(ui._bars.size).toBe(2);
|
|
ui.shutdown();
|
|
expect(ui._bars.size).toBe(0);
|
|
expect(scene._graphicsAdded.every(g => g.destroy.mock.calls.length > 0)).toBe(true);
|
|
});
|
|
});
|