117 lines
4.9 KiB
Python
117 lines
4.9 KiB
Python
|
|
"""FT for the gatekeeper invite via #id_bud_btn slide-out.
|
||
|
|
|
||
|
|
Replaces the legacy inline `<form action="invite_gamer">` panel inside
|
||
|
|
the gatekeeper modal. The bud-btn lives at the upper-right corner of
|
||
|
|
the right sidebar (footer in landscape); slide-out hosts the email/
|
||
|
|
username field + OK btn. Submit fires async POST to
|
||
|
|
epic:invite_gamer w. Accept: application/json — server returns
|
||
|
|
{brief, recipient_display}, JS shows the slide-down Brief banner.
|
||
|
|
"""
|
||
|
|
from selenium.webdriver.common.by import By
|
||
|
|
|
||
|
|
from apps.billboard.models import Brief
|
||
|
|
from apps.epic.models import Room, RoomInvite
|
||
|
|
from apps.lyric.models import User
|
||
|
|
|
||
|
|
from .base import FunctionalTest
|
||
|
|
|
||
|
|
|
||
|
|
class GatekeeperBudBtnPresenceTest(FunctionalTest):
|
||
|
|
"""The bud-btn renders for the room owner during gate phase, and is
|
||
|
|
absent for non-owners (friend invites are owner-only)."""
|
||
|
|
|
||
|
|
def setUp(self):
|
||
|
|
super().setUp()
|
||
|
|
self.owner = User.objects.create(email="owner@test.io", username="owner")
|
||
|
|
self.gamer = User.objects.create(email="gamer@test.io", username="gamer")
|
||
|
|
self.room = Room.objects.create(name="Bingobango", owner=self.owner)
|
||
|
|
self.room_url = f"{self.live_server_url}/gameboard/room/{self.room.id}/gate/"
|
||
|
|
|
||
|
|
def test_bud_btn_renders_for_owner(self):
|
||
|
|
self.create_pre_authenticated_session("owner@test.io")
|
||
|
|
self.browser.get(self.room_url)
|
||
|
|
self.wait_for(lambda: self.browser.find_element(By.ID, "id_bud_btn"))
|
||
|
|
|
||
|
|
def test_bud_btn_absent_for_non_owner(self):
|
||
|
|
# A registered non-owner viewer doesn't see the invite affordance.
|
||
|
|
self.create_pre_authenticated_session("gamer@test.io")
|
||
|
|
self.browser.get(self.room_url)
|
||
|
|
# Gatekeeper-specific element confirms page rendered
|
||
|
|
self.wait_for(lambda: self.browser.find_element(By.CSS_SELECTOR, ".gate-modal"))
|
||
|
|
self.assertFalse(self.browser.find_elements(By.ID, "id_bud_btn"))
|
||
|
|
|
||
|
|
def test_legacy_invite_email_input_is_gone(self):
|
||
|
|
"""Sanity: the old inline form has been removed."""
|
||
|
|
self.create_pre_authenticated_session("owner@test.io")
|
||
|
|
self.browser.get(self.room_url)
|
||
|
|
self.wait_for(lambda: self.browser.find_element(By.CSS_SELECTOR, ".gate-modal"))
|
||
|
|
self.assertFalse(self.browser.find_elements(By.ID, "id_invite_email"))
|
||
|
|
|
||
|
|
|
||
|
|
class GatekeeperBudBtnAsyncInviteTest(FunctionalTest):
|
||
|
|
"""OK on the bud-btn slide-out fires the async invite — RoomInvite
|
||
|
|
persisted, Brief w/ kind=GAME_INVITE created, slide-down banner shown."""
|
||
|
|
|
||
|
|
def setUp(self):
|
||
|
|
super().setUp()
|
||
|
|
self.owner = User.objects.create(email="owner@test.io", username="owner")
|
||
|
|
self.alice = User.objects.create(email="alice@test.io", username="alice")
|
||
|
|
self.room = Room.objects.create(name="Bingobango", owner=self.owner)
|
||
|
|
self.room_url = f"{self.live_server_url}/gameboard/room/{self.room.id}/gate/"
|
||
|
|
self.create_pre_authenticated_session("owner@test.io")
|
||
|
|
self.browser.get(self.room_url)
|
||
|
|
|
||
|
|
def _open_panel_and_invite(self, recipient):
|
||
|
|
bud_btn = self.wait_for(lambda: self.browser.find_element(By.ID, "id_bud_btn"))
|
||
|
|
bud_btn.click()
|
||
|
|
recipient_input = self.wait_for(
|
||
|
|
lambda: self.browser.find_element(By.ID, "id_recipient")
|
||
|
|
)
|
||
|
|
recipient_input.send_keys(recipient)
|
||
|
|
self.browser.find_element(
|
||
|
|
By.CSS_SELECTOR, "#id_bud_panel .btn.btn-confirm"
|
||
|
|
).click()
|
||
|
|
return bud_btn
|
||
|
|
|
||
|
|
def test_invite_creates_room_invite(self):
|
||
|
|
self._open_panel_and_invite("alice@test.io")
|
||
|
|
self.wait_for(lambda: self.assertEqual(
|
||
|
|
RoomInvite.objects.filter(
|
||
|
|
room=self.room, invitee_email="alice@test.io"
|
||
|
|
).count(),
|
||
|
|
1,
|
||
|
|
))
|
||
|
|
|
||
|
|
def test_invite_spawns_game_invite_brief(self):
|
||
|
|
self._open_panel_and_invite("alice@test.io")
|
||
|
|
self.wait_for(lambda: self.assertEqual(
|
||
|
|
Brief.objects.filter(
|
||
|
|
owner=self.owner, kind=Brief.KIND_GAME_INVITE,
|
||
|
|
).count(),
|
||
|
|
1,
|
||
|
|
))
|
||
|
|
|
||
|
|
def test_invite_renders_slide_down_banner(self):
|
||
|
|
self._open_panel_and_invite("alice@test.io")
|
||
|
|
self.wait_for(lambda: self.browser.find_element(By.CSS_SELECTOR, ".note-banner"))
|
||
|
|
|
||
|
|
def test_invite_closes_panel_after_success(self):
|
||
|
|
bud_btn = self._open_panel_and_invite("alice@test.io")
|
||
|
|
self.wait_for(lambda: self.assertNotIn("active", bud_btn.get_attribute("class")))
|
||
|
|
|
||
|
|
def test_invite_username_resolves_to_user_email(self):
|
||
|
|
"""Username-typed invite stores the resolved User's email."""
|
||
|
|
self._open_panel_and_invite("alice")
|
||
|
|
self.wait_for(lambda: self.assertEqual(
|
||
|
|
RoomInvite.objects.filter(
|
||
|
|
room=self.room, invitee_email="alice@test.io"
|
||
|
|
).count(),
|
||
|
|
1,
|
||
|
|
))
|
||
|
|
|
||
|
|
def test_invite_auto_adds_recipient_to_owner_buds(self):
|
||
|
|
self._open_panel_and_invite("alice@test.io")
|
||
|
|
self.wait_for(lambda: self.assertIn(
|
||
|
|
self.alice, list(self.owner.buds.all())
|
||
|
|
))
|