Adds more bill status visibility to the dashboard
This commit is contained in:
1 parent
a104685daf
commit
1919d43bf0
6 files changed
+360
-10
No files matched your search
@@ -0,0 +1,110 @@
|
||||
"""Tests for ``scraper.dashboard.bill_status`` — the "why is this bill here?"
|
||||
classifier (API_CONTRACT §5 "upcoming" item 2: a bill should not be a vague
|
||||
"pending" when its floor history already shows a terminal / current state).
|
||||
|
||||
Pure, no DB: ``derive_status(description)`` -> ``{status, reason,
|
||||
possibly_closed}``. The *latest* matching action in the chronological log wins;
|
||||
the contract's "default to including, flag possibly_closed" applies when the
|
||||
source can't disambiguate.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from scraper.dashboard import bill_status
|
||||
from scraper.dashboard.bill_status import derive_status, is_closed
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# the motivating case: a passed bill sitting in "unfinished business"
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_awaiting_concurrence_in_senate_amendments_is_open():
|
||||
# AB1099: passed the Assembly, now awaiting Senate-amendment concurrence.
|
||||
r = derive_status(
|
||||
"Vote required: 41 2026 Aug. 30 - Read third time. Passed. "
|
||||
"Ordered to the Assembly. (Ayes 39. Noes 0.). Aug. 30 - In Assembly. "
|
||||
"Concurrence in Senate amendments pending. View Details",
|
||||
"AB 1099")
|
||||
assert r["status"] == "open"
|
||||
assert "concurrence" in r["reason"].lower()
|
||||
assert r["possibly_closed"] is False
|
||||
assert not is_closed(r)
|
||||
|
||||
|
||||
def test_passed_is_not_terminal_but_closed_terms_are():
|
||||
# "Passed" (one chamber) is an in-progress step -> open, not dropped.
|
||||
passed = derive_status("Read third time. Passed. Ordered to the Assembly.",
|
||||
"AB 1")
|
||||
assert passed["status"] == "open"
|
||||
|
||||
# "To inactive file" is a terminal/acted state -> closed, possibly_closed.
|
||||
inact = derive_status("2026 Aug. 25 - To inactive file on motion of "
|
||||
"Assembly Member Jackson. View Details", "AB 2")
|
||||
assert inact["status"] == "closed"
|
||||
assert inact["possibly_closed"] is True
|
||||
assert is_closed(inact)
|
||||
assert "inactive" in inact["reason"].lower()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# latest-action-wins + priority
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_latest_action_in_log_wins():
|
||||
# A bill that passed long ago but now has "Motion to reconsider
|
||||
# continued" surfaces the *current* reconsideration state, not the old pass.
|
||||
r = derive_status(
|
||||
"2025 Sep. 13 - Read third time. Passed. Ordered to the Assembly. "
|
||||
"Sep. 13 - In Assembly. Assembly refused to concur in Senate "
|
||||
"amendments. (Ayes 34. Noes 27.) Motion to reconsider on the next "
|
||||
"legislative day made. ... 2026 Aug. 30 - Motion to reconsider "
|
||||
"continued. View Details",
|
||||
"AB 1231")
|
||||
assert "reconsider" in r["reason"].lower()
|
||||
assert r["status"] == "open"
|
||||
|
||||
|
||||
def test_priority_breates_ties_on_same_span():
|
||||
# "Motion to reconsider" must win over a bare "passed" even though both
|
||||
# match; the specific/current fact dominates.
|
||||
r = derive_status("Passed. Motion to reconsider made.", "AB 1")
|
||||
assert "reconsider" in r["reason"].lower()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# unknown / content-free -> default to including + flag (API_CONTRACT §5)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_content_free_defaults_to_unknown_and_flags():
|
||||
# A bare dated line with no action text -> "On file", never a false pass.
|
||||
r = derive_status("Vote required: 41 2026 May 27 - View Details", "AB 3")
|
||||
assert r["status"] == "unknown"
|
||||
assert r["possibly_closed"] is None # can't confirm -> not asserted open
|
||||
assert "on file" in r["reason"].lower()
|
||||
|
||||
|
||||
def test_empty_description_is_unknown_not_crash():
|
||||
for text in (None, "", " "):
|
||||
r = derive_status(text, "AB 4")
|
||||
assert r["status"] == "unknown"
|
||||
assert r["possibly_closed"] is None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# a few more real-world terminal / open signals
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_engrossed_and_withdrawn_are_closed():
|
||||
assert is_closed(derive_status("Engrossed. View Details", "AB 5"))
|
||||
assert is_closed(derive_status("Withdrawn from committee. View Details",
|
||||
"AB 6"))
|
||||
|
||||
|
||||
def test_in_committee_and_scheduled_hearing_are_open():
|
||||
assert derive_status("Referred to Com. on Health. View Details", "AB 7")["status"] == "open"
|
||||
assert derive_status("June 17 - Set for first hearing. View Details",
|
||||
"AB 8")["status"] == "open"
|
||||
|
||||
|
||||
def test_return_shape_is_stable():
|
||||
r = derive_status("Pending. View Details", "AB 9")
|
||||
assert set(r.keys()) == {"status", "reason", "possibly_closed"}
|
||||
Reference in new issue
Block a user