My Sea per-spread positions + draw-order JS config + position labels — Sprint 5 iter 3 follow-up — TDD
User-locked spec 2026-05-19: each three-card spread uses a DIFFERENT 3-position subset of the 6 surrounding positions, in its own draw order. Replaces the iter-3 binary `data-spread-shape="three-card|six-card"` model w. per-spread `data-spread="<value>"`. Closes iter 3 cleanly + scaffolds the draw-order data iter 4 will consume. Position subsets (per spread): PPF → leave (1) · cover (2) · loom (3) SAO → lay (1) · cover (2) · crown (3) MBS → crown (1) · lay (2) · loom (3) DOS → loom (1) · cross (2) · cover (3) Waite-Smith → all 6 surrounding (cover · cross · crown · lay · loom · leave) Escape Velocity → all 6 surrounding (cover · cross · lay · leave · crown · loom) All 6 cells continue to render in DOM unconditionally — `.my-sea-cross[data-spread="<value>"]` SCSS rules hide inactive positions per spread via `display: none`. Cover/cross live nested inside `.sea-pos-core` so their absolute-overlay positioning rules from `_card-deck.scss:1310-1331` carry over for free. **Position labels** (re-appropriated `.sea-stack-name` typography per user) — `.sea-pos-label` inside each empty `.sea-card-slot--empty` carries the per-spread caption. Server-renders SAO's labels by default (lay=Situation, cover=Action, crown=Outcome); JS swaps labels via `POSITION_LABELS[spread]` lookup on combobox change. Inactive-for-spread positions render their span w. empty `textContent` so JS only has to set text, never toggle visibility. Celtic Cross variants share the gameroom's existing position vocabulary (Crown/Beneath/Cover/Cross/Before/Behind). **DRAW_ORDER JS const** baked into the inline picker IIFE — array of position names per spread, ready for iter 4's deck-click-deposit logic to consume. Exposed via `window._mySeaDrawOrder` so iter-4 click handlers can `window._mySeaDrawOrder[currentSpread][nextSlotIdx]` to resolve the target position. No click handlers wired yet — iter 4 territory. **Selenium trap caught**: the combobox click-twice-on-the-toggle bug — re-clicking the combobox while `aria-expanded='true'` closes the dropdown (combobox.js's toggle behavior). Test 3's spread-cycling iterates through 6 spreads, each needs the dropdown OPEN before clicking a new option; added a `_pick(value)` helper that checks `aria-expanded` first. Files: - `templates/apps/gameboard/my_sea.html` — `.my-sea-cross[data-spread]` w. server-rendered default; each empty slot wraps a `<span class="sea-pos-label" data-position="<name>">` (SAO labels seeded inline, others empty initially); inline IIFE adds `DRAW_ORDER` + `POSITION_LABELS` consts + `syncLabels()` that swaps captions on `change`. - `static_src/scss/_gameboard.scss` — drops the `data-spread-shape="three-card"|"six-card"` rules; adds 4 per-spread visibility rules (PPF/SAO/MBS/DOS). Celtic Cross variants inherit the gameroom's full 3×3 grid w. no overrides. `.sea-pos-label` style mirrors `.sea-stack-name` from _card-deck.scss line 1557 (small-uppercase-letter-spaced-scaleY) sans the polarity color — these aren't deck identifiers, just spread-position captions. - `apps/gameboard/tests/integrated/test_views.py` — IT `test_cross_carries_initial_three_card_spread_shape` renamed + retargeted to `data-spread="situation-action-outcome"`; new IT `test_template_renders_sao_position_labels_on_default` pins the seeded SAO labels + empty spans for inactive positions. - `functional_tests/test_game_my_sea.py` — iter-2's `test_picker_hides_six_card_only_positions_by_default` renamed to `test_picker_renders_sao_default_position_subset` w. SAO-specific visibility expectations (lay/cover/crown visible; leave/loom/cross hidden). iter-3's `test_picking_celtic_cross_reveals_six_card_positions` rewritten + expanded to `test_picking_spread_swaps_data_spread_and_position_visibility` — cycles through all 6 spreads, asserts `data-spread` attribute + per-position `is_displayed()` for each. New `test_per_spread_position_labels_render_and_update` cycles through 5 spreads (SAO default + 4 switches) asserting captions match the spec. Tests: 33/33 FT green across test_bill_my_sign + test_game_my_sea; 1049/1049 IT/UT green in 52s. Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -695,9 +695,27 @@ class MySeaSpreadFormTemplateTest(TestCase):
|
||||
'data-value="situation-action-outcome" aria-selected="true"', html,
|
||||
)
|
||||
|
||||
def test_cross_carries_initial_three_card_spread_shape(self):
|
||||
def test_cross_carries_initial_data_spread_sao(self):
|
||||
# `.my-sea-cross[data-spread]` is the per-spread visibility key;
|
||||
# default-spread context value renders into the attribute. SCSS
|
||||
# rules in _gameboard.scss hide the inactive positions per spread.
|
||||
response = self.client.get(reverse("my_sea"))
|
||||
self.assertContains(response, 'data-spread-shape="three-card"')
|
||||
self.assertContains(response, 'data-spread="situation-action-outcome"')
|
||||
|
||||
def test_template_renders_sao_position_labels_on_default(self):
|
||||
# Server-renders the SAO position labels into the empty drop-zone
|
||||
# `.sea-pos-label` spans so the page is correct before JS boots.
|
||||
# JS swaps labels on spread change.
|
||||
response = self.client.get(reverse("my_sea"))
|
||||
html = response.content.decode()
|
||||
self.assertIn('data-position="lay">Situation</span>', html)
|
||||
self.assertIn('data-position="cover">Action</span>', html)
|
||||
self.assertIn('data-position="crown">Outcome</span>', html)
|
||||
# Inactive-for-SAO positions render their span but w. empty
|
||||
# textContent (JS fills them on spread switch).
|
||||
self.assertIn('data-position="leave"></span>', html)
|
||||
self.assertIn('data-position="loom"></span>', html)
|
||||
self.assertIn('data-position="cross"></span>', html)
|
||||
|
||||
def test_form_col_renders_decks_lock_hand_del_and_reversal_hint(self):
|
||||
response = self.client.get(reverse("my_sea"))
|
||||
|
||||
Reference in New Issue
Block a user