File size: 7,444 Bytes
f824c7f f8adedd f824c7f f8adedd f824c7f f8adedd f824c7f f8adedd f824c7f f8adedd f824c7f f8adedd f824c7f 97aee42 f824c7f 97aee42 f824c7f | 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | """Integration tests: verify FE components correctly consume BE models."""
from __future__ import annotations
import json
from app.components.gap_card import render_gap_card
from app.components.profile_card import render_profile_card
from app.components.progress_tracker import render_progress_tracker
from app.components.trial_card import render_trial_card
from app.services.mock_data import (
MOCK_ELIGIBILITY_LEDGERS,
MOCK_PATIENT_PROFILE,
MOCK_TRIAL_CANDIDATES,
)
from app.services.state_manager import JOURNEY_STATES
from trialpath.models import (
EligibilityLedger,
PatientProfile,
SearchAnchors,
TrialCandidate,
)
class TestMockDataIntegrity:
"""Verify mock data uses real BE models correctly."""
def test_mock_profile_is_patient_profile(self):
assert isinstance(MOCK_PATIENT_PROFILE, PatientProfile)
def test_mock_trials_are_trial_candidates(self):
for t in MOCK_TRIAL_CANDIDATES:
assert isinstance(t, TrialCandidate)
def test_mock_ledgers_are_eligibility_ledgers(self):
for lg in MOCK_ELIGIBILITY_LEDGERS:
assert isinstance(lg, EligibilityLedger)
def test_mock_ledger_nct_ids_match_trials(self):
trial_ids = {t.nct_id for t in MOCK_TRIAL_CANDIDATES}
ledger_ids = {lg.nct_id for lg in MOCK_ELIGIBILITY_LEDGERS}
assert ledger_ids == trial_ids
def test_mock_profile_has_minimum_prescreen_data(self):
assert MOCK_PATIENT_PROFILE.has_minimum_prescreen_data()
def test_mock_profile_serializes_to_json(self):
data = MOCK_PATIENT_PROFILE.model_dump_json()
restored = PatientProfile.model_validate_json(data)
assert restored.patient_id == MOCK_PATIENT_PROFILE.patient_id
def test_mock_trials_serialize_to_json(self):
for t in MOCK_TRIAL_CANDIDATES:
data = t.model_dump_json()
restored = TrialCandidate.model_validate_json(data)
assert restored.nct_id == t.nct_id
def test_mock_ledgers_serialize_to_json(self):
for lg in MOCK_ELIGIBILITY_LEDGERS:
data = lg.model_dump_json()
restored = EligibilityLedger.model_validate_json(data)
assert restored.nct_id == lg.nct_id
class TestComponentModelIntegration:
"""Verify FE components produce correct output from BE models."""
def test_profile_card_renders_mock_profile(self):
spec = render_profile_card(MOCK_PATIENT_PROFILE)
assert spec["patient_id"] == "MOCK-P001"
assert spec["has_minimum_prescreen_data"] is True
assert len(spec["biomarkers"]) == 3
def test_trial_card_renders_green_trial(self):
# MOCK-NCT-FLAURA2 is LIKELY_ELIGIBLE -> green
trial = MOCK_TRIAL_CANDIDATES[1]
ledger = MOCK_ELIGIBILITY_LEDGERS[1]
spec = render_trial_card(trial, ledger)
assert spec["traffic_light"] == "green"
assert spec["nct_id"] == "MOCK-NCT-FLAURA2"
def test_trial_card_renders_yellow_trial(self):
# MOCK-NCT-KEYNOTE999 is UNCERTAIN -> yellow
trial = MOCK_TRIAL_CANDIDATES[0]
ledger = MOCK_ELIGIBILITY_LEDGERS[0]
spec = render_trial_card(trial, ledger)
assert spec["traffic_light"] == "yellow"
assert len(spec["gaps"]) == 1
def test_trial_card_renders_red_trial(self):
# MOCK-NCT-CM817 is LIKELY_INELIGIBLE -> red
trial = MOCK_TRIAL_CANDIDATES[2]
ledger = MOCK_ELIGIBILITY_LEDGERS[2]
spec = render_trial_card(trial, ledger)
assert spec["traffic_light"] == "red"
def test_gap_card_renders_from_ledger_gap(self):
ledger = MOCK_ELIGIBILITY_LEDGERS[0]
gap = ledger.gaps[0]
spec = render_gap_card(gap, affected_trials=["MOCK-NCT-KEYNOTE999"])
assert "Brain MRI" in spec["description"]
assert spec["importance_color"] == "red" # high importance
def test_progress_tracker_all_states(self):
for state in JOURNEY_STATES:
spec = render_progress_tracker(state)
assert len(spec["steps"]) == 5
current_steps = [s for s in spec["steps"] if s["status"] == "current"]
assert len(current_steps) == 1
class TestDoctorPacketGeneration:
"""Verify doctor packet export generates valid JSON/Markdown."""
def test_json_packet_structure(self):
profile = MOCK_PATIENT_PROFILE
ledgers = MOCK_ELIGIBILITY_LEDGERS
eligible = sum(1 for lg in ledgers if lg.traffic_light == "green")
uncertain = sum(1 for lg in ledgers if lg.traffic_light == "yellow")
ineligible = sum(1 for lg in ledgers if lg.traffic_light == "red")
total_gaps = sum(len(lg.gaps) for lg in ledgers)
packet = {
"patient_id": profile.patient_id,
"summary": {
"eligible_count": eligible,
"uncertain_count": uncertain,
"ineligible_count": ineligible,
"total_gaps": total_gaps,
},
"trials": [
{
"nct_id": lg.nct_id,
"overall_assessment": lg.overall_assessment.value,
"met": lg.met_count,
"not_met": lg.not_met_count,
"unknown": lg.unknown_count,
"gaps": [g.description for g in lg.gaps],
}
for lg in ledgers
],
}
serialized = json.dumps(packet, indent=2)
restored = json.loads(serialized)
assert restored["patient_id"] == "MOCK-P001"
assert restored["summary"]["eligible_count"] == 1
assert restored["summary"]["uncertain_count"] == 1
assert restored["summary"]["ineligible_count"] == 1
assert restored["summary"]["total_gaps"] == 2
assert len(restored["trials"]) == 3
def test_all_trial_nct_ids_in_packet(self):
ledgers = MOCK_ELIGIBILITY_LEDGERS
packet_ids = [lg.nct_id for lg in ledgers]
expected_ids = ["MOCK-NCT-KEYNOTE999", "MOCK-NCT-FLAURA2", "MOCK-NCT-CM817"]
assert packet_ids == expected_ids
class TestSearchAnchorsFromProfile:
"""Verify BE model can generate SearchAnchors from PatientProfile."""
def test_profile_to_search_anchors(self):
profile = MOCK_PATIENT_PROFILE
assert profile.diagnosis is not None
assert profile.performance_status is not None
anchors = SearchAnchors(
condition=profile.diagnosis.primary_condition,
subtype=profile.diagnosis.histology,
biomarkers=[b.name for b in profile.biomarkers],
stage=profile.diagnosis.stage,
age=profile.demographics.age,
performance_status_max=profile.performance_status.value,
)
assert anchors.condition == "Non-Small Cell Lung Cancer"
assert "EGFR" in anchors.biomarkers
assert anchors.stage == "IIIB"
assert anchors.age == 62
def test_search_anchors_serializes(self):
profile = MOCK_PATIENT_PROFILE
assert profile.diagnosis is not None
anchors = SearchAnchors(
condition=profile.diagnosis.primary_condition,
biomarkers=[b.name for b in profile.biomarkers],
stage=profile.diagnosis.stage,
)
data = anchors.model_dump_json()
restored = SearchAnchors.model_validate_json(data)
assert restored.condition == anchors.condition
|