Files
tavolo/server/tests/test_routes_me.py
T
woggioni a9eb97e6e1
CI / Build and push docker image (push) Successful in 1m11s
Stop requesting the user email from the OIDC provider
OIDCConfig now asks for the openid and profile scopes only: kaya-oidc's
default would also request email, which the platform never stores or
exposes. The display-name fallback drops the email claim too
(preferred_username, name, then the sub).

Tests pin the configured scopes and cover an IdP that still returns an
email claim: the claim is ignored and absent from /api/me.
2026-10-14 23:58:40 +08:00

71 lines
2.9 KiB
Python

"""Tests for the whoami endpoint and the static SPA host."""
from __future__ import annotations
import dataclasses
import tempfile
import unittest
from pathlib import Path
from unittest import mock
from httpx import ASGITransport, AsyncClient
from tavolo.app import app
from tavolo.config import settings
from tests.helpers import async_test, oidc_user
class MeRouteTest(unittest.TestCase):
@async_test
async def test_me_authenticated(self) -> None:
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://127.0.0.1") as client:
with oidc_user("alice", email="alice@example.com"):
response = await client.get("/api/me")
self.assertEqual(200, response.status_code)
# The email claim the IdP returns is neither stored nor exposed.
self.assertEqual({"sub": "alice", "name": "alice"}, response.json())
@async_test
async def test_me_unauthenticated(self) -> None:
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://127.0.0.1") as client:
response = await client.get("/api/me")
self.assertEqual(401, response.status_code)
class StaticRouteTest(unittest.TestCase):
"""The app only serves the SPA shell; asset files under /static are
served by Granian and are not reachable through the ASGI transport."""
@async_test
async def test_serves_shell_and_spa_fallback(self) -> None:
with tempfile.TemporaryDirectory() as dist:
(Path(dist) / "index.html").write_text("<html>spa</html>")
patched = dataclasses.replace(settings, static_dir=dist)
with mock.patch("tavolo.static.settings", patched):
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://127.0.0.1") as client:
index = await client.get("/")
self.assertEqual(200, index.status_code)
self.assertEqual("text/html; charset=utf-8", index.headers["content-type"])
self.assertIn(b"spa", index.content)
# Unknown client-side route falls back to the app shell.
fallback = await client.get("/game/some-id")
self.assertEqual(200, fallback.status_code)
self.assertIn(b"spa", fallback.content)
@async_test
async def test_missing_dist_returns_404(self) -> None:
patched = dataclasses.replace(settings, static_dir="/nonexistent-dist")
with mock.patch("tavolo.static.settings", patched):
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://127.0.0.1") as client:
response = await client.get("/")
self.assertEqual(404, response.status_code)
if __name__ == "__main__":
unittest.main()