Ma Sói Backend Testing
Workflow
- Identify the backend component to test:
server/gameEngine.js → pure function unit tests (role config, win conditions, wolf count).
server/index.js socket handlers → integration tests with mock socket/Redis.
server/db/redis.js → Redis data layer tests with mock/in-memory store.
server/db/postgres.js → PostgreSQL data layer tests with mock client.
- Authentication flow → register/login handler tests with bcrypt mock.
- Write tests following patterns in
references/be-test-patterns.md.
- Run tests:
node --check server/index.js (syntax baseline).
node --check server/gameEngine.js (syntax baseline).
cd server && npm test (if test script configured).
- For concurrency tests, simulate concurrent socket events and verify
withRoomLock serial execution.
Test Categories
Unit Tests — gameEngine.js
calcWolfCount(n) returns correct wolf count for player counts 4–18.
getRoleConfig(n, customRoles) produces valid role list with correct wolf/villager ratio.
sanitizeCustomRoles(roles, n) enforces wolf count limits and role constraints.
assignRoles(players, customRoles) returns exactly n assignments with shuffled distribution.
checkWinCondition(players) for all win/draw/continue states.
generateRoomCode() produces valid 6-character alphanumeric codes.
Unit Tests — Socket Handler Logic
auth handler validates credentials and maps userId to socketId.
create_room handler creates room with correct initial state.
join_room handler enforces room existence, capacity, and game-not-started.
toggle_ready handler toggles player ready state correctly.
start_game handler validates player count, ready state, and assigns roles.
night_action handler validates role, phase, and alive status before accepting action.
cast_vote handler validates phase, alive status, and target validity.
Integration Tests — Night Resolution
- Wolf kill with no saves → target dies.
- Doctor saves wolf target → target lives.
- Witch saves wolf target → target lives, save potion consumed.
- Witch poisons + wolf kill → 2 deaths in one night.
- Doctor saves target, witch also saves same target → no double-save error.
- Hunter dies at night →
hunter_must_shoot triggers correctly.
- All night actions skip → peaceful night, no deaths.
- Timer-forced resolution → pending actions auto-resolved as skip.
Integration Tests — Vote Resolution
- Majority vote → target dies.
- Tie vote → nobody dies.
- Idiot first hanging → survives,
idiotRevealed = true.
- Idiot second hanging → actually dies.
- Wolf King hanged →
wolf_king_must_choose triggers drag mechanic.
- Hunter hanged →
hunter_must_shoot triggers.
- Chain: Wolf King drags Hunter → Hunter shoots → chain resolution.
Integration Tests — Room Lifecycle
- Create room → join → ready → start → play → end → play again.
- Host disconnect → host transfer to next player.
- All players disconnect → room cleanup after timeout.
- Kick player → player removed, room state updated.
- Leave room → player removed, host transfer if needed.
- Close room → all players notified, room deleted.
Data Layer Tests — Redis
saveRoom(room) serializes and stores room state.
getRoom(code) deserializes room state correctly.
deleteRoom(code) removes room and associated keys.
saveUserRoom(userId, roomCode) and getUserRoom(userId) mapping.
clearUserRoom(userId) cleanup.
- Room TTL and expiry behavior.
Data Layer Tests — PostgreSQL
createUser(username, passwordHash) inserts correctly.
findUserByUsername(username) returns user or null.
saveGameResult(gameData) persists game history.
getGameHistory(userId) returns sorted game history.
- Connection pool handling and error recovery.
Authentication Tests
- Register with valid credentials → user created, token returned.
- Register with duplicate username → error returned.
- Login with correct password → authenticated.
- Login with wrong password → rejected.
- Guest auth → temporary userId assigned.
- Socket reconnect with existing userId → session restored.
Concurrency & Lock Tests
withRoomLock(code, fn) ensures serial execution.
- Concurrent
night_action from two wolves → only one WOLF_ATTACK set.
- Concurrent
resolveNight calls → only one resolution executes.
- Concurrent
resolveVote calls → only one resolution executes.
- Lock cleanup after function throws error.
Test Infrastructure
Recommended Setup
- Test runner: Vitest (preferred) or Node.js built-in test runner (
node --test).
- Mock Redis: In-memory Map-based mock for
server/db/redis.js.
- Mock PostgreSQL: In-memory array-based mock for
server/db/postgres.js.
- Mock Socket.IO: Custom mock tracking emitted events, connected clients, and rooms.
- Mock bcrypt: Deterministic mock for faster tests (skip real hashing).
Test File Structure
server/
__tests__/
unit/
gameEngine.test.js # Pure function unit tests
roomCode.test.js # Room code generation tests
integration/
nightResolve.test.js # Night resolution scenarios
voteResolve.test.js # Vote resolution scenarios
roomLifecycle.test.js # Room create/join/leave/close
auth.test.js # Register/login/guest auth
data/
redis.test.js # Redis data layer tests
postgres.test.js # PostgreSQL data layer tests
concurrency/
roomLock.test.js # withRoomLock serial execution
raceCondition.test.js # Concurrent action tests
mocks/
mockRedis.js # In-memory Redis mock
mockPostgres.js # In-memory PostgreSQL mock
mockSocket.js # Socket.IO mock with event tracking
Verification Commands
# Syntax check (always run first)
node --check server/index.js
node --check server/gameEngine.js
# Run all backend tests
cd server && npm test
# Run specific test file
cd server && npx vitest run __tests__/unit/gameEngine.test.js
# Run with coverage
cd server && npx vitest run --coverage
References
Load references/be-test-patterns.md when writing or reviewing backend tests.
1---2name: masoi-be-testing3description: Create and maintain backend unit tests, integration tests, and API tests for Ma Sói server. Covers gameEngine.js pure functions, Socket.IO handler logic, Redis/PostgreSQL data layer, authentication, room lifecycle, and timer-driven resolution. Use when adding server-side test coverage, debugging server logic, or verifying backend changes.4---56# Ma Sói Backend Testing78## Workflow9101. Identify the backend component to test:11 - `server/gameEngine.js` → pure function unit tests (role config, win conditions, wolf count).12 - `server/index.js` socket handlers → integration tests with mock socket/Redis.13 - `server/db/redis.js` → Redis data layer tests with mock/in-memory store.14 - `server/db/postgres.js` → PostgreSQL data layer tests with mock client.15 - Authentication flow → register/login handler tests with bcrypt mock.162. Write tests following patterns in `references/be-test-patterns.md`.173. Run tests:18 - `node --check server/index.js` (syntax baseline).19 - `node --check server/gameEngine.js` (syntax baseline).20 - `cd server && npm test` (if test script configured).214. For concurrency tests, simulate concurrent socket events and verify `withRoomLock` serial execution.2223## Test Categories2425### Unit Tests — gameEngine.js2627- `calcWolfCount(n)` returns correct wolf count for player counts 4–18.28- `getRoleConfig(n, customRoles)` produces valid role list with correct wolf/villager ratio.29- `sanitizeCustomRoles(roles, n)` enforces wolf count limits and role constraints.30- `assignRoles(players, customRoles)` returns exactly n assignments with shuffled distribution.31- `checkWinCondition(players)` for all win/draw/continue states.32- `generateRoomCode()` produces valid 6-character alphanumeric codes.3334### Unit Tests — Socket Handler Logic3536- `auth` handler validates credentials and maps userId to socketId.37- `create_room` handler creates room with correct initial state.38- `join_room` handler enforces room existence, capacity, and game-not-started.39- `toggle_ready` handler toggles player ready state correctly.40- `start_game` handler validates player count, ready state, and assigns roles.41- `night_action` handler validates role, phase, and alive status before accepting action.42- `cast_vote` handler validates phase, alive status, and target validity.4344### Integration Tests — Night Resolution4546- Wolf kill with no saves → target dies.47- Doctor saves wolf target → target lives.48- Witch saves wolf target → target lives, save potion consumed.49- Witch poisons + wolf kill → 2 deaths in one night.50- Doctor saves target, witch also saves same target → no double-save error.51- Hunter dies at night → `hunter_must_shoot` triggers correctly.52- All night actions skip → peaceful night, no deaths.53- Timer-forced resolution → pending actions auto-resolved as skip.5455### Integration Tests — Vote Resolution5657- Majority vote → target dies.58- Tie vote → nobody dies.59- Idiot first hanging → survives, `idiotRevealed = true`.60- Idiot second hanging → actually dies.61- Wolf King hanged → `wolf_king_must_choose` triggers drag mechanic.62- Hunter hanged → `hunter_must_shoot` triggers.63- Chain: Wolf King drags Hunter → Hunter shoots → chain resolution.6465### Integration Tests — Room Lifecycle6667- Create room → join → ready → start → play → end → play again.68- Host disconnect → host transfer to next player.69- All players disconnect → room cleanup after timeout.70- Kick player → player removed, room state updated.71- Leave room → player removed, host transfer if needed.72- Close room → all players notified, room deleted.7374### Data Layer Tests — Redis7576- `saveRoom(room)` serializes and stores room state.77- `getRoom(code)` deserializes room state correctly.78- `deleteRoom(code)` removes room and associated keys.79- `saveUserRoom(userId, roomCode)` and `getUserRoom(userId)` mapping.80- `clearUserRoom(userId)` cleanup.81- Room TTL and expiry behavior.8283### Data Layer Tests — PostgreSQL8485- `createUser(username, passwordHash)` inserts correctly.86- `findUserByUsername(username)` returns user or null.87- `saveGameResult(gameData)` persists game history.88- `getGameHistory(userId)` returns sorted game history.89- Connection pool handling and error recovery.9091### Authentication Tests9293- Register with valid credentials → user created, token returned.94- Register with duplicate username → error returned.95- Login with correct password → authenticated.96- Login with wrong password → rejected.97- Guest auth → temporary userId assigned.98- Socket reconnect with existing userId → session restored.99100### Concurrency & Lock Tests101102- `withRoomLock(code, fn)` ensures serial execution.103- Concurrent `night_action` from two wolves → only one `WOLF_ATTACK` set.104- Concurrent `resolveNight` calls → only one resolution executes.105- Concurrent `resolveVote` calls → only one resolution executes.106- Lock cleanup after function throws error.107108## Test Infrastructure109110### Recommended Setup111- **Test runner**: Vitest (preferred) or Node.js built-in test runner (`node --test`).112- **Mock Redis**: In-memory Map-based mock for `server/db/redis.js`.113- **Mock PostgreSQL**: In-memory array-based mock for `server/db/postgres.js`.114- **Mock Socket.IO**: Custom mock tracking emitted events, connected clients, and rooms.115- **Mock bcrypt**: Deterministic mock for faster tests (skip real hashing).116117### Test File Structure118```119server/120 __tests__/121 unit/122 gameEngine.test.js # Pure function unit tests123 roomCode.test.js # Room code generation tests124 integration/125 nightResolve.test.js # Night resolution scenarios126 voteResolve.test.js # Vote resolution scenarios127 roomLifecycle.test.js # Room create/join/leave/close128 auth.test.js # Register/login/guest auth129 data/130 redis.test.js # Redis data layer tests131 postgres.test.js # PostgreSQL data layer tests132 concurrency/133 roomLock.test.js # withRoomLock serial execution134 raceCondition.test.js # Concurrent action tests135 mocks/136 mockRedis.js # In-memory Redis mock137 mockPostgres.js # In-memory PostgreSQL mock138 mockSocket.js # Socket.IO mock with event tracking139```140141## Verification Commands142143```bash144# Syntax check (always run first)145node --check server/index.js146node --check server/gameEngine.js147148# Run all backend tests149cd server && npm test150151# Run specific test file152cd server && npx vitest run __tests__/unit/gameEngine.test.js153154# Run with coverage155cd server && npx vitest run --coverage156```157158## References159160Load `references/be-test-patterns.md` when writing or reviewing backend tests.