"""Shared test fixtures. Unit tests run against an in-memory sqlite DB (shared across sessions via StaticPool) so the suite needs no external services. The Postgres/pgvector path is exercised by guarded integration tests (``TEST_DATABASE_URL``). """ from __future__ import annotations import os import pytest import pytest_asyncio from sqlalchemy.pool import StaticPool # Ensure env is sane before any app import reads Settings. os.environ.setdefault("DATABASE_URL", "sqlite+aiosqlite://") os.environ.setdefault("TESTING", "1") os.environ.setdefault("ADMIN_TOKEN", "test-admin-token") os.environ.setdefault("SHOPIFY_APP_PROXY_SECRET", "test-proxy-secret") from app import db # noqa: E402 @pytest_asyncio.fixture async def db_session(): """A fresh in-memory sqlite DB with all tables created, per test.""" db.init_engine( "sqlite+aiosqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) # Import models so they register on Base.metadata before create_all. try: import app.models # noqa: F401 except ModuleNotFoundError: pass await db.create_all() async with db.get_sessionmaker()() as session: yield session await db.get_engine().dispose() @pytest.fixture def is_postgres() -> bool: return db.is_postgres(os.environ.get("DATABASE_URL", "")) @pytest_asyncio.fixture async def tenant(db_session): """A committed tenant for route tests (slug 't1').""" from app.models import Tenant t = Tenant(slug="t1", name="Tienda 1", brand_name="Asistente T1") db_session.add(t) await db_session.commit() return t @pytest_asyncio.fixture async def default_tenant(db_session): """A committed 'default' tenant. Its shopify_shop matches the proxy tests' BASE shop so the signed App Proxy path resolves to it BY SHOP (that path no longer falls back to the default tenant for an unknown shop).""" from app.models import Tenant t = Tenant( slug="default", name="Default", brand_name="Asistente", shopify_shop="x.myshopify.com", ) db_session.add(t) await db_session.commit() return t @pytest.fixture(autouse=True) def _reset_order_limiter(): """Isolate the in-process rate limiters between tests.""" from app.ratelimit import get_order_limiter from app.routes import chat get_order_limiter().clear() chat._chat_limiter.clear() yield get_order_limiter().clear() chat._chat_limiter.clear() @pytest_asyncio.fixture async def app_client(db_session): """ASGI test client whose DB dependency is bound to the test session.""" import httpx from app.db import get_session from app.main import create_app app = create_app() async def _override_session(): yield db_session app.dependency_overrides[get_session] = _override_session transport = httpx.ASGITransport(app=app) async with httpx.AsyncClient(transport=transport, base_url="http://testserver") as client: yield app, client app.dependency_overrides.clear()