fix(tests): use admin_client for admin-protected endpoints
Some checks failed
CI / backend-tests (pull_request) Successful in 26s
CI / frontend-tests (pull_request) Failing after 29s

After adding require_admin to admin endpoints, tests using
unauthenticated client or auth_client got 401/403. Also fix mock user
ID to be a valid UUID (was "test-user-123", now a proper UUID4).

- Add admin_override and admin_client fixtures to conftest
- Update test_pokemon.py, test_games.py, test_genlocke_boss.py to use
  admin_client for write operations on admin endpoints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-21 11:39:10 +01:00
parent afd1c2543a
commit c17e776408
4 changed files with 269 additions and 242 deletions

View File

@@ -17,9 +17,9 @@ GAME_PAYLOAD = {
@pytest.fixture
async def game(auth_client: AsyncClient) -> dict:
async def game(admin_client: AsyncClient) -> dict:
"""A game created via the API (no version_group_id)."""
response = await auth_client.post(BASE, json=GAME_PAYLOAD)
response = await admin_client.post(BASE, json=GAME_PAYLOAD)
assert response.status_code == 201
return response.json()
@@ -68,8 +68,8 @@ class TestListGames:
class TestCreateGame:
async def test_creates_and_returns_game(self, auth_client: AsyncClient):
response = await auth_client.post(BASE, json=GAME_PAYLOAD)
async def test_creates_and_returns_game(self, admin_client: AsyncClient):
response = await admin_client.post(BASE, json=GAME_PAYLOAD)
assert response.status_code == 201
data = response.json()
assert data["name"] == "Pokemon Red"
@@ -77,15 +77,15 @@ class TestCreateGame:
assert isinstance(data["id"], int)
async def test_duplicate_slug_returns_409(
self, auth_client: AsyncClient, game: dict
self, admin_client: AsyncClient, game: dict
):
response = await auth_client.post(
response = await admin_client.post(
BASE, json={**GAME_PAYLOAD, "name": "Pokemon Red v2"}
)
assert response.status_code == 409
async def test_missing_required_field_returns_422(self, auth_client: AsyncClient):
response = await auth_client.post(BASE, json={"name": "Pokemon Red"})
async def test_missing_required_field_returns_422(self, admin_client: AsyncClient):
response = await admin_client.post(BASE, json={"name": "Pokemon Red"})
assert response.status_code == 422
@@ -115,35 +115,35 @@ class TestGetGame:
class TestUpdateGame:
async def test_updates_name(self, auth_client: AsyncClient, game: dict):
response = await auth_client.put(
async def test_updates_name(self, admin_client: AsyncClient, game: dict):
response = await admin_client.put(
f"{BASE}/{game['id']}", json={"name": "Pokemon Blue"}
)
assert response.status_code == 200
assert response.json()["name"] == "Pokemon Blue"
async def test_slug_unchanged_on_partial_update(
self, auth_client: AsyncClient, game: dict
self, admin_client: AsyncClient, game: dict
):
response = await auth_client.put(
response = await admin_client.put(
f"{BASE}/{game['id']}", json={"name": "New Name"}
)
assert response.json()["slug"] == "red"
async def test_not_found_returns_404(self, auth_client: AsyncClient):
async def test_not_found_returns_404(self, admin_client: AsyncClient):
assert (
await auth_client.put(f"{BASE}/9999", json={"name": "x"})
await admin_client.put(f"{BASE}/9999", json={"name": "x"})
).status_code == 404
async def test_duplicate_slug_returns_409(self, auth_client: AsyncClient):
await auth_client.post(
async def test_duplicate_slug_returns_409(self, admin_client: AsyncClient):
await admin_client.post(
BASE, json={**GAME_PAYLOAD, "slug": "blue", "name": "Blue"}
)
r1 = await auth_client.post(
r1 = await admin_client.post(
BASE, json={**GAME_PAYLOAD, "slug": "red", "name": "Red"}
)
game_id = r1.json()["id"]
response = await auth_client.put(f"{BASE}/{game_id}", json={"slug": "blue"})
response = await admin_client.put(f"{BASE}/{game_id}", json={"slug": "blue"})
assert response.status_code == 409
@@ -153,13 +153,13 @@ class TestUpdateGame:
class TestDeleteGame:
async def test_deletes_game(self, auth_client: AsyncClient, game: dict):
response = await auth_client.delete(f"{BASE}/{game['id']}")
async def test_deletes_game(self, admin_client: AsyncClient, game: dict):
response = await admin_client.delete(f"{BASE}/{game['id']}")
assert response.status_code == 204
assert (await auth_client.get(f"{BASE}/{game['id']}")).status_code == 404
assert (await admin_client.get(f"{BASE}/{game['id']}")).status_code == 404
async def test_not_found_returns_404(self, auth_client: AsyncClient):
assert (await auth_client.delete(f"{BASE}/9999")).status_code == 404
async def test_not_found_returns_404(self, admin_client: AsyncClient):
assert (await admin_client.delete(f"{BASE}/9999")).status_code == 404
# ---------------------------------------------------------------------------
@@ -195,9 +195,9 @@ class TestListByRegion:
class TestCreateRoute:
async def test_creates_route(self, auth_client: AsyncClient, game_with_vg: tuple):
async def test_creates_route(self, admin_client: AsyncClient, game_with_vg: tuple):
game_id, _ = game_with_vg
response = await auth_client.post(
response = await admin_client.post(
f"{BASE}/{game_id}/routes",
json={"name": "Pallet Town", "order": 1},
)
@@ -208,35 +208,35 @@ class TestCreateRoute:
assert isinstance(data["id"], int)
async def test_game_detail_includes_route(
self, auth_client: AsyncClient, game_with_vg: tuple
self, admin_client: AsyncClient, game_with_vg: tuple
):
game_id, _ = game_with_vg
await auth_client.post(
await admin_client.post(
f"{BASE}/{game_id}/routes", json={"name": "Route 1", "order": 1}
)
response = await auth_client.get(f"{BASE}/{game_id}")
response = await admin_client.get(f"{BASE}/{game_id}")
routes = response.json()["routes"]
assert len(routes) == 1
assert routes[0]["name"] == "Route 1"
async def test_game_without_version_group_returns_400(
self, auth_client: AsyncClient, game: dict
self, admin_client: AsyncClient, game: dict
):
response = await auth_client.post(
response = await admin_client.post(
f"{BASE}/{game['id']}/routes",
json={"name": "Route 1", "order": 1},
)
assert response.status_code == 400
async def test_list_routes_excludes_routes_without_encounters(
self, auth_client: AsyncClient, game_with_vg: tuple
self, admin_client: AsyncClient, game_with_vg: tuple
):
"""list_game_routes only returns routes that have Pokemon encounters."""
game_id, _ = game_with_vg
await auth_client.post(
await admin_client.post(
f"{BASE}/{game_id}/routes", json={"name": "Route 1", "order": 1}
)
response = await auth_client.get(f"{BASE}/{game_id}/routes?flat=true")
response = await admin_client.get(f"{BASE}/{game_id}/routes?flat=true")
assert response.status_code == 200
assert response.json() == []
@@ -248,15 +248,15 @@ class TestCreateRoute:
class TestUpdateRoute:
async def test_updates_route_name(
self, auth_client: AsyncClient, game_with_vg: tuple
self, admin_client: AsyncClient, game_with_vg: tuple
):
game_id, _ = game_with_vg
r = (
await auth_client.post(
await admin_client.post(
f"{BASE}/{game_id}/routes", json={"name": "Old Name", "order": 1}
)
).json()
response = await auth_client.put(
response = await admin_client.put(
f"{BASE}/{game_id}/routes/{r['id']}",
json={"name": "New Name"},
)
@@ -264,11 +264,11 @@ class TestUpdateRoute:
assert response.json()["name"] == "New Name"
async def test_route_not_found_returns_404(
self, auth_client: AsyncClient, game_with_vg: tuple
self, admin_client: AsyncClient, game_with_vg: tuple
):
game_id, _ = game_with_vg
assert (
await auth_client.put(f"{BASE}/{game_id}/routes/9999", json={"name": "x"})
await admin_client.put(f"{BASE}/{game_id}/routes/9999", json={"name": "x"})
).status_code == 404
@@ -278,26 +278,26 @@ class TestUpdateRoute:
class TestDeleteRoute:
async def test_deletes_route(self, auth_client: AsyncClient, game_with_vg: tuple):
async def test_deletes_route(self, admin_client: AsyncClient, game_with_vg: tuple):
game_id, _ = game_with_vg
r = (
await auth_client.post(
await admin_client.post(
f"{BASE}/{game_id}/routes", json={"name": "Route 1", "order": 1}
)
).json()
assert (
await auth_client.delete(f"{BASE}/{game_id}/routes/{r['id']}")
await admin_client.delete(f"{BASE}/{game_id}/routes/{r['id']}")
).status_code == 204
# No longer in game detail
detail = (await auth_client.get(f"{BASE}/{game_id}")).json()
detail = (await admin_client.get(f"{BASE}/{game_id}")).json()
assert all(route["id"] != r["id"] for route in detail["routes"])
async def test_route_not_found_returns_404(
self, auth_client: AsyncClient, game_with_vg: tuple
self, admin_client: AsyncClient, game_with_vg: tuple
):
game_id, _ = game_with_vg
assert (
await auth_client.delete(f"{BASE}/{game_id}/routes/9999")
await admin_client.delete(f"{BASE}/{game_id}/routes/9999")
).status_code == 404
@@ -307,20 +307,20 @@ class TestDeleteRoute:
class TestReorderRoutes:
async def test_reorders_routes(self, auth_client: AsyncClient, game_with_vg: tuple):
async def test_reorders_routes(self, admin_client: AsyncClient, game_with_vg: tuple):
game_id, _ = game_with_vg
r1 = (
await auth_client.post(
await admin_client.post(
f"{BASE}/{game_id}/routes", json={"name": "A", "order": 1}
)
).json()
r2 = (
await auth_client.post(
await admin_client.post(
f"{BASE}/{game_id}/routes", json={"name": "B", "order": 2}
)
).json()
response = await auth_client.put(
response = await admin_client.put(
f"{BASE}/{game_id}/routes/reorder",
json={
"routes": [{"id": r1["id"], "order": 2}, {"id": r2["id"], "order": 1}]