Files
ping-mee-self-service-platform/portal/tests/test_preferences.py
ebbe.bassandClaude Sonnet 5.5 0dc079a8ac feat: add page shell, preferences and translations
Base layout with top bar, role-based menu, profile menu and phone layout; theme, language and German form of address kept in cookies; German formal, German informal and English text; Fluent avatar bundled in the image by a Node build stage; placeholder pages for the Publisher and Admin groups.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N3t4WL7bd9bdHHNjEsxzqC
2026-10-17 21:05:40 +02:00

89 lines
3.3 KiB
Python

"""Per-device preferences: cookies in, validated values out (AD-15)."""
import pytest
from django.test import Client, RequestFactory
from portal.shell import preferences
from portal.shell.preferences import Preferences
def request_with(cookies=None, accept_language=""):
request = RequestFactory().get("/", HTTP_ACCEPT_LANGUAGE=accept_language)
request.COOKIES.update(cookies or {})
return request
def test_without_cookies_the_defaults_apply():
prefs = preferences.from_request(request_with())
assert prefs == Preferences(theme="system", language="en", form="sie")
@pytest.mark.parametrize(
("header", "expected"),
[("de-DE,de;q=0.9,en;q=0.5", "de"), ("en-GB", "en"), ("fr-FR", "en"), ("", "en")],
)
def test_the_language_defaults_from_the_browser(header, expected):
assert preferences.from_request(request_with(accept_language=header)).language == expected
def test_valid_cookies_are_used_and_beat_the_browser():
cookies = {"pm_theme": "dark", "pm_lang": "en", "pm_form": "du"}
prefs = preferences.from_request(request_with(cookies, accept_language="de"))
assert prefs == Preferences(theme="dark", language="en", form="du")
@pytest.mark.parametrize("value", ["", "blue", "<script>", "DARK", "x" * 500])
def test_forged_cookie_values_fall_back_to_the_defaults(value):
cookies = {"pm_theme": value, "pm_lang": value, "pm_form": value}
prefs = preferences.from_request(request_with(cookies))
assert prefs == Preferences(theme="system", language="en", form="sie")
def test_the_informal_form_only_changes_german():
assert Preferences(language="de", form="du").language_code == "de-du"
assert Preferences(language="de", form="sie").language_code == "de"
assert Preferences(language="en", form="du").language_code == "en"
def test_only_valid_choices_are_taken_from_a_submission():
assert preferences.chosen({"theme": "dark", "language": "xx", "form": "du"}) == {
"pm_theme": "dark",
"pm_form": "du",
}
assert preferences.chosen({}) == {}
# -- the preferences address ------------------------------------------------------------------
def test_choosing_sets_the_cookies_and_returns_to_the_page():
response = Client().post(
"/preferences", {"theme": "dark", "language": "de", "form": "du", "next": "/x?y=1"}
)
assert response.status_code == 302 and response["Location"] == "/x?y=1"
for name, value in (("pm_theme", "dark"), ("pm_lang", "de"), ("pm_form", "du")):
cookie = response.cookies[name]
assert cookie.value == value
assert cookie["samesite"] == "Lax" and cookie["secure"] and not cookie["httponly"]
assert cookie["max-age"] == preferences.COOKIE_MAX_AGE
def test_an_invalid_value_sets_no_cookie():
response = Client().post("/preferences", {"theme": "neon", "language": "fr"})
assert not response.cookies
@pytest.mark.parametrize("target", ["https://evil.example.test/", "//evil.example.test", "x", ""])
def test_the_return_address_cannot_leave_the_site(target):
response = Client().post("/preferences", {"theme": "dark", "next": target})
assert response["Location"] == "/"
def test_choosing_needs_post():
assert Client().get("/preferences").status_code == 405
def test_choosing_needs_a_csrf_token():
strict = Client(enforce_csrf_checks=True)
assert strict.post("/preferences", {"theme": "dark"}).status_code == 403