wired PICK SKY server-side polarity countdown via threading.Timer (tasks.py); fixed polarity_done overlay gating on refresh; cleared sig-select floats on overlay dismiss; filtered Redact events from Most Recent applet

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-04-13 00:34:05 -04:00
parent df421fb6c0
commit 32d8d97360
22 changed files with 1028 additions and 88 deletions

View File

@@ -101,7 +101,7 @@ class BillboardScrollTest(FunctionalTest):
self.assertIn("deposits a Free Token for slot 2 (expires in 7 days).", scroll.text)
# Role selection event is rendered as prose
self.assertIn("elects to start as the Player", scroll.text)
self.assertIn("assumes 1st Chair", scroll.text)
# ------------------------------------------------------------------ #
# Test 3 — current user's events are right-aligned; others' are left #
@@ -354,3 +354,149 @@ class BillscrollEntryLayoutTest(FunctionalTest):
# events[0] is the backdated record (oldest first, ascending order)
old_ts = events[0].find_element(By.CSS_SELECTOR, ".drama-event-time")
self.assertRegex(old_ts.text, r"\d{2}\s+[A-Z][a-z]{2}\s+\d{4}")
class BillscrollGearMenuTest(FunctionalTest):
"""
FT: the billscroll page has a gear menu that filters events by label.
Frame = all regular (non-struck) drama entries.
Redact = struck-through (retracted) entries, e.g. a WAIT NVM after TAKE SIG.
Scenario (one gamer, Role + Sig events):
1. Both labels checked by default — all events visible.
2. Uncheck Redact → OK: struck entries disappear.
3. Recheck Redact + uncheck Frame → OK: regular entries gone; struck
entries visible (but still render struck-through — they remain "redacted"
in the narrative sense).
4. Recheck Frame → OK: all entries return.
"""
def setUp(self):
super().setUp()
self.founder = User.objects.create(email="founder@geartest.io")
self.room = Room.objects.create(name="Gear Filter Room", owner=self.founder)
# Two Frame events — ROLE_SELECTED, non-struck
record(self.room, GameEvent.ROLE_SELECTED, actor=self.founder,
role="PC", slot_number=1, role_display="Player")
record(self.room, GameEvent.ROLE_SELECTED, actor=self.founder,
role="NC", slot_number=2, role_display="Narrator")
# Two Redact events — SIG_READY with retracted=True → event.struck is True
sig1 = record(self.room, GameEvent.SIG_READY, actor=self.founder,
card_name="The Wanderer", corner_rank="0", suit_icon="")
sig1.data["retracted"] = True
sig1.save(update_fields=["data"])
sig2 = record(self.room, GameEvent.SIG_READY, actor=self.founder,
card_name="Maid of Brands", corner_rank="M",
suit_icon="fa-wand-sparkles")
sig2.data["retracted"] = True
sig2.save(update_fields=["data"])
def _go_to_scroll(self):
self.create_pre_authenticated_session("founder@geartest.io")
self.browser.get(
self.live_server_url + f"/billboard/room/{self.room.id}/scroll/"
)
self.wait_for(
lambda: self.browser.find_element(By.ID, "id_drama_scroll")
)
def _open_gear(self):
"""Click the gear btn and return the now-visible menu element."""
gear = self.wait_for(
lambda: self.browser.find_element(
By.CSS_SELECTOR,
".gear-btn[data-menu-target='id_billscroll_menu']"
)
)
self.browser.execute_script("arguments[0].click()", gear)
return self.wait_for(
lambda: self.browser.find_element(By.ID, "id_billscroll_menu")
)
def _visible_events(self, label):
"""Count displayed .drama-event elements with the given data-label."""
els = self.browser.find_elements(
By.CSS_SELECTOR, f".drama-event[data-label='{label}']"
)
return sum(1 for e in els if e.is_displayed())
# ------------------------------------------------------------------ #
# Step 1 — gear menu opens; both labels present and pre-checked #
# ------------------------------------------------------------------ #
def test_gear_menu_shows_frame_and_redact_checkboxes(self):
self._go_to_scroll()
menu = self._open_gear()
self.assertTrue(menu.is_displayed())
frame_cb = menu.find_element(By.CSS_SELECTOR, "input[value='frame']")
redact_cb = menu.find_element(By.CSS_SELECTOR, "input[value='redact']")
self.assertTrue(frame_cb.is_selected())
self.assertTrue(redact_cb.is_selected())
self.assertIn("Frame", menu.text)
self.assertIn("Redact", menu.text)
# ------------------------------------------------------------------ #
# Steps 2 4 — filter flow #
# ------------------------------------------------------------------ #
def test_gear_menu_filter_flow(self):
self._go_to_scroll()
# Step 1: all 4 events visible (2 frame + 2 redact)
self.assertEqual(self._visible_events("frame"), 2)
self.assertEqual(self._visible_events("redact"), 2)
# Step 2: uncheck Redact → OK → struck entries disappear
menu = self._open_gear()
menu.find_element(By.CSS_SELECTOR, "input[value='redact']").click()
menu.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
self.wait_for(lambda: self.assertEqual(self._visible_events("redact"), 0))
self.assertEqual(self._visible_events("frame"), 2)
# Step 3: recheck Redact + uncheck Frame → OK
# Redact events re-appear (still struck-through); Frame events gone.
menu = self._open_gear()
menu.find_element(By.CSS_SELECTOR, "input[value='redact']").click() # recheck
menu.find_element(By.CSS_SELECTOR, "input[value='frame']").click() # uncheck
menu.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
self.wait_for(lambda: self.assertEqual(self._visible_events("frame"), 0))
self.assertEqual(self._visible_events("redact"), 2)
# Struck-through entries still carry the .struck class (visually "gone" in narrative)
redact_bodies = self.browser.find_elements(
By.CSS_SELECTOR, ".drama-event[data-label='redact'] .drama-event-body"
)
self.assertTrue(all("struck" in b.get_attribute("class") for b in redact_bodies))
# Step 4: recheck Frame → OK → all events return
menu = self._open_gear()
menu.find_element(By.CSS_SELECTOR, "input[value='frame']").click() # recheck
menu.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
self.wait_for(lambda: self.assertEqual(self._visible_events("frame"), 2))
self.assertEqual(self._visible_events("redact"), 2)
# ------------------------------------------------------------------ #
# Persistence — filter survives a full page reload #
# ------------------------------------------------------------------ #
def test_filter_selection_persists_across_refresh(self):
self._go_to_scroll()
# Uncheck Redact → OK: struck entries disappear
menu = self._open_gear()
menu.find_element(By.CSS_SELECTOR, "input[value='redact']").click()
menu.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
self.wait_for(lambda: self.assertEqual(self._visible_events("redact"), 0))
# Hard reload — same URL, same session cookie
self.browser.refresh()
self.wait_for(lambda: self.browser.find_element(By.ID, "id_drama_scroll"))
# Struck entries still absent after reload
self.wait_for(lambda: self.assertEqual(self._visible_events("redact"), 0))
self.assertEqual(self._visible_events("frame"), 2)
# Gear menu still shows Redact unchecked
menu = self._open_gear()
redact_cb = menu.find_element(By.CSS_SELECTOR, "input[value='redact']")
self.assertFalse(redact_cb.is_selected())