my-sea: second spectate broadcast — seat ring updates live on deposit / BYE — TDD

Extends the async-witness WS so a visitor joining (deposit) or leaving (BYE)
pushes the seat ring to the other watchers — they see members come + go without
a refresh, same channel as the live draw.

- views.py: `_my_sea_seats(owner)` extracted (owner 1C + present invitees 2C-6C
  by deposit order, sans per-viewer is_self) — used by BOTH the my_sea_visit
  render (layers is_self on) AND a new guarded `_notify_sea_seats(owner_id)`
  broadcast. Fired from my_sea_visit_insert_token (seat taken) +
  my_sea_visit_leave (seat freed).
- consumers.py: MySeaSpectateConsumer gains a `sea_seats` handler.
- my_sea_visit.html: the WS client re-renders the `.table-seat` ring from a
  `sea_seats` message, re-marking the viewer's own --self chair via the embedded
  seat token + re-firing the one-shot seated glow (localStorage-gated).

Tests: +1 channels relay IT (sea_seats received) + 2 view ITs (deposit / BYE
each broadcast the ring). Existing multi-seat ITs stay green on the refactored
helper. Client re-render needs live 3-party verification on staging.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-05-29 23:42:22 -04:00
parent 32836704b7
commit 0693a422d2
5 changed files with 130 additions and 23 deletions

View File

@@ -79,3 +79,16 @@ class MySeaSpectateConsumerTest(TransactionTestCase):
msg = await comm.receive_json_from()
self.assertEqual(msg, {"type": "sea_draw", "hand": hand})
await comm.disconnect()
async def test_present_invitee_receives_seat_updates(self):
await database_sync_to_async(self._invite)(present=True)
comm = self._comm(self.bud)
connected, _ = await comm.connect()
self.assertTrue(connected)
from channels.layers import get_channel_layer
seats = [{"n": 1, "label": "1C", "present": True, "token": "owner-x"}]
await get_channel_layer().group_send(
f"mysea_{self.owner.id}", {"type": "sea_seats", "seats": seats})
msg = await comm.receive_json_from()
self.assertEqual(msg, {"type": "sea_seats", "seats": seats})
await comm.disconnect()