- 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)
252 lines
12 KiB
Plaintext
252 lines
12 KiB
Plaintext
PASS tests/PathfindingService.test.ts
|
|
PathfindingService
|
|
constructor
|
|
✓ creates an EasyStar instance with correct config (11 ms)
|
|
setGrid
|
|
✓ sets the grid and acceptable tiles on EasyStar (2 ms)
|
|
setWalkable
|
|
✓ marks a tile as blocked (1) and updates EasyStar grid (1 ms)
|
|
✓ marks a tile as walkable (0) (1 ms)
|
|
✓ no-ops on out-of-bounds coordinates (1 ms)
|
|
✓ no-ops when value unchanged
|
|
findPath
|
|
✓ resolves with path when EasyStar finds one (2 ms)
|
|
✓ resolves with null when no path exists (2 ms)
|
|
isValidMove
|
|
✓ returns true when a path exists between adjacent tiles (2 ms)
|
|
✓ returns false when no path exists (1 ms)
|
|
✓ returns false when to tile is blocked (1 ms)
|
|
straight-line path
|
|
✓ returns direct horizontal path on clear grid (1 ms)
|
|
|
|
PASS tests/roomLogic.test.ts
|
|
roomLogic
|
|
nextTeam
|
|
✓ should return ukraine for empty player list (9 ms)
|
|
✓ should balance: 1 ukraine → next is russia (2 ms)
|
|
✓ should balance: 1 ukraine + 1 russia → next is ukraine (1 ms)
|
|
✓ should maintain balance with 2 ukraine + 1 russia → next is russia (1 ms)
|
|
✓ should maintain balance with 2 each → next is ukraine (1 ms)
|
|
canJoin
|
|
✓ should allow join when below max (1 ms)
|
|
✓ should reject when at max (1 ms)
|
|
✓ should reject when above max (1 ms)
|
|
createPlayer
|
|
✓ should create a player with correct defaults (1 ms)
|
|
✓ should create a russia player (1 ms)
|
|
disconnectPlayer
|
|
✓ should set connected to false and ready to false (1 ms)
|
|
|
|
PASS tests/index.test.ts
|
|
server
|
|
✓ placeholder — integration test passed via curl (7 ms)
|
|
|
|
PASS tests/inputHandler.test.ts
|
|
handleInput - spawnUnit
|
|
✓ delegates to UnitManager.spawnUnit and returns the unit (2 ms)
|
|
✓ uses infantry if unitType is infantry (1 ms)
|
|
handleInput - moveUnit
|
|
✓ delegates to UnitManager.moveUnit
|
|
handleInput - attackUnit
|
|
✓ delegates to UnitManager.attackUnit (1 ms)
|
|
handleInput - damageUnit
|
|
✓ delegates to UnitManager.damageUnit
|
|
handleInput - removeDeadUnits
|
|
✓ delegates to UnitManager.removeDeadUnits (1 ms)
|
|
handleInput - applyEvent
|
|
✓ applies a UnitEvent to a unit (1 ms)
|
|
handleInput - unknown type
|
|
✓ returns null for unrecognized message type
|
|
handleInput - getUnitsInRange
|
|
✓ returns units in range for the given team
|
|
handleInput - full client flow
|
|
✓ spawn → move → damage → cleanup (1 ms)
|
|
|
|
PASS tests/EconomyService.test.ts
|
|
EconomyService
|
|
✓ should initialize a player with default values (0 resources, 0 incomeRate, lastTick=0) (7 ms)
|
|
✓ should return 0 for an unknown player
|
|
✓ should return current resources for a known player (1 ms)
|
|
✓ should add income when 1000ms has elapsed since lastTick (1 ms)
|
|
✓ should NOT add income before 1000ms has elapsed
|
|
✓ should accumulate income for multiple elapsed intervals (1 ms)
|
|
✓ should add nothing when incomeRate is 0
|
|
✓ should only count whole intervals (1500ms → 1 tick, not 1.5) (1 ms)
|
|
✓ should track lastTick per player independently (1 ms)
|
|
✓ should return true when player has sufficient resources (1 ms)
|
|
✓ should return false when player has insufficient resources
|
|
✓ should return true when cost equals resources exactly (1 ms)
|
|
✓ should return false for an unknown player
|
|
✓ should reduce resources and return true on success
|
|
✓ should return false and leave resources unchanged when insufficient (1 ms)
|
|
✓ should return false for an unknown player without mutating state
|
|
✓ should add income to an existing player
|
|
✓ should auto-initialize a player when addIncome is called before initPlayer (1 ms)
|
|
✓ should default to adding 0 when no amount is provided
|
|
✓ should set the income rate for a known player
|
|
✓ should auto-initialize a player when setIncomeRate is called before initPlayer (1 ms)
|
|
✓ should keep multiple players' economies independent
|
|
✓ should allow initializing a player multiple times (reset) (1 ms)
|
|
|
|
PASS tests/unit-states.test.ts
|
|
UnitState enum
|
|
✓ has 5 states: IDLING, MOVING, ATTACKING, DYING, DESTROYED (7 ms)
|
|
UnitEvent enum
|
|
✓ has 7 events (1 ms)
|
|
STATE_TRANSITIONS
|
|
✓ IDLING transitions: MOVE → MOVING, ATTACK → ATTACKING, DIE → DYING (1 ms)
|
|
✓ MOVING transitions: ARRIVED → IDLING, ENEMY_SPOTTED → ATTACKING, DIE → DYING (1 ms)
|
|
✓ ATTACKING transitions: TARGET_LOST → IDLING, OUT_OF_RANGE → MOVING, DIE → DYING (1 ms)
|
|
✓ DYING has no explicit transitions (empty object) (1 ms)
|
|
✓ DESTROYED has no transitions (terminal)
|
|
✓ has entries for all 5 states
|
|
✓ all transition targets are valid UnitState values (2 ms)
|
|
isValidTransition
|
|
✓ returns true for valid transition: IDLING + MOVE → MOVING
|
|
✓ returns true for valid transition: ATTACKING + TARGET_LOST → IDLING (1 ms)
|
|
✓ returns false for invalid transition: IDLING + ARRIVED → whatever
|
|
✓ returns false for wrong target: IDLING + MOVE → ATTACKING
|
|
✓ returns false from DESTROYED (terminal)
|
|
✓ returns false for unknown state (safety)
|
|
validEventsFor
|
|
✓ returns [MOVE, ATTACK, DIE] for IDLING (1 ms)
|
|
✓ returns [] for DESTROYED
|
|
✓ returns [] for unknown state
|
|
nextState
|
|
✓ returns MOVING for IDLING + MOVE (1 ms)
|
|
✓ returns DYING for ATTACKING + DIE
|
|
✓ returns null for invalid transition
|
|
✓ returns null for unknown state (1 ms)
|
|
✓ returns null when event not valid for state (2 ms)
|
|
|
|
PASS tests/UnitManager.test.ts
|
|
UnitManager - spawnUnit
|
|
✓ creates a unit with id, ownerId, type, team, position (7 ms)
|
|
✓ new unit starts IDLING with full health
|
|
✓ different types get the right max health (tank=150, infantry=100)
|
|
✓ assigns unique IDs to each unit
|
|
✓ stores units internally (getUnit retrieves by id) (1 ms)
|
|
✓ getUnit returns undefined for unknown id
|
|
UnitManager - moveUnit
|
|
✓ sets path and transitions to MOVING (1 ms)
|
|
✓ does nothing for non-existent unit id
|
|
✓ does nothing for dead unit
|
|
UnitManager - attackUnit
|
|
✓ sets targetId and transitions to ATTACKING
|
|
✓ does nothing for non-existent attacker (2 ms)
|
|
✓ does nothing for dead attacker (1 ms)
|
|
UnitManager - damageUnit
|
|
✓ reduces health.current by the damage amount (1 ms)
|
|
✓ transitions to DYING when health reaches 0
|
|
✓ clamps health.current to 0 on overkill (1 ms)
|
|
✓ does nothing for non-existent unit
|
|
✓ does nothing for already dead unit
|
|
UnitManager - removeDeadUnits
|
|
✓ returns IDs of units in DYING state (2 ms)
|
|
✓ removes dead units from internal storage
|
|
✓ returns empty array when no units are dead (1 ms)
|
|
✓ returns multiple IDs when multiple units are dead (1 ms)
|
|
UnitManager - getUnitsInRange
|
|
✓ returns units within the given range (1 ms)
|
|
✓ filters by team
|
|
✓ returns empty array when no units in range (1 ms)
|
|
✓ does not return dead units
|
|
✓ excludes units from the querying team
|
|
UnitManager - full lifecycle
|
|
✓ spawn → move → attack → damage → destroy cycle (1 ms)
|
|
UnitManager - applyEvent
|
|
✓ applies a valid state transition event (1 ms)
|
|
✓ ignores invalid transition (does not change state)
|
|
✓ returns null for non-existent unit
|
|
|
|
PASS tests/GameState.test.ts
|
|
GameState schema
|
|
✓ should initialize with an empty players array (7 ms)
|
|
✓ should allow adding a Player with id, team, and ready (2 ms)
|
|
✓ should track connected status and role (1 ms)
|
|
✓ should support multiple players with different teams (1 ms)
|
|
|
|
PASS tests/generateCode.test.ts
|
|
generateCode
|
|
✓ should return a string of the requested length (6 ms)
|
|
✓ should return a string for length 6 (1 ms)
|
|
✓ should only contain uppercase alphanumeric characters (11 ms)
|
|
✓ should not contain ambiguous characters (0, O, 1, I, L) (25 ms)
|
|
✓ should generate different codes on successive calls (1 ms)
|
|
|
|
PASS tests/building-types.test.ts
|
|
BUILDING_TYPES
|
|
✓ has 5 building types (3 ms)
|
|
✓ COMMAND_CENTER: no build cost, no productions, no income, health 1000 (2 ms)
|
|
✓ BARRACKS: cost 50 ammo, build time 10s, produces infantry, health 400, maxQueue 5 (1 ms)
|
|
✓ VEHICLE_DEPOT: cost 100 fuel, build time 20s, produces tank, health 600, maxQueue 3 (1 ms)
|
|
✓ LOGISTICS: cost 75 fuel, income +5 fuel/tick, health 350 (1 ms)
|
|
✓ AMMO_FACTORY: cost 75 ammo, income +5 ammo/tick, health 350
|
|
getBuildingType
|
|
✓ returns the building config for a valid id (1 ms)
|
|
✓ returns undefined for an unknown id
|
|
getAllBuildingTypes
|
|
✓ returns the full BUILDING_TYPES map
|
|
|
|
PASS tests/systems/CombatResolver.test.ts
|
|
CombatResolver.findTarget
|
|
✓ returns null for empty target list (3 ms)
|
|
✓ returns the only target when one is in range (1 ms)
|
|
✓ returns null when the only target is out of range
|
|
✓ picks the closest target when multiple are in range
|
|
✓ skips dead targets
|
|
✓ returns null when all targets are dead (1 ms)
|
|
✓ picks weakest (lowest HP) when priority is 'weakest'
|
|
✓ picks strongest (highest HP) when priority is 'strongest'
|
|
✓ defaults to closest when priority is omitted
|
|
✓ filters by line of sight — target behind wall is skipped
|
|
✓ selects target with clear line of sight when grid is provided
|
|
CombatResolver.hasLineOfSight
|
|
✓ returns true for adjacent tiles on empty grid
|
|
✓ returns true for diagonal on empty grid
|
|
✓ returns false when a wall tile is on the horizontal path (1 ms)
|
|
✓ returns false when a wall tile is on the vertical path
|
|
✓ returns false when a wall tile is on the diagonal path
|
|
✓ does not block on the starting tile
|
|
✓ returns true when start and target are the same tile
|
|
✓ returns true for empty grid
|
|
✓ returns true for long clear horizontal line
|
|
✓ clamps out-of-bounds coordinates to grid edges
|
|
CombatResolver.calculateDamage
|
|
✓ applies base damage with no armor and no crit (1 ms)
|
|
✓ reduces damage by armor
|
|
✓ applies armor piercing — reduces effective armor
|
|
✓ always deals at least 1 damage when damage > 0
|
|
✓ returns 0 damage when base damage is 0 (no min-1 for zero)
|
|
✓ crits multiply damage (1 ms)
|
|
✓ crit + armor piercing work together
|
|
✓ uses default damage modifiers when damageType is unknown
|
|
✓ includes damage type in result
|
|
CombatResolver.applyDamage
|
|
✓ subtracts damage from health
|
|
✓ marks unit as dead when health reaches 0
|
|
✓ marks unit as dead when health goes below 0
|
|
✓ does not modify already-dead units
|
|
✓ returns a new object (does not mutate original)
|
|
✓ preserves other fields on the unit (1 ms)
|
|
CombatResolver damage modifiers
|
|
✓ rifle modifier: AP 0.1, critChance 0.05, critMultiplier 1.5
|
|
✓ cannon modifier: AP 0.5, critChance 0.10, critMultiplier 2.0
|
|
✓ default modifier for unknown damage types
|
|
CombatResolver distance
|
|
✓ calculates euclidean distance between two points
|
|
✓ returns 0 for same point
|
|
|
|
PASS tests/GameRoom.test.ts
|
|
GameRoom wiring
|
|
✓ should delegate onJoin to roomLogic helpers (3 ms)
|
|
✓ should throw on exceeding maxClients (4 ms)
|
|
✓ should delegate onLeave to disconnectPlayer helper (1 ms)
|
|
|
|
A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them.
|
|
Test Suites: 12 passed, 12 total
|
|
Tests: 172 passed, 172 total
|
|
Snapshots: 0 total
|
|
Time: 5.596 s, estimated 6 s
|
|
Ran all test suites.
|