Files
dreamweaver/backend/tests/test_reading_events.py

161 lines
5.5 KiB
Python

"""Reading event API tests."""
import pytest
from httpx import ASGITransport, AsyncClient
from sqlalchemy import select
from app.db.database import get_db
from app.db.models import MemoryItem
from app.main import app
pytestmark = pytest.mark.asyncio
async def _create_profile(client: AsyncClient) -> str:
response = await client.post(
"/api/profiles",
json={"name": "小明", "gender": "male"},
)
assert response.status_code == 201
return response.json()["id"]
async def test_create_reading_event_updates_stats_and_memory(
db_session,
test_user,
auth_token,
test_story,
):
async def override_get_db():
yield db_session
app.dependency_overrides[get_db] = override_get_db
transport = ASGITransport(app=app)
try:
async with AsyncClient(transport=transport, base_url="http://test") as client:
client.cookies.set("access_token", auth_token)
profile_id = await _create_profile(client)
response = await client.post(
"/api/reading-events",
json={
"child_profile_id": profile_id,
"story_id": test_story.id,
"event_type": "completed",
"reading_time": 120,
},
)
assert response.status_code == 201
data = response.json()
assert data["child_profile_id"] == profile_id
assert data["story_id"] == test_story.id
assert data["event_type"] == "completed"
response = await client.get(f"/api/profiles/{profile_id}")
assert response.status_code == 200
profile = response.json()
assert profile["stories_count"] == 1
assert profile["total_reading_time"] == 120
result = await db_session.execute(
select(MemoryItem).where(MemoryItem.child_profile_id == profile_id)
)
items = result.scalars().all()
assert len(items) == 1
assert items[0].type == "recent_story"
assert items[0].value["story_id"] == test_story.id
assert items[0].value["mode"] == test_story.mode
assert items[0].value["reading_time"] == 120
assert items[0].value["source"] == "reading_event"
timeline_response = await client.get(f"/api/profiles/{profile_id}/timeline")
assert timeline_response.status_code == 200
timeline_events = timeline_response.json()["events"]
reading_events = [
event for event in timeline_events if event["type"] == "reading_event"
]
memory_events = [event for event in timeline_events if event["type"] == "memory"]
assert reading_events
assert memory_events
assert reading_events[0]["metadata"]["story_id"] == test_story.id
assert reading_events[0]["metadata"]["reading_time"] == 120
assert memory_events[0]["metadata"]["memory_type"] == "recent_story"
assert memory_events[0]["metadata"]["story_id"] == test_story.id
response = await client.post(
"/api/reading-events",
json={
"child_profile_id": profile_id,
"story_id": test_story.id,
"event_type": "skipped",
"reading_time": 0,
},
)
assert response.status_code == 201
result = await db_session.execute(
select(MemoryItem).where(MemoryItem.child_profile_id == profile_id)
)
assert len(result.scalars().all()) == 1
response = await client.post(
"/api/reading-events",
json={
"child_profile_id": profile_id,
"story_id": test_story.id,
"event_type": "completed",
"reading_time": 0,
},
)
assert response.status_code == 201
response = await client.get(f"/api/profiles/{profile_id}")
assert response.status_code == 200
profile = response.json()
assert profile["stories_count"] == 1
assert profile["total_reading_time"] == 120
finally:
app.dependency_overrides.clear()
async def test_reading_event_validation_errors(
db_session,
test_user,
auth_token,
):
async def override_get_db():
yield db_session
app.dependency_overrides[get_db] = override_get_db
transport = ASGITransport(app=app)
try:
async with AsyncClient(transport=transport, base_url="http://test") as client:
client.cookies.set("access_token", auth_token)
response = await client.post(
"/api/reading-events",
json={
"child_profile_id": "not-exist",
"event_type": "started",
"reading_time": 0,
},
)
assert response.status_code == 404
profile_id = await _create_profile(client)
response = await client.post(
"/api/reading-events",
json={
"child_profile_id": profile_id,
"story_id": 999999,
"event_type": "completed",
"reading_time": 0,
},
)
assert response.status_code == 404
finally:
app.dependency_overrides.clear()