My Sea iter 6c: bud-btn invite stub + #id_my_sea_menu gear (NVM-only, %applet-menu-styled, on both /gameboard/my-sea/ and the gatekeeper) + PAID DRAW now deletes the row and redirects to ?phase=picker so the user drops straight into picking cards instead of looping back to GATE VIEW — Sprint 5 iter 6c of My Sea roadmap — TDD
Bundled fix for the PAID-DRAW-loops-to-GATE-VIEW bug surfaced 2026-05-20 in live testing: previously the view reset `created_at = now()` + cleared the hand, but the row's continued existence meant `quota_spent=True` on the next render → landing rendered GATE VIEW → user clicked it → back to gatekeeper → loop. Now PAID DRAW does `active_draw.delete()` after debiting the token + then redirects to `/gameboard/my-sea/?phase=picker`. The my_sea view honors `?phase=picker` (only when no active_draw exists — can't bypass post-DEL GATE VIEW) by forcing `show_picker=True` so the user lands in the picker ready to draw. First card draw creates a fresh row w. fresh `created_at`, starting the new 24h quota cycle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1561,3 +1561,98 @@ class MySeaBudBtnStubTest(FunctionalTest):
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, ".note-banner")
|
||||
)
|
||||
self.assertIn("coming soon", brief.text.lower())
|
||||
|
||||
|
||||
class MySeaGearBtnTest(FunctionalTest):
|
||||
"""Sprint 6 iter 6c — `.gear-btn` on every my-sea page state
|
||||
(landing / picker / gatekeeper). Opens a NVM-only menu (DEL/BYE
|
||||
deliberately omitted — gear is for "back out without committing");
|
||||
NVM nav-backs to /gameboard/ mirroring the room's gear-menu
|
||||
convention. Same partial included on both /gameboard/my-sea/ and
|
||||
/gameboard/my-sea/gate/ so visual + behavior is identical."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
_seed_earthman_sig_pile()
|
||||
_seed_gameboard_applets()
|
||||
self.email = "gear@test.io"
|
||||
self.gamer = User.objects.create(email=self.email)
|
||||
_assign_sig(self.gamer)
|
||||
# Seed a quota row so the gatekeeper has an active_draw context.
|
||||
from apps.gameboard.models import MySeaDraw
|
||||
MySeaDraw.objects.create(
|
||||
user=self.gamer, spread="situation-action-outcome",
|
||||
significator_id=self.gamer.significator_id, hand=[],
|
||||
)
|
||||
|
||||
def test_gear_btn_renders_on_gatekeeper(self):
|
||||
self.create_pre_authenticated_session(self.email)
|
||||
self.browser.get(self.live_server_url + "/gameboard/my-sea/gate/")
|
||||
gear = self.wait_for(
|
||||
lambda: self.browser.find_element(
|
||||
By.CSS_SELECTOR, ".my-sea-page .gear-btn"
|
||||
)
|
||||
)
|
||||
# Menu wired via data-menu-target.
|
||||
self.assertEqual(
|
||||
gear.get_attribute("data-menu-target"),
|
||||
"id_my_sea_menu",
|
||||
)
|
||||
|
||||
def test_gear_btn_renders_on_landing_without_active_draw(self):
|
||||
"""User direction 2026-05-20 — gear stays on /gameboard/my-sea/
|
||||
even when no gatekeeper / no active_draw row exists. Fresh user
|
||||
with a sig + no draw lands here + still sees the gear."""
|
||||
from apps.gameboard.models import MySeaDraw
|
||||
MySeaDraw.objects.filter(user=self.gamer).delete()
|
||||
self.create_pre_authenticated_session(self.email)
|
||||
self.browser.get(self.live_server_url + "/gameboard/my-sea/")
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(
|
||||
By.CSS_SELECTOR, ".my-sea-page .gear-btn"
|
||||
)
|
||||
)
|
||||
|
||||
def test_gear_btn_opens_menu_with_nvm_only(self):
|
||||
self.create_pre_authenticated_session(self.email)
|
||||
self.browser.get(self.live_server_url + "/gameboard/my-sea/gate/")
|
||||
gear = self.wait_for(
|
||||
lambda: self.browser.find_element(
|
||||
By.CSS_SELECTOR, ".my-sea-page .gear-btn"
|
||||
)
|
||||
)
|
||||
gear.click()
|
||||
menu = self.wait_for(
|
||||
lambda: self.browser.find_element(By.ID, "id_my_sea_menu")
|
||||
)
|
||||
self.assertEqual(menu.value_of_css_property("display"), "block")
|
||||
# NVM link present, DEL + BYE deliberately absent.
|
||||
nvm = menu.find_element(By.CSS_SELECTOR, ".btn-cancel")
|
||||
self.assertIn("/gameboard/", nvm.get_attribute("href"))
|
||||
self.assertEqual(
|
||||
len(menu.find_elements(By.CSS_SELECTOR, ".btn-danger")), 0,
|
||||
)
|
||||
self.assertEqual(
|
||||
len(menu.find_elements(By.CSS_SELECTOR, ".btn-abandon")), 0,
|
||||
)
|
||||
|
||||
def test_nvm_navigates_back_to_gameboard(self):
|
||||
self.create_pre_authenticated_session(self.email)
|
||||
self.browser.get(self.live_server_url + "/gameboard/my-sea/gate/")
|
||||
gear = self.wait_for(
|
||||
lambda: self.browser.find_element(
|
||||
By.CSS_SELECTOR, ".my-sea-page .gear-btn"
|
||||
)
|
||||
)
|
||||
gear.click()
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.ID, "id_my_sea_menu")
|
||||
)
|
||||
self.browser.find_element(
|
||||
By.CSS_SELECTOR, "#id_my_sea_menu .btn-cancel"
|
||||
).click()
|
||||
self.wait_for(
|
||||
lambda: self.assertRegex(
|
||||
self.browser.current_url, r"/gameboard/$"
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user