import importlib.util import pytest spacy_model = importlib.util.find_spec("en_core_web_sm") pytest.importorskip("fastapi") from fastapi.testclient import TestClient # noqa: E402 from app.server import app # noqa: E402 client = TestClient(app) class FakeLLM: provider, model = "fake", "fake-1" def available(self): return True def describe(self): return "fake:fake-1" def complete_json(self, system, user): return ({"summary": "A short test summary.", "languages": ["English"], "chapters": [{"segId": "p002", "title": "Birth"}], "headings": [{"heading": "Holocaust survivors", "category": "Topical", "confidence": 0.8, "segId": "p002", "quote": "I was born in Lodz"}, {"heading": "Holocaust survivors", "category": "Topical", "confidence": 0.8, "segId": "p002", "quote": "a sentence that is not there"}], "journeys": [{"from": "Lodz", "to": "Auschwitz", "when": "1944", "how": "train", "segId": "p004", "quote": "they took us by train from Lodz to Auschwitz"}], "claims": []}, {"provider": "fake", "model": "fake-1", "latency_ms": 1, "input_tokens": 1, "output_tokens": 1}) def test_health_and_demo_listing(): assert client.get("/api/health").json()["ok"] is True ids = [i["id"] for i in client.get("/api/interviews").json()] assert "DEMO-0001" in ids brief = client.get("/api/interviews/DEMO-0001").json() assert brief["testimony"]["id"] == "DEMO-0001" assert client.get("/api/interviews/..%2Fsecrets").status_code in (400, 404) def test_index_served(): r = client.get("/") assert r.status_code == 200 and "CuratorBot" in r.text assert "/static/app.js?v=" in r.text and "/static/style.css?v=" in r.text # fresh assets after each deploy @pytest.mark.skipif(spacy_model is None, reason="en_core_web_sm not installed") def test_analyse_end_to_end_with_fake_llm(monkeypatch): import curatorbot.llm as llm monkeypatch.setattr(llm, "LLMClient", lambda *a, **k: FakeLLM()) monkeypatch.setenv("CURATORBOT_DEMO_PASSCODE", "pw") text = "Q: Where were you born?\nA: I was born in Lodz in 1928.\nQ: What happened?\nA: In 1944 they took us by train from Lodz to Auschwitz." assert client.post("/api/analyse", json={"transcript": text}).status_code == 401 r = client.post("/api/analyse", json={"transcript": text}, headers={"X-Demo-Passcode": "pw"}) assert r.status_code == 200, r.text b = r.json() model = [h for h in b["agent"]["headings"] if h.get("source") != "rule"] assert [h["grounded"] for h in model] == [True, False] rule = [h for h in b["agent"]["headings"] if h.get("source") == "rule"] assert rule and all(h["category"] == "Form" and h["rule"] for h in rule) # convention headings, marked as rule-based assert b["agent"]["journeys"][0]["fromKey"] == "lodz" and b["agent"]["journeys"][0]["toKey"] == "birkenau" assert any(m["key"] == "lodz" for m in b["mentions"])