Files
wownerogue/test/tavernRoom.test.js
jwinterm fad2a695bd Wownerogue
A browser-based roguelike synchronized with crypto block timing. A run is a race
against the next block: reach the exit before the block lands, or the house wins.
The same codebase runs the solo dungeon, the social Tavern, and operator-selected
PvP and race rulesets, with separate free and paid leaderboards.

Self-hostable under the MIT License. See README.md to run it, docs/ARCHITECTURE.md
for the design, and docs/DEPLOY.md to operate an instance.
2026-07-27 08:23:01 -04:00

101 lines
4.3 KiB
JavaScript

const Room = require('../src/multiplayer/Room');
const Occupant = require('../src/multiplayer/Occupant');
describe('Room: shared real-time engine (Tavern instance)', () => {
test('builds a rectangular walkable map with at least one spawn', () => {
const room = new Room({ id: 'test-room', type: 'tavern' });
expect(room.rows).toBeGreaterThan(0);
expect(room.cols).toBeGreaterThan(0);
expect(room.spawns.length).toBeGreaterThan(0);
// Border is solid; a spawn tile is walkable.
expect(room.isWalkable(0, 0)).toBe(false);
const s = room.spawns[0];
expect(room.isWalkable(s.x, s.y)).toBe(true);
});
test('occupants join at a spawn and appear in the snapshot', () => {
const room = new Room({ id: 'r' });
const a = room.addOccupant('alice', { name: 'Alice', avatar: 'default' });
room.addOccupant('bob', { name: 'Bob' });
expect(a).toBeInstanceOf(Occupant);
expect(room.size).toBe(2);
const ids = room.snapshot().occupants.map(o => o.id).sort();
expect(ids).toEqual(['alice', 'bob']);
});
test('full state includes walkability for designed rooms without ASCII layout', () => {
const room = new Room({
id: 'designed',
roomData: {
cols: 2,
rows: 2,
walkable: [[true, false], [false, true]]
}
});
const state = room.fullState();
expect(state.layout).toBeNull();
expect(state.walkable).toEqual([[true, false], [false, true]]);
});
test('server-authoritative movement: a valid step moves and sets facing', () => {
const room = new Room({ id: 'r' });
const occ = room.addOccupant('alice');
const startX = occ.x;
const res = room.moveOccupant('alice', 1, 0); // step right (spawn has open floor right)
expect(res.moved).toBe(true);
expect(occ.x).toBe(startX + 1);
expect(occ.facing).toBe('right');
});
test('rejects diagonal, multi-tile and no-op requests', () => {
const room = new Room({ id: 'r' });
room.addOccupant('alice');
expect(room.moveOccupant('alice', 1, 1).moved).toBe(false); // diagonal
expect(room.moveOccupant('alice', 0, 0).moved).toBe(false); // no-op
expect(room.moveOccupant('ghost', 1, 0).moved).toBe(false); // not in room
});
test('cannot walk through walls or off the map', () => {
const room = new Room({ id: 'r' });
const occ = room.addOccupant('alice');
for (let i = 0; i < 40; i++) room.moveOccupant('alice', -1, 0); // slam left
expect(occ.x).toBeGreaterThanOrEqual(0);
expect(room.isWalkable(occ.x, occ.y)).toBe(true); // still on floor
expect(room.isWalkable(occ.x - 1, occ.y)).toBe(false); // wall to the left
});
test('match rooms (solidOccupants) block stepping onto another occupant', () => {
const match = new Room({ id: 'm', solidOccupants: true });
const p = match.addOccupant('p'); // spawn A
const q = match.addOccupant('q'); // spawn B, adjacent to A
expect(Math.abs(p.x - q.x) + Math.abs(p.y - q.y)).toBe(1);
const res = match.moveOccupant('q', Math.sign(p.x - q.x), Math.sign(p.y - q.y));
expect(res.moved).toBe(false);
expect(res.reason).toBe('occupied');
});
test('tavern rooms let occupants share a tile (open doorways, no blocking griefing)', () => {
const tavern = new Room({ id: 't', solidOccupants: false });
const p = tavern.addOccupant('p');
const q = tavern.addOccupant('q');
const res = tavern.moveOccupant('q', Math.sign(p.x - q.x), Math.sign(p.y - q.y));
expect(res.moved).toBe(true);
expect(tavern.isOccupied(p.x, p.y)).toBe(true); // both share the tile, allowed
});
test('tick is a heartbeat that increments and never throws', () => {
const room = new Room({ id: 'r' });
for (let i = 0; i < 5; i++) room.tick();
expect(room.tickCount).toBe(5);
expect(room.snapshot().tick).toBe(5);
});
test('removeOccupant clears them from the snapshot', () => {
const room = new Room({ id: 'r' });
room.addOccupant('alice');
expect(room.removeOccupant('alice')).toBe(true);
expect(room.size).toBe(0);
expect(room.snapshot().occupants).toEqual([]);
});
});