from django.urls import reverse from selenium.webdriver.common.by import By from apps.drama.models import GameEvent, record from apps.epic.models import Room from apps.lyric.models import User from .base import FunctionalTest def _guard_rect(browser): """Return the guard portal's bounding rect (reflects CSS transform).""" return browser.execute_script( "return document.getElementById('id_guard_portal').getBoundingClientRect().toJSON()" ) def _elem_rect(browser, element): """Return an element's bounding rect.""" return browser.execute_script( "return arguments[0].getBoundingClientRect().toJSON()", element ) class NavbarByeTest(FunctionalTest): """ The BYE btn-abandon replaces LOG OUT in the identity group. It should confirm before logging out and its tooltip must appear below the button (not above, which would be off-screen in the navbar). """ def setUp(self): super().setUp() self.create_pre_authenticated_session("disco@test.io") # ------------------------------------------------------------------ # # T1 — BYE btn present; "Log Out" text gone # # ------------------------------------------------------------------ # def test_bye_btn_replaces_log_out(self): self.browser.get(self.live_server_url) self.wait_for(lambda: self.browser.find_element(By.ID, "id_logout")) logout_btn = self.browser.find_element(By.ID, "id_logout") self.assertEqual(logout_btn.text, "BYE") self.assertIn("btn-abandon", logout_btn.get_attribute("class")) self.assertNotIn("btn-primary", logout_btn.get_attribute("class")) # Old "Log Out" text nowhere in navbar navbar = self.browser.find_element(By.CSS_SELECTOR, ".navbar") self.assertNotIn("Log Out", navbar.text) # ------------------------------------------------------------------ # # T2 — BYE tooltip appears below btn # # ------------------------------------------------------------------ # def test_bye_tooltip_appears_below_btn(self): self.browser.get(self.live_server_url) btn = self.wait_for( lambda: self.browser.find_element(By.ID, "id_logout") ) btn_rect = _elem_rect(self.browser, btn) # Click BYE — guard should become active self.browser.execute_script("arguments[0].click()", btn) self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, "#id_guard_portal.active" ) ) portal_rect = _guard_rect(self.browser) self.assertGreaterEqual( portal_rect["top"], btn_rect["bottom"] - 2, # 2 px tolerance for sub-pixel rounding "Guard portal should appear below the BYE btn, not above it", ) # ------------------------------------------------------------------ # # T3 — BYE btn logs out on confirm # # ------------------------------------------------------------------ # def test_bye_btn_logs_out_on_confirm(self): self.browser.get(self.live_server_url) btn = self.wait_for( lambda: self.browser.find_element(By.ID, "id_logout") ) self.browser.execute_script("arguments[0].click()", btn) self.confirm_guard() self.wait_for( lambda: self.browser.find_element(By.CSS_SELECTOR, "input[name=email]") ) navbar = self.browser.find_element(By.CSS_SELECTOR, ".navbar") self.assertNotIn("disco@test.io", navbar.text) # ------------------------------------------------------------------ # # T4 — No CONT GAME btn when user has no rooms with events # # ------------------------------------------------------------------ # def test_cont_game_btn_absent_without_recent_room(self): self.browser.get(self.live_server_url) self.wait_for( lambda: self.browser.find_element(By.ID, "id_logout") ) cont_game_btns = self.browser.find_elements(By.ID, "id_cont_game") self.assertEqual( len(cont_game_btns), 0, "CONT GAME btn should not appear when user has no rooms with events", ) class NavbarContGameTest(FunctionalTest): """ When the authenticated user has at least one room with a game event the CONT GAME btn-primary appears in the navbar and navigates to that room on confirmation. Its tooltip must also appear below the button. """ def setUp(self): super().setUp() self.create_pre_authenticated_session("disco@test.io") self.user = User.objects.get(email="disco@test.io") self.room = Room.objects.create(name="Arena of Peril", owner=self.user) record( self.room, GameEvent.SLOT_FILLED, actor=self.user, slot_number=1, token_type="coin", token_display="Coin-on-a-String", renewal_days=7, ) # ------------------------------------------------------------------ # # T5 — CONT GAME btn present when recent room exists # # ------------------------------------------------------------------ # def test_cont_game_btn_present(self): self.browser.get(self.live_server_url) self.wait_for( lambda: self.browser.find_element(By.ID, "id_cont_game") ) btn = self.browser.find_element(By.ID, "id_cont_game") self.assertIn("btn-primary", btn.get_attribute("class")) # ------------------------------------------------------------------ # # T6 — CONT GAME tooltip appears below btn # # ------------------------------------------------------------------ # def test_cont_game_tooltip_appears_below_btn(self): self.browser.get(self.live_server_url) btn = self.wait_for( lambda: self.browser.find_element(By.ID, "id_cont_game") ) btn_rect = _elem_rect(self.browser, btn) self.browser.execute_script("arguments[0].click()", btn) self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, "#id_guard_portal.active" ) ) portal_rect = _guard_rect(self.browser) self.assertGreaterEqual( portal_rect["top"], btn_rect["bottom"] - 2, "Guard portal should appear below the CONT GAME btn, not above it", ) # ------------------------------------------------------------------ # # T7 — CONT GAME navigates to the room on confirm # # ------------------------------------------------------------------ # def test_cont_game_navigates_to_room_on_confirm(self): self.browser.get(self.live_server_url) btn = self.wait_for( lambda: self.browser.find_element(By.ID, "id_cont_game") ) self.browser.execute_script("arguments[0].click()", btn) self.confirm_guard() self.wait_for( lambda: self.assertIn(str(self.room.id), self.browser.current_url) )