- selectedTeamCode에 무승부 예약 코드 'DRAW' 허용 (sideOf가 draw 진영 반환)
- RTDB /votes/{gameId}/counts에 drawCount 추가, 투표 요약 응답에 포함
- 채점 규칙 변경: 무승부 경기는 'DRAW' 투표만 적중, 팀 투표는 오답 (기존: 전원 적중 처리)
- 무승부 경기(completed + winningTeamCode 없음)도 onGameCompleted 트리거에서 즉시 채점 (기존: dailyArchive 리컨실까지 지연)
- 어드민 수동 종료(POST /admin/game/end)에 winningTeamCode: 'DRAW' 지원
- VOTE_FLOW.md 갱신, voteRepository 무승부 투표/카운트 재분배 테스트 추가
178 lines
6.2 KiB
TypeScript
178 lines
6.2 KiB
TypeScript
import { beforeEach, describe, expect, it } from "vitest";
|
|
import { rtdb } from "../../src/firebase";
|
|
import {
|
|
changeVote,
|
|
deleteGameVotes,
|
|
getAllUserVotes,
|
|
getCounts,
|
|
getUserDateVotes,
|
|
getUserVote,
|
|
submitVote,
|
|
} from "../../src/repositories/voteRepository";
|
|
import type { DateString } from "../../src/types/dateString";
|
|
|
|
const gameId = "20260412HTLG0";
|
|
const gameId2 = "20260412WOSK0";
|
|
const uid = "test-uid-1";
|
|
const uid2 = "test-uid-2";
|
|
const date = "2026-04-12" as DateString;
|
|
|
|
describe("voteRepository (RTDB)", () => {
|
|
beforeEach(async () => {
|
|
console.log("[setup] /votes, /userVotes 초기화");
|
|
await rtdb.ref("/votes").remove();
|
|
await rtdb.ref("/userVotes").remove();
|
|
});
|
|
|
|
describe("submitVote", () => {
|
|
it("home 투표 시 homeCount가 1 증가하고 인덱스가 저장된다", async () => {
|
|
await submitVote({ gameId, uid, date, side: "home", team: "LG" });
|
|
|
|
const counts = await getCounts(gameId);
|
|
const userVote = await getUserVote(gameId, uid);
|
|
const dateVotes = await getUserDateVotes(uid, date);
|
|
console.log("[home vote] counts:", counts);
|
|
console.log("[home vote] userVote:", userVote);
|
|
console.log("[home vote] dateVotes:", dateVotes);
|
|
|
|
expect(counts).toEqual({ homeCount: 1, awayCount: 0, drawCount: 0 });
|
|
expect(userVote).toEqual({ team: "LG" });
|
|
expect(dateVotes[gameId]).toEqual({ team: "LG" });
|
|
});
|
|
|
|
it("away 투표 시 awayCount만 증가한다", async () => {
|
|
await submitVote({ gameId, uid, date, side: "away", team: "KIA" });
|
|
|
|
const counts = await getCounts(gameId);
|
|
console.log("[away vote] counts:", counts);
|
|
expect(counts).toEqual({ homeCount: 0, awayCount: 1, drawCount: 0 });
|
|
});
|
|
|
|
it("무승부 투표 시 drawCount만 증가하고 team은 DRAW로 저장된다", async () => {
|
|
await submitVote({ gameId, uid, date, side: "draw", team: "DRAW" });
|
|
|
|
const counts = await getCounts(gameId);
|
|
const userVote = await getUserVote(gameId, uid);
|
|
console.log("[draw vote] counts:", counts);
|
|
expect(counts).toEqual({ homeCount: 0, awayCount: 0, drawCount: 1 });
|
|
expect(userVote).toEqual({ team: "DRAW" });
|
|
});
|
|
});
|
|
|
|
describe("changeVote", () => {
|
|
it("home→away 변경 시 카운트가 재분배되고 인덱스가 갱신된다", async () => {
|
|
await submitVote({ gameId, uid, date, side: "home", team: "LG" });
|
|
console.log("[change] 초기:", await getCounts(gameId));
|
|
|
|
await changeVote({
|
|
gameId,
|
|
uid,
|
|
date,
|
|
oldSide: "home",
|
|
newSide: "away",
|
|
newTeam: "KIA",
|
|
});
|
|
|
|
const counts = await getCounts(gameId);
|
|
const userVote = await getUserVote(gameId, uid);
|
|
const dateVotes = await getUserDateVotes(uid, date);
|
|
console.log("[change] 변경 후 counts:", counts);
|
|
console.log("[change] userVote:", userVote);
|
|
|
|
expect(counts).toEqual({ homeCount: 0, awayCount: 1, drawCount: 0 });
|
|
expect(userVote).toEqual({ team: "KIA" });
|
|
expect(dateVotes[gameId]).toEqual({ team: "KIA" });
|
|
});
|
|
|
|
it("home→draw 변경 시 drawCount로 재분배된다", async () => {
|
|
await submitVote({ gameId, uid, date, side: "home", team: "LG" });
|
|
|
|
await changeVote({
|
|
gameId,
|
|
uid,
|
|
date,
|
|
oldSide: "home",
|
|
newSide: "draw",
|
|
newTeam: "DRAW",
|
|
});
|
|
|
|
const counts = await getCounts(gameId);
|
|
const userVote = await getUserVote(gameId, uid);
|
|
console.log("[change→draw] counts:", counts);
|
|
expect(counts).toEqual({ homeCount: 0, awayCount: 0, drawCount: 1 });
|
|
expect(userVote).toEqual({ team: "DRAW" });
|
|
});
|
|
});
|
|
|
|
describe("getUserVote", () => {
|
|
it("존재하지 않으면 null을 반환한다", async () => {
|
|
const result = await getUserVote(gameId, "nonexistent-uid");
|
|
expect(result).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("getCounts", () => {
|
|
it("counts 노드가 없으면 0으로 채워 반환한다", async () => {
|
|
const result = await getCounts("nonexistent-game");
|
|
console.log("[counts-empty]", result);
|
|
expect(result).toEqual({ homeCount: 0, awayCount: 0, drawCount: 0 });
|
|
});
|
|
});
|
|
|
|
describe("getAllUserVotes", () => {
|
|
it("여러 유저의 투표를 맵으로 반환한다", async () => {
|
|
await submitVote({ gameId, uid, date, side: "home", team: "LG" });
|
|
await submitVote({ gameId, uid: uid2, date, side: "away", team: "KIA" });
|
|
|
|
const all = await getAllUserVotes(gameId);
|
|
console.log("[all votes]", all);
|
|
expect(Object.keys(all).sort()).toEqual([uid, uid2].sort());
|
|
expect(all[uid]).toEqual({ team: "LG" });
|
|
expect(all[uid2]).toEqual({ team: "KIA" });
|
|
});
|
|
|
|
it("투표가 없으면 빈 객체를 반환한다", async () => {
|
|
const result = await getAllUserVotes("nonexistent-game");
|
|
expect(result).toEqual({});
|
|
});
|
|
});
|
|
|
|
describe("getUserDateVotes", () => {
|
|
it("특정 날짜의 여러 경기 투표를 맵으로 반환한다", async () => {
|
|
await submitVote({ gameId, uid, date, side: "home", team: "LG" });
|
|
await submitVote({
|
|
gameId: gameId2,
|
|
uid,
|
|
date,
|
|
side: "away",
|
|
team: "키움",
|
|
});
|
|
|
|
const result = await getUserDateVotes(uid, date);
|
|
console.log("[date votes]", result);
|
|
expect(Object.keys(result).sort()).toEqual([gameId, gameId2].sort());
|
|
expect(result[gameId]).toEqual({ team: "LG" });
|
|
expect(result[gameId2]).toEqual({ team: "키움" });
|
|
});
|
|
});
|
|
|
|
describe("deleteGameVotes", () => {
|
|
it("/votes/{gameId}는 삭제되지만 /userVotes 인덱스는 남는다", async () => {
|
|
await submitVote({ gameId, uid, date, side: "home", team: "LG" });
|
|
|
|
await deleteGameVotes(gameId);
|
|
|
|
const counts = await getCounts(gameId);
|
|
const users = await getAllUserVotes(gameId);
|
|
const dateVotes = await getUserDateVotes(uid, date);
|
|
console.log("[delete] counts:", counts);
|
|
console.log("[delete] users:", users);
|
|
console.log("[delete] dateVotes (남아있음):", dateVotes);
|
|
|
|
expect(counts).toEqual({ homeCount: 0, awayCount: 0, drawCount: 0 });
|
|
expect(users).toEqual({});
|
|
expect(dateVotes[gameId]).toEqual({ team: "LG" });
|
|
});
|
|
});
|
|
});
|