from __future__ import annotations
import os
import sys
from typing import Generator
# Ensure backend root is on sys.path
backend_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
if backend_dir not in sys.path:
sys.path.insert(0, backend_dir)
# Default test database resolution
DEFAULT_TEST_DB_URL = "sqlite:///./test_lifecycle.db"
def get_test_database_url() -> str:
"""
Returns the database URL for the test session.
Prioritizes TEST_DATABASE_URL; if not set, defaults to an isolated SQLite file
so test runs never clobber active development databases.
"""
return os.environ.get("TEST_DATABASE_URL") or os.environ.get("DATABASE_TEST_URL") or DEFAULT_TEST_DB_URL
import pytest
from fastapi.testclient import TestClient
from app.main import create_app
from app.store import get_store, reset_store
@pytest.fixture(scope="session", autouse=True)
def initialize_test_database():
"""Configure store with test database for the entire test session."""
test_db_url = get_test_database_url()
reset_store(test_db_url)
yield
# Cleanup test db file after session if local file
if test_db_url.startswith("sqlite:///./") and os.path.exists("./test_lifecycle.db"):
try:
os.remove("./test_lifecycle.db")
except OSError:
pass
@pytest.fixture(autouse=True)
def reset_store_state():
"""Ensure every test starts with fresh seed data."""
store = get_store()
store.seed()
yield
store.seed()
@pytest.fixture
def client() -> Generator[TestClient, None, None]:
app = create_app()
with TestClient(app) as test_client:
yield test_client
@pytest.fixture
def test_client(client: TestClient) -> TestClient:
"""Alias for backwards compatibility with test_client fixtures."""
return client
@pytest.fixture
def auth_token(client: TestClient) -> str:
res = client.post(
"/api/v1/auth/login",
json={"email": "alex@example.com", "password": "password123"},
)
assert res.status_code == 200
return res.json()["token"]
@pytest.fixture
def auth_headers(auth_token: str) -> dict:
return {"Authorization": f"Bearer {auth_token}"}