billboard applets: single-root wrapper for HTMX swap; full context on toggle — TDD
- _applets.html wraps menu + container in one #id_billboard_applets_wrapper div; form's hx-target is now the wrapper, so OK no longer leaves a stale duplicate menu in the DOM (which previously caused the next OK to revert prior toggles) - toggle_billboard_applets passes full context (recent_room, recent_events, viewer, my_rooms) via factored _billboard_context helper, so Most Recent + My Scrolls keep their content after a toggle instead of falling through to the empty fallback - applets.js: register id_billboard_applets_wrapper as an applet container so post-swap menu cleanup runs - BillboardAppletsTest: portrait viewport in setUp; FT covers content preservation, no-revert on second toggle, & post-refresh state - 4 new ITs: Most Recent renders Coin-on-a-String after toggle; My Scrolls renders room name; response has single menu div; second toggle preserves prior hidden state Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -198,6 +198,7 @@ class BillboardAppletsTest(FunctionalTest):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.browser.set_window_size(800, 1200)
|
||||
self.founder = User.objects.create(email="founder@test.io")
|
||||
self.room = Room.objects.create(name="Arcane Assembly", owner=self.founder)
|
||||
for slug, name, cols, rows in [
|
||||
@@ -248,6 +249,97 @@ class BillboardAppletsTest(FunctionalTest):
|
||||
self.browser.execute_script("arguments[0].click()", gear_btn)
|
||||
self.wait_for_slow(lambda: self.assertTrue(menu.is_displayed()))
|
||||
|
||||
def test_toggling_applets_keeps_content_and_persists_per_applet(self):
|
||||
# Seed an event so Most Recent renders prose, not the empty fallback
|
||||
record(
|
||||
self.room, GameEvent.SLOT_FILLED, actor=self.founder,
|
||||
slot_number=1, token_type="coin",
|
||||
token_display="Coin-on-a-String", renewal_days=7,
|
||||
)
|
||||
|
||||
self.create_pre_authenticated_session("founder@test.io")
|
||||
self.browser.get(self.live_server_url + "/billboard/")
|
||||
|
||||
# All three applets visible; Most Recent shows event prose, My Scrolls shows the room
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.ID, "id_applet_billboard_most_recent")
|
||||
)
|
||||
most_recent = self.browser.find_element(By.ID, "id_applet_billboard_most_recent")
|
||||
self.assertIn("Coin-on-a-String", most_recent.text)
|
||||
self.assertIn(
|
||||
"Arcane Assembly",
|
||||
self.browser.find_element(By.ID, "id_applet_billboard_my_scrolls").text,
|
||||
)
|
||||
|
||||
# Open gear, uncheck Contacts, click OK
|
||||
gear = self.browser.find_element(By.CSS_SELECTOR, ".billboard-page .gear-btn")
|
||||
self.browser.execute_script("arguments[0].click()", gear)
|
||||
menu = self.wait_for(
|
||||
lambda: self.browser.find_element(By.ID, "id_billboard_applet_menu")
|
||||
)
|
||||
contacts_cb = menu.find_element(
|
||||
By.CSS_SELECTOR, "input[value='billboard-my-contacts']"
|
||||
)
|
||||
self.browser.execute_script("arguments[0].click()", contacts_cb)
|
||||
menu.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
|
||||
|
||||
# Contacts is hidden; Most Recent + My Scrolls keep their content (bug #2)
|
||||
self.wait_for(
|
||||
lambda: self.assertEqual(
|
||||
self.browser.find_elements(By.ID, "id_applet_billboard_my_contacts"),
|
||||
[],
|
||||
)
|
||||
)
|
||||
most_recent = self.browser.find_element(By.ID, "id_applet_billboard_most_recent")
|
||||
self.assertIn("Coin-on-a-String", most_recent.text)
|
||||
self.assertIn(
|
||||
"Arcane Assembly",
|
||||
self.browser.find_element(By.ID, "id_applet_billboard_my_scrolls").text,
|
||||
)
|
||||
|
||||
# Second toggle: hide Most Recent. Contacts must NOT come back (bug #1)
|
||||
gear = self.browser.find_element(By.CSS_SELECTOR, ".billboard-page .gear-btn")
|
||||
self.browser.execute_script("arguments[0].click()", gear)
|
||||
menu = self.wait_for(
|
||||
lambda: self.browser.find_element(By.ID, "id_billboard_applet_menu")
|
||||
)
|
||||
# The freshly-rendered menu must reflect DB state (Contacts unchecked)
|
||||
contacts_cb = menu.find_element(
|
||||
By.CSS_SELECTOR, "input[value='billboard-my-contacts']"
|
||||
)
|
||||
self.assertFalse(contacts_cb.is_selected())
|
||||
most_recent_cb = menu.find_element(
|
||||
By.CSS_SELECTOR, "input[value='billboard-most-recent']"
|
||||
)
|
||||
self.browser.execute_script("arguments[0].click()", most_recent_cb)
|
||||
menu.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
|
||||
|
||||
# Most Recent gone; Contacts still hidden (the stale-form bug would re-show it)
|
||||
self.wait_for(
|
||||
lambda: self.assertEqual(
|
||||
self.browser.find_elements(By.ID, "id_applet_billboard_most_recent"),
|
||||
[],
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
self.browser.find_elements(By.ID, "id_applet_billboard_my_contacts"),
|
||||
[],
|
||||
)
|
||||
|
||||
# And after a hard refresh both stay hidden, menu reflects DB
|
||||
self.browser.refresh()
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.ID, "id_applet_billboard_my_scrolls")
|
||||
)
|
||||
self.assertEqual(
|
||||
self.browser.find_elements(By.ID, "id_applet_billboard_my_contacts"),
|
||||
[],
|
||||
)
|
||||
self.assertEqual(
|
||||
self.browser.find_elements(By.ID, "id_applet_billboard_most_recent"),
|
||||
[],
|
||||
)
|
||||
|
||||
|
||||
class BillscrollAppletsTest(FunctionalTest):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user