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:
@@ -124,6 +124,71 @@ class ToggleBillboardAppletsTest(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "apps/billboard/_partials/_applets.html")
|
||||
|
||||
def test_htmx_toggle_response_renders_most_recent_with_real_events(self):
|
||||
# Seed a room + event so Most Recent should render prose, not the empty fallback.
|
||||
room = Room.objects.create(name="Sound Chamber", owner=self.user)
|
||||
record(
|
||||
room, GameEvent.SLOT_FILLED, actor=self.user,
|
||||
slot_number=1, token_type="coin",
|
||||
token_display="Coin-on-a-String", renewal_days=7,
|
||||
)
|
||||
response = self.client.post(
|
||||
reverse("billboard:toggle_applets"),
|
||||
{"applets": [
|
||||
"billboard-my-scrolls",
|
||||
"billboard-my-contacts",
|
||||
"billboard-most-recent",
|
||||
]},
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Coin-on-a-String")
|
||||
# And My Scrolls renders the room name (needs my_rooms in context).
|
||||
self.assertContains(response, "Sound Chamber")
|
||||
|
||||
def test_htmx_toggle_response_has_single_applet_menu_div(self):
|
||||
# The response is hx-swapped into the page; if it contains both the menu
|
||||
# div and the applets-container div, the original menu remains and the
|
||||
# next gear-click resurrects stale form state. Response must contain the
|
||||
# menu exactly once (the wrapper) — never two siblings of the same id.
|
||||
response = self.client.post(
|
||||
reverse("billboard:toggle_applets"),
|
||||
{"applets": ["billboard-my-scrolls"]},
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
body = response.content.decode("utf-8")
|
||||
self.assertEqual(body.count('id="id_billboard_applet_menu"'), 1)
|
||||
|
||||
def test_second_toggle_preserves_prior_hidden_state(self):
|
||||
# First toggle: hide Contacts only.
|
||||
self.client.post(
|
||||
reverse("billboard:toggle_applets"),
|
||||
{"applets": [
|
||||
"new-post", "my-posts",
|
||||
"billboard-my-scrolls",
|
||||
"billboard-most-recent",
|
||||
]},
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
# Second toggle: hide Most Recent additionally — Contacts must stay hidden.
|
||||
self.client.post(
|
||||
reverse("billboard:toggle_applets"),
|
||||
{"applets": [
|
||||
"new-post", "my-posts",
|
||||
"billboard-my-scrolls",
|
||||
]},
|
||||
HTTP_HX_REQUEST="true",
|
||||
)
|
||||
from apps.applets.models import UserApplet
|
||||
contacts = Applet.objects.get(slug="billboard-my-contacts")
|
||||
most_recent = Applet.objects.get(slug="billboard-most-recent")
|
||||
self.assertFalse(
|
||||
UserApplet.objects.get(user=self.user, applet=contacts).visible
|
||||
)
|
||||
self.assertFalse(
|
||||
UserApplet.objects.get(user=self.user, applet=most_recent).visible
|
||||
)
|
||||
|
||||
|
||||
class BillscrollViewTest(TestCase):
|
||||
def setUp(self):
|
||||
|
||||
Reference in New Issue
Block a user