Spaces:
Sleeping
Sleeping
File size: 3,201 Bytes
a7ea8bc bd5e8e1 a7ea8bc bd5e8e1 a7ea8bc bd5e8e1 a7ea8bc bd5e8e1 a7ea8bc bd5e8e1 a7ea8bc bd5e8e1 a7ea8bc bd5e8e1 a7ea8bc bd5e8e1 a7ea8bc bd5e8e1 a7ea8bc bd5e8e1 a7ea8bc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | """Render-time smoke test using Streamlit's AppTest API.
This actually executes `app.main()` the way a real Streamlit session would,
so it catches errors that pure imports miss (missing i18n keys, session_state
crashes, render-time exceptions in module handlers).
We patch out the network-calling chat() function so we don't need an API key.
"""
from __future__ import annotations
import sys
import traceback
import types
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))
def _fake_chat(*args, **kwargs):
return "(stubbed Claude reply for smoke test)"
def _fake_chat_structured(*args, **kwargs):
# Return a valid empty-ish instance of whatever Pydantic schema is passed.
schema = kwargs.get("schema")
if schema is None and args:
schema = args[0]
try:
return schema(overall_mood="neutral", distortions=[], summary="stubbed journal summary")
except Exception:
return None
# Stub backend.claude_client before anything in the module tree imports it, so
# the render test never depends on dotenv, provider SDKs, API keys, or network.
cc = types.ModuleType("backend.claude_client")
cc.chat = _fake_chat # type: ignore[attr-defined]
cc.chat_structured = _fake_chat_structured # type: ignore[attr-defined]
cc.get_active_provider_label = lambda: "Smoke-test LLM stub" # type: ignore[attr-defined]
sys.modules["backend.claude_client"] = cc
try:
from streamlit.testing.v1 import AppTest
except Exception as e:
print("AppTest not available:", e)
sys.exit(2)
print("=== Streamlit AppTest render ===")
failures = []
JOURNAL_SECTIONS = [
("journal", "Journal"),
("phq9", "PHQ-9"),
("gad7", "GAD-7"),
("checkin", "Daily check-in"),
("dashboard", "My patterns"),
]
def run_with_lang(lang_code: str, label: str, journal_section: str, section_label: str) -> None:
at = AppTest.from_file(str(ROOT / "app.py"), default_timeout=30)
# Pre-set the language in session_state so we exercise every label lookup path.
at.session_state["saathi_language"] = lang_code
at.session_state["cognitive_journal_section"] = journal_section
at.run()
if at.exception:
print(f" FAIL [{label} / {section_label}] rendered with exceptions:")
for ex in at.exception:
print(f" - {ex.value if hasattr(ex, 'value') else ex}")
failures.append(f"{label}:{section_label}")
else:
print(f" OK [{label} / {section_label}] rendered clean ({len(at.tabs)} tabs)")
for code, label in [
("en", "English"),
("hi", "Hindi"),
("bn", "Bengali"),
("ta", "Tamil"),
("te", "Telugu"),
("mr", "Marathi"),
("ur", "Urdu"),
]:
for journal_section, section_label in JOURNAL_SECTIONS:
try:
run_with_lang(code, label, journal_section, section_label)
except Exception as e:
print(f" FAIL [{label} / {section_label}] crashed: {e}")
traceback.print_exc()
failures.append(f"{label}:{section_label}")
print()
if failures:
print(f"FAIL — {len(failures)} render errors: {failures}")
sys.exit(1)
else:
print("ALL RENDERS PASSED")
sys.exit(0)
|