import json import pytest from fastapi.testclient import TestClient @pytest.fixture def client(tmp_path, monkeypatch): db = tmp_path / "t.sqlite3" monkeypatch.setenv("GOODNEWS_DB", str(db)) monkeypatch.setenv("GOODNEWS_PUBLIC_BASE_URL", "http://testserver") import importlib import goodnews.api as api importlib.reload(api) from goodnews.db import connect, init_db c = connect(str(db)); init_db(c) c.execute("INSERT INTO sources (id,name,feed_url,trust_score) VALUES (1,'S','http://s/f',5)") c.execute("INSERT INTO articles (id,source_id,canonical_url,title,url_hash) VALUES (1,1,'http://s/1','t1','h1')") c.commit(); c.close() return api.create_app(), api def _signed_in(app, api): tc = TestClient(app) sent = {} import goodnews.email_send as es orig = es.send_magic_link es.send_magic_link = lambda to, link: sent.update(link=link) try: tc.post("/api/auth/email/start", json={"email": "a@b.com"}) tc.post("/api/auth/email/verify", json={"token": sent["link"].split("token=")[1]}) finally: es.send_magic_link = orig return tc def test_prefs_roundtrip(client): app, api = client tc = _signed_in(app, api) assert tc.get("/api/prefs").json() == {"prefs": None} # nothing yet → seed from device tc.put("/api/prefs", json={"prefs": {"mute_topics": ["health"], "avoid_terms": ["war"]}}) assert tc.get("/api/prefs").json()["prefs"]["mute_topics"] == ["health"] def test_account_info_and_export(client): app, api = client tc = _signed_in(app, api) tc.post("/api/saved/1") info = tc.get("/api/account").json() assert info["user"]["email"] == "a@b.com" assert info["providers"] == ["email"] and info["sessions"] >= 1 and info["saved_count"] == 1 exp = tc.get("/api/account/export") assert exp.headers["content-disposition"].endswith("upbeatbytes-data.json") data = json.loads(exp.content) assert data["account"]["email"] == "a@b.com" and {a["id"] for a in data["saved"]} == {1} def test_logout_all_and_delete(client): app, api = client tc = _signed_in(app, api) tc.post("/api/saved/1") assert tc.post("/api/account/logout-all").json() == {"ok": True} assert tc.get("/api/auth/me").json() is None # session revoked tc2 = _signed_in(app, api) # same email → same account, has the save assert tc2.get("/api/saved/ids").json() == [1] assert tc2.delete("/api/account").json() == {"ok": True} assert tc2.get("/api/auth/me").json() is None # a fresh sign-in is a brand-new account (old data gone) tc3 = _signed_in(app, api) assert tc3.get("/api/saved/ids").json() == []