From 558f8fe2453a6e96d565bf56d6b680f8d05f04ef Mon Sep 17 00:00:00 2001 From: Asger Geel Weirsoee Date: Sun, 15 Mar 2026 07:55:48 +0000 Subject: [PATCH] fix(gameplay): restore reveal before scoreboard --- .../src/app/api-contract-smoke.spec.ts | 8 ++++++- lobby/tests.py | 22 ++++++++++++++----- lobby/views.py | 13 +++++------ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/frontend/angular/src/app/api-contract-smoke.spec.ts b/frontend/angular/src/app/api-contract-smoke.spec.ts index 429e28c..b630734 100644 --- a/frontend/angular/src/app/api-contract-smoke.spec.ts +++ b/frontend/angular/src/app/api-contract-smoke.spec.ts @@ -104,9 +104,15 @@ describe('SPA Angular API contract smoke (host/player foundation)', () => { if (url === '/lobby/sessions/ABCD12/questions/77/scores/calculate') { expect(body).toEqual({}); return { - session: { code: 'ABCD12', status: 'scoreboard', current_round: 1 }, + session: { code: 'ABCD12', status: 'reveal', current_round: 1 }, round_question: { id: 77, round_number: 1 }, events_created: 2, + reveal: { + round_question_id: 77, + correct_answer: 'A', + lies: [], + guesses: [] + }, leaderboard: [ { id: 9, nickname: 'Maja', score: 200 }, { id: 10, nickname: 'Bo', score: 150 } diff --git a/lobby/tests.py b/lobby/tests.py index 2495309..d11b541 100644 --- a/lobby/tests.py +++ b/lobby/tests.py @@ -701,7 +701,7 @@ class ScoreCalculationTests(TestCase): self.player_two = Player.objects.create(session=self.session, nickname="Mads") self.player_three = Player.objects.create(session=self.session, nickname="Nora") - def test_host_can_calculate_scores_and_transition_to_scoreboard(self): + def test_host_can_calculate_scores_and_transition_to_reveal(self): 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, @@ -728,7 +728,7 @@ class ScoreCalculationTests(TestCase): self.assertEqual(response.status_code, 200) payload = response.json() - self.assertEqual(payload["session"]["status"], GameSession.Status.SCOREBOARD) + self.assertEqual(payload["session"]["status"], GameSession.Status.REVEAL) self.assertEqual(payload["events_created"], 2) self.player_one.refresh_from_db() @@ -737,7 +737,7 @@ class ScoreCalculationTests(TestCase): self.assertEqual(self.player_one.score, 5) self.assertEqual(self.player_three.score, 4) - self.assertEqual(self.session.status, GameSession.Status.SCOREBOARD) + self.assertEqual(self.session.status, GameSession.Status.REVEAL) def test_calculate_scores_requires_host(self): self.client.login(username="other_score", password="secret123") @@ -813,6 +813,16 @@ class RevealRoundFlowTests(TestCase): self.assertEqual(response.status_code, 403) self.assertEqual(response.json()["error"], "Only host can view scoreboard") + def test_reveal_scoreboard_rejects_scoreboard_phase(self): + self.session.status = GameSession.Status.SCOREBOARD + self.session.save(update_fields=["status"]) + self.client.login(username="host_reveal", password="secret123") + + response = self.client.get(reverse("lobby:reveal_scoreboard", kwargs={"code": self.session.code})) + + self.assertEqual(response.status_code, 400) + self.assertEqual(response.json()["error"], "Scoreboard is only available in reveal phase") + def test_host_can_finish_game_from_scoreboard(self): self.client.login(username="host_reveal", password="secret123") self.client.get(reverse("lobby:reveal_scoreboard", kwargs={"code": self.session.code})) @@ -881,7 +891,7 @@ class RevealRoundFlowTests(TestCase): self.assertEqual(self.session.status, GameSession.Status.LOBBY) self.assertEqual(self.session.current_round, 2) - def test_reveal_scoreboard_allows_repeated_reads_from_scoreboard_phase(self): + def test_reveal_scoreboard_rejects_repeated_reads_after_promotion(self): self.client.login(username="host_reveal", password="secret123") first_response = self.client.get( @@ -898,8 +908,8 @@ class RevealRoundFlowTests(TestCase): ) self.assertEqual(first_response.status_code, 200) - self.assertEqual(second_response.status_code, 200) - self.assertEqual(second_response.json()["session"]["status"], GameSession.Status.SCOREBOARD) + self.assertEqual(second_response.status_code, 400) + self.assertEqual(second_response.json()["error"], "Scoreboard is only available in reveal phase") def test_start_next_round_rejects_wrong_phase(self): self.client.login(username="host_reveal", password="secret123") diff --git a/lobby/views.py b/lobby/views.py index 73c17ee..0aa1ea6 100644 --- a/lobby/views.py +++ b/lobby/views.py @@ -714,12 +714,11 @@ def reveal_scoreboard(request: HttpRequest, code: str) -> JsonResponse: with transaction.atomic(): locked_session = GameSession.objects.select_for_update().get(pk=session.pk) - if locked_session.status not in {GameSession.Status.REVEAL, GameSession.Status.SCOREBOARD}: - return JsonResponse({"error": "Scoreboard is only available in reveal or scoreboard phase"}, status=400) + if locked_session.status != GameSession.Status.REVEAL: + return JsonResponse({"error": "Scoreboard is only available in reveal phase"}, status=400) - if locked_session.status == GameSession.Status.REVEAL: - locked_session.status = GameSession.Status.SCOREBOARD - locked_session.save(update_fields=["status"]) + locked_session.status = GameSession.Status.SCOREBOARD + locked_session.save(update_fields=["status"]) leaderboard = list( Player.objects.filter(session=session) @@ -897,7 +896,7 @@ def calculate_scores(request: HttpRequest, code: str, round_question_id: int) -> ScoreEvent.objects.bulk_create(score_events) - locked_session.status = GameSession.Status.SCOREBOARD + locked_session.status = GameSession.Status.REVEAL locked_session.save(update_fields=["status"]) leaderboard = list( @@ -910,7 +909,7 @@ def calculate_scores(request: HttpRequest, code: str, round_question_id: int) -> { "session": { "code": session.code, - "status": GameSession.Status.SCOREBOARD, + "status": GameSession.Status.REVEAL, "current_round": session.current_round, }, "round_question": {