fix(tests): use admin_client for admin-protected endpoints
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:
@@ -7,7 +7,7 @@ from httpx import ASGITransport, AsyncClient
|
|||||||
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
||||||
|
|
||||||
import app.models # noqa: F401 — ensures all models register with Base.metadata
|
import app.models # noqa: F401 — ensures all models register with Base.metadata
|
||||||
from app.core.auth import AuthUser, get_current_user
|
from app.core.auth import AuthUser, get_current_user, require_admin
|
||||||
from app.core.database import Base, get_session
|
from app.core.database import Base, get_session
|
||||||
from app.main import app
|
from app.main import app
|
||||||
|
|
||||||
@@ -70,7 +70,11 @@ async def client(db_session):
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_auth_user():
|
def mock_auth_user():
|
||||||
"""Return a mock authenticated user for tests."""
|
"""Return a mock authenticated user for tests."""
|
||||||
return AuthUser(id="test-user-123", email="test@example.com", role="authenticated")
|
return AuthUser(
|
||||||
|
id="00000000-0000-4000-a000-000000000001",
|
||||||
|
email="test@example.com",
|
||||||
|
role="authenticated",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -94,11 +98,34 @@ async def auth_client(db_session, auth_override):
|
|||||||
yield ac
|
yield ac
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def admin_override(mock_auth_user):
|
||||||
|
"""Override require_admin and get_current_user to return a mock user."""
|
||||||
|
|
||||||
|
def _override():
|
||||||
|
return mock_auth_user
|
||||||
|
|
||||||
|
app.dependency_overrides[require_admin] = _override
|
||||||
|
app.dependency_overrides[get_current_user] = _override
|
||||||
|
yield
|
||||||
|
app.dependency_overrides.pop(require_admin, None)
|
||||||
|
app.dependency_overrides.pop(get_current_user, None)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def admin_client(db_session, admin_override):
|
||||||
|
"""Async HTTP client with mocked admin authentication."""
|
||||||
|
async with AsyncClient(
|
||||||
|
transport=ASGITransport(app=app), base_url="http://test"
|
||||||
|
) as ac:
|
||||||
|
yield ac
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def valid_token():
|
def valid_token():
|
||||||
"""Generate a valid JWT token for testing."""
|
"""Generate a valid JWT token for testing."""
|
||||||
payload = {
|
payload = {
|
||||||
"sub": "test-user-123",
|
"sub": "00000000-0000-4000-a000-000000000001",
|
||||||
"email": "test@example.com",
|
"email": "test@example.com",
|
||||||
"role": "authenticated",
|
"role": "authenticated",
|
||||||
"aud": "authenticated",
|
"aud": "authenticated",
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ GAME_PAYLOAD = {
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@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)."""
|
"""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
|
assert response.status_code == 201
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
@@ -68,8 +68,8 @@ class TestListGames:
|
|||||||
|
|
||||||
|
|
||||||
class TestCreateGame:
|
class TestCreateGame:
|
||||||
async def test_creates_and_returns_game(self, auth_client: AsyncClient):
|
async def test_creates_and_returns_game(self, admin_client: AsyncClient):
|
||||||
response = await auth_client.post(BASE, json=GAME_PAYLOAD)
|
response = await admin_client.post(BASE, json=GAME_PAYLOAD)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
data = response.json()
|
data = response.json()
|
||||||
assert data["name"] == "Pokemon Red"
|
assert data["name"] == "Pokemon Red"
|
||||||
@@ -77,15 +77,15 @@ class TestCreateGame:
|
|||||||
assert isinstance(data["id"], int)
|
assert isinstance(data["id"], int)
|
||||||
|
|
||||||
async def test_duplicate_slug_returns_409(
|
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"}
|
BASE, json={**GAME_PAYLOAD, "name": "Pokemon Red v2"}
|
||||||
)
|
)
|
||||||
assert response.status_code == 409
|
assert response.status_code == 409
|
||||||
|
|
||||||
async def test_missing_required_field_returns_422(self, auth_client: AsyncClient):
|
async def test_missing_required_field_returns_422(self, admin_client: AsyncClient):
|
||||||
response = await auth_client.post(BASE, json={"name": "Pokemon Red"})
|
response = await admin_client.post(BASE, json={"name": "Pokemon Red"})
|
||||||
assert response.status_code == 422
|
assert response.status_code == 422
|
||||||
|
|
||||||
|
|
||||||
@@ -115,35 +115,35 @@ class TestGetGame:
|
|||||||
|
|
||||||
|
|
||||||
class TestUpdateGame:
|
class TestUpdateGame:
|
||||||
async def test_updates_name(self, auth_client: AsyncClient, game: dict):
|
async def test_updates_name(self, admin_client: AsyncClient, game: dict):
|
||||||
response = await auth_client.put(
|
response = await admin_client.put(
|
||||||
f"{BASE}/{game['id']}", json={"name": "Pokemon Blue"}
|
f"{BASE}/{game['id']}", json={"name": "Pokemon Blue"}
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json()["name"] == "Pokemon Blue"
|
assert response.json()["name"] == "Pokemon Blue"
|
||||||
|
|
||||||
async def test_slug_unchanged_on_partial_update(
|
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"}
|
f"{BASE}/{game['id']}", json={"name": "New Name"}
|
||||||
)
|
)
|
||||||
assert response.json()["slug"] == "red"
|
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 (
|
assert (
|
||||||
await auth_client.put(f"{BASE}/9999", json={"name": "x"})
|
await admin_client.put(f"{BASE}/9999", json={"name": "x"})
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|
||||||
async def test_duplicate_slug_returns_409(self, auth_client: AsyncClient):
|
async def test_duplicate_slug_returns_409(self, admin_client: AsyncClient):
|
||||||
await auth_client.post(
|
await admin_client.post(
|
||||||
BASE, json={**GAME_PAYLOAD, "slug": "blue", "name": "Blue"}
|
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"}
|
BASE, json={**GAME_PAYLOAD, "slug": "red", "name": "Red"}
|
||||||
)
|
)
|
||||||
game_id = r1.json()["id"]
|
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
|
assert response.status_code == 409
|
||||||
|
|
||||||
|
|
||||||
@@ -153,13 +153,13 @@ class TestUpdateGame:
|
|||||||
|
|
||||||
|
|
||||||
class TestDeleteGame:
|
class TestDeleteGame:
|
||||||
async def test_deletes_game(self, auth_client: AsyncClient, game: dict):
|
async def test_deletes_game(self, admin_client: AsyncClient, game: dict):
|
||||||
response = await auth_client.delete(f"{BASE}/{game['id']}")
|
response = await admin_client.delete(f"{BASE}/{game['id']}")
|
||||||
assert response.status_code == 204
|
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):
|
async def test_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (await auth_client.delete(f"{BASE}/9999")).status_code == 404
|
assert (await admin_client.delete(f"{BASE}/9999")).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -195,9 +195,9 @@ class TestListByRegion:
|
|||||||
|
|
||||||
|
|
||||||
class TestCreateRoute:
|
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
|
game_id, _ = game_with_vg
|
||||||
response = await auth_client.post(
|
response = await admin_client.post(
|
||||||
f"{BASE}/{game_id}/routes",
|
f"{BASE}/{game_id}/routes",
|
||||||
json={"name": "Pallet Town", "order": 1},
|
json={"name": "Pallet Town", "order": 1},
|
||||||
)
|
)
|
||||||
@@ -208,35 +208,35 @@ class TestCreateRoute:
|
|||||||
assert isinstance(data["id"], int)
|
assert isinstance(data["id"], int)
|
||||||
|
|
||||||
async def test_game_detail_includes_route(
|
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
|
game_id, _ = game_with_vg
|
||||||
await auth_client.post(
|
await admin_client.post(
|
||||||
f"{BASE}/{game_id}/routes", json={"name": "Route 1", "order": 1}
|
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"]
|
routes = response.json()["routes"]
|
||||||
assert len(routes) == 1
|
assert len(routes) == 1
|
||||||
assert routes[0]["name"] == "Route 1"
|
assert routes[0]["name"] == "Route 1"
|
||||||
|
|
||||||
async def test_game_without_version_group_returns_400(
|
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",
|
f"{BASE}/{game['id']}/routes",
|
||||||
json={"name": "Route 1", "order": 1},
|
json={"name": "Route 1", "order": 1},
|
||||||
)
|
)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
||||||
async def test_list_routes_excludes_routes_without_encounters(
|
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."""
|
"""list_game_routes only returns routes that have Pokemon encounters."""
|
||||||
game_id, _ = game_with_vg
|
game_id, _ = game_with_vg
|
||||||
await auth_client.post(
|
await admin_client.post(
|
||||||
f"{BASE}/{game_id}/routes", json={"name": "Route 1", "order": 1}
|
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.status_code == 200
|
||||||
assert response.json() == []
|
assert response.json() == []
|
||||||
|
|
||||||
@@ -248,15 +248,15 @@ class TestCreateRoute:
|
|||||||
|
|
||||||
class TestUpdateRoute:
|
class TestUpdateRoute:
|
||||||
async def test_updates_route_name(
|
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
|
game_id, _ = game_with_vg
|
||||||
r = (
|
r = (
|
||||||
await auth_client.post(
|
await admin_client.post(
|
||||||
f"{BASE}/{game_id}/routes", json={"name": "Old Name", "order": 1}
|
f"{BASE}/{game_id}/routes", json={"name": "Old Name", "order": 1}
|
||||||
)
|
)
|
||||||
).json()
|
).json()
|
||||||
response = await auth_client.put(
|
response = await admin_client.put(
|
||||||
f"{BASE}/{game_id}/routes/{r['id']}",
|
f"{BASE}/{game_id}/routes/{r['id']}",
|
||||||
json={"name": "New Name"},
|
json={"name": "New Name"},
|
||||||
)
|
)
|
||||||
@@ -264,11 +264,11 @@ class TestUpdateRoute:
|
|||||||
assert response.json()["name"] == "New Name"
|
assert response.json()["name"] == "New Name"
|
||||||
|
|
||||||
async def test_route_not_found_returns_404(
|
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
|
game_id, _ = game_with_vg
|
||||||
assert (
|
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
|
).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
@@ -278,26 +278,26 @@ class TestUpdateRoute:
|
|||||||
|
|
||||||
|
|
||||||
class TestDeleteRoute:
|
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
|
game_id, _ = game_with_vg
|
||||||
r = (
|
r = (
|
||||||
await auth_client.post(
|
await admin_client.post(
|
||||||
f"{BASE}/{game_id}/routes", json={"name": "Route 1", "order": 1}
|
f"{BASE}/{game_id}/routes", json={"name": "Route 1", "order": 1}
|
||||||
)
|
)
|
||||||
).json()
|
).json()
|
||||||
assert (
|
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
|
).status_code == 204
|
||||||
# No longer in game detail
|
# 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"])
|
assert all(route["id"] != r["id"] for route in detail["routes"])
|
||||||
|
|
||||||
async def test_route_not_found_returns_404(
|
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
|
game_id, _ = game_with_vg
|
||||||
assert (
|
assert (
|
||||||
await auth_client.delete(f"{BASE}/{game_id}/routes/9999")
|
await admin_client.delete(f"{BASE}/{game_id}/routes/9999")
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
@@ -307,20 +307,20 @@ class TestDeleteRoute:
|
|||||||
|
|
||||||
|
|
||||||
class TestReorderRoutes:
|
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
|
game_id, _ = game_with_vg
|
||||||
r1 = (
|
r1 = (
|
||||||
await auth_client.post(
|
await admin_client.post(
|
||||||
f"{BASE}/{game_id}/routes", json={"name": "A", "order": 1}
|
f"{BASE}/{game_id}/routes", json={"name": "A", "order": 1}
|
||||||
)
|
)
|
||||||
).json()
|
).json()
|
||||||
r2 = (
|
r2 = (
|
||||||
await auth_client.post(
|
await admin_client.post(
|
||||||
f"{BASE}/{game_id}/routes", json={"name": "B", "order": 2}
|
f"{BASE}/{game_id}/routes", json={"name": "B", "order": 2}
|
||||||
)
|
)
|
||||||
).json()
|
).json()
|
||||||
|
|
||||||
response = await auth_client.put(
|
response = await admin_client.put(
|
||||||
f"{BASE}/{game_id}/routes/reorder",
|
f"{BASE}/{game_id}/routes/reorder",
|
||||||
json={
|
json={
|
||||||
"routes": [{"id": r1["id"], "order": 2}, {"id": r2["id"], "order": 1}]
|
"routes": [{"id": r1["id"], "order": 2}, {"id": r2["id"], "order": 1}]
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ async def games_ctx(db_session: AsyncSession) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def ctx(db_session: AsyncSession, client: AsyncClient, games_ctx: dict) -> dict:
|
async def ctx(db_session: AsyncSession, admin_client: AsyncClient, games_ctx: dict) -> dict:
|
||||||
"""Full context: routes + pokemon + genlocke + encounter for advance/transfer tests."""
|
"""Full context: routes + pokemon + genlocke + encounter for advance/transfer tests."""
|
||||||
route1 = Route(name="GT Route 1", version_group_id=games_ctx["vg1_id"], order=1)
|
route1 = Route(name="GT Route 1", version_group_id=games_ctx["vg1_id"], order=1)
|
||||||
route2 = Route(name="GT Route 2", version_group_id=games_ctx["vg2_id"], order=1)
|
route2 = Route(name="GT Route 2", version_group_id=games_ctx["vg2_id"], order=1)
|
||||||
@@ -67,7 +67,7 @@ async def ctx(db_session: AsyncSession, client: AsyncClient, games_ctx: dict) ->
|
|||||||
db_session.add(pikachu)
|
db_session.add(pikachu)
|
||||||
await db_session.commit()
|
await db_session.commit()
|
||||||
|
|
||||||
r = await client.post(
|
r = await admin_client.post(
|
||||||
GENLOCKES_BASE,
|
GENLOCKES_BASE,
|
||||||
json={
|
json={
|
||||||
"name": "Test Genlocke",
|
"name": "Test Genlocke",
|
||||||
@@ -80,7 +80,7 @@ async def ctx(db_session: AsyncSession, client: AsyncClient, games_ctx: dict) ->
|
|||||||
leg1 = next(leg for leg in genlocke["legs"] if leg["legOrder"] == 1)
|
leg1 = next(leg for leg in genlocke["legs"] if leg["legOrder"] == 1)
|
||||||
run_id = leg1["runId"]
|
run_id = leg1["runId"]
|
||||||
|
|
||||||
enc_r = await client.post(
|
enc_r = await admin_client.post(
|
||||||
f"{RUNS_BASE}/{run_id}/encounters",
|
f"{RUNS_BASE}/{run_id}/encounters",
|
||||||
json={"routeId": route1.id, "pokemonId": pikachu.id, "status": "caught"},
|
json={"routeId": route1.id, "pokemonId": pikachu.id, "status": "caught"},
|
||||||
)
|
)
|
||||||
@@ -104,13 +104,13 @@ async def ctx(db_session: AsyncSession, client: AsyncClient, games_ctx: dict) ->
|
|||||||
|
|
||||||
|
|
||||||
class TestListGenlockes:
|
class TestListGenlockes:
|
||||||
async def test_empty_returns_empty_list(self, client: AsyncClient):
|
async def test_empty_returns_empty_list(self, admin_client: AsyncClient):
|
||||||
response = await client.get(GENLOCKES_BASE)
|
response = await admin_client.get(GENLOCKES_BASE)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == []
|
assert response.json() == []
|
||||||
|
|
||||||
async def test_returns_created_genlocke(self, client: AsyncClient, ctx: dict):
|
async def test_returns_created_genlocke(self, admin_client: AsyncClient, ctx: dict):
|
||||||
response = await client.get(GENLOCKES_BASE)
|
response = await admin_client.get(GENLOCKES_BASE)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
names = [g["name"] for g in response.json()]
|
names = [g["name"] for g in response.json()]
|
||||||
assert "Test Genlocke" in names
|
assert "Test Genlocke" in names
|
||||||
@@ -123,9 +123,9 @@ class TestListGenlockes:
|
|||||||
|
|
||||||
class TestCreateGenlocke:
|
class TestCreateGenlocke:
|
||||||
async def test_creates_with_legs_and_first_run(
|
async def test_creates_with_legs_and_first_run(
|
||||||
self, client: AsyncClient, games_ctx: dict
|
self, admin_client: AsyncClient, games_ctx: dict
|
||||||
):
|
):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
GENLOCKES_BASE,
|
GENLOCKES_BASE,
|
||||||
json={
|
json={
|
||||||
"name": "My Genlocke",
|
"name": "My Genlocke",
|
||||||
@@ -144,14 +144,14 @@ class TestCreateGenlocke:
|
|||||||
leg2 = next(leg for leg in data["legs"] if leg["legOrder"] == 2)
|
leg2 = next(leg for leg in data["legs"] if leg["legOrder"] == 2)
|
||||||
assert leg2["runId"] is None
|
assert leg2["runId"] is None
|
||||||
|
|
||||||
async def test_empty_game_ids_returns_400(self, client: AsyncClient):
|
async def test_empty_game_ids_returns_400(self, admin_client: AsyncClient):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
GENLOCKES_BASE, json={"name": "Bad", "gameIds": []}
|
GENLOCKES_BASE, json={"name": "Bad", "gameIds": []}
|
||||||
)
|
)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
||||||
async def test_invalid_game_id_returns_404(self, client: AsyncClient):
|
async def test_invalid_game_id_returns_404(self, admin_client: AsyncClient):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
GENLOCKES_BASE, json={"name": "Bad", "gameIds": [9999]}
|
GENLOCKES_BASE, json={"name": "Bad", "gameIds": [9999]}
|
||||||
)
|
)
|
||||||
assert response.status_code == 404
|
assert response.status_code == 404
|
||||||
@@ -164,9 +164,9 @@ class TestCreateGenlocke:
|
|||||||
|
|
||||||
class TestGetGenlocke:
|
class TestGetGenlocke:
|
||||||
async def test_returns_genlocke_with_legs_and_stats(
|
async def test_returns_genlocke_with_legs_and_stats(
|
||||||
self, client: AsyncClient, ctx: dict
|
self, admin_client: AsyncClient, ctx: dict
|
||||||
):
|
):
|
||||||
response = await client.get(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}")
|
response = await admin_client.get(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json()
|
||||||
assert data["id"] == ctx["genlocke_id"]
|
assert data["id"] == ctx["genlocke_id"]
|
||||||
@@ -174,8 +174,8 @@ class TestGetGenlocke:
|
|||||||
assert "stats" in data
|
assert "stats" in data
|
||||||
assert data["stats"]["totalLegs"] == 2
|
assert data["stats"]["totalLegs"] == 2
|
||||||
|
|
||||||
async def test_not_found_returns_404(self, client: AsyncClient):
|
async def test_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (await client.get(f"{GENLOCKES_BASE}/9999")).status_code == 404
|
assert (await admin_client.get(f"{GENLOCKES_BASE}/9999")).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -184,30 +184,30 @@ class TestGetGenlocke:
|
|||||||
|
|
||||||
|
|
||||||
class TestUpdateGenlocke:
|
class TestUpdateGenlocke:
|
||||||
async def test_updates_name(self, client: AsyncClient, ctx: dict):
|
async def test_updates_name(self, admin_client: AsyncClient, ctx: dict):
|
||||||
response = await client.patch(
|
response = await admin_client.patch(
|
||||||
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}", json={"name": "Renamed"}
|
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}", json={"name": "Renamed"}
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json()["name"] == "Renamed"
|
assert response.json()["name"] == "Renamed"
|
||||||
|
|
||||||
async def test_not_found_returns_404(self, client: AsyncClient):
|
async def test_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (
|
assert (
|
||||||
await client.patch(f"{GENLOCKES_BASE}/9999", json={"name": "x"})
|
await admin_client.patch(f"{GENLOCKES_BASE}/9999", json={"name": "x"})
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
class TestDeleteGenlocke:
|
class TestDeleteGenlocke:
|
||||||
async def test_deletes_genlocke(self, client: AsyncClient, ctx: dict):
|
async def test_deletes_genlocke(self, admin_client: AsyncClient, ctx: dict):
|
||||||
assert (
|
assert (
|
||||||
await client.delete(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}")
|
await admin_client.delete(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}")
|
||||||
).status_code == 204
|
).status_code == 204
|
||||||
assert (
|
assert (
|
||||||
await client.get(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}")
|
await admin_client.get(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}")
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|
||||||
async def test_not_found_returns_404(self, client: AsyncClient):
|
async def test_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (await client.delete(f"{GENLOCKES_BASE}/9999")).status_code == 404
|
assert (await admin_client.delete(f"{GENLOCKES_BASE}/9999")).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -216,8 +216,8 @@ class TestDeleteGenlocke:
|
|||||||
|
|
||||||
|
|
||||||
class TestGenlockeLegs:
|
class TestGenlockeLegs:
|
||||||
async def test_adds_leg(self, client: AsyncClient, ctx: dict):
|
async def test_adds_leg(self, admin_client: AsyncClient, ctx: dict):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs",
|
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs",
|
||||||
json={"gameId": ctx["game1_id"]},
|
json={"gameId": ctx["game1_id"]},
|
||||||
)
|
)
|
||||||
@@ -225,28 +225,28 @@ class TestGenlockeLegs:
|
|||||||
legs = response.json()["legs"]
|
legs = response.json()["legs"]
|
||||||
assert len(legs) == 3 # was 2, now 3
|
assert len(legs) == 3 # was 2, now 3
|
||||||
|
|
||||||
async def test_remove_leg_without_run(self, client: AsyncClient, ctx: dict):
|
async def test_remove_leg_without_run(self, admin_client: AsyncClient, ctx: dict):
|
||||||
# Leg 2 has no run yet — can be removed
|
# Leg 2 has no run yet — can be removed
|
||||||
leg2 = next(leg for leg in ctx["genlocke"]["legs"] if leg["legOrder"] == 2)
|
leg2 = next(leg for leg in ctx["genlocke"]["legs"] if leg["legOrder"] == 2)
|
||||||
response = await client.delete(
|
response = await admin_client.delete(
|
||||||
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/{leg2['id']}"
|
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/{leg2['id']}"
|
||||||
)
|
)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
|
|
||||||
async def test_remove_leg_with_run_returns_400(
|
async def test_remove_leg_with_run_returns_400(
|
||||||
self, client: AsyncClient, ctx: dict
|
self, admin_client: AsyncClient, ctx: dict
|
||||||
):
|
):
|
||||||
# Leg 1 has a run — cannot remove
|
# Leg 1 has a run — cannot remove
|
||||||
leg1 = next(leg for leg in ctx["genlocke"]["legs"] if leg["legOrder"] == 1)
|
leg1 = next(leg for leg in ctx["genlocke"]["legs"] if leg["legOrder"] == 1)
|
||||||
response = await client.delete(
|
response = await admin_client.delete(
|
||||||
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/{leg1['id']}"
|
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/{leg1['id']}"
|
||||||
)
|
)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
||||||
async def test_add_leg_invalid_game_returns_404(
|
async def test_add_leg_invalid_game_returns_404(
|
||||||
self, client: AsyncClient, ctx: dict
|
self, admin_client: AsyncClient, ctx: dict
|
||||||
):
|
):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs",
|
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs",
|
||||||
json={"gameId": 9999},
|
json={"gameId": 9999},
|
||||||
)
|
)
|
||||||
@@ -259,33 +259,33 @@ class TestGenlockeLegs:
|
|||||||
|
|
||||||
|
|
||||||
class TestAdvanceLeg:
|
class TestAdvanceLeg:
|
||||||
async def test_uncompleted_run_returns_400(self, client: AsyncClient, ctx: dict):
|
async def test_uncompleted_run_returns_400(self, admin_client: AsyncClient, ctx: dict):
|
||||||
"""Cannot advance when leg 1's run is still active."""
|
"""Cannot advance when leg 1's run is still active."""
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/1/advance"
|
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/1/advance"
|
||||||
)
|
)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
||||||
async def test_no_next_leg_returns_400(self, client: AsyncClient, games_ctx: dict):
|
async def test_no_next_leg_returns_400(self, admin_client: AsyncClient, games_ctx: dict):
|
||||||
"""A single-leg genlocke cannot be advanced."""
|
"""A single-leg genlocke cannot be advanced."""
|
||||||
r = await client.post(
|
r = await admin_client.post(
|
||||||
GENLOCKES_BASE,
|
GENLOCKES_BASE,
|
||||||
json={"name": "Single Leg", "gameIds": [games_ctx["game1_id"]]},
|
json={"name": "Single Leg", "gameIds": [games_ctx["game1_id"]]},
|
||||||
)
|
)
|
||||||
genlocke = r.json()
|
genlocke = r.json()
|
||||||
run_id = genlocke["legs"][0]["runId"]
|
run_id = genlocke["legs"][0]["runId"]
|
||||||
await client.patch(f"{RUNS_BASE}/{run_id}", json={"status": "completed"})
|
await admin_client.patch(f"{RUNS_BASE}/{run_id}", json={"status": "completed"})
|
||||||
|
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{GENLOCKES_BASE}/{genlocke['id']}/legs/1/advance"
|
f"{GENLOCKES_BASE}/{genlocke['id']}/legs/1/advance"
|
||||||
)
|
)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
||||||
async def test_advances_to_next_leg(self, client: AsyncClient, ctx: dict):
|
async def test_advances_to_next_leg(self, admin_client: AsyncClient, ctx: dict):
|
||||||
"""Completing the current run allows advancing to the next leg."""
|
"""Completing the current run allows advancing to the next leg."""
|
||||||
await client.patch(f"{RUNS_BASE}/{ctx['run_id']}", json={"status": "completed"})
|
await admin_client.patch(f"{RUNS_BASE}/{ctx['run_id']}", json={"status": "completed"})
|
||||||
|
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/1/advance"
|
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/1/advance"
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
@@ -293,11 +293,11 @@ class TestAdvanceLeg:
|
|||||||
leg2 = next(leg for leg in legs if leg["legOrder"] == 2)
|
leg2 = next(leg for leg in legs if leg["legOrder"] == 2)
|
||||||
assert leg2["runId"] is not None
|
assert leg2["runId"] is not None
|
||||||
|
|
||||||
async def test_advances_with_transfers(self, client: AsyncClient, ctx: dict):
|
async def test_advances_with_transfers(self, admin_client: AsyncClient, ctx: dict):
|
||||||
"""Advancing with transfer_encounter_ids creates egg encounters in the next leg."""
|
"""Advancing with transfer_encounter_ids creates egg encounters in the next leg."""
|
||||||
await client.patch(f"{RUNS_BASE}/{ctx['run_id']}", json={"status": "completed"})
|
await admin_client.patch(f"{RUNS_BASE}/{ctx['run_id']}", json={"status": "completed"})
|
||||||
|
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/1/advance",
|
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/1/advance",
|
||||||
json={"transferEncounterIds": [ctx["encounter_id"]]},
|
json={"transferEncounterIds": [ctx["encounter_id"]]},
|
||||||
)
|
)
|
||||||
@@ -308,7 +308,7 @@ class TestAdvanceLeg:
|
|||||||
assert new_run_id is not None
|
assert new_run_id is not None
|
||||||
|
|
||||||
# The new run should contain the transferred (egg) encounter
|
# The new run should contain the transferred (egg) encounter
|
||||||
run_detail = (await client.get(f"{RUNS_BASE}/{new_run_id}")).json()
|
run_detail = (await admin_client.get(f"{RUNS_BASE}/{new_run_id}")).json()
|
||||||
assert len(run_detail["encounters"]) == 1
|
assert len(run_detail["encounters"]) == 1
|
||||||
|
|
||||||
|
|
||||||
@@ -318,56 +318,56 @@ class TestAdvanceLeg:
|
|||||||
|
|
||||||
|
|
||||||
class TestGenlockeGraveyard:
|
class TestGenlockeGraveyard:
|
||||||
async def test_returns_empty_graveyard(self, client: AsyncClient, ctx: dict):
|
async def test_returns_empty_graveyard(self, admin_client: AsyncClient, ctx: dict):
|
||||||
response = await client.get(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/graveyard")
|
response = await admin_client.get(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/graveyard")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json()
|
||||||
assert data["entries"] == []
|
assert data["entries"] == []
|
||||||
assert data["totalDeaths"] == 0
|
assert data["totalDeaths"] == 0
|
||||||
|
|
||||||
async def test_not_found_returns_404(self, client: AsyncClient):
|
async def test_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (await client.get(f"{GENLOCKES_BASE}/9999/graveyard")).status_code == 404
|
assert (await admin_client.get(f"{GENLOCKES_BASE}/9999/graveyard")).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
class TestGenlockeLineages:
|
class TestGenlockeLineages:
|
||||||
async def test_returns_empty_lineages(self, client: AsyncClient, ctx: dict):
|
async def test_returns_empty_lineages(self, admin_client: AsyncClient, ctx: dict):
|
||||||
response = await client.get(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/lineages")
|
response = await admin_client.get(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/lineages")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json()
|
||||||
assert data["lineages"] == []
|
assert data["lineages"] == []
|
||||||
assert data["totalLineages"] == 0
|
assert data["totalLineages"] == 0
|
||||||
|
|
||||||
async def test_not_found_returns_404(self, client: AsyncClient):
|
async def test_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (await client.get(f"{GENLOCKES_BASE}/9999/lineages")).status_code == 404
|
assert (await admin_client.get(f"{GENLOCKES_BASE}/9999/lineages")).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
class TestGenlockeRetiredFamilies:
|
class TestGenlockeRetiredFamilies:
|
||||||
async def test_returns_empty_retired_families(self, client: AsyncClient, ctx: dict):
|
async def test_returns_empty_retired_families(self, admin_client: AsyncClient, ctx: dict):
|
||||||
response = await client.get(
|
response = await admin_client.get(
|
||||||
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/retired-families"
|
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/retired-families"
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json()
|
||||||
assert data["retired_pokemon_ids"] == []
|
assert data["retired_pokemon_ids"] == []
|
||||||
|
|
||||||
async def test_not_found_returns_404(self, client: AsyncClient):
|
async def test_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (
|
assert (
|
||||||
await client.get(f"{GENLOCKES_BASE}/9999/retired-families")
|
await admin_client.get(f"{GENLOCKES_BASE}/9999/retired-families")
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
class TestLegSurvivors:
|
class TestLegSurvivors:
|
||||||
async def test_returns_survivors(self, client: AsyncClient, ctx: dict):
|
async def test_returns_survivors(self, admin_client: AsyncClient, ctx: dict):
|
||||||
"""The one caught encounter in leg 1 shows up as a survivor."""
|
"""The one caught encounter in leg 1 shows up as a survivor."""
|
||||||
response = await client.get(
|
response = await admin_client.get(
|
||||||
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/1/survivors"
|
f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/1/survivors"
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert len(response.json()) == 1
|
assert len(response.json()) == 1
|
||||||
|
|
||||||
async def test_leg_not_found_returns_404(self, client: AsyncClient, ctx: dict):
|
async def test_leg_not_found_returns_404(self, admin_client: AsyncClient, ctx: dict):
|
||||||
assert (
|
assert (
|
||||||
await client.get(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/99/survivors")
|
await admin_client.get(f"{GENLOCKES_BASE}/{ctx['genlocke_id']}/legs/99/survivors")
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
@@ -385,13 +385,13 @@ BOSS_PAYLOAD = {
|
|||||||
|
|
||||||
|
|
||||||
class TestBossCRUD:
|
class TestBossCRUD:
|
||||||
async def test_empty_list(self, client: AsyncClient, games_ctx: dict):
|
async def test_empty_list(self, admin_client: AsyncClient, games_ctx: dict):
|
||||||
response = await client.get(f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses")
|
response = await admin_client.get(f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == []
|
assert response.json() == []
|
||||||
|
|
||||||
async def test_creates_boss(self, client: AsyncClient, games_ctx: dict):
|
async def test_creates_boss(self, admin_client: AsyncClient, games_ctx: dict):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses", json=BOSS_PAYLOAD
|
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses", json=BOSS_PAYLOAD
|
||||||
)
|
)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
@@ -400,50 +400,50 @@ class TestBossCRUD:
|
|||||||
assert data["levelCap"] == 14
|
assert data["levelCap"] == 14
|
||||||
assert data["pokemon"] == []
|
assert data["pokemon"] == []
|
||||||
|
|
||||||
async def test_updates_boss(self, client: AsyncClient, games_ctx: dict):
|
async def test_updates_boss(self, admin_client: AsyncClient, games_ctx: dict):
|
||||||
boss = (
|
boss = (
|
||||||
await client.post(
|
await admin_client.post(
|
||||||
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses", json=BOSS_PAYLOAD
|
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses", json=BOSS_PAYLOAD
|
||||||
)
|
)
|
||||||
).json()
|
).json()
|
||||||
response = await client.put(
|
response = await admin_client.put(
|
||||||
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses/{boss['id']}",
|
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses/{boss['id']}",
|
||||||
json={"levelCap": 20},
|
json={"levelCap": 20},
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json()["levelCap"] == 20
|
assert response.json()["levelCap"] == 20
|
||||||
|
|
||||||
async def test_deletes_boss(self, client: AsyncClient, games_ctx: dict):
|
async def test_deletes_boss(self, admin_client: AsyncClient, games_ctx: dict):
|
||||||
boss = (
|
boss = (
|
||||||
await client.post(
|
await admin_client.post(
|
||||||
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses", json=BOSS_PAYLOAD
|
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses", json=BOSS_PAYLOAD
|
||||||
)
|
)
|
||||||
).json()
|
).json()
|
||||||
assert (
|
assert (
|
||||||
await client.delete(
|
await admin_client.delete(
|
||||||
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses/{boss['id']}"
|
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses/{boss['id']}"
|
||||||
)
|
)
|
||||||
).status_code == 204
|
).status_code == 204
|
||||||
assert (
|
assert (
|
||||||
await client.get(f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses")
|
await admin_client.get(f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses")
|
||||||
).json() == []
|
).json() == []
|
||||||
|
|
||||||
async def test_boss_not_found_returns_404(
|
async def test_boss_not_found_returns_404(
|
||||||
self, client: AsyncClient, games_ctx: dict
|
self, admin_client: AsyncClient, games_ctx: dict
|
||||||
):
|
):
|
||||||
assert (
|
assert (
|
||||||
await client.put(
|
await admin_client.put(
|
||||||
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses/9999",
|
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses/9999",
|
||||||
json={"levelCap": 10},
|
json={"levelCap": 10},
|
||||||
)
|
)
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|
||||||
async def test_invalid_game_returns_404(self, client: AsyncClient):
|
async def test_invalid_game_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (await client.get(f"{GAMES_BASE}/9999/bosses")).status_code == 404
|
assert (await admin_client.get(f"{GAMES_BASE}/9999/bosses")).status_code == 404
|
||||||
|
|
||||||
async def test_game_without_version_group_returns_400(self, client: AsyncClient):
|
async def test_game_without_version_group_returns_400(self, admin_client: AsyncClient):
|
||||||
game = (
|
game = (
|
||||||
await client.post(
|
await admin_client.post(
|
||||||
GAMES_BASE,
|
GAMES_BASE,
|
||||||
json={
|
json={
|
||||||
"name": "No VG",
|
"name": "No VG",
|
||||||
@@ -454,7 +454,7 @@ class TestBossCRUD:
|
|||||||
)
|
)
|
||||||
).json()
|
).json()
|
||||||
assert (
|
assert (
|
||||||
await client.get(f"{GAMES_BASE}/{game['id']}/bosses")
|
await admin_client.get(f"{GAMES_BASE}/{game['id']}/bosses")
|
||||||
).status_code == 400
|
).status_code == 400
|
||||||
|
|
||||||
|
|
||||||
@@ -465,27 +465,27 @@ class TestBossCRUD:
|
|||||||
|
|
||||||
class TestBossResults:
|
class TestBossResults:
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def boss_ctx(self, client: AsyncClient, games_ctx: dict) -> dict:
|
async def boss_ctx(self, admin_client: AsyncClient, games_ctx: dict) -> dict:
|
||||||
"""A boss battle and a run for boss-result tests."""
|
"""A boss battle and a run for boss-result tests."""
|
||||||
boss = (
|
boss = (
|
||||||
await client.post(
|
await admin_client.post(
|
||||||
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses", json=BOSS_PAYLOAD
|
f"{GAMES_BASE}/{games_ctx['game1_id']}/bosses", json=BOSS_PAYLOAD
|
||||||
)
|
)
|
||||||
).json()
|
).json()
|
||||||
run = (
|
run = (
|
||||||
await client.post(
|
await admin_client.post(
|
||||||
RUNS_BASE, json={"gameId": games_ctx["game1_id"], "name": "Boss Run"}
|
RUNS_BASE, json={"gameId": games_ctx["game1_id"], "name": "Boss Run"}
|
||||||
)
|
)
|
||||||
).json()
|
).json()
|
||||||
return {"boss_id": boss["id"], "run_id": run["id"]}
|
return {"boss_id": boss["id"], "run_id": run["id"]}
|
||||||
|
|
||||||
async def test_empty_list(self, client: AsyncClient, boss_ctx: dict):
|
async def test_empty_list(self, admin_client: AsyncClient, boss_ctx: dict):
|
||||||
response = await client.get(f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results")
|
response = await admin_client.get(f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == []
|
assert response.json() == []
|
||||||
|
|
||||||
async def test_creates_boss_result(self, client: AsyncClient, boss_ctx: dict):
|
async def test_creates_boss_result(self, admin_client: AsyncClient, boss_ctx: dict):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results",
|
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results",
|
||||||
json={"bossBattleId": boss_ctx["boss_id"], "result": "won", "attempts": 1},
|
json={"bossBattleId": boss_ctx["boss_id"], "result": "won", "attempts": 1},
|
||||||
)
|
)
|
||||||
@@ -495,13 +495,13 @@ class TestBossResults:
|
|||||||
assert data["attempts"] == 1
|
assert data["attempts"] == 1
|
||||||
assert data["completedAt"] is not None
|
assert data["completedAt"] is not None
|
||||||
|
|
||||||
async def test_upserts_existing_result(self, client: AsyncClient, boss_ctx: dict):
|
async def test_upserts_existing_result(self, admin_client: AsyncClient, boss_ctx: dict):
|
||||||
"""POSTing the same boss twice updates the result (upsert)."""
|
"""POSTing the same boss twice updates the result (upsert)."""
|
||||||
await client.post(
|
await admin_client.post(
|
||||||
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results",
|
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results",
|
||||||
json={"bossBattleId": boss_ctx["boss_id"], "result": "won", "attempts": 1},
|
json={"bossBattleId": boss_ctx["boss_id"], "result": "won", "attempts": 1},
|
||||||
)
|
)
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results",
|
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results",
|
||||||
json={"bossBattleId": boss_ctx["boss_id"], "result": "lost", "attempts": 3},
|
json={"bossBattleId": boss_ctx["boss_id"], "result": "lost", "attempts": 3},
|
||||||
)
|
)
|
||||||
@@ -510,31 +510,31 @@ class TestBossResults:
|
|||||||
assert response.json()["attempts"] == 3
|
assert response.json()["attempts"] == 3
|
||||||
# Still only one record
|
# Still only one record
|
||||||
all_results = (
|
all_results = (
|
||||||
await client.get(f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results")
|
await admin_client.get(f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results")
|
||||||
).json()
|
).json()
|
||||||
assert len(all_results) == 1
|
assert len(all_results) == 1
|
||||||
|
|
||||||
async def test_deletes_boss_result(self, client: AsyncClient, boss_ctx: dict):
|
async def test_deletes_boss_result(self, admin_client: AsyncClient, boss_ctx: dict):
|
||||||
result = (
|
result = (
|
||||||
await client.post(
|
await admin_client.post(
|
||||||
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results",
|
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results",
|
||||||
json={"bossBattleId": boss_ctx["boss_id"], "result": "won"},
|
json={"bossBattleId": boss_ctx["boss_id"], "result": "won"},
|
||||||
)
|
)
|
||||||
).json()
|
).json()
|
||||||
assert (
|
assert (
|
||||||
await client.delete(
|
await admin_client.delete(
|
||||||
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results/{result['id']}"
|
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results/{result['id']}"
|
||||||
)
|
)
|
||||||
).status_code == 204
|
).status_code == 204
|
||||||
assert (
|
assert (
|
||||||
await client.get(f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results")
|
await admin_client.get(f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results")
|
||||||
).json() == []
|
).json() == []
|
||||||
|
|
||||||
async def test_invalid_run_returns_404(self, client: AsyncClient, boss_ctx: dict):
|
async def test_invalid_run_returns_404(self, admin_client: AsyncClient, boss_ctx: dict):
|
||||||
assert (await client.get(f"{RUNS_BASE}/9999/boss-results")).status_code == 404
|
assert (await admin_client.get(f"{RUNS_BASE}/9999/boss-results")).status_code == 404
|
||||||
|
|
||||||
async def test_invalid_boss_returns_404(self, client: AsyncClient, boss_ctx: dict):
|
async def test_invalid_boss_returns_404(self, admin_client: AsyncClient, boss_ctx: dict):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results",
|
f"{RUNS_BASE}/{boss_ctx['run_id']}/boss-results",
|
||||||
json={"bossBattleId": 9999, "result": "won"},
|
json={"bossBattleId": 9999, "result": "won"},
|
||||||
)
|
)
|
||||||
@@ -547,8 +547,8 @@ class TestBossResults:
|
|||||||
|
|
||||||
|
|
||||||
class TestStats:
|
class TestStats:
|
||||||
async def test_returns_stats_structure(self, client: AsyncClient):
|
async def test_returns_stats_structure(self, admin_client: AsyncClient):
|
||||||
response = await client.get(STATS_BASE)
|
response = await admin_client.get(STATS_BASE)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json()
|
||||||
assert data["totalRuns"] == 0
|
assert data["totalRuns"] == 0
|
||||||
@@ -556,9 +556,9 @@ class TestStats:
|
|||||||
assert data["topCaughtPokemon"] == []
|
assert data["topCaughtPokemon"] == []
|
||||||
assert data["typeDistribution"] == []
|
assert data["typeDistribution"] == []
|
||||||
|
|
||||||
async def test_reflects_created_data(self, client: AsyncClient, ctx: dict):
|
async def test_reflects_created_data(self, admin_client: AsyncClient, ctx: dict):
|
||||||
"""Stats should reflect the run and encounter created in ctx."""
|
"""Stats should reflect the run and encounter created in ctx."""
|
||||||
response = await client.get(STATS_BASE)
|
response = await admin_client.get(STATS_BASE)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json()
|
||||||
assert data["totalRuns"] >= 1
|
assert data["totalRuns"] >= 1
|
||||||
@@ -572,23 +572,23 @@ class TestStats:
|
|||||||
|
|
||||||
|
|
||||||
class TestExport:
|
class TestExport:
|
||||||
async def test_export_games_returns_list(self, client: AsyncClient):
|
async def test_export_games_returns_list(self, admin_client: AsyncClient):
|
||||||
response = await client.get(f"{EXPORT_BASE}/games")
|
response = await admin_client.get(f"{EXPORT_BASE}/games")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert isinstance(response.json(), list)
|
assert isinstance(response.json(), list)
|
||||||
|
|
||||||
async def test_export_pokemon_returns_list(self, client: AsyncClient):
|
async def test_export_pokemon_returns_list(self, admin_client: AsyncClient):
|
||||||
response = await client.get(f"{EXPORT_BASE}/pokemon")
|
response = await admin_client.get(f"{EXPORT_BASE}/pokemon")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert isinstance(response.json(), list)
|
assert isinstance(response.json(), list)
|
||||||
|
|
||||||
async def test_export_evolutions_returns_list(self, client: AsyncClient):
|
async def test_export_evolutions_returns_list(self, admin_client: AsyncClient):
|
||||||
response = await client.get(f"{EXPORT_BASE}/evolutions")
|
response = await admin_client.get(f"{EXPORT_BASE}/evolutions")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert isinstance(response.json(), list)
|
assert isinstance(response.json(), list)
|
||||||
|
|
||||||
async def test_export_game_routes_not_found_returns_404(self, client: AsyncClient):
|
async def test_export_game_routes_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (await client.get(f"{EXPORT_BASE}/games/9999/routes")).status_code == 404
|
assert (await admin_client.get(f"{EXPORT_BASE}/games/9999/routes")).status_code == 404
|
||||||
|
|
||||||
async def test_export_game_bosses_not_found_returns_404(self, client: AsyncClient):
|
async def test_export_game_bosses_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (await client.get(f"{EXPORT_BASE}/games/9999/bosses")).status_code == 404
|
assert (await admin_client.get(f"{EXPORT_BASE}/games/9999/bosses")).status_code == 404
|
||||||
|
|||||||
@@ -29,21 +29,21 @@ CHARMANDER_DATA = {
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def pikachu(client: AsyncClient) -> dict:
|
async def pikachu(admin_client: AsyncClient) -> dict:
|
||||||
response = await client.post(POKEMON_BASE, json=PIKACHU_DATA)
|
response = await admin_client.post(POKEMON_BASE, json=PIKACHU_DATA)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def charmander(client: AsyncClient) -> dict:
|
async def charmander(admin_client: AsyncClient) -> dict:
|
||||||
response = await client.post(POKEMON_BASE, json=CHARMANDER_DATA)
|
response = await admin_client.post(POKEMON_BASE, json=CHARMANDER_DATA)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def ctx(db_session: AsyncSession, client: AsyncClient) -> dict:
|
async def ctx(db_session: AsyncSession, admin_client: AsyncClient) -> dict:
|
||||||
"""Full context: game + route + two pokemon + nuzlocke encounter on pikachu."""
|
"""Full context: game + route + two pokemon + nuzlocke encounter on pikachu."""
|
||||||
vg = VersionGroup(name="Poke Test VG", slug="poke-test-vg")
|
vg = VersionGroup(name="Poke Test VG", slug="poke-test-vg")
|
||||||
db_session.add(vg)
|
db_session.add(vg)
|
||||||
@@ -63,11 +63,11 @@ async def ctx(db_session: AsyncSession, client: AsyncClient) -> dict:
|
|||||||
db_session.add(route)
|
db_session.add(route)
|
||||||
await db_session.flush()
|
await db_session.flush()
|
||||||
|
|
||||||
r1 = await client.post(POKEMON_BASE, json=PIKACHU_DATA)
|
r1 = await admin_client.post(POKEMON_BASE, json=PIKACHU_DATA)
|
||||||
assert r1.status_code == 201
|
assert r1.status_code == 201
|
||||||
pikachu = r1.json()
|
pikachu = r1.json()
|
||||||
|
|
||||||
r2 = await client.post(POKEMON_BASE, json=CHARMANDER_DATA)
|
r2 = await admin_client.post(POKEMON_BASE, json=CHARMANDER_DATA)
|
||||||
assert r2.status_code == 201
|
assert r2.status_code == 201
|
||||||
charmander = r2.json()
|
charmander = r2.json()
|
||||||
|
|
||||||
@@ -146,8 +146,8 @@ class TestListPokemon:
|
|||||||
|
|
||||||
|
|
||||||
class TestCreatePokemon:
|
class TestCreatePokemon:
|
||||||
async def test_creates_pokemon(self, client: AsyncClient):
|
async def test_creates_pokemon(self, admin_client: AsyncClient):
|
||||||
response = await client.post(POKEMON_BASE, json=PIKACHU_DATA)
|
response = await admin_client.post(POKEMON_BASE, json=PIKACHU_DATA)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
data = response.json()
|
data = response.json()
|
||||||
assert data["name"] == "pikachu"
|
assert data["name"] == "pikachu"
|
||||||
@@ -156,16 +156,16 @@ class TestCreatePokemon:
|
|||||||
assert isinstance(data["id"], int)
|
assert isinstance(data["id"], int)
|
||||||
|
|
||||||
async def test_duplicate_pokeapi_id_returns_409(
|
async def test_duplicate_pokeapi_id_returns_409(
|
||||||
self, client: AsyncClient, pikachu: dict
|
self, admin_client: AsyncClient, pikachu: dict
|
||||||
):
|
):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
POKEMON_BASE,
|
POKEMON_BASE,
|
||||||
json={**PIKACHU_DATA, "name": "pikachu-copy"},
|
json={**PIKACHU_DATA, "name": "pikachu-copy"},
|
||||||
)
|
)
|
||||||
assert response.status_code == 409
|
assert response.status_code == 409
|
||||||
|
|
||||||
async def test_missing_required_returns_422(self, client: AsyncClient):
|
async def test_missing_required_returns_422(self, admin_client: AsyncClient):
|
||||||
response = await client.post(POKEMON_BASE, json={"name": "pikachu"})
|
response = await admin_client.post(POKEMON_BASE, json={"name": "pikachu"})
|
||||||
assert response.status_code == 422
|
assert response.status_code == 422
|
||||||
|
|
||||||
|
|
||||||
@@ -190,25 +190,25 @@ class TestGetPokemon:
|
|||||||
|
|
||||||
|
|
||||||
class TestUpdatePokemon:
|
class TestUpdatePokemon:
|
||||||
async def test_updates_name(self, client: AsyncClient, pikachu: dict):
|
async def test_updates_name(self, admin_client: AsyncClient, pikachu: dict):
|
||||||
response = await client.put(
|
response = await admin_client.put(
|
||||||
f"{POKEMON_BASE}/{pikachu['id']}", json={"name": "Pikachu"}
|
f"{POKEMON_BASE}/{pikachu['id']}", json={"name": "Pikachu"}
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json()["name"] == "Pikachu"
|
assert response.json()["name"] == "Pikachu"
|
||||||
|
|
||||||
async def test_duplicate_pokeapi_id_returns_409(
|
async def test_duplicate_pokeapi_id_returns_409(
|
||||||
self, client: AsyncClient, pikachu: dict, charmander: dict
|
self, admin_client: AsyncClient, pikachu: dict, charmander: dict
|
||||||
):
|
):
|
||||||
response = await client.put(
|
response = await admin_client.put(
|
||||||
f"{POKEMON_BASE}/{pikachu['id']}",
|
f"{POKEMON_BASE}/{pikachu['id']}",
|
||||||
json={"pokeapiId": charmander["pokeapiId"]},
|
json={"pokeapiId": charmander["pokeapiId"]},
|
||||||
)
|
)
|
||||||
assert response.status_code == 409
|
assert response.status_code == 409
|
||||||
|
|
||||||
async def test_not_found_returns_404(self, client: AsyncClient):
|
async def test_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (
|
assert (
|
||||||
await client.put(f"{POKEMON_BASE}/9999", json={"name": "x"})
|
await admin_client.put(f"{POKEMON_BASE}/9999", json={"name": "x"})
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
@@ -218,22 +218,22 @@ class TestUpdatePokemon:
|
|||||||
|
|
||||||
|
|
||||||
class TestDeletePokemon:
|
class TestDeletePokemon:
|
||||||
async def test_deletes_pokemon(self, client: AsyncClient, charmander: dict):
|
async def test_deletes_pokemon(self, admin_client: AsyncClient, charmander: dict):
|
||||||
assert (
|
assert (
|
||||||
await client.delete(f"{POKEMON_BASE}/{charmander['id']}")
|
await admin_client.delete(f"{POKEMON_BASE}/{charmander['id']}")
|
||||||
).status_code == 204
|
).status_code == 204
|
||||||
assert (
|
assert (
|
||||||
await client.get(f"{POKEMON_BASE}/{charmander['id']}")
|
await admin_client.get(f"{POKEMON_BASE}/{charmander['id']}")
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|
||||||
async def test_not_found_returns_404(self, client: AsyncClient):
|
async def test_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (await client.delete(f"{POKEMON_BASE}/9999")).status_code == 404
|
assert (await admin_client.delete(f"{POKEMON_BASE}/9999")).status_code == 404
|
||||||
|
|
||||||
async def test_pokemon_with_encounters_returns_409(
|
async def test_pokemon_with_encounters_returns_409(
|
||||||
self, client: AsyncClient, ctx: dict
|
self, admin_client: AsyncClient, ctx: dict
|
||||||
):
|
):
|
||||||
"""Pokemon referenced by a nuzlocke encounter cannot be deleted."""
|
"""Pokemon referenced by a nuzlocke encounter cannot be deleted."""
|
||||||
response = await client.delete(f"{POKEMON_BASE}/{ctx['pikachu_id']}")
|
response = await admin_client.delete(f"{POKEMON_BASE}/{ctx['pikachu_id']}")
|
||||||
assert response.status_code == 409
|
assert response.status_code == 409
|
||||||
|
|
||||||
|
|
||||||
@@ -249,9 +249,9 @@ class TestPokemonFamilies:
|
|||||||
assert response.json()["families"] == []
|
assert response.json()["families"] == []
|
||||||
|
|
||||||
async def test_returns_family_grouping(
|
async def test_returns_family_grouping(
|
||||||
self, client: AsyncClient, pikachu: dict, charmander: dict
|
self, admin_client: AsyncClient, pikachu: dict, charmander: dict
|
||||||
):
|
):
|
||||||
await client.post(
|
await admin_client.post(
|
||||||
EVO_BASE,
|
EVO_BASE,
|
||||||
json={
|
json={
|
||||||
"fromPokemonId": pikachu["id"],
|
"fromPokemonId": pikachu["id"],
|
||||||
@@ -259,7 +259,7 @@ class TestPokemonFamilies:
|
|||||||
"trigger": "level-up",
|
"trigger": "level-up",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
response = await client.get(f"{POKEMON_BASE}/families")
|
response = await admin_client.get(f"{POKEMON_BASE}/families")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
families = response.json()["families"]
|
families = response.json()["families"]
|
||||||
assert len(families) == 1
|
assert len(families) == 1
|
||||||
@@ -280,9 +280,9 @@ class TestPokemonEvolutionChain:
|
|||||||
assert response.json() == []
|
assert response.json() == []
|
||||||
|
|
||||||
async def test_returns_chain_for_multi_stage(
|
async def test_returns_chain_for_multi_stage(
|
||||||
self, client: AsyncClient, pikachu: dict, charmander: dict
|
self, admin_client: AsyncClient, pikachu: dict, charmander: dict
|
||||||
):
|
):
|
||||||
await client.post(
|
await admin_client.post(
|
||||||
EVO_BASE,
|
EVO_BASE,
|
||||||
json={
|
json={
|
||||||
"fromPokemonId": pikachu["id"],
|
"fromPokemonId": pikachu["id"],
|
||||||
@@ -290,7 +290,7 @@ class TestPokemonEvolutionChain:
|
|||||||
"trigger": "level-up",
|
"trigger": "level-up",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
response = await client.get(f"{POKEMON_BASE}/{pikachu['id']}/evolution-chain")
|
response = await admin_client.get(f"{POKEMON_BASE}/{pikachu['id']}/evolution-chain")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
chain = response.json()
|
chain = response.json()
|
||||||
assert len(chain) == 1
|
assert len(chain) == 1
|
||||||
@@ -317,9 +317,9 @@ class TestListEvolutions:
|
|||||||
assert data["total"] == 0
|
assert data["total"] == 0
|
||||||
|
|
||||||
async def test_returns_created_evolution(
|
async def test_returns_created_evolution(
|
||||||
self, client: AsyncClient, pikachu: dict, charmander: dict
|
self, admin_client: AsyncClient, pikachu: dict, charmander: dict
|
||||||
):
|
):
|
||||||
await client.post(
|
await admin_client.post(
|
||||||
EVO_BASE,
|
EVO_BASE,
|
||||||
json={
|
json={
|
||||||
"fromPokemonId": pikachu["id"],
|
"fromPokemonId": pikachu["id"],
|
||||||
@@ -327,14 +327,14 @@ class TestListEvolutions:
|
|||||||
"trigger": "level-up",
|
"trigger": "level-up",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
response = await client.get(EVO_BASE)
|
response = await admin_client.get(EVO_BASE)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json()["total"] == 1
|
assert response.json()["total"] == 1
|
||||||
|
|
||||||
async def test_filter_by_trigger(
|
async def test_filter_by_trigger(
|
||||||
self, client: AsyncClient, pikachu: dict, charmander: dict
|
self, admin_client: AsyncClient, pikachu: dict, charmander: dict
|
||||||
):
|
):
|
||||||
await client.post(
|
await admin_client.post(
|
||||||
EVO_BASE,
|
EVO_BASE,
|
||||||
json={
|
json={
|
||||||
"fromPokemonId": pikachu["id"],
|
"fromPokemonId": pikachu["id"],
|
||||||
@@ -342,9 +342,9 @@ class TestListEvolutions:
|
|||||||
"trigger": "use-item",
|
"trigger": "use-item",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
hit = await client.get(EVO_BASE, params={"trigger": "use-item"})
|
hit = await admin_client.get(EVO_BASE, params={"trigger": "use-item"})
|
||||||
assert hit.json()["total"] == 1
|
assert hit.json()["total"] == 1
|
||||||
miss = await client.get(EVO_BASE, params={"trigger": "level-up"})
|
miss = await admin_client.get(EVO_BASE, params={"trigger": "level-up"})
|
||||||
assert miss.json()["total"] == 0
|
assert miss.json()["total"] == 0
|
||||||
|
|
||||||
|
|
||||||
@@ -355,9 +355,9 @@ class TestListEvolutions:
|
|||||||
|
|
||||||
class TestCreateEvolution:
|
class TestCreateEvolution:
|
||||||
async def test_creates_evolution(
|
async def test_creates_evolution(
|
||||||
self, client: AsyncClient, pikachu: dict, charmander: dict
|
self, admin_client: AsyncClient, pikachu: dict, charmander: dict
|
||||||
):
|
):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
EVO_BASE,
|
EVO_BASE,
|
||||||
json={
|
json={
|
||||||
"fromPokemonId": pikachu["id"],
|
"fromPokemonId": pikachu["id"],
|
||||||
@@ -374,9 +374,9 @@ class TestCreateEvolution:
|
|||||||
assert data["toPokemon"]["name"] == "charmander"
|
assert data["toPokemon"]["name"] == "charmander"
|
||||||
|
|
||||||
async def test_invalid_from_pokemon_returns_404(
|
async def test_invalid_from_pokemon_returns_404(
|
||||||
self, client: AsyncClient, charmander: dict
|
self, admin_client: AsyncClient, charmander: dict
|
||||||
):
|
):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
EVO_BASE,
|
EVO_BASE,
|
||||||
json={
|
json={
|
||||||
"fromPokemonId": 9999,
|
"fromPokemonId": 9999,
|
||||||
@@ -387,9 +387,9 @@ class TestCreateEvolution:
|
|||||||
assert response.status_code == 404
|
assert response.status_code == 404
|
||||||
|
|
||||||
async def test_invalid_to_pokemon_returns_404(
|
async def test_invalid_to_pokemon_returns_404(
|
||||||
self, client: AsyncClient, pikachu: dict
|
self, admin_client: AsyncClient, pikachu: dict
|
||||||
):
|
):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
EVO_BASE,
|
EVO_BASE,
|
||||||
json={
|
json={
|
||||||
"fromPokemonId": pikachu["id"],
|
"fromPokemonId": pikachu["id"],
|
||||||
@@ -408,9 +408,9 @@ class TestCreateEvolution:
|
|||||||
class TestUpdateEvolution:
|
class TestUpdateEvolution:
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def evolution(
|
async def evolution(
|
||||||
self, client: AsyncClient, pikachu: dict, charmander: dict
|
self, admin_client: AsyncClient, pikachu: dict, charmander: dict
|
||||||
) -> dict:
|
) -> dict:
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
EVO_BASE,
|
EVO_BASE,
|
||||||
json={
|
json={
|
||||||
"fromPokemonId": pikachu["id"],
|
"fromPokemonId": pikachu["id"],
|
||||||
@@ -420,16 +420,16 @@ class TestUpdateEvolution:
|
|||||||
)
|
)
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
async def test_updates_trigger(self, client: AsyncClient, evolution: dict):
|
async def test_updates_trigger(self, admin_client: AsyncClient, evolution: dict):
|
||||||
response = await client.put(
|
response = await admin_client.put(
|
||||||
f"{EVO_BASE}/{evolution['id']}", json={"trigger": "use-item"}
|
f"{EVO_BASE}/{evolution['id']}", json={"trigger": "use-item"}
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json()["trigger"] == "use-item"
|
assert response.json()["trigger"] == "use-item"
|
||||||
|
|
||||||
async def test_not_found_returns_404(self, client: AsyncClient):
|
async def test_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (
|
assert (
|
||||||
await client.put(f"{EVO_BASE}/9999", json={"trigger": "level-up"})
|
await admin_client.put(f"{EVO_BASE}/9999", json={"trigger": "level-up"})
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
@@ -441,9 +441,9 @@ class TestUpdateEvolution:
|
|||||||
class TestDeleteEvolution:
|
class TestDeleteEvolution:
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def evolution(
|
async def evolution(
|
||||||
self, client: AsyncClient, pikachu: dict, charmander: dict
|
self, admin_client: AsyncClient, pikachu: dict, charmander: dict
|
||||||
) -> dict:
|
) -> dict:
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
EVO_BASE,
|
EVO_BASE,
|
||||||
json={
|
json={
|
||||||
"fromPokemonId": pikachu["id"],
|
"fromPokemonId": pikachu["id"],
|
||||||
@@ -453,12 +453,12 @@ class TestDeleteEvolution:
|
|||||||
)
|
)
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
async def test_deletes_evolution(self, client: AsyncClient, evolution: dict):
|
async def test_deletes_evolution(self, admin_client: AsyncClient, evolution: dict):
|
||||||
assert (await client.delete(f"{EVO_BASE}/{evolution['id']}")).status_code == 204
|
assert (await admin_client.delete(f"{EVO_BASE}/{evolution['id']}")).status_code == 204
|
||||||
assert (await client.get(EVO_BASE)).json()["total"] == 0
|
assert (await admin_client.get(EVO_BASE)).json()["total"] == 0
|
||||||
|
|
||||||
async def test_not_found_returns_404(self, client: AsyncClient):
|
async def test_not_found_returns_404(self, admin_client: AsyncClient):
|
||||||
assert (await client.delete(f"{EVO_BASE}/9999")).status_code == 404
|
assert (await admin_client.delete(f"{EVO_BASE}/9999")).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -467,13 +467,13 @@ class TestDeleteEvolution:
|
|||||||
|
|
||||||
|
|
||||||
class TestRouteEncounters:
|
class TestRouteEncounters:
|
||||||
async def test_empty_list_for_route(self, client: AsyncClient, ctx: dict):
|
async def test_empty_list_for_route(self, admin_client: AsyncClient, ctx: dict):
|
||||||
response = await client.get(f"{ROUTE_BASE}/{ctx['route_id']}/pokemon")
|
response = await admin_client.get(f"{ROUTE_BASE}/{ctx['route_id']}/pokemon")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == []
|
assert response.json() == []
|
||||||
|
|
||||||
async def test_creates_route_encounter(self, client: AsyncClient, ctx: dict):
|
async def test_creates_route_encounter(self, admin_client: AsyncClient, ctx: dict):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon",
|
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon",
|
||||||
json={
|
json={
|
||||||
"pokemonId": ctx["charmander_id"],
|
"pokemonId": ctx["charmander_id"],
|
||||||
@@ -490,8 +490,8 @@ class TestRouteEncounters:
|
|||||||
assert data["encounterRate"] == 10
|
assert data["encounterRate"] == 10
|
||||||
assert data["pokemon"]["name"] == "charmander"
|
assert data["pokemon"]["name"] == "charmander"
|
||||||
|
|
||||||
async def test_invalid_route_returns_404(self, client: AsyncClient, ctx: dict):
|
async def test_invalid_route_returns_404(self, admin_client: AsyncClient, ctx: dict):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{ROUTE_BASE}/9999/pokemon",
|
f"{ROUTE_BASE}/9999/pokemon",
|
||||||
json={
|
json={
|
||||||
"pokemonId": ctx["charmander_id"],
|
"pokemonId": ctx["charmander_id"],
|
||||||
@@ -504,8 +504,8 @@ class TestRouteEncounters:
|
|||||||
)
|
)
|
||||||
assert response.status_code == 404
|
assert response.status_code == 404
|
||||||
|
|
||||||
async def test_invalid_pokemon_returns_404(self, client: AsyncClient, ctx: dict):
|
async def test_invalid_pokemon_returns_404(self, admin_client: AsyncClient, ctx: dict):
|
||||||
response = await client.post(
|
response = await admin_client.post(
|
||||||
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon",
|
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon",
|
||||||
json={
|
json={
|
||||||
"pokemonId": 9999,
|
"pokemonId": 9999,
|
||||||
@@ -518,8 +518,8 @@ class TestRouteEncounters:
|
|||||||
)
|
)
|
||||||
assert response.status_code == 404
|
assert response.status_code == 404
|
||||||
|
|
||||||
async def test_updates_route_encounter(self, client: AsyncClient, ctx: dict):
|
async def test_updates_route_encounter(self, admin_client: AsyncClient, ctx: dict):
|
||||||
r = await client.post(
|
r = await admin_client.post(
|
||||||
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon",
|
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon",
|
||||||
json={
|
json={
|
||||||
"pokemonId": ctx["charmander_id"],
|
"pokemonId": ctx["charmander_id"],
|
||||||
@@ -531,23 +531,23 @@ class TestRouteEncounters:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
enc = r.json()
|
enc = r.json()
|
||||||
response = await client.put(
|
response = await admin_client.put(
|
||||||
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon/{enc['id']}",
|
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon/{enc['id']}",
|
||||||
json={"encounterRate": 25},
|
json={"encounterRate": 25},
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json()["encounterRate"] == 25
|
assert response.json()["encounterRate"] == 25
|
||||||
|
|
||||||
async def test_update_not_found_returns_404(self, client: AsyncClient, ctx: dict):
|
async def test_update_not_found_returns_404(self, admin_client: AsyncClient, ctx: dict):
|
||||||
assert (
|
assert (
|
||||||
await client.put(
|
await admin_client.put(
|
||||||
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon/9999",
|
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon/9999",
|
||||||
json={"encounterRate": 5},
|
json={"encounterRate": 5},
|
||||||
)
|
)
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|
||||||
async def test_deletes_route_encounter(self, client: AsyncClient, ctx: dict):
|
async def test_deletes_route_encounter(self, admin_client: AsyncClient, ctx: dict):
|
||||||
r = await client.post(
|
r = await admin_client.post(
|
||||||
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon",
|
f"{ROUTE_BASE}/{ctx['route_id']}/pokemon",
|
||||||
json={
|
json={
|
||||||
"pokemonId": ctx["charmander_id"],
|
"pokemonId": ctx["charmander_id"],
|
||||||
@@ -560,13 +560,13 @@ class TestRouteEncounters:
|
|||||||
)
|
)
|
||||||
enc = r.json()
|
enc = r.json()
|
||||||
assert (
|
assert (
|
||||||
await client.delete(f"{ROUTE_BASE}/{ctx['route_id']}/pokemon/{enc['id']}")
|
await admin_client.delete(f"{ROUTE_BASE}/{ctx['route_id']}/pokemon/{enc['id']}")
|
||||||
).status_code == 204
|
).status_code == 204
|
||||||
assert (
|
assert (
|
||||||
await client.get(f"{ROUTE_BASE}/{ctx['route_id']}/pokemon")
|
await admin_client.get(f"{ROUTE_BASE}/{ctx['route_id']}/pokemon")
|
||||||
).json() == []
|
).json() == []
|
||||||
|
|
||||||
async def test_delete_not_found_returns_404(self, client: AsyncClient, ctx: dict):
|
async def test_delete_not_found_returns_404(self, admin_client: AsyncClient, ctx: dict):
|
||||||
assert (
|
assert (
|
||||||
await client.delete(f"{ROUTE_BASE}/{ctx['route_id']}/pokemon/9999")
|
await admin_client.delete(f"{ROUTE_BASE}/{ctx['route_id']}/pokemon/9999")
|
||||||
).status_code == 404
|
).status_code == 404
|
||||||
|
|||||||
Reference in New Issue
Block a user