feat: ordre naturel des sections Configurations et avatar utilisateur #113
This commit is contained in:
+95
-1
@@ -308,4 +308,98 @@ class TestAdmin:
|
||||
resp = auth_client.post("/api/auth/logout", headers={
|
||||
"Authorization": f"Bearer {token}",
|
||||
})
|
||||
assert resp.status_code == 200
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
# Profile avatar (#113)
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
# 1×1 transparent PNG.
|
||||
TINY_PNG = (
|
||||
"data:image/png;base64,"
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8"
|
||||
"z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
|
||||
)
|
||||
|
||||
|
||||
class TestAvatar:
|
||||
def _login(self, client):
|
||||
resp = client.post("/api/auth/login", json={
|
||||
"username": "admin", "password": "chab30",
|
||||
})
|
||||
return resp.json()["access_token"]
|
||||
|
||||
def _headers(self, token):
|
||||
return {"Authorization": f"Bearer {token}"}
|
||||
|
||||
def test_me_returns_avatar_field(self, auth_client):
|
||||
"""GET /api/auth/me exposes the avatar key (None by default)."""
|
||||
token = self._login(auth_client)
|
||||
resp = auth_client.get("/api/auth/me", headers=self._headers(token))
|
||||
assert resp.status_code == 200
|
||||
assert "avatar" in resp.json()
|
||||
assert resp.json()["avatar"] is None
|
||||
|
||||
def test_patch_me_sets_avatar(self, auth_client):
|
||||
"""A valid PNG data-URL is persisted and returned by GET /me."""
|
||||
token = self._login(auth_client)
|
||||
resp = auth_client.patch("/api/auth/me", headers=self._headers(token),
|
||||
json={"avatar": TINY_PNG})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["avatar"] == TINY_PNG
|
||||
me = auth_client.get("/api/auth/me", headers=self._headers(token)).json()
|
||||
assert me["avatar"] == TINY_PNG
|
||||
|
||||
def test_patch_me_avatar_empty_string_clears(self, auth_client):
|
||||
"""Sending an empty string removes the avatar."""
|
||||
token = self._login(auth_client)
|
||||
auth_client.patch("/api/auth/me", headers=self._headers(token),
|
||||
json={"avatar": TINY_PNG})
|
||||
resp = auth_client.patch("/api/auth/me", headers=self._headers(token),
|
||||
json={"avatar": ""})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["avatar"] is None
|
||||
|
||||
def test_patch_me_avatar_rejects_svg(self, auth_client):
|
||||
"""SVG data-URLs are refused (XSS surface)."""
|
||||
token = self._login(auth_client)
|
||||
svg = "data:image/svg+xml;base64,PHN2Zz48L3N2Zz4="
|
||||
resp = auth_client.patch("/api/auth/me", headers=self._headers(token),
|
||||
json={"avatar": svg})
|
||||
assert resp.status_code == 400
|
||||
|
||||
def test_patch_me_avatar_rejects_non_image_payload(self, auth_client):
|
||||
"""A PNG data-URL header over non-image bytes is refused."""
|
||||
token = self._login(auth_client)
|
||||
fake = "data:image/png;base64,aGVsbG8gd29ybGQ=" # "hello world"
|
||||
resp = auth_client.patch("/api/auth/me", headers=self._headers(token),
|
||||
json={"avatar": fake})
|
||||
assert resp.status_code == 400
|
||||
|
||||
def test_patch_me_avatar_rejects_too_large(self, auth_client):
|
||||
"""Payloads above the size cap are refused before any decode."""
|
||||
token = self._login(auth_client)
|
||||
huge = "data:image/png;base64," + "A" * 500_000
|
||||
resp = auth_client.patch("/api/auth/me", headers=self._headers(token),
|
||||
json={"avatar": huge})
|
||||
assert resp.status_code == 400
|
||||
|
||||
def test_patch_me_avatar_rejects_invalid_base64(self, auth_client):
|
||||
"""Malformed base64 inside a well-formed data-URL is refused."""
|
||||
token = self._login(auth_client)
|
||||
resp = auth_client.patch("/api/auth/me", headers=self._headers(token),
|
||||
json={"avatar": "data:image/png;base64,@@not-base64@@"})
|
||||
assert resp.status_code == 400
|
||||
|
||||
def test_login_user_payload_includes_avatar(self, auth_client):
|
||||
"""The login response user object carries the avatar for the sidebar."""
|
||||
token = self._login(auth_client)
|
||||
auth_client.patch("/api/auth/me", headers=self._headers(token),
|
||||
json={"avatar": TINY_PNG})
|
||||
# Re-login to get a fresh user payload.
|
||||
resp = auth_client.post("/api/auth/login", json={
|
||||
"username": "admin", "password": "chab30",
|
||||
})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["user"]["avatar"] == TINY_PNG
|
||||
Reference in New Issue
Block a user