fix(lobby): promote zero-score reveals to scoreboard
Some checks failed
CI / test-and-quality (push) Failing after 2m35s
CI / test-and-quality (pull_request) Failing after 2m36s

This commit is contained in:
2026-03-16 03:01:02 +00:00
parent 3706bc3b1c
commit bfa4ab859c
2 changed files with 62 additions and 7 deletions

View File

@@ -788,6 +788,68 @@ class CanonicalRoundFlowTests(TestCase):
self.assertEqual([entry["nickname"] for entry in payload["scoreboard"]], ["Luna", "Nora", "Mads"])
self.assertEqual(payload["reveal"]["correct_answer"], "Shakespeare")
@patch("lobby.views.sync_broadcast_phase_event")
@patch("lobby.views._resolve_scores")
def test_session_detail_promotes_zero_score_event_reveal_to_scoreboard(self, mock_resolve_scores, mock_sync_broadcast):
self.client.login(username="host_canonical", password="secret123")
self.session.status = GameSession.Status.GUESS
self.session.save(update_fields=["status"])
round_config = RoundConfig.objects.create(
session=self.session,
number=1,
category=self.category,
points_correct=5,
points_bluff=2,
)
round_question = RoundQuestion.objects.create(
session=self.session,
round_number=1,
question=self.question,
correct_answer="Shakespeare",
)
LieAnswer.objects.create(round_question=round_question, player=self.players[0], text="Marlowe")
LieAnswer.objects.create(round_question=round_question, player=self.players[1], text="Chaucer")
LieAnswer.objects.create(round_question=round_question, player=self.players[2], text="Austen")
mock_resolve_scores.return_value = ([], [
{"id": player.id, "nickname": player.nickname, "score": player.score}
for player in sorted(self.players, key=lambda player: player.nickname)
])
guess_targets = ["Shakespeare", "Shakespeare", "Shakespeare"]
guess_responses = []
for player, selected_text in zip(self.players, guess_targets, strict=True):
guess_responses.append(
self.client.post(
reverse("lobby:submit_guess", kwargs={"code": self.session.code, "round_question_id": round_question.id}),
data={"player_id": player.id, "session_token": player.session_token, "selected_text": selected_text},
content_type="application/json",
)
)
self.assertTrue(all(response.status_code == 201 for response in guess_responses))
self.assertEqual(guess_responses[-1].json()["session"]["status"], GameSession.Status.REVEAL)
self.assertEqual(ScoreEvent.objects.filter(session=self.session, meta__round_question_id=round_question.id).count(), 0)
detail_response = self.client.get(reverse("lobby:session_detail", kwargs={"code": self.session.code}))
self.assertEqual(detail_response.status_code, 200)
payload = detail_response.json()
self.assertEqual(payload["session"]["status"], GameSession.Status.SCOREBOARD)
self.assertEqual(payload["phase_view_model"]["current_phase"], GameSession.Status.SCOREBOARD)
self.assertTrue(payload["phase_view_model"]["readiness"]["scoreboard_ready"])
self.assertEqual(payload["reveal"]["correct_answer"], "Shakespeare")
mock_resolve_scores.assert_called_once_with(self.session, round_question, round_config)
mock_sync_broadcast.assert_any_call(
self.session.code,
"phase.scoreboard",
{
"leaderboard": payload["scoreboard"],
"current_round": self.session.current_round,
},
)
@patch("lobby.views.sync_broadcast_phase_event")
@patch("lobby.views._resolve_scores")
@patch("lobby.views.GameSession.objects.get")

View File

@@ -247,13 +247,6 @@ def _maybe_promote_reveal_to_scoreboard(session: GameSession) -> GameSession:
if current_round_question is None:
return session
has_round_scores = ScoreEvent.objects.filter(
session=session,
meta__round_question_id=current_round_question.id,
).exists()
if not has_round_scores:
return session
with transaction.atomic():
locked_session = GameSession.objects.select_for_update().get(pk=session.pk)
if locked_session.status != GameSession.Status.REVEAL: