feat: HUD overlay via UIScene — health bar, quick slots, inventory info (Phase 4.7)
UIScene renders as overlay on top of GameScene: - Health bar (top-left) with color transitions green→yellow→red - 4 quick slots (bottom-center) with active highlight, item symbols and counts - Inventory weight/slots info (bottom-right) - Controls hint (top-right) GameScene pushes state to Phaser registry each frame. Phase 4 (Player Systems) complete — 222 tests passing. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
73
tests/ui.test.ts
Normal file
73
tests/ui.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Tests for UIScene helper functions and HUD state contract
|
||||
*/
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ElementRegistry } from '../src/chemistry/elements';
|
||||
import { CompoundRegistry } from '../src/chemistry/compounds';
|
||||
import { QuickSlots, SLOT_COUNT } from '../src/player/quickslots';
|
||||
import { Inventory } from '../src/player/inventory';
|
||||
import { Health } from '../src/ecs/components';
|
||||
|
||||
/** Mirror of UIScene's getItemDisplayColor for testability */
|
||||
function getItemDisplayColor(itemId: string): number {
|
||||
const el = ElementRegistry.getBySymbol(itemId);
|
||||
if (el) return parseInt(el.color.replace('#', ''), 16);
|
||||
const comp = CompoundRegistry.getById(itemId);
|
||||
if (comp) return parseInt(comp.color.replace('#', ''), 16);
|
||||
return 0xffffff;
|
||||
}
|
||||
|
||||
/** Mirror of UIScene's getItemDisplayName for testability */
|
||||
function getItemDisplayName(itemId: string): string {
|
||||
const el = ElementRegistry.getBySymbol(itemId);
|
||||
if (el) return el.symbol;
|
||||
const comp = CompoundRegistry.getById(itemId);
|
||||
if (comp) return comp.formula;
|
||||
return itemId;
|
||||
}
|
||||
|
||||
describe('HUD display helpers', () => {
|
||||
it('getItemDisplayColor returns correct color for element', () => {
|
||||
const color = getItemDisplayColor('Fe');
|
||||
expect(color).toBeGreaterThan(0);
|
||||
expect(color).not.toBe(0xffffff); // Not the fallback
|
||||
});
|
||||
|
||||
it('getItemDisplayColor returns fallback for unknown item', () => {
|
||||
expect(getItemDisplayColor('totally_unknown')).toBe(0xffffff);
|
||||
});
|
||||
|
||||
it('getItemDisplayName returns symbol for element', () => {
|
||||
expect(getItemDisplayName('Fe')).toBe('Fe');
|
||||
expect(getItemDisplayName('Na')).toBe('Na');
|
||||
});
|
||||
|
||||
it('getItemDisplayName returns formula for compound', () => {
|
||||
const name = getItemDisplayName('H2O');
|
||||
expect(name).toBe('H₂O');
|
||||
});
|
||||
|
||||
it('getItemDisplayName returns raw id for unknown', () => {
|
||||
expect(getItemDisplayName('xyz')).toBe('xyz');
|
||||
});
|
||||
});
|
||||
|
||||
describe('HUD registry state contract', () => {
|
||||
it('QuickSlots.getAll returns array of length SLOT_COUNT', () => {
|
||||
const qs = new QuickSlots();
|
||||
expect(qs.getAll()).toHaveLength(SLOT_COUNT);
|
||||
});
|
||||
|
||||
it('Inventory provides required state fields', () => {
|
||||
const inv = new Inventory(500, 20);
|
||||
expect(typeof inv.getTotalWeight()).toBe('number');
|
||||
expect(typeof inv.maxWeight).toBe('number');
|
||||
expect(typeof inv.slotCount).toBe('number');
|
||||
expect(Array.isArray(inv.getItems())).toBe(true);
|
||||
});
|
||||
|
||||
it('Health component arrays are accessible', () => {
|
||||
expect(Array.isArray(Health.current)).toBe(true);
|
||||
expect(Array.isArray(Health.max)).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user