feat: add canonical reveal payload for issue 289
Some checks failed
CI / test-and-quality (push) Failing after 2m14s

This commit is contained in:
2026-03-15 11:13:57 +00:00
parent f0ebc25da7
commit 2c524d7d2d
2 changed files with 157 additions and 0 deletions

View File

@@ -687,6 +687,7 @@ class ScoreCalculationTests(TestCase):
self.player_three = Player.objects.create(session=self.session, nickname="Nora")
def test_host_can_calculate_scores_and_transition_to_reveal(self):
LieAnswer.objects.create(round_question=self.round_question, player=self.player_three, text="Padel")
Guess.objects.create(round_question=self.round_question, player=self.player_one, selected_text="Tennis", is_correct=True)
Guess.objects.create(
round_question=self.round_question,
@@ -715,6 +716,57 @@ class ScoreCalculationTests(TestCase):
payload = response.json()
self.assertEqual(payload["session"]["status"], GameSession.Status.REVEAL)
self.assertEqual(payload["events_created"], 2)
self.assertEqual(payload["reveal"]["correct_answer"], "Tennis")
self.assertEqual(
payload["reveal"]["lies"],
[
{
"player_id": self.player_three.id,
"nickname": "Nora",
"text": "Padel",
"created_at": payload["reveal"]["lies"][0]["created_at"],
}
],
)
self.assertEqual(
[
{
"player_id": item["player_id"],
"nickname": item["nickname"],
"selected_text": item["selected_text"],
"is_correct": item["is_correct"],
"fooled_player_id": item["fooled_player_id"],
"fooled_player_nickname": item.get("fooled_player_nickname"),
}
for item in payload["reveal"]["guesses"]
],
[
{
"player_id": self.player_one.id,
"nickname": "Luna",
"selected_text": "Tennis",
"is_correct": True,
"fooled_player_id": None,
"fooled_player_nickname": None,
},
{
"player_id": self.player_two.id,
"nickname": "Mads",
"selected_text": "Padel",
"is_correct": False,
"fooled_player_id": self.player_three.id,
"fooled_player_nickname": "Nora",
},
{
"player_id": self.player_three.id,
"nickname": "Nora",
"selected_text": "Padel",
"is_correct": False,
"fooled_player_id": self.player_three.id,
"fooled_player_nickname": "Nora",
},
],
)
self.player_one.refresh_from_db()
self.player_three.refresh_from_db()
@@ -1149,7 +1201,62 @@ class SessionDetailRoundQuestionTests(TestCase):
self.assertEqual(payload["round_question"]["id"], round_question.id)
self.assertEqual(payload["round_question"]["prompt"], self.question.prompt)
def test_session_detail_includes_reveal_payload_for_active_round_question(self):
self.session.status = GameSession.Status.REVEAL
self.session.save(update_fields=["status"])
round_question = RoundQuestion.objects.create(
session=self.session,
round_number=1,
question=self.question,
correct_answer=self.question.correct_answer,
)
liar = Player.objects.create(session=self.session, nickname="Bluffer")
guesser = Player.objects.create(session=self.session, nickname="Guesser")
LieAnswer.objects.create(round_question=round_question, player=liar, text="Tesla")
Guess.objects.create(
round_question=round_question,
player=guesser,
selected_text="Tesla",
is_correct=False,
fooled_player=liar,
)
response = self.client.get(reverse("lobby:session_detail", kwargs={"code": self.session.code}))
self.assertEqual(response.status_code, 200)
payload = response.json()
self.assertEqual(payload["reveal"]["round_question_id"], round_question.id)
self.assertEqual(payload["reveal"]["correct_answer"], "Edison")
self.assertEqual(
[
{"player_id": lie["player_id"], "nickname": lie["nickname"], "text": lie["text"]}
for lie in payload["reveal"]["lies"]
],
[{"player_id": liar.id, "nickname": "Bluffer", "text": "Tesla"}],
)
self.assertEqual(
[
{
"player_id": guess["player_id"],
"nickname": guess["nickname"],
"selected_text": guess["selected_text"],
"is_correct": guess["is_correct"],
"fooled_player_id": guess["fooled_player_id"],
"fooled_player_nickname": guess.get("fooled_player_nickname"),
}
for guess in payload["reveal"]["guesses"]
],
[
{
"player_id": guesser.id,
"nickname": "Guesser",
"selected_text": "Tesla",
"is_correct": False,
"fooled_player_id": liar.id,
"fooled_player_nickname": "Bluffer",
}
],
)
class SessionDetailPhaseViewModelTests(TestCase):

View File

@@ -61,6 +61,52 @@ def _create_unique_session_code() -> str:
raise RuntimeError("Could not generate unique session code")
def _build_player_ref(player: Player | None) -> dict | None:
if player is None:
return None
return {
"player_id": player.id,
"nickname": player.nickname,
}
def _build_reveal_payload(round_question: RoundQuestion | None) -> dict | None:
if round_question is None:
return None
lies = [
{
**_build_player_ref(lie.player),
"text": lie.text,
"created_at": lie.created_at.isoformat(),
}
for lie in round_question.lies.select_related("player").order_by("created_at", "id")
]
guesses = []
for guess in round_question.guesses.select_related("player", "fooled_player").order_by("created_at", "id"):
guess_payload = {
**_build_player_ref(guess.player),
"selected_text": guess.selected_text,
"is_correct": guess.is_correct,
"created_at": guess.created_at.isoformat(),
"fooled_player_id": guess.fooled_player_id,
}
if guess.fooled_player is not None:
guess_payload["fooled_player_nickname"] = guess.fooled_player.nickname
guesses.append(guess_payload)
return {
"round_question_id": round_question.id,
"round_number": round_question.round_number,
"prompt": round_question.question.prompt,
"correct_answer": round_question.correct_answer,
"lies": lies,
"guesses": guesses,
}
def _build_phase_view_model(session: GameSession, *, players_count: int, has_round_question: bool) -> dict:
status = session.status
in_lobby = status == GameSession.Status.LOBBY
@@ -238,6 +284,9 @@ def session_detail(request: HttpRequest, code: str) -> JsonResponse:
},
"players": players,
"round_question": round_question_payload,
"reveal": _build_reveal_payload(current_round_question)
if session.status == GameSession.Status.REVEAL and current_round_question
else None,
"phase_view_model": phase_view_model,
}
)
@@ -909,6 +958,7 @@ def calculate_scores(request: HttpRequest, code: str, round_question_id: int) ->
"id": round_question.id,
"round_number": round_question.round_number,
},
"reveal": _build_reveal_payload(round_question),
"events_created": len(score_events),
"leaderboard": leaderboard,
}