"""FTs for the My Sea standalone page sign-gate. Sprint 4b of [[project-my-sea-roadmap]]. The /gameboard/my-sea/ page is gated behind sig selection — when `user.significator` is None, render a Look!-formatted Brief-style line w. FYI (→ /billboard/my-sign/) + BACK (→ /gameboard/) instead of the draw UX. The My Sea applet on /gameboard/ mirrors the gate hint in its empty-state slot. """ from selenium.webdriver.common.by import By from .base import FunctionalTest from .sig_page import _assign_sig, _seed_earthman_sig_pile from apps.applets.models import Applet from apps.epic.models import personal_sig_cards from apps.lyric.models import User def _seed_gameboard_applets(): """My Sea + the rest of the gameboard applets so /gameboard/ renders without missing-applet errors during the applet-side assertions. Mirrors the migration seed (0003 + 0008) — every slug must have a matching _applet-.html partial under apps/gameboard/_partials/.""" for slug, name, cols, rows, ctx in [ ("my-sea", "My Sea", 12, 4, "gameboard"), ("game-kit", "Game Kit", 4, 3, "gameboard"), ("new-game", "New Game", 4, 3, "gameboard"), ("my-games", "My Games", 4, 4, "gameboard"), ]: Applet.objects.get_or_create( slug=slug, defaults={"name": name, "context": ctx, "default_visible": True, "grid_cols": cols, "grid_rows": rows}, ) class MySeaSignGateTest(FunctionalTest): """Sign-gate UX on the standalone /gameboard/my-sea/ page + the /gameboard/ My Sea applet. User without a saved sig sees a Look!- formatted nudge w. FYI to the picker + BACK to the gameboard.""" def setUp(self): super().setUp() _seed_earthman_sig_pile() _seed_gameboard_applets() self.email = "sea@test.io" self.gamer = User.objects.create(email=self.email) sig_pile = personal_sig_cards(self.gamer) self.target_card = sig_pile[0] if sig_pile else None self.assertIsNotNone( self.target_card, "personal_sig_cards(user) returned no cards — check Earthman seed", ) # ── Test 1 ─────────────────────────────────────────────────────────────── def test_no_sig_renders_lookline_gate_on_standalone_page(self): """User without significator → /gameboard/my-sea/ shows the Look!- formatted Brief-style line w. the gate copy + FYI + BACK buttons.""" self.create_pre_authenticated_session(self.email) self.browser.get(self.live_server_url + "/gameboard/my-sea/") gate = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, ".my-sea-sign-gate" ) ) text = gate.text self.assertIn("Look!", text) self.assertIn("pick your sign", text.lower()) self.assertIn("drawing the Sea", text) # FYI + BACK action buttons fyi = gate.find_element(By.CSS_SELECTOR, ".my-sea-sign-gate__fyi") self.assertTrue(fyi.is_displayed()) back = gate.find_element(By.CSS_SELECTOR, ".my-sea-sign-gate__back") self.assertTrue(back.is_displayed()) # ── Test 2 ─────────────────────────────────────────────────────────────── def test_gate_fyi_links_to_my_sign_picker(self): """FYI button is an `` pointing at /billboard/my-sign/.""" self.create_pre_authenticated_session(self.email) self.browser.get(self.live_server_url + "/gameboard/my-sea/") fyi = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, ".my-sea-sign-gate__fyi" ) ) href = fyi.get_attribute("href") or "" self.assertTrue( href.endswith("/billboard/my-sign/"), f"FYI should link to /billboard/my-sign/, got {href!r}", ) # ── Test 3 ─────────────────────────────────────────────────────────────── def test_gate_back_links_to_gameboard(self): """BACK button is an `` pointing at /gameboard/.""" self.create_pre_authenticated_session(self.email) self.browser.get(self.live_server_url + "/gameboard/my-sea/") back = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, ".my-sea-sign-gate__back" ) ) href = back.get_attribute("href") or "" self.assertTrue( href.endswith("/gameboard/"), f"BACK should link to /gameboard/, got {href!r}", ) # ── Test 4 ─────────────────────────────────────────────────────────────── def test_with_sig_skips_gate_and_renders_draw_shell(self): """User w. saved significator → no .my-sea-sign-gate on the page; draw shell renders normally (Sprint 3 placeholder).""" _assign_sig(self.gamer, self.target_card) 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") ) self.assertEqual( len(self.browser.find_elements(By.CSS_SELECTOR, ".my-sea-sign-gate")), 0, "Gate should not render when user has a saved significator", ) # ── Test 5 ─────────────────────────────────────────────────────────────── def test_no_sig_applet_mirrors_gate_with_fyi_link(self): """On /gameboard/, the My Sea applet's empty state shows the same Look!-formatted gate w. FYI link to /billboard/my-sign/ when the user has no significator. Provides a consistent UX across surfaces.""" self.create_pre_authenticated_session(self.email) self.browser.get(self.live_server_url + "/gameboard/") applet_gate = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, "#id_applet_my_sea .my-sea-sign-gate" ) ) self.assertIn("Look!", applet_gate.text) fyi = applet_gate.find_element(By.CSS_SELECTOR, ".my-sea-sign-gate__fyi") href = fyi.get_attribute("href") or "" self.assertTrue(href.endswith("/billboard/my-sign/")) # ── Test 6 ─────────────────────────────────────────────────────────────── def test_with_sig_applet_renders_default_empty_state(self): """Applet w. saved sig → no gate, empty-state placeholder (until Sprint 7 wires up the latest-draw rendering).""" _assign_sig(self.gamer, self.target_card) self.create_pre_authenticated_session(self.email) self.browser.get(self.live_server_url + "/gameboard/") self.wait_for( lambda: self.browser.find_element(By.CSS_SELECTOR, "#id_applet_my_sea") ) self.assertEqual( len(self.browser.find_elements( By.CSS_SELECTOR, "#id_applet_my_sea .my-sea-sign-gate" )), 0, )