test(i18n): cover locale fallback and backend error payloads
This commit is contained in:
@@ -360,6 +360,8 @@ class LieSubmissionTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()["error_code"], "lie_submission_closed")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Lie submission window has closed")
|
self.assertEqual(response.json()["error"], "Lie submission window has closed")
|
||||||
|
|
||||||
def test_submit_lie_rejects_duplicate_submission(self):
|
def test_submit_lie_rejects_duplicate_submission(self):
|
||||||
@@ -381,6 +383,8 @@ class LieSubmissionTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 409)
|
self.assertEqual(response.status_code, 409)
|
||||||
|
self.assertEqual(response.json()["error_code"], "lie_already_submitted")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Lie already submitted for this player")
|
self.assertEqual(response.json()["error"], "Lie already submitted for this player")
|
||||||
|
|
||||||
def test_submit_lie_requires_session_token(self):
|
def test_submit_lie_requires_session_token(self):
|
||||||
@@ -401,6 +405,8 @@ class LieSubmissionTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()["error_code"], "session_token_required")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "session_token is required")
|
self.assertEqual(response.json()["error"], "session_token is required")
|
||||||
|
|
||||||
def test_submit_lie_rejects_invalid_session_token(self):
|
def test_submit_lie_rejects_invalid_session_token(self):
|
||||||
@@ -421,8 +427,33 @@ class LieSubmissionTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
self.assertEqual(response.json()["error_code"], "invalid_player_session_token")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Invalid player session token")
|
self.assertEqual(response.json()["error"], "Invalid player session token")
|
||||||
|
|
||||||
|
def test_submit_lie_uses_danish_locale_payload_from_accept_language(self):
|
||||||
|
round_question = RoundQuestion.objects.create(
|
||||||
|
session=self.session,
|
||||||
|
round_number=1,
|
||||||
|
question=self.question,
|
||||||
|
correct_answer=self.question.correct_answer,
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
reverse(
|
||||||
|
"lobby:submit_lie",
|
||||||
|
kwargs={"code": self.session.code, "round_question_id": round_question.id},
|
||||||
|
),
|
||||||
|
data={"player_id": self.player.id, "session_token": "invalid-token", "text": "Sydney"},
|
||||||
|
content_type="application/json",
|
||||||
|
HTTP_ACCEPT_LANGUAGE="da-DK,da;q=0.9,en;q=0.1",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
self.assertEqual(response.json()["error_code"], "invalid_player_session_token")
|
||||||
|
self.assertEqual(response.json()["locale"], "da")
|
||||||
|
self.assertEqual(response.json()["error"], "Ugyldigt spiller-session-token")
|
||||||
|
|
||||||
class MixAnswersTests(TestCase):
|
class MixAnswersTests(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.host = User.objects.create_user(username="host", password="secret123")
|
self.host = User.objects.create_user(username="host", password="secret123")
|
||||||
@@ -582,6 +613,8 @@ class GuessSubmissionTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
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")
|
self.assertEqual(response.json()["error"], "Guess submission is only allowed in guess phase")
|
||||||
|
|
||||||
def test_submit_guess_rejects_unknown_answer(self):
|
def test_submit_guess_rejects_unknown_answer(self):
|
||||||
@@ -595,6 +628,8 @@ class GuessSubmissionTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()["error_code"], "selected_answer_invalid")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Selected answer is not part of this round")
|
self.assertEqual(response.json()["error"], "Selected answer is not part of this round")
|
||||||
|
|
||||||
def test_submit_guess_rejects_duplicate_submission(self):
|
def test_submit_guess_rejects_duplicate_submission(self):
|
||||||
@@ -610,6 +645,8 @@ class GuessSubmissionTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 409)
|
self.assertEqual(response.status_code, 409)
|
||||||
|
self.assertEqual(response.json()["error_code"], "guess_already_submitted")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Guess already submitted for this player")
|
self.assertEqual(response.json()["error"], "Guess already submitted for this player")
|
||||||
|
|
||||||
def test_submit_guess_rejects_after_deadline(self):
|
def test_submit_guess_rejects_after_deadline(self):
|
||||||
@@ -626,6 +663,8 @@ class GuessSubmissionTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()["error_code"], "guess_submission_closed")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Guess submission window has closed")
|
self.assertEqual(response.json()["error"], "Guess submission window has closed")
|
||||||
|
|
||||||
|
|
||||||
@@ -641,6 +680,8 @@ class GuessSubmissionTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()["error_code"], "session_token_required")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
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):
|
def test_submit_guess_rejects_invalid_session_token(self):
|
||||||
@@ -654,6 +695,8 @@ class GuessSubmissionTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
self.assertEqual(response.json()["error_code"], "invalid_player_session_token")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Invalid player session token")
|
self.assertEqual(response.json()["error"], "Invalid player session token")
|
||||||
|
|
||||||
|
|
||||||
@@ -735,6 +778,8 @@ class ScoreCalculationTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
self.assertEqual(response.json()["error_code"], "host_only_calculate_scores")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Only host can calculate scores")
|
self.assertEqual(response.json()["error"], "Only host can calculate scores")
|
||||||
|
|
||||||
def test_calculate_scores_rejects_duplicate_calculation(self):
|
def test_calculate_scores_rejects_duplicate_calculation(self):
|
||||||
@@ -756,6 +801,8 @@ class ScoreCalculationTests(TestCase):
|
|||||||
|
|
||||||
self.assertEqual(first.status_code, 200)
|
self.assertEqual(first.status_code, 200)
|
||||||
self.assertEqual(second.status_code, 409)
|
self.assertEqual(second.status_code, 409)
|
||||||
|
self.assertEqual(second.json()["error_code"], "scores_already_calculated")
|
||||||
|
self.assertEqual(second.json()["locale"], "en")
|
||||||
self.assertEqual(second.json()["error"], "Scores already calculated for this round question")
|
self.assertEqual(second.json()["error"], "Scores already calculated for this round question")
|
||||||
|
|
||||||
|
|
||||||
@@ -793,6 +840,8 @@ class RevealRoundFlowTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
self.assertEqual(response.json()["error_code"], "host_only_view_scoreboard")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Only host can view scoreboard")
|
self.assertEqual(response.json()["error"], "Only host can view scoreboard")
|
||||||
|
|
||||||
def test_host_can_finish_game_from_reveal(self):
|
def test_host_can_finish_game_from_reveal(self):
|
||||||
@@ -825,6 +874,8 @@ class RevealRoundFlowTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
self.assertEqual(response.json()["error_code"], "host_only_finish_game")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Only host can finish game")
|
self.assertEqual(response.json()["error"], "Only host can finish game")
|
||||||
|
|
||||||
def test_finish_game_rejects_wrong_phase(self):
|
def test_finish_game_rejects_wrong_phase(self):
|
||||||
@@ -840,6 +891,8 @@ class RevealRoundFlowTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()["error_code"], "finish_game_invalid_phase")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Game can only be finished from reveal phase")
|
self.assertEqual(response.json()["error"], "Game can only be finished from reveal phase")
|
||||||
|
|
||||||
def test_host_can_start_next_round_from_reveal(self):
|
def test_host_can_start_next_round_from_reveal(self):
|
||||||
@@ -874,8 +927,26 @@ class RevealRoundFlowTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()["error_code"], "next_round_invalid_phase")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
self.assertEqual(response.json()["error"], "Next round can only start from reveal phase")
|
self.assertEqual(response.json()["error"], "Next round can only start from reveal phase")
|
||||||
|
|
||||||
|
def test_reveal_scoreboard_unsupported_locale_falls_back_to_en_deterministically(self):
|
||||||
|
self.client.login(username="other_reveal", password="secret123")
|
||||||
|
|
||||||
|
response = self.client.get(
|
||||||
|
reverse(
|
||||||
|
"lobby:reveal_scoreboard",
|
||||||
|
kwargs={"code": self.session.code},
|
||||||
|
),
|
||||||
|
HTTP_ACCEPT_LANGUAGE="fr-FR,fr;q=0.9",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
self.assertEqual(response.json()["error_code"], "host_only_view_scoreboard")
|
||||||
|
self.assertEqual(response.json()["locale"], "en")
|
||||||
|
self.assertEqual(response.json()["error"], "Only host can view scoreboard")
|
||||||
|
|
||||||
class UiScreenTests(TestCase):
|
class UiScreenTests(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.host = User.objects.create_user(username="host_ui", password="secret123")
|
self.host = User.objects.create_user(username="host_ui", password="secret123")
|
||||||
@@ -1342,6 +1413,15 @@ class I18nResolverTests(TestCase):
|
|||||||
self.assertEqual(result, "missing_key")
|
self.assertEqual(result, "missing_key")
|
||||||
self.assertTrue(any("i18n key missing in shared catalog" in entry for entry in logs.output))
|
self.assertTrue(any("i18n key missing in shared catalog" in entry for entry in logs.output))
|
||||||
|
|
||||||
|
def test_missing_backend_error_code_is_logged_with_context(self):
|
||||||
|
from lobby.i18n import resolve_error_key
|
||||||
|
|
||||||
|
with self.assertLogs("lobby.i18n", level="WARNING") as logs:
|
||||||
|
result = resolve_error_key("missing_code")
|
||||||
|
|
||||||
|
self.assertEqual(result, "missing_code")
|
||||||
|
self.assertTrue(any("i18n error code missing in shared catalog" in entry for entry in logs.output))
|
||||||
|
|
||||||
def test_missing_locale_translation_falls_back_to_default_locale(self):
|
def test_missing_locale_translation_falls_back_to_default_locale(self):
|
||||||
with patch(
|
with patch(
|
||||||
"lobby.i18n.lobby_i18n_error_messages",
|
"lobby.i18n.lobby_i18n_error_messages",
|
||||||
|
|||||||
Reference in New Issue
Block a user