r""" conditions/j2930_j2001_update.py — document condition #5 (CPT `J2930 & J2001`): both codes get the same treatment, uncheck + zero the Billed Fee. See that module's own docstring for why J2930 is NOT replaced with J2919 despite the document's wording — the client corrected an earlier build that attempted the replacement. python tests\test_conditions_j2930_j2001_update.py Uses hcfa_claim.html: this is the screen the checkbox/fee primitive (`zero_and_uncheck_cpt_rows`) is actually verified against (see test_hcfa_claim.py's own note on ub_claim.html's checkboxes carrying no ng-click at all). Neither J2001 nor J2930 has a row of its own in that fixture, so `_inject_cpt_row()` adds one for whichever code a case needs, the same way the other condition test files inject their own rows, rather than growing the shared fixture. """ import sys import pathlib import inspect ROOT = pathlib.Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "src")) FIXTURE = pathlib.Path(__file__).resolve().parent / "fixtures" / "hcfa_claim.html" from ecw_bot.conditions import j2930_j2001_update # noqa: E402 from ecw_bot.conditions.base import ConditionResult, run_all # noqa: E402 from ecw_bot.pages import claim_form # noqa: E402 from ecw_bot.selectors import claim_form as sel # noqa: E402 CASES = [] def case(fn): CASES.append(fn) return fn def _inject_cpt_row(page, code, row_id="CPTROW_3", checked=True, fee="45.00"): page.evaluate( """(args) => { const tbody = document.querySelector( '#claimCPTCodesTable8888888888888 tbody'); const addRowTr = tbody.querySelector('tr:last-child'); const tr = document.createElement('tr'); tr.id = args.rowId; tr.innerHTML = '' + '' + ''; tbody.insertBefore(tr, addRowTr); }""", {"code": code, "rowId": row_id, "checked": checked, "fee": fee}) def _inject_j2001_row(page, checked=True, fee="45.00"): _inject_cpt_row(page, "J2001", checked=checked, fee=fee) @case def detect_true_when_j2001_is_on_the_claim(): data = {"cpt": [{"code": "99213"}, {"code": "J2001"}]} assert j2930_j2001_update.detect("C1", data) is True @case def detect_false_when_j2001_is_absent(): data = {"cpt": [{"code": "99213"}, {"code": "J7298"}]} assert j2930_j2001_update.detect("C1", data) is False @case def detect_true_when_j2930_is_on_the_claim_alone(): data = {"cpt": [{"code": "J2930"}]} assert j2930_j2001_update.detect("C1", data) is True @case def detect_ignores_case_and_spaces_like_the_helper_does(): """ Review, 2026-10-12: zero_and_uncheck_cpt_rows() matches ignoring case, so detect() must too — or a "j2001" is never excluded. """ for code in ("j2001", " J2930 ", "j2930"): data = {"cpt": [{"code": code}]} assert j2930_j2001_update.detect("C1", data) is True, code @case def detect_false_with_no_cpt_key_at_all(): assert j2930_j2001_update.detect("C1", {}) is False @case def apply_unchecks_and_zeroes_j2001_only(page): page.goto(FIXTURE.as_uri()) _inject_j2001_row(page, checked=True, fee="45.00") data = {"cpt": [{"code": "J2001"}]} result = j2930_j2001_update.apply(page, "9103000", data) assert isinstance(result, ConditionResult) assert result.condition_name == "j2930_j2001_update" assert result.changed is True assert len(result.changes) == 1, result.changes c = result.changes[0] assert c["code"] == "J2001", c assert c["unchecked"] is True, c assert c["fee"] == {"before": "45.00", "after": "0.00"}, c j2001_row = page.locator(sel.SEL_CPT_ROWS).nth(3) assert j2001_row.locator(sel.SEL_CPT_ASSIGN_TO_PATIENT).first.is_checked() is False assert j2001_row.locator(sel.SEL_CPT_BILLED_FEE).first.input_value() == "0.00" row0_fee = page.locator(sel.SEL_CPT_ROWS).nth(0).locator( sel.SEL_CPT_BILLED_FEE).first assert row0_fee.input_value() == "210.00", \ "99213 must be left alone — only J2001 is targeted" @case def apply_unchecks_and_zeroes_j2930_the_same_way(page): """ The client's correction, proven directly: J2930 gets exactly the same uncheck + zero-fee treatment as J2001 — no row removal, no J2919 ever added. """ page.goto(FIXTURE.as_uri()) _inject_cpt_row(page, "J2930", checked=True, fee="120.00") data = {"cpt": [{"code": "J2930"}]} result = j2930_j2001_update.apply(page, "9103000", data) assert result.changed is True assert len(result.changes) == 1, result.changes c = result.changes[0] assert c["code"] == "J2930", c assert c["unchecked"] is True, c assert c["fee"] == {"before": "120.00", "after": "0.00"}, c assert claim_form.cpt_code_present(page, "J2930"), \ "J2930's row must still exist — unchecked/zeroed, never removed" @case def apply_handles_both_codes_on_the_same_claim(page): page.goto(FIXTURE.as_uri()) _inject_cpt_row(page, "J2001", row_id="CPTROW_3", checked=True, fee="45.00") _inject_cpt_row(page, "J2930", row_id="CPTROW_4", checked=True, fee="120.00") data = {"cpt": [{"code": "J2001"}, {"code": "J2930"}]} result = j2930_j2001_update.apply(page, "9103000", data) assert result.changed is True by_code = {c["code"]: c for c in result.changes} assert set(by_code) == {"J2001", "J2930"}, result.changes assert by_code["J2001"]["fee"]["after"] == "0.00", by_code assert by_code["J2930"]["fee"]["after"] == "0.00", by_code row0_fee = page.locator(sel.SEL_CPT_ROWS).nth(0).locator( sel.SEL_CPT_BILLED_FEE).first assert row0_fee.input_value() == "210.00", \ "99213 must be left alone — neither target code" @case def apply_is_a_no_op_once_j2001_is_already_excluded(page): page.goto(FIXTURE.as_uri()) _inject_j2001_row(page, checked=False, fee="0.00") data = {"cpt": [{"code": "J2001"}]} result = j2930_j2001_update.apply(page, "9103000", data) assert result.changed is False assert result.changes == [] @case def apply_is_a_no_op_when_j2001_is_not_on_the_claim(page): page.goto(FIXTURE.as_uri()) data = {"cpt": [{"code": "99213"}]} result = j2930_j2001_update.apply(page, "9103000", data) assert result.changed is False assert result.changes == [] @case def describe_names_j2001_and_the_fee_change(page): page.goto(FIXTURE.as_uri()) _inject_j2001_row(page, checked=True, fee="45.00") data = {"cpt": [{"code": "J2001"}]} result = j2930_j2001_update.apply(page, "9103000", data) text = j2930_j2001_update.describe(result) assert "J2001" in text, text assert "45.00" in text and "0.00" in text, text @case def run_all_fires_j2930_j2001_update_alongside_others_independently(page): """ Against the REAL registry, not fakes — proves this condition is wired into conditions.CONDITIONS and does not collide with the depression-DX or telehealth conditions, which key off icd/progress_notes, not cpt. """ page.goto(FIXTURE.as_uri()) _inject_j2001_row(page, checked=True, fee="45.00") data = {"cpt": [{"code": "J2001"}]} results = run_all(page, "9103000", data) assert len(results) == 1, results assert results[0].condition_name == "j2930_j2001_update", results def main() -> int: if not FIXTURE.exists(): print(f" FAIL fixture missing: {FIXTURE}") return 1 try: from playwright.sync_api import sync_playwright except ImportError: print(" SKIP playwright is not installed") return 0 failures = 0 with sync_playwright() as pw: browser = pw.chromium.launch(headless=True) page = browser.new_page() for fn in CASES: name = fn.__name__.replace("_", " ") try: if len(inspect.signature(fn).parameters) == 0: fn() else: fn(page) print(f" ok {name}") except AssertionError as exc: print(f" FAIL {name}: {exc}") failures += 1 except Exception as exc: print(f" ERROR {name}: {type(exc).__name__}: {exc}") failures += 1 browser.close() print(f"\n{len(CASES) - failures}/{len(CASES)} passed") return 1 if failures else 0 if __name__ == "__main__": sys.exit(main())