r""" web/app.py and web/repo.py — the results portal, against a fake repository and a fake database connection (no SQL Server needed). Spec: docs/superpowers/specs/2026-10-19-results-portal-redesign-design.md. python tests\test_web_app.py Claim numbers here are made up. """ import io import re import sys import json import pathlib import tempfile import contextlib from datetime import date, datetime, timedelta from decimal import Decimal ROOT = pathlib.Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT)) sys.path.insert(0, str(ROOT / "src")) from fastapi.testclient import TestClient # noqa: E402 from web import app as web_app # noqa: E402 from web.repo import SqlResultsRepo # noqa: E402 from ecw_bot.core import results_db as rdb # noqa: E402 from web import users as portal_users # noqa: E402 sys.path.insert(0, str(ROOT / "tests")) from test_portal_users import FakeUserStore # noqa: E402 CASES = [] def case(fn): CASES.append(fn) return fn DAY = date(2026, 10, 16) RUN_AM = datetime(2026, 10, 16, 10, 30, 0) # 10 claims run RUN_PM = datetime(2026, 10, 16, 14, 15, 0) # 20 claims run, same day RUN_OLD = datetime(2026, 10, 15, 11, 0, 0) def _row(claim, category, s_no, run_at=RUN_PM, **over): row = {c: None for _, c in rdb.COLUMNS} row.update({"id": s_no, "run_at": run_at, "run_mode": "VERIFY", "s_no": s_no, "claim_no": claim, "category": category, "service_date": date(2026, 7, 31), "payer": "Medicaid", "charges": Decimal("1365.00"), "comments": f"comment {claim}", "current_status": "Corrections pending (not saved)", "details_json": json.dumps({"fired": ["dummy_codes"]})}) row.update(over) return row def _day(day, claims, runs, p, f, r): return {"day": day, "claims": claims, "runs": runs, "pass_count": p, "fail_count": f, "review_count": r} class FakeRepo: def __init__(self, days=None, rows=None, fail=False): self._days = days if days is not None else [ _day(DAY, 3, 2, 1, 1, 1), _day(RUN_OLD.date(), 2, 1, 2, 0, 0)] self._rows = rows if rows is not None else [ _row("9000001", "Pass", 1, RUN_AM), _row("9000002", "Fail", 1, details_json=None), _row("9000003", "Review", 2, payer="HCFA Medicare")] self.fail = fail self.calls = [] def _maybe_fail(self): if self.fail: raise self.fail if isinstance(self.fail, Exception) \ else RuntimeError("Login failed for user") def runs(self): self._maybe_fail() return [{"run_at": RUN_PM, "run_mode": "VERIFY", "claims": 2, "pass_count": 0, "fail_count": 1, "review_count": 1}] def results(self, run_at, category=None, claim_no=None): self.calls.append(("results", run_at, category, claim_no)) self._maybe_fail() return [r for r in self._rows if (not category or r["category"] == category)] def days(self, limit=90): self.calls.append(("days",)) self._maybe_fail() return self._days def day_results(self, day): self.calls.append(("day_results", day)) self._maybe_fail() return [dict(r) for r in self._rows if r["run_at"].date() == day] def claim_history(self, claim_no): self.calls.append(("claim_history", claim_no)) self._maybe_fail() return [dict(r) for r in self._rows if claim_no in r["claim_no"]] delete_fails = None def delete_run(self, run_at): self.calls.append(("delete_run", run_at)) if self.delete_fails: raise self.delete_fails kept = [r for r in self._rows if r["run_at"] != run_at] gone, self._rows = len(self._rows) - len(kept), kept return gone TESTER_PASSWORD = "tester-password-1" def signed_in(repo, runner, base_url="http://127.0.0.1:8000", role="Admin", **kw): """(client, app): the Portal with one Portal User, signed in — every page needs a Sign-in since 2026-10-22 (EEWA-32). A foreign host gets its 400 before any Sign-in, so there it is not tried.""" store = FakeUserStore() portal_users.Accounts(store).create_user("tester", "Tester", role, TESTER_PASSWORD) # No run events unless a test brings its own: the real Logs\ would # make the Dashboard's last-run banner depend on the PC. kw.setdefault("logs_dir", tempfile.mkdtemp()) app = web_app.create_app(repo, runner=runner, users_store=store, **kw) client = TestClient(app, base_url=base_url) if base_url in web_app.ALLOWED_ORIGINS: r = client.post("/signin", headers={"Origin": base_url}, data={ "username": "tester", "password": TESTER_PASSWORD, "token": app.state.run_token, "next": "/account/password"}) # A page that reads no database: FakeRepo(fail=True) must not # break the Sign-in itself. assert r.status_code == 200, r.status_code assert r.url.path == "/account/password", r.url return client, app def _client(repo=None, base_url="http://127.0.0.1:8000"): repo = repo or FakeRepo() client, _ = signed_in(repo, FakeRunner(), base_url=base_url) return client, repo class FakeRunner: def __init__(self, running=False, stop_fails=None): self.running = running self.stop_fails = stop_fails self.calls = [] def _st(self): return {"running": self.running, "starting": False, "pid": 1, "started_at": "2026-10-14T10:00:00", "ended_at": None, "exit_code": None, "stopped_by_operator": False, "source": "web", "log_path": None, "out_path": None} def start(self, started_by=""): self.calls.append("start") self.started_by = started_by if self.running: raise web_app.AlreadyRunning("A run is already going (started x)") self.running = True return self._st() def stop(self, stopped_by=""): self.calls.append("stop") self.stopped_by = stopped_by if self.stop_fails: raise web_app.StopFailed(self.stop_fails) if not self.running: raise web_app.NotRunning("No run is going") self.running = False return self._st() def status(self): return self._st() def _bot_client(runner=None): runner = runner or FakeRunner() client, app = signed_in(FakeRepo(), runner) return (client, runner, app.state.run_token) _GOOD_ORIGIN = {"Origin": "http://127.0.0.1:8000"} _PAGES = ("/", "/days", f"/day/{DAY.isoformat()}", "/claim?claim_no=9000") def _quiet(fn, *a, **k): with contextlib.redirect_stdout(io.StringIO()): return fn(*a, **k) def _css_rule(html, selector): """What `selector { ... }` in the page's ")] rule = css[css.index("\n " + selector + " {"):] return rule[:rule.index("}")] # ── Dashboard ──────────────────────────────────────────────────────────────── @case def the_dashboard_has_no_claims_table(): """Operator, 2026-10-19: the claims table (three quarters of the page) is not on the home page — the Bot run card, today's counts, Find a claim and one Claim status button are.""" client, repo = _client() html = client.get("/").text assert "30Checked today' \ in html, html assert f'href="/day/{today.isoformat()}?category=Fail">5<' \ in html # No run today: zeros, not yesterday's numbers. html = _client(FakeRepo(days=[_day(today - timedelta(days=1), 9, 1, 9, 0, 0)]))[0].get("/").text assert '0Checked today' \ in html @case def the_dashboard_shows_todays_pass_rate(): today = date.today() html = _client(FakeRepo(days=[_day(today, 30, 2, 24, 5, 1)]))[0] \ .get("/").text assert '80% pass' in html html = _client(FakeRepo(days=[]))[0].get("/").text assert 'class="rate"' not in html, "no claims today: no rate" @case def the_dashboard_shows_the_last_seven_days_oldest_first(): today = date.today() days = [_day(today - timedelta(days=i), 10 + i, 1, 8, 2, i % 2) for i in range(9)] # newest first, as repo html = _client(FakeRepo(days=days))[0].get("/").text assert 'id="week"' in html shown = re.findall(r'data-day="([\d-]+)"', html) assert shown == [(today - timedelta(days=i)).isoformat() for i in range(6, -1, -1)], shown assert f'href="/day/{(today - timedelta(days=3)).isoformat()}"' in html assert 'data-n="13"' in html, "a day's claims count" @case def the_dashboard_lists_todays_top_fail_and_review_reasons(): run = datetime.combine(date.today(), datetime.min.time()) \ + timedelta(hours=10) tele = "Telehealth (POS 02, modifier 93 on 99213)" rows = ([_row(f"90000{i}", "Fail", i, run, comments=tele) for i in range(1, 4)] + [_row("9000005", "Fail", 5, run, comments="ICD "), _row("9000006", "Review", 6, run, comments="Could not search"), _row("9000007", "Pass", 7, run, comments="Clean claims")]) html = _client(FakeRepo(days=[_day(date.today(), 6, 1, 1, 4, 1)], rows=rows))[0].get("/").text box = html.split('id="reasons"', 1)[1].split("", 1)[0] assert box.index(tele) < box.index("ICD <pointer>") \ < box.index("Could not search"), box assert '3' in box, "grouped, with its count" assert "Clean claims" not in box, "Pass is not a reason" html = _client(FakeRepo(rows=[]))[0].get("/").text assert "No Fail or Review today" in html @case def the_dashboard_lists_todays_runs_newest_first(): """Operator, 2026-10-30 (the approved mockup): a Runs today card — each run's start, its mode and its claims by result, from the same rows the reasons card reads, so no second query.""" today = datetime.combine(date.today(), datetime.min.time()) first, second = today + timedelta(hours=16, minutes=39), \ today + timedelta(hours=17, minutes=18) rows = ([_row("9000001", "Pass", 1, first), _row("9000002", "Fail", 2, first)] + [_row(f"900001{i}", "Pass", i, second) for i in range(3)]) client, repo = _client(FakeRepo(days=[_day(date.today(), 5, 2, 4, 1, 0)], rows=rows)) html = client.get("/").text box = html.split('id="runs-today"', 1)[1].split("", 1)[0] assert box.index("5:18 PM") < box.index("4:39 PM"), box assert "3 claims" in box and "2 claims" in box, box assert repo.calls == [("days",), ("day_results", date.today())], \ repo.calls @case def the_dashboard_greets_the_signed_in_user(): html = _client()[0].get("/").text assert re.search(r"Good (morning|afternoon|evening), ", html), html[:400] @case def every_page_has_the_footer_and_marks_where_you_are(): client, _ = _client() for path in _PAGES: html = client.get(path).text foot = html.split('