fix(gameplay): align scoreboard phase contract
This commit is contained in:
139
lobby/tests.py
139
lobby/tests.py
@@ -401,7 +401,9 @@ class LieSubmissionTests(TestCase):
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.json()["error"], "session_token is required")
|
||||
self.assertEqual(response.json()["error_code"], "session_token_required")
|
||||
self.assertEqual(response.json()["locale"], "en")
|
||||
self.assertEqual(response.json()["error"], "Session token is required.")
|
||||
|
||||
def test_submit_lie_rejects_invalid_session_token(self):
|
||||
round_question = RoundQuestion.objects.create(
|
||||
@@ -582,7 +584,9 @@ class GuessSubmissionTests(TestCase):
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.json()["error"], "Guess submission is only allowed in guess phase")
|
||||
self.assertEqual(response.json()["error_code"], "guess_submission_invalid_phase")
|
||||
self.assertEqual(response.json()["locale"], "en")
|
||||
self.assertEqual(response.json()["error"], "Guess submission is only allowed in guess phase.")
|
||||
|
||||
def test_submit_guess_rejects_unknown_answer(self):
|
||||
response = self.client.post(
|
||||
@@ -641,7 +645,7 @@ class GuessSubmissionTests(TestCase):
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.json()["error"], "session_token is required")
|
||||
self.assertEqual(response.json()["error"], "Session token is required.")
|
||||
|
||||
def test_submit_guess_rejects_invalid_session_token(self):
|
||||
response = self.client.post(
|
||||
@@ -686,7 +690,9 @@ 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_reveal(self):
|
||||
def test_host_can_calculate_scores_and_transition_to_scoreboard(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,
|
||||
@@ -713,8 +719,52 @@ class ScoreCalculationTests(TestCase):
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
payload = response.json()
|
||||
self.assertEqual(payload["session"]["status"], GameSession.Status.REVEAL)
|
||||
self.assertEqual(payload["session"]["status"], GameSession.Status.SCOREBOARD)
|
||||
self.assertEqual(payload["events_created"], 2)
|
||||
self.assertEqual(payload["reveal"]["round_question_id"], self.round_question.id)
|
||||
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(
|
||||
payload["reveal"]["guesses"],
|
||||
[
|
||||
{
|
||||
"player_id": self.player_one.id,
|
||||
"nickname": "Luna",
|
||||
"selected_text": "Tennis",
|
||||
"is_correct": True,
|
||||
"created_at": payload["reveal"]["guesses"][0]["created_at"],
|
||||
"fooled_player_id": None,
|
||||
},
|
||||
{
|
||||
"player_id": self.player_two.id,
|
||||
"nickname": "Mads",
|
||||
"selected_text": "Padel",
|
||||
"is_correct": False,
|
||||
"created_at": payload["reveal"]["guesses"][1]["created_at"],
|
||||
"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,
|
||||
"created_at": payload["reveal"]["guesses"][2]["created_at"],
|
||||
"fooled_player_id": self.player_three.id,
|
||||
"fooled_player_nickname": "Nora",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
self.player_one.refresh_from_db()
|
||||
self.player_three.refresh_from_db()
|
||||
@@ -722,7 +772,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.REVEAL)
|
||||
self.assertEqual(self.session.status, GameSession.Status.SCOREBOARD)
|
||||
|
||||
def test_calculate_scores_requires_host(self):
|
||||
self.client.login(username="other_score", password="secret123")
|
||||
@@ -735,7 +785,7 @@ class ScoreCalculationTests(TestCase):
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.json()["error"], "Only host can calculate scores")
|
||||
self.assertEqual(response.json()["error"], "Only the host can calculate scores.")
|
||||
|
||||
def test_calculate_scores_rejects_duplicate_calculation(self):
|
||||
Guess.objects.create(round_question=self.round_question, player=self.player_one, selected_text="Tennis", is_correct=True)
|
||||
@@ -756,14 +806,14 @@ class ScoreCalculationTests(TestCase):
|
||||
|
||||
self.assertEqual(first.status_code, 200)
|
||||
self.assertEqual(second.status_code, 409)
|
||||
self.assertEqual(second.json()["error"], "Scores already calculated for this round question")
|
||||
self.assertEqual(second.json()["error"], "Scores have already been calculated for this round question.")
|
||||
|
||||
|
||||
class RevealRoundFlowTests(TestCase):
|
||||
def setUp(self):
|
||||
self.host = User.objects.create_user(username="host_reveal", password="secret123")
|
||||
self.other_user = User.objects.create_user(username="other_reveal", password="secret123")
|
||||
self.session = GameSession.objects.create(host=self.host, code="RVL123", status=GameSession.Status.REVEAL)
|
||||
self.session = GameSession.objects.create(host=self.host, code="RVL123", status=GameSession.Status.SCOREBOARD)
|
||||
self.player_one = Player.objects.create(session=self.session, nickname="Luna", score=9)
|
||||
self.player_two = Player.objects.create(session=self.session, nickname="Mads", score=3)
|
||||
|
||||
@@ -779,7 +829,7 @@ class RevealRoundFlowTests(TestCase):
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
payload = response.json()
|
||||
self.assertEqual(payload["session"]["status"], GameSession.Status.REVEAL)
|
||||
self.assertEqual(payload["session"]["status"], GameSession.Status.SCOREBOARD)
|
||||
self.assertEqual([item["nickname"] for item in payload["leaderboard"]], ["Luna", "Mads"])
|
||||
|
||||
def test_reveal_scoreboard_requires_host(self):
|
||||
@@ -793,9 +843,9 @@ class RevealRoundFlowTests(TestCase):
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.json()["error"], "Only host can view scoreboard")
|
||||
self.assertEqual(response.json()["error"], "Only the host can view the scoreboard.")
|
||||
|
||||
def test_host_can_finish_game_from_reveal(self):
|
||||
def test_host_can_finish_game_from_scoreboard(self):
|
||||
self.client.login(username="host_reveal", password="secret123")
|
||||
|
||||
response = self.client.post(
|
||||
@@ -825,7 +875,7 @@ class RevealRoundFlowTests(TestCase):
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.json()["error"], "Only host can finish game")
|
||||
self.assertEqual(response.json()["error"], "Only the host can finish the game.")
|
||||
|
||||
def test_finish_game_rejects_wrong_phase(self):
|
||||
self.client.login(username="host_reveal", password="secret123")
|
||||
@@ -840,9 +890,9 @@ class RevealRoundFlowTests(TestCase):
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.json()["error"], "Game can only be finished from reveal phase")
|
||||
self.assertEqual(response.json()["error"], "Game can only be finished from scoreboard phase.")
|
||||
|
||||
def test_host_can_start_next_round_from_reveal(self):
|
||||
def test_host_can_start_next_round_from_scoreboard(self):
|
||||
self.client.login(username="host_reveal", password="secret123")
|
||||
|
||||
response = self.client.post(
|
||||
@@ -874,7 +924,7 @@ class RevealRoundFlowTests(TestCase):
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.json()["error"], "Next round can only start from reveal phase")
|
||||
self.assertEqual(response.json()["error"], "Next round can only start from scoreboard phase.")
|
||||
|
||||
class UiScreenTests(TestCase):
|
||||
def setUp(self):
|
||||
@@ -1149,7 +1199,51 @@ 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_canonical_reveal_payload_in_reveal_phase(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="Løgnhals")
|
||||
guesser = Player.objects.create(session=self.session, nickname="Detektiv")
|
||||
correct_player = Player.objects.create(session=self.session, nickname="Sandhed")
|
||||
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,
|
||||
)
|
||||
Guess.objects.create(
|
||||
round_question=round_question,
|
||||
player=correct_player,
|
||||
selected_text="Edison",
|
||||
is_correct=True,
|
||||
)
|
||||
|
||||
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(payload["reveal"]["lies"][0]["player_id"], liar.id)
|
||||
self.assertEqual(payload["reveal"]["lies"][0]["nickname"], "Løgnhals")
|
||||
self.assertEqual(payload["reveal"]["lies"][0]["text"], "Tesla")
|
||||
self.assertEqual(payload["reveal"]["guesses"][0]["player_id"], guesser.id)
|
||||
self.assertEqual(payload["reveal"]["guesses"][0]["selected_text"], "Tesla")
|
||||
self.assertFalse(payload["reveal"]["guesses"][0]["is_correct"])
|
||||
self.assertEqual(payload["reveal"]["guesses"][0]["fooled_player_id"], liar.id)
|
||||
self.assertEqual(payload["reveal"]["guesses"][0]["fooled_player_nickname"], "Løgnhals")
|
||||
self.assertEqual(payload["reveal"]["guesses"][1]["player_id"], correct_player.id)
|
||||
self.assertEqual(payload["reveal"]["guesses"][1]["selected_text"], "Edison")
|
||||
self.assertTrue(payload["reveal"]["guesses"][1]["is_correct"])
|
||||
self.assertIsNone(payload["reveal"]["guesses"][1]["fooled_player_id"])
|
||||
|
||||
|
||||
class SessionDetailPhaseViewModelTests(TestCase):
|
||||
@@ -1218,10 +1312,19 @@ class SessionDetailPhaseViewModelTests(TestCase):
|
||||
reveal_payload = self.client.get(reverse("lobby:session_detail", kwargs={"code": self.session.code})).json()
|
||||
reveal_phase = reveal_payload["phase_view_model"]
|
||||
self.assertTrue(reveal_phase["host"]["can_reveal_scoreboard"])
|
||||
self.assertTrue(reveal_phase["host"]["can_start_next_round"])
|
||||
self.assertTrue(reveal_phase["host"]["can_finish_game"])
|
||||
self.assertFalse(reveal_phase["host"]["can_start_next_round"])
|
||||
self.assertFalse(reveal_phase["host"]["can_finish_game"])
|
||||
self.assertFalse(reveal_phase["player"]["can_view_final_result"])
|
||||
|
||||
self.session.status = GameSession.Status.SCOREBOARD
|
||||
self.session.save(update_fields=["status"])
|
||||
scoreboard_payload = self.client.get(reverse("lobby:session_detail", kwargs={"code": self.session.code})).json()
|
||||
scoreboard_phase = scoreboard_payload["phase_view_model"]
|
||||
self.assertFalse(scoreboard_phase["host"]["can_reveal_scoreboard"])
|
||||
self.assertTrue(scoreboard_phase["host"]["can_start_next_round"])
|
||||
self.assertTrue(scoreboard_phase["host"]["can_finish_game"])
|
||||
self.assertFalse(scoreboard_phase["player"]["can_view_final_result"])
|
||||
|
||||
self.session.status = GameSession.Status.FINISHED
|
||||
self.session.save(update_fields=["status"])
|
||||
finished_payload = self.client.get(reverse("lobby:session_detail", kwargs={"code": self.session.code})).json()
|
||||
|
||||
Reference in New Issue
Block a user