Cardiosense-AG commited on
Commit
a612609
·
verified ·
1 Parent(s): d60dc7a

Create integration_v2.py

Browse files
Files changed (1) hide show
  1. tests/integration_v2.py +103 -0
tests/integration_v2.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # tests/integration_v2.py
2
+ """
3
+ Integration sanity check for AI E-Consult V2 core layers.
4
+ Run with: python -m tests.integration_v2
5
+ """
6
+
7
+ import sys
8
+ import json
9
+ from pathlib import Path
10
+ from typing import Dict, Any
11
+
12
+ # Ensure repo root on path
13
+ REPO_ROOT = Path(__file__).resolve().parents[1]
14
+ if str(REPO_ROOT) not in sys.path:
15
+ sys.path.insert(0, str(REPO_ROOT))
16
+
17
+ from src import config, billing, modal_templates, store # noqa: E402
18
+
19
+ RESULTS = {"passed": 0, "failed": 0}
20
+
21
+ def _ok(name: str):
22
+ RESULTS["passed"] += 1
23
+ print(f"[PASS] {name}")
24
+
25
+ def _fail(name: str, e: Exception):
26
+ RESULTS["failed"] += 1
27
+ print(f"[FAIL] {name}: {e}")
28
+
29
+ def check(name: str):
30
+ def deco(fn):
31
+ def wrapper():
32
+ try:
33
+ fn()
34
+ _ok(name)
35
+ except Exception as e:
36
+ _fail(name, e)
37
+ return wrapper
38
+ return deco
39
+
40
+ @check("seed_cases_and_v2_schema")
41
+ def test_seed_cases_and_v2_schema():
42
+ created = store.seed_cases(reset=True)
43
+ assert len(created) == 4
44
+ for cid in created:
45
+ case = store.read_case(cid)
46
+ assert case and case["schema_version"] == config.SCHEMA_VERSION
47
+ for k in ["status", "created_at", "updated_at", "billing", "explainability"]:
48
+ assert k in case
49
+
50
+ @check("load_sample_case")
51
+ def test_load_sample_case():
52
+ items = store.list_cases()
53
+ assert items, "No cases after seeding"
54
+ case = store.read_case(items[0]["case_id"])
55
+ assert case is not None
56
+ print(" case_id:", case["case_id"], "status:", case["status"])
57
+
58
+ @check("billing_autosuggest_representative")
59
+ def test_billing_autosuggest_representative():
60
+ combos = [(5, False), (12, True), (35, True)]
61
+ for minutes, spoke in combos:
62
+ sugg = billing.autosuggest_cpt(minutes=minutes, spoke=spoke)
63
+ assert isinstance(sugg, list) and len(sugg) >= 1
64
+ codes = [s.code for s in sugg]
65
+ print(f" minutes={minutes} spoke={spoke} -> {codes} (eligible={[s.code for s in sugg if s.eligible]})")
66
+
67
+ @check("modal_previews_safe_without_streamlit")
68
+ def test_modal_previews_safe_without_streamlit():
69
+ # Build a simple note and claim, then render via modal helpers.
70
+ cases = store.list_cases()
71
+ case = store.read_case(cases[0]["case_id"])
72
+ assert case
73
+ note_md = f"# Consult Note for {case['patient']['name']}\n\nGenerated for integration preview."
74
+ pick = billing.autosuggest_cpt(minutes=12, spoke=True)
75
+ code = next((s.code for s in pick if s.eligible), "99447")
76
+ rate = next((s.rate for s in pick if s.code == code), 55.0)
77
+ claim = billing.build_837_claim(case, code=code, rate=rate, minutes=12, spoke=True, attested=True)
78
+ # These calls are safe even if Streamlit is missing—helpers no-op or use fallbacks
79
+ modal_templates.show_consult_note_preview(note_md)
80
+ modal_templates.show_837_claim_preview(claim)
81
+
82
+ @check("export_filename_determinism")
83
+ def test_export_filename_determinism():
84
+ p1 = config.make_export_path("INTEG", "consult_note.md")
85
+ p2 = config.make_export_path("INTEG", "claim_837.json")
86
+ assert p1.parent.exists() and p2.parent.exists()
87
+ assert p1.name.startswith("EC-INTEG_") and p1.name.endswith("_consult_note.md")
88
+ assert p2.name.startswith("EC-INTEG_") and p2.name.endswith("_claim_837.json")
89
+
90
+ def main():
91
+ test_seed_cases_and_v2_schema()
92
+ test_load_sample_case()
93
+ test_billing_autosuggest_representative()
94
+ test_modal_previews_safe_without_streamlit()
95
+ test_export_filename_determinism()
96
+
97
+ total = RESULTS["passed"] + RESULTS["failed"]
98
+ print(f"\n=== Integration Summary: {RESULTS['passed']} passed, {RESULTS['failed']} failed, {total} total ===")
99
+ if RESULTS["failed"]:
100
+ raise SystemExit(1)
101
+
102
+ if __name__ == "__main__":
103
+ main()