Skip to content

Commit c1bd4b8

Browse files
committed
Add edge case tests and improve mobile scroll for scenario list
- 8 new game engine edge case tests (no-burn orders, skip ordnance/combat, wrong player rejection, destroyed ships in movement, fleet elimination, blockade runner landing) - Make scenario selection screen scrollable on mobile
1 parent 21367b1 commit c1bd4b8

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

src/shared/__tests__/game-engine.test.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,3 +810,81 @@ describe('Fleet Action scenario', () => {
810810
}
811811
});
812812
});
813+
814+
describe('Edge cases', () => {
815+
it('no-burn orders for all ships produces valid movement', () => {
816+
const orders: AstrogationOrder[] = initialState.ships
817+
.filter(s => s.owner === 0)
818+
.map(s => ({ shipId: s.id, burn: null }));
819+
const result = processAstrogation(initialState, 0, orders, map);
820+
expect('error' in result).toBe(false);
821+
});
822+
823+
it('skip ordnance when no ordnance exists', () => {
824+
initialState.phase = 'ordnance';
825+
const result = skipOrdnance(initialState, 0);
826+
expect('error' in result).toBe(false);
827+
});
828+
829+
it('skip combat when no enemies are nearby', () => {
830+
initialState.phase = 'combat';
831+
const result = skipCombat(initialState, 0, map);
832+
expect('error' in result).toBe(false);
833+
});
834+
835+
it('wrong player cannot submit orders', () => {
836+
// Player 0 is active, try submitting as player 1
837+
const orders: AstrogationOrder[] = initialState.ships
838+
.filter(s => s.owner === 1)
839+
.map(s => ({ shipId: s.id, burn: null }));
840+
const result = processAstrogation(initialState, 1, orders, map);
841+
expect('error' in result).toBe(true);
842+
});
843+
844+
it('destroyed ships are skipped in movement', () => {
845+
const ship = initialState.ships[0];
846+
ship.destroyed = true;
847+
const orders: AstrogationOrder[] = [{ shipId: ship.id, burn: null }];
848+
const result = processAstrogation(initialState, 0, orders, map);
849+
expect('error' in result).toBe(false);
850+
});
851+
852+
it('fleet action ends when one side is eliminated', () => {
853+
const fleetState = createGame(SCENARIOS.fleetAction, map, 'FLT02', findBaseHex);
854+
// Destroy all of player 1's ships
855+
fleetState.ships.filter(s => s.owner === 1).forEach(s => { s.destroyed = true; });
856+
857+
// Run a no-op astrogation to trigger checkGameEnd
858+
const orders: AstrogationOrder[] = fleetState.ships
859+
.filter(s => s.owner === 0)
860+
.map(s => ({ shipId: s.id, burn: null }));
861+
const result = processAstrogation(fleetState, 0, orders, map);
862+
if (!('error' in result)) {
863+
expect(result.state.phase).toBe('gameOver');
864+
expect(result.state.winner).toBe(0);
865+
}
866+
});
867+
868+
it('blockade runner wins by landing on Mars', () => {
869+
const blockadeState = createGame(SCENARIOS.blockade, map, 'BLK02', findBaseHex);
870+
const runner = blockadeState.ships.find(s => s.owner === 0)!;
871+
// Position runner just outside Mars gravity, drifting toward Mars surface
872+
// Mars center is {q:10, r:8}, gravity ring at radius 1
873+
// Ship at {q:12, r:7} with velocity {dq:-1, dr:0} drifts to base hex {q:11, r:7}
874+
// Gravity then deflects it onto Mars surface — triggers landing on non-destructive body
875+
runner.position = { q: 12, r: 7 };
876+
runner.velocity = { dq: -1, dr: 0 };
877+
runner.landed = false;
878+
879+
// Process drift-only turn (no burn)
880+
const orders: AstrogationOrder[] = blockadeState.ships
881+
.filter(s => s.owner === 0)
882+
.map(s => ({ shipId: s.id, burn: null }));
883+
const result = processAstrogation(blockadeState, 0, orders, map);
884+
if (!('error' in result)) {
885+
expect(result.state.phase).toBe('gameOver');
886+
expect(result.state.winner).toBe(0);
887+
expect(result.state.winReason).toContain('Mars');
888+
}
889+
});
890+
});

static/style.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,15 @@ body {
3434
justify-content: center;
3535
z-index: 10;
3636
background: rgba(10, 10, 26, 0.85);
37+
overflow-y: auto;
38+
-webkit-overflow-scrolling: touch;
3739
}
3840

3941
.menu-content {
4042
text-align: center;
4143
max-width: 360px;
4244
padding: 2rem;
45+
margin: auto; /* Center when screen scrolls */
4346
}
4447

4548
.title {

0 commit comments

Comments
 (0)