64388b75bf
End-to-end coverage of the tenancy/people flow and the privacy seam (private-tree isolation, public-tree view-but-not-edit, duplicate-email conflict, auth-required). DB-backed tests run against TEST_DATABASE_URL and skip cleanly when it is unset, so the no-DB suite still runs anywhere. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Justin Paul <justin@jpaul.me>
48 lines
1.4 KiB
Python
48 lines
1.4 KiB
Python
"""Test fixtures.
|
|
|
|
DB-backed tests require ``TEST_DATABASE_URL`` (an async URL to a *disposable*
|
|
Postgres); without it they skip, so the no-DB unit suite still runs anywhere.
|
|
The schema is built from the models via ``create_all`` and dropped per test for
|
|
isolation.
|
|
"""
|
|
|
|
import os
|
|
|
|
import pytest_asyncio
|
|
from httpx import ASGITransport, AsyncClient
|
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
|
|
|
import app.models # noqa: F401 — register all models on Base.metadata
|
|
from app.core.db import get_session
|
|
from app.main import app
|
|
from app.models import Base
|
|
|
|
TEST_DATABASE_URL = os.getenv("TEST_DATABASE_URL")
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def client():
|
|
if not TEST_DATABASE_URL:
|
|
import pytest
|
|
|
|
pytest.skip("TEST_DATABASE_URL not set")
|
|
|
|
engine = create_async_engine(TEST_DATABASE_URL)
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.drop_all)
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
|
|
sessionmaker = async_sessionmaker(engine, expire_on_commit=False, class_=AsyncSession)
|
|
|
|
async def _override_session():
|
|
async with sessionmaker() as session:
|
|
yield session
|
|
|
|
app.dependency_overrides[get_session] = _override_session
|
|
transport = ASGITransport(app=app)
|
|
async with AsyncClient(transport=transport, base_url="http://test") as http_client:
|
|
yield http_client
|
|
|
|
app.dependency_overrides.clear()
|
|
await engine.dispose()
|