"""PATCH /api/settings/digest persists opt-in + tone.""" from __future__ import annotations import asyncio def _build(tmp_path): from fastapi import FastAPI from fastapi.testclient import TestClient from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine from app import db as db_mod from app.auth import sign_session from app.db import Base from app.models import User from app.routers import api as api_router engine = create_async_engine(f"sqlite+aiosqlite:///{tmp_path}/s.db") factory = async_sessionmaker(engine, expire_on_commit=False) db_mod._engine = engine db_mod._session_factory = factory async def _seed(): async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) async with factory() as s: s.add(User(id=1, email="u@x", tier="paid", email_digest_opt_in=True)) await s.commit() asyncio.run(_seed()) app = FastAPI() app.include_router(api_router.router, prefix="/api") return TestClient(app), sign_session(1) def test_patch_round_trip(tmp_path): client, sess = _build(tmp_path) r = client.patch( "/api/settings/digest", json={"opt_in": False, "tone": "NOVICE"}, cookies={"cassandra_session": sess}, ) assert r.status_code == 200, r.text assert r.json() == {"opt_in": False, "tone": "NOVICE"} async def _check(): from app import db as db_mod from app.models import User async with db_mod._session_factory() as s: u = await s.get(User, 1) assert u.email_digest_opt_in is False assert u.digest_tone == "NOVICE" asyncio.run(_check()) def test_patch_rejects_invalid_tone(tmp_path): client, sess = _build(tmp_path) r = client.patch( "/api/settings/digest", json={"opt_in": True, "tone": "PRO"}, cookies={"cassandra_session": sess}, ) assert r.status_code == 422 def test_patch_requires_auth(tmp_path): client, _ = _build(tmp_path) r = client.patch("/api/settings/digest", json={"opt_in": True, "tone": "NOVICE"}) assert r.status_code in (401, 303)