import os 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)) # http base → cookies aren't Secure-only, so the TestClient round-trips them 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.close() return api.create_app(), api def test_magic_link_end_to_end(client, monkeypatch): app, api = client sent = {} # capture the link instead of sending real email monkeypatch.setattr(api.email_send, "send_magic_link", lambda to, link: sent.update(to=to, link=link)) tc = TestClient(app) # not signed in assert tc.get("/api/auth/me").json() is None # request a link r = tc.post("/api/auth/email/start", json={"email": "Jay@Example.com"}) assert r.status_code == 200 and r.json() == {"ok": True} assert sent["to"] == "jay@example.com" token = sent["link"].split("token=")[1] # verify → session established (cookie set), user created r = tc.post("/api/auth/email/verify", json={"token": token}) assert r.status_code == 200 body = r.json() assert body["user"]["email"] == "jay@example.com" and body["token"] # cookie now authenticates /me me = tc.get("/api/auth/me").json() assert me and me["email"] == "jay@example.com" # bearer token also works (app clients) bare = TestClient(app) me2 = bare.get("/api/auth/me", headers={"Authorization": f"Bearer {body['token']}"}).json() assert me2["email"] == "jay@example.com" # reusing the magic link fails (single use) assert tc.post("/api/auth/email/verify", json={"token": token}).status_code == 400 # logout clears the session assert tc.post("/api/auth/logout").json() == {"ok": True} assert tc.get("/api/auth/me").json() is None def test_start_rejects_bad_email(client): app, _ = client tc = TestClient(app) assert tc.post("/api/auth/email/start", json={"email": "nope"}).status_code == 422 def test_verify_bad_token(client): app, _ = client tc = TestClient(app) assert tc.post("/api/auth/email/verify", json={"token": "garbage"}).status_code == 400