fix(auth): revert to Better-Auth session-cookie auth, preserve email-in feature

- Revert auth/dependencies.py, auth/routes.py, services/auth.py, schemas.py
  to Better-Auth session-cookie auth (removed JWT register/login/refresh)
- Preserve GET /auth/me/email-in-address endpoint
- Fix UUIDString TypeDecorator: process_result_value returns uuid.UUID
  (not str) so SQLAlchemy 2.0 sentinel tracking matches UUID-to-UUID
- Fix seed_data fixture: look up real user_id from session token via
  sessions table; purchases now reference actual user FK
- Update purchase_data fixture to use session-cookie auth
- Update test_auth_endpoints, test_auth_validation to cookie-based tests
- Remove TestRegistrationErrors and TestLoginErrors (no longer applicable)
- Update test_openapi.py expected routes and count
- Update test_error_handler.py to use PATCH /auth/me validation

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
CartSnitch Engineer Bot
2026-04-03 09:15:00 +00:00
parent b52fae5894
commit 18ff5795ac
13 changed files with 543 additions and 591 deletions
+53 -18
View File
@@ -1,46 +1,82 @@
"""Integration tests for purchase endpoints."""
import secrets
import uuid
from datetime import date
from datetime import UTC, datetime, date, timedelta
from decimal import Decimal
import pytest
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
from sqlalchemy import text
from cartsnitch_api.auth.jwt import create_access_token
from cartsnitch_api.models import Purchase, PurchaseItem, Store, User
from cartsnitch_api.models import Purchase, PurchaseItem, Store
@pytest.fixture
async def purchase_data(db_engine):
"""Seed a user, store, purchase, and items."""
"""Seed a user, store, purchase, and items using session-cookie auth."""
factory = async_sessionmaker(db_engine, class_=AsyncSession, expire_on_commit=False)
async with factory() as session:
from cartsnitch_api.auth.passwords import hash_password
user_id = str(uuid.uuid4())
session_token = secrets.token_urlsafe(32)
now = datetime.now(UTC).isoformat()
expires = (datetime.now(UTC) + timedelta(days=7)).isoformat()
user = User(
email="buyer@example.com",
hashed_password=hash_password("testpass123"),
display_name="Buyer",
# Create the user
await session.execute(
text(
"INSERT INTO users (id, email, hashed_password, display_name, email_inbound_token, created_at, updated_at) "
"VALUES (:id, :email, :hashed_password, :display_name, :email_inbound_token, :created_at, :updated_at)"
),
{
"id": user_id,
"email": "buyer@example.com",
"hashed_password": "not-used-with-better-auth",
"display_name": "Buyer",
"email_inbound_token": secrets.token_urlsafe(16),
"created_at": now,
"updated_at": now,
},
)
store = Store(name="Kroger", slug="kroger")
session.add_all([user, store])
await session.commit()
await session.refresh(user)
# Create the session
await session.execute(
text(
"INSERT INTO sessions (id, token, user_id, expires_at, created_at, updated_at) "
"VALUES (:id, :token, :user_id, :expires_at, :created_at, :updated_at)"
),
{
"id": str(uuid.uuid4()),
"token": session_token,
"user_id": user_id,
"expires_at": expires,
"created_at": now,
"updated_at": now,
},
)
# Create the store
store = Store(name="Kroger", slug="kroger", id=uuid.uuid4())
session.add(store)
await session.flush()
await session.refresh(store)
# Create the purchase
purchase = Purchase(
user_id=user.id,
id=uuid.uuid4(),
user_id=uuid.UUID(user_id),
store_id=store.id,
receipt_id="receipt-001",
purchase_date=date(2026, 3, 10),
total=Decimal("42.50"),
)
session.add(purchase)
await session.commit()
await session.flush()
await session.refresh(purchase)
# Create the purchase item
item = PurchaseItem(
id=uuid.uuid4(),
purchase_id=purchase.id,
product_name_raw="Organic Milk 1gal",
quantity=Decimal("1"),
@@ -50,12 +86,11 @@ async def purchase_data(db_engine):
session.add(item)
await session.commit()
token = create_access_token(user.id)
return {
"user": user,
"user_id": user_id,
"store": store,
"purchase": purchase,
"headers": {"Authorization": f"Bearer {token}"},
"headers": {"Cookie": f"better-auth.session_token={session_token}"},
}