import re from collections.abc import AsyncIterator import pytest from httpx import ASGITransport, AsyncClient from porchlight.app import create_app from porchlight.config import Settings from porchlight.rate_limit import limiter @pytest.fixture def settings() -> Settings: return Settings(issuer="http://localhost:8000", sqlite_path=":memory:", session_https_only=False) @pytest.fixture async def client(settings: Settings) -> AsyncIterator[AsyncClient]: app = create_app(settings) transport = ASGITransport(app=app) async with app.router.lifespan_context(app), AsyncClient(transport=transport, base_url=settings.issuer) as ac: yield ac @pytest.fixture(autouse=True) def _reset_rate_limiter() -> None: """Reset the rate limiter storage before each test.""" limiter.reset() async def get_csrf_token(client: AsyncClient) -> str: """Get a CSRF token by visiting the login page. Returns the token string. The session cookie is automatically stored in the client's cookie jar (httpx.AsyncClient persists cookies). """ resp = await client.get("/login") match = re.search(r'name="csrf-token" content="([^"]+)"', resp.text) assert match, "CSRF meta tag not found in page" return match.group(1)