M9: 게임 26종 30초 요약 카드·[?] 지금 할 수 있는 것 내용
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
57
apps/web/src/games/mafia/help.test.ts
Normal file
57
apps/web/src/games/mafia/help.test.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { expect, test } from 'bun:test';
|
||||
import { applyAction, seatIds, setupGame, usersOf } from '../help-kit.test-util';
|
||||
import { GAMES } from '@bg/games';
|
||||
import { helpNow } from './help';
|
||||
|
||||
const ids = seatIds(7);
|
||||
const users = usersOf(ids);
|
||||
const view = (s: unknown, who: string | null) => GAMES.mafia!.view(s, who) as any;
|
||||
const T = 1_700_000_000_000;
|
||||
|
||||
function game() {
|
||||
const { state } = setupGame('mafia', 7, { mafiaCount: 2 });
|
||||
const byRole = (r: string) => state.players.filter((p: any) => p.role === r).map((p: any) => p.id as string);
|
||||
return { state, mafia: byRole('mafia'), police: byRole('police')[0]!, doctor: byRole('doctor')[0]!, citizen: byRole('citizen')[0]! };
|
||||
}
|
||||
const night = { kind: 'night', startedAt: T, endsAt: T + 30_000, mafiaTarget: null, mafiaPickedBy: null, investigate: null, heal: null, mediumPeek: null };
|
||||
|
||||
test('마피아: 직업 확인 / 관전', () => {
|
||||
const { state, citizen } = game();
|
||||
expect(helpNow(view(state, citizen), citizen, users)).toContain('[내 직업] 카드를 꾹');
|
||||
const spec = helpNow(view(state, null), null, users);
|
||||
expect(spec).toContain('관전 중에는 전체 채팅과 발표만');
|
||||
expect(spec).not.toContain('마피아예요');
|
||||
});
|
||||
|
||||
test('마피아: 밤 안내는 내 직업에 맞게, 남의 직업은 말하지 않아요', () => {
|
||||
const g = game();
|
||||
const s = { ...g.state, day: 1, phase: night };
|
||||
const [m1, m2] = g.mafia;
|
||||
const mt = helpNow(view(s, m1!), m1!, users);
|
||||
expect(mt).toContain('나는 마피아예요');
|
||||
expect(mt).toContain(`동료 마피아는 ${users[m2!]!.nickname}님`);
|
||||
expect(helpNow(view(s, g.police), g.police, users)).toContain('나는 경찰이에요');
|
||||
expect(helpNow(view(s, g.doctor), g.doctor, users)).toContain('나는 의사예요');
|
||||
const c = helpNow(view(s, g.citizen), g.citizen, users);
|
||||
expect(c).toContain('지금은 할 일이 없어요');
|
||||
for (const t of [c, helpNow(view(s, null), null, users)]) {
|
||||
expect(t).not.toContain('마피아예요');
|
||||
expect(t).not.toContain('경찰');
|
||||
expect(t).not.toContain('의사');
|
||||
}
|
||||
// 마피아가 고르면 동료에게 대상과 고른 사람이 보여요.
|
||||
const s2 = applyAction('mafia', s, m1!, { type: 'mafiaTarget', target: g.citizen });
|
||||
expect(helpNow(view(s2, m2!), m2!, users)).toContain(`${users[m1!]!.nickname}님이 골랐어요`);
|
||||
});
|
||||
|
||||
test('마피아: 지목 투표 → 찬반 투표, 탈락한 사람', () => {
|
||||
const g = game();
|
||||
const vote = { ...g.state, day: 2, phase: { kind: 'vote', startedAt: T, endsAt: T + 20_000, votes: {} } };
|
||||
expect(helpNow(view(vote, g.citizen), g.citizen, users)).toContain('[기권]');
|
||||
const confirm = { ...g.state, day: 2, phase: { kind: 'confirm', startedAt: T, endsAt: T + 10_000, accused: g.citizen, ballots: {} } };
|
||||
expect(helpNow(view(confirm, g.police), g.police, users)).toContain('[찬성 (탈락)]');
|
||||
expect(helpNow(view(confirm, g.citizen), g.citizen, users)).toContain('나를 탈락시킬지');
|
||||
expect(helpNow(view(confirm, null), null, users)).toContain(`${users[g.citizen]!.nickname}님을 탈락시킬지`);
|
||||
const dead = { ...confirm, players: g.state.players.map((p: any) => (p.id === g.doctor ? { ...p, alive: false, diedDay: 1, diedBy: 'mafia' } : p)) };
|
||||
expect(helpNow(view(dead, g.doctor), g.doctor, users)).toContain('[죽은 사람] 채팅');
|
||||
});
|
||||
Reference in New Issue
Block a user