new model fields & migrations for apps.epic & apps.lyric; new FTs, ITs & UTs passing
; some styling changes effected primarily to _gatekeetper.html modal
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import time
|
||||
|
||||
from datetime import timedelta
|
||||
from django.utils import timezone
|
||||
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
from .base import FunctionalTest
|
||||
from apps.applets.models import Applet
|
||||
from apps.epic.models import Room, GateSlot
|
||||
from apps.lyric.models import User
|
||||
from apps.epic.models import Room, GateSlot, select_token
|
||||
from apps.lyric.models import Token, User
|
||||
|
||||
|
||||
class GatekeeperTest(FunctionalTest):
|
||||
@@ -39,7 +39,7 @@ class GatekeeperTest(FunctionalTest):
|
||||
)
|
||||
# 4. Page shows room name, GATHERING status
|
||||
body = self.browser.find_element(By.TAG_NAME, "body")
|
||||
self.assertIn("Test Room", body.text)
|
||||
self.assertIn("TEST ROOM", body.text)
|
||||
self.assertIn("GATHERING GAMERS", body.text)
|
||||
# 5. Six token slot circles are visible, all empty
|
||||
slots = self.browser.find_elements(By.CSS_SELECTOR, ".gate-slot")
|
||||
@@ -82,7 +82,7 @@ class GatekeeperTest(FunctionalTest):
|
||||
slots = self.browser.find_elements(By.CSS_SELECTOR, ".gate-slot")
|
||||
self.assertIn("filled", slots[0].get_attribute("class"))
|
||||
self.assertEqual(
|
||||
len(self.browser.find_elements(By.CSS_SELECTOR, ".btn-confirm")), 0
|
||||
len(self.browser.find_elements(By.CSS_SELECTOR, ".gate-slot .btn-confirm")), 0
|
||||
)
|
||||
|
||||
def test_room_appears_in_my_games_after_creation(self):
|
||||
@@ -308,7 +308,7 @@ class CoinSlotTest(FunctionalTest):
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, ".gate-slot.filled")
|
||||
)
|
||||
self.assertEqual(
|
||||
len(self.browser.find_elements(By.CSS_SELECTOR, ".btn-confirm")), 0
|
||||
len(self.browser.find_elements(By.CSS_SELECTOR, ".gate-slot .btn-confirm")), 0
|
||||
)
|
||||
slot = self.room.gate_slots.get(slot_number=1)
|
||||
slot.refresh_from_db()
|
||||
@@ -374,5 +374,130 @@ class CoinSlotTest(FunctionalTest):
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
len(self.browser.find_elements(By.CSS_SELECTOR, ".btn-confirm")), 0
|
||||
len(self.browser.find_elements(By.CSS_SELECTOR, ".gate-slot .btn-confirm")), 0
|
||||
)
|
||||
|
||||
|
||||
class TokenPriorityTest(FunctionalTest):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
Applet.objects.get_or_create(
|
||||
slug="new-game", defaults={"name": "New Game", "context": "gameboard"}
|
||||
)
|
||||
Applet.objects.get_or_create(
|
||||
slug="my-games", defaults={"name": "My Games", "context": "gameboard"}
|
||||
)
|
||||
self.create_pre_authenticated_session("gamer@test.io")
|
||||
self.gamer = User.objects.get(email="gamer@test.io")
|
||||
self.room = Room.objects.create(name="Token Room", owner=self.gamer)
|
||||
self.gate_url = self.live_server_url + f"/gameboard/room/{self.room.id}/gate/"
|
||||
self.coin = Token.objects.get(user=self.gamer, token_type=Token.COIN)
|
||||
|
||||
def test_coin_is_used_by_default(self):
|
||||
# 1. COIN token created at signup, not yet leased to a room
|
||||
self.assertEqual(self.coin.token_type, Token.COIN)
|
||||
self.assertIsNone(self.coin.current_room)
|
||||
# 2. Gamer drops token and confirms
|
||||
self.browser.get(self.gate_url)
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, "button.token-rails")
|
||||
).click()
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, ".btn-confirm")
|
||||
).click()
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, ".gate-slot.filled")
|
||||
)
|
||||
# 3. Coin is now leased to this room, page not refreshed
|
||||
self.assertEqual(self.browser.current_url, self.gate_url)
|
||||
self.coin.refresh_from_db()
|
||||
self.assertEqual(self.coin.current_room, self.room)
|
||||
|
||||
def test_free_token_used_when_coin_in_use(self):
|
||||
# 1. Coin already leased to another room
|
||||
other_room = Room.objects.create(name="Other Room", owner=self.gamer)
|
||||
self.coin.current_room = other_room
|
||||
self.coin.save()
|
||||
# 2. Gamer has one unexpired free token (signup gives one; delete it and add fresh)
|
||||
Token.objects.filter(user=self.gamer, token_type=Token.FREE).delete()
|
||||
Token.objects.create(
|
||||
user=self.gamer,
|
||||
token_type=Token.FREE,
|
||||
expires_at=timezone.now() + timedelta(days=7),
|
||||
)
|
||||
# 3. Gamer drops token → Free Token consumed
|
||||
self.browser.get(self.gate_url)
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, "button.token-rails")
|
||||
).click()
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, ".btn-confirm")
|
||||
).click()
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, ".gate-slot.filled")
|
||||
)
|
||||
self.assertEqual(
|
||||
Token.objects.filter(user=self.gamer, token_type=Token.FREE).count(), 0
|
||||
)
|
||||
# 4. Coin untouched, still leased to other room
|
||||
self.assertEqual(self.browser.current_url, self.gate_url)
|
||||
self.coin.refresh_from_db()
|
||||
self.assertEqual(self.coin.current_room, other_room)
|
||||
|
||||
def test_tithe_token_used_when_free_tokens_exhausted(self):
|
||||
# 1. Coin in use, no Free Tokens, one Tithe Token
|
||||
other_room = Room.objects.create(name="Other Room", owner=self.gamer)
|
||||
self.coin.current_room = other_room
|
||||
self.coin.save()
|
||||
Token.objects.filter(user=self.gamer, token_type=Token.FREE).delete()
|
||||
tithe = Token.objects.create(user=self.gamer, token_type=Token.TITHE)
|
||||
# 2. Gamer drops token → tithe consumed
|
||||
self.browser.get(self.gate_url)
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, "button.token-rails")
|
||||
).click()
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, ".btn-confirm")
|
||||
).click()
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, ".gate-slot.filled")
|
||||
)
|
||||
# Tithe row deleted, page hasn't refreshed
|
||||
self.assertEqual(self.browser.current_url, self.gate_url)
|
||||
self.assertFalse(Token.objects.filter(pk=tithe.pk).exists())
|
||||
|
||||
def test_slot_blocked_when_no_tokens_available(self):
|
||||
# Coin in use, no Free Tokens, no Tithe Tokens → depleted state
|
||||
other_room = Room.objects.create(name="Other Room", owner=self.gamer)
|
||||
self.coin.current_room = other_room
|
||||
self.coin.save()
|
||||
Token.objects.filter(user=self.gamer, token_type=Token.FREE).delete()
|
||||
self.browser.get(self.gate_url)
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, ".token-slot.depleted")
|
||||
)
|
||||
self.assertEqual(
|
||||
len(self.browser.find_elements(By.CSS_SELECTOR, "button.token-rails")), 0
|
||||
)
|
||||
|
||||
def test_staff_backstage_pass_bypasses_token_cost(self):
|
||||
# 1. Staff user has a PASS token
|
||||
self.gamer.is_staff = True
|
||||
self.gamer.save()
|
||||
pass_token = Token.objects.create(user=self.gamer, token_type=Token.PASS)
|
||||
# 2. Drops token, confirms as normal
|
||||
self.browser.get(self.gate_url)
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, "button.token-rails")
|
||||
).click()
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, ".btn-confirm")
|
||||
).click()
|
||||
self.wait_for(
|
||||
lambda: self.browser.find_element(By.CSS_SELECTOR, ".gate-slot.filled")
|
||||
)
|
||||
# 3. Pass not consumed, coin not leased; no reload
|
||||
self.assertEqual(self.browser.current_url, self.gate_url)
|
||||
self.assertTrue(Token.objects.filter(pk=pass_token.pk).exists())
|
||||
self.coin.refresh_from_db()
|
||||
self.assertIsNone(self.coin.current_room)
|
||||
|
||||
Reference in New Issue
Block a user