wrongmove/tests/unit/test_decision_routes.py
Viktor Barzin 341de89004
feat: add decision API routes with tests
PUT /api/decisions/{listing_id} to set decision,
GET /api/decisions to list all user decisions,
DELETE /api/decisions/{listing_id} to remove a decision.
All 6 API route tests pass.
2026-02-21 13:54:38 +00:00

128 lines
4.2 KiB
Python

"""Unit tests for decision API routes."""
import pytest
from httpx import ASGITransport, AsyncClient
from sqlalchemy import Engine
from sqlmodel import SQLModel, Session, create_engine
from models.user import User
from models.decision import ListingDecision # noqa: F401 - needed for table creation
from api.auth import get_current_user, User as AuthUser
@pytest.fixture
def decision_engine() -> Engine:
engine = create_engine(
"sqlite:///:memory:",
echo=False,
connect_args={"check_same_thread": False},
)
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
session.add(User(id=1, email="test@example.com"))
session.commit()
yield engine # type: ignore[misc]
SQLModel.metadata.drop_all(engine)
@pytest.fixture
async def client(decision_engine: Engine) -> AsyncClient:
import database
import api.app as api_app
import api.decision_routes as decision_routes_mod
import api.poi_routes as poi_routes_mod
app = api_app.app
mock_user = AuthUser(
sub="test-user-id", email="test@example.com", name="Test User"
)
app.dependency_overrides[get_current_user] = lambda: mock_user
original_db = database.engine
original_app = api_app.engine
original_decision = decision_routes_mod.engine
original_poi = poi_routes_mod.engine
database.engine = decision_engine
api_app.engine = decision_engine
decision_routes_mod.engine = decision_engine
poi_routes_mod.engine = decision_engine
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as c:
yield c # type: ignore[misc]
database.engine = original_db
api_app.engine = original_app
decision_routes_mod.engine = original_decision
poi_routes_mod.engine = original_poi
app.dependency_overrides.clear()
class TestDecisionRoutes:
@pytest.mark.asyncio
async def test_set_decision(self, client: AsyncClient) -> None:
resp = await client.put(
"/api/decisions/100",
json={"decision": "liked", "listing_type": "RENT"},
)
assert resp.status_code == 200
data = resp.json()
assert data["decision"] == "liked"
assert data["listing_id"] == 100
@pytest.mark.asyncio
async def test_get_decisions(self, client: AsyncClient) -> None:
await client.put(
"/api/decisions/100",
json={"decision": "liked", "listing_type": "RENT"},
)
resp = await client.get("/api/decisions")
assert resp.status_code == 200
data = resp.json()
assert len(data) == 1
@pytest.mark.asyncio
async def test_delete_decision(self, client: AsyncClient) -> None:
await client.put(
"/api/decisions/100",
json={"decision": "liked", "listing_type": "RENT"},
)
resp = await client.delete(
"/api/decisions/100", params={"listing_type": "RENT"}
)
assert resp.status_code == 200
assert resp.json()["success"] is True
@pytest.mark.asyncio
async def test_delete_nonexistent_returns_404(
self, client: AsyncClient
) -> None:
resp = await client.delete(
"/api/decisions/999", params={"listing_type": "RENT"}
)
assert resp.status_code == 404
@pytest.mark.asyncio
async def test_invalid_decision_returns_400(
self, client: AsyncClient
) -> None:
resp = await client.put(
"/api/decisions/100",
json={"decision": "maybe", "listing_type": "RENT"},
)
assert resp.status_code == 400
@pytest.mark.asyncio
async def test_update_decision(self, client: AsyncClient) -> None:
await client.put(
"/api/decisions/100",
json={"decision": "liked", "listing_type": "RENT"},
)
resp = await client.put(
"/api/decisions/100",
json={"decision": "disliked", "listing_type": "RENT"},
)
assert resp.status_code == 200
assert resp.json()["decision"] == "disliked"
# Still only one decision
resp2 = await client.get("/api/decisions")
assert len(resp2.json()) == 1