"""Shared pytest fixtures: an in-memory DB and a FastAPI TestClient. The client is created WITHOUT the context-manager form on purpose, so the app lifespan (which runs real Alembic migrations against the configured DB_PATH) never fires. Tables come from SQLModel.metadata.create_all against a throwaway in-memory database instead. """ import pytest from fastapi.testclient import TestClient from sqlalchemy.pool import StaticPool from sqlmodel import Session, SQLModel, create_engine import ten31portal.models # noqa: F401 — importing registers every table on SQLModel.metadata from ten31portal.auth import hash_password from ten31portal.database import get_session from ten31portal.main import app from ten31portal.models import User, UserRole @pytest.fixture def engine(): eng = create_engine( "sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool, # one shared in-memory connection across sessions ) SQLModel.metadata.create_all(eng) yield eng SQLModel.metadata.drop_all(eng) @pytest.fixture def session(engine): with Session(engine) as s: yield s @pytest.fixture def client(engine): def override_get_session(): with Session(engine) as s: yield s app.dependency_overrides[get_session] = override_get_session yield TestClient(app) app.dependency_overrides.clear() def make_user(session, *, username="admin", password="password123", role=UserRole.approver, name="Test User", email=None, **kwargs): user = User( name=name, username=username, email=email, password_hash=hash_password(password), role=role, **kwargs, ) session.add(user) session.commit() session.refresh(user) return user @pytest.fixture def approver(session): return make_user(session, username="approver", role=UserRole.approver) @pytest.fixture def auth_client(client, approver): """A TestClient already logged in as an approver (a writer).""" resp = client.post( "/api/auth/login", json={"login": "approver", "password": "password123"} ) assert resp.status_code == 200, resp.text return client