functional_tests/room_page.py: extract shared FT helpers into a dedicated module so renaming a test_X.py file doesn't cascade-break sibling imports — _fill_room_via_orm (was in test_room_role_select, imported by test_room_tray + test_deck_contribution + test_game_invite + test_room_gatekeeper + test_room_sig_select), _assign_all_roles (was in test_room_sig_select, imported by test_room_tray + test_deck_contribution), and _equip_earthman_deck (duplicated verbatim in test_room_role_select + test_component_tray_tooltip — the test_component_tray_tooltip copy of _fill_room_via_orm was also a near-duplicate, missing only the gamers-return both call sites discarded anyway); SIG_SEAT_ORDER constant moves along since _assign_all_roles depends on it; mirrors the existing post_page.py pattern; underscored helper names kept so the "test infrastructure, not API" signal survives the relocation; dropped now-unused per-file imports (DeckVariant from test_room_role_select; Note/DeckVariant/TableSeat/TarotCard from test_room_sig_select; GateSlot from test_component_tray_tooltip); regression gate: GatekeeperTest (8 FTs) green via the new helper home; smoke-imports green across all 8 touched modules
Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
112
src/functional_tests/room_page.py
Normal file
112
src/functional_tests/room_page.py
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
"""Room-page FT helpers — extracted from the per-page FT modules so the
|
||||||
|
helpers can be imported without coupling consumer FTs to a sibling test
|
||||||
|
file's lifecycle (renames, deletions). Mirrors the post_page.py pattern.
|
||||||
|
|
||||||
|
Naming: underscored to signal "test infrastructure, not API surface", but
|
||||||
|
they're public within `functional_tests/` — direct imports are fine.
|
||||||
|
|
||||||
|
Consumers:
|
||||||
|
test_room_role_select / test_room_sig_select — define-and-use
|
||||||
|
test_component_tray_tooltip — _equip_earthman_deck
|
||||||
|
test_room_tray / test_deck_contribution — both core helpers
|
||||||
|
test_game_invite / test_room_gatekeeper — _fill_room_via_orm
|
||||||
|
"""
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from apps.drama.models import Note
|
||||||
|
from apps.epic.models import (
|
||||||
|
DeckVariant, GateSlot, Room, TableSeat, TarotCard,
|
||||||
|
)
|
||||||
|
from apps.lyric.models import User
|
||||||
|
|
||||||
|
|
||||||
|
SIG_SEAT_ORDER = ["PC", "NC", "EC", "SC", "AC", "BC"]
|
||||||
|
|
||||||
|
|
||||||
|
def _equip_earthman_deck(user):
|
||||||
|
# get_or_create: TransactionTestCase.flush() wipes migration-seeded
|
||||||
|
# DeckVariants between tests, so subsequent tests in the same run can't
|
||||||
|
# find it via filter().
|
||||||
|
deck, _ = DeckVariant.objects.get_or_create(
|
||||||
|
slug="earthman",
|
||||||
|
defaults={"name": "Earthman", "card_count": 106, "is_default": True},
|
||||||
|
)
|
||||||
|
user.equipped_deck = deck
|
||||||
|
user.save(update_fields=["equipped_deck"])
|
||||||
|
|
||||||
|
|
||||||
|
def _fill_room_via_orm(room, emails):
|
||||||
|
"""Fill all 6 gate slots and set gate_status=OPEN. Returns list of gamers."""
|
||||||
|
gamers = []
|
||||||
|
for i, email in enumerate(emails, start=1):
|
||||||
|
gamer, _ = User.objects.get_or_create(email=email)
|
||||||
|
slot = room.gate_slots.get(slot_number=i)
|
||||||
|
slot.gamer = gamer
|
||||||
|
slot.status = GateSlot.FILLED
|
||||||
|
slot.save()
|
||||||
|
gamers.append(gamer)
|
||||||
|
room.gate_status = Room.OPEN
|
||||||
|
room.save()
|
||||||
|
return gamers
|
||||||
|
|
||||||
|
|
||||||
|
def _assign_all_roles(room, role_order=None):
|
||||||
|
"""Assign roles to all slots, reveal them, and advance to SIG_SELECT.
|
||||||
|
Also ensures all gamers have an equipped_deck (required for sig_deck_cards)."""
|
||||||
|
if role_order is None:
|
||||||
|
role_order = SIG_SEAT_ORDER[:]
|
||||||
|
earthman, _ = DeckVariant.objects.get_or_create(
|
||||||
|
slug="earthman",
|
||||||
|
defaults={"name": "Earthman Deck", "card_count": 108, "is_default": True},
|
||||||
|
)
|
||||||
|
# Seed the 18 sig deck cards (migration data is flushed in TransactionTestCase FTs).
|
||||||
|
# _sig_unique_cards() filters arcana=MIDDLE, suits BRANDS/CROWNS/BLADES/GRAILS (Earthman).
|
||||||
|
_NAME = {11: "Maid", 12: "Jack", 13: "Queen", 14: "King"}
|
||||||
|
for suit in ("BRANDS", "CROWNS", "BLADES", "GRAILS"):
|
||||||
|
for number in (11, 12, 13, 14):
|
||||||
|
TarotCard.objects.get_or_create(
|
||||||
|
deck_variant=earthman,
|
||||||
|
slug=f"{_NAME[number].lower()}-of-{suit.lower()}-em",
|
||||||
|
defaults={"arcana": "MIDDLE", "suit": suit, "number": number,
|
||||||
|
"name": f"{_NAME[number]} of {suit.capitalize()}",
|
||||||
|
"levity_qualifier": "Elevated",
|
||||||
|
"gravity_qualifier": "Graven"},
|
||||||
|
)
|
||||||
|
# Numbers 0–1 are the sig deck's Major Arcana (unlocked via Note).
|
||||||
|
# Seed them with correct Earthman names and qualifiers, then unlock for all gamers.
|
||||||
|
for number, name, slug in [
|
||||||
|
(0, "The Nomad", "the-nomad"),
|
||||||
|
(1, "The Schizo", "the-schizo"),
|
||||||
|
]:
|
||||||
|
TarotCard.objects.get_or_create(
|
||||||
|
deck_variant=earthman,
|
||||||
|
slug=slug,
|
||||||
|
defaults={"arcana": "MAJOR", "number": number, "name": name,
|
||||||
|
"levity_qualifier": "Enlightened",
|
||||||
|
"gravity_qualifier": "Engraven"},
|
||||||
|
)
|
||||||
|
for slot in room.gate_slots.order_by("slot_number"):
|
||||||
|
if slot.gamer:
|
||||||
|
Note.objects.get_or_create(
|
||||||
|
user=slot.gamer, slug="super-nomad",
|
||||||
|
defaults={"earned_at": timezone.now()},
|
||||||
|
)
|
||||||
|
Note.objects.get_or_create(
|
||||||
|
user=slot.gamer, slug="super-schizo",
|
||||||
|
defaults={"earned_at": timezone.now()},
|
||||||
|
)
|
||||||
|
for slot in room.gate_slots.order_by("slot_number"):
|
||||||
|
if slot.gamer and not slot.gamer.equipped_deck:
|
||||||
|
slot.gamer.equipped_deck = earthman
|
||||||
|
slot.gamer.save(update_fields=["equipped_deck"])
|
||||||
|
TableSeat.objects.update_or_create(
|
||||||
|
room=room,
|
||||||
|
slot_number=slot.slot_number,
|
||||||
|
defaults={
|
||||||
|
"gamer": slot.gamer,
|
||||||
|
"role": role_order[slot.slot_number - 1],
|
||||||
|
"role_revealed": True,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
room.table_status = Room.SIG_SELECT
|
||||||
|
room.save()
|
||||||
@@ -14,28 +14,11 @@ from selenium.webdriver.common.by import By
|
|||||||
|
|
||||||
from .base import FunctionalTest
|
from .base import FunctionalTest
|
||||||
from apps.applets.models import Applet
|
from apps.applets.models import Applet
|
||||||
from apps.epic.models import DeckVariant, GateSlot, Room, TableSeat, TarotCard
|
from apps.epic.models import DeckVariant, Room, TableSeat, TarotCard
|
||||||
from apps.lyric.models import User
|
from apps.lyric.models import User
|
||||||
|
|
||||||
|
|
||||||
def _equip_earthman_deck(user):
|
from .room_page import _equip_earthman_deck, _fill_room_via_orm
|
||||||
deck, _ = DeckVariant.objects.get_or_create(
|
|
||||||
slug="earthman",
|
|
||||||
defaults={"name": "Earthman", "card_count": 106, "is_default": True},
|
|
||||||
)
|
|
||||||
user.equipped_deck = deck
|
|
||||||
user.save(update_fields=["equipped_deck"])
|
|
||||||
|
|
||||||
|
|
||||||
def _fill_room_via_orm(room, emails):
|
|
||||||
for i, email in enumerate(emails, start=1):
|
|
||||||
gamer, _ = User.objects.get_or_create(email=email)
|
|
||||||
slot = room.gate_slots.get(slot_number=i)
|
|
||||||
slot.gamer = gamer
|
|
||||||
slot.status = GateSlot.FILLED
|
|
||||||
slot.save()
|
|
||||||
room.gate_status = Room.OPEN
|
|
||||||
room.save()
|
|
||||||
|
|
||||||
|
|
||||||
class TrayRoleCardTooltipTest(FunctionalTest):
|
class TrayRoleCardTooltipTest(FunctionalTest):
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ from apps.applets.models import Applet
|
|||||||
from apps.epic.models import DeckVariant, GateSlot, Room, TableSeat
|
from apps.epic.models import DeckVariant, GateSlot, Room, TableSeat
|
||||||
from apps.lyric.models import User
|
from apps.lyric.models import User
|
||||||
from functional_tests.base import FunctionalTest
|
from functional_tests.base import FunctionalTest
|
||||||
from functional_tests.test_room_role_select import _fill_room_via_orm
|
from functional_tests.room_page import _fill_room_via_orm
|
||||||
from functional_tests.test_room_sig_select import _assign_all_roles
|
|
||||||
|
|
||||||
FOUNDER_EMAIL = "founder@test.io"
|
FOUNDER_EMAIL = "founder@test.io"
|
||||||
GAMER_EMAIL = "gamer@test.io"
|
GAMER_EMAIL = "gamer@test.io"
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ except ImportError:
|
|||||||
_BILLPOST_READY = False
|
_BILLPOST_READY = False
|
||||||
from apps.lyric.models import User
|
from apps.lyric.models import User
|
||||||
from functional_tests.base import FunctionalTest
|
from functional_tests.base import FunctionalTest
|
||||||
from functional_tests.test_room_role_select import _fill_room_via_orm
|
from functional_tests.room_page import _fill_room_via_orm
|
||||||
|
|
||||||
FOUNDER_EMAIL = "founder@test.io"
|
FOUNDER_EMAIL = "founder@test.io"
|
||||||
INVITEE_EMAIL = "invitee@test.io"
|
INVITEE_EMAIL = "invitee@test.io"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from .base import FunctionalTest
|
|||||||
from apps.applets.models import Applet
|
from apps.applets.models import Applet
|
||||||
from apps.epic.models import Room, GateSlot, select_token
|
from apps.epic.models import Room, GateSlot, select_token
|
||||||
from apps.lyric.models import Token, User
|
from apps.lyric.models import Token, User
|
||||||
from .test_room_role_select import _fill_room_via_orm
|
from .room_page import _fill_room_via_orm
|
||||||
|
|
||||||
|
|
||||||
class GatekeeperTest(FunctionalTest):
|
class GatekeeperTest(FunctionalTest):
|
||||||
|
|||||||
@@ -8,37 +8,12 @@ from selenium.webdriver.common.by import By
|
|||||||
|
|
||||||
from .base import FunctionalTest, ChannelsFunctionalTest
|
from .base import FunctionalTest, ChannelsFunctionalTest
|
||||||
from .management.commands.create_session import create_pre_authenticated_session
|
from .management.commands.create_session import create_pre_authenticated_session
|
||||||
|
from .room_page import _equip_earthman_deck, _fill_room_via_orm
|
||||||
from apps.applets.models import Applet
|
from apps.applets.models import Applet
|
||||||
from apps.epic.models import DeckVariant, Room, GateSlot, TableSeat
|
from apps.epic.models import Room, GateSlot, TableSeat
|
||||||
from apps.lyric.models import User
|
from apps.lyric.models import User
|
||||||
|
|
||||||
|
|
||||||
def _equip_earthman_deck(user):
|
|
||||||
# get_or_create: TransactionTestCase.flush() wipes migration-seeded DeckVariants
|
|
||||||
# between tests, so subsequent tests in the same run can't find it via filter().
|
|
||||||
deck, _ = DeckVariant.objects.get_or_create(
|
|
||||||
slug="earthman",
|
|
||||||
defaults={"name": "Earthman", "card_count": 106, "is_default": True},
|
|
||||||
)
|
|
||||||
user.equipped_deck = deck
|
|
||||||
user.save(update_fields=["equipped_deck"])
|
|
||||||
|
|
||||||
|
|
||||||
def _fill_room_via_orm(room, emails):
|
|
||||||
"""Fill all 6 gate slots and set gate_status=OPEN. Returns list of gamers."""
|
|
||||||
gamers = []
|
|
||||||
for i, email in enumerate(emails, start=1):
|
|
||||||
gamer, _ = User.objects.get_or_create(email=email)
|
|
||||||
slot = room.gate_slots.get(slot_number=i)
|
|
||||||
slot.gamer = gamer
|
|
||||||
slot.status = GateSlot.FILLED
|
|
||||||
slot.save()
|
|
||||||
gamers.append(gamer)
|
|
||||||
room.gate_status = Room.OPEN
|
|
||||||
room.save()
|
|
||||||
return gamers
|
|
||||||
|
|
||||||
|
|
||||||
class RoleSelectTest(FunctionalTest):
|
class RoleSelectTest(FunctionalTest):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ from selenium.webdriver.common.by import By
|
|||||||
|
|
||||||
from .base import FunctionalTest, ChannelsFunctionalTest
|
from .base import FunctionalTest, ChannelsFunctionalTest
|
||||||
from .management.commands.create_session import create_pre_authenticated_session
|
from .management.commands.create_session import create_pre_authenticated_session
|
||||||
|
from .room_page import (
|
||||||
|
SIG_SEAT_ORDER, _assign_all_roles, _fill_room_via_orm,
|
||||||
|
)
|
||||||
from apps.applets.models import Applet
|
from apps.applets.models import Applet
|
||||||
from apps.drama.models import Note
|
from apps.epic.models import Room
|
||||||
from apps.epic.models import DeckVariant, Room, TableSeat, TarotCard
|
|
||||||
from apps.lyric.models import User
|
from apps.lyric.models import User
|
||||||
|
|
||||||
from .test_room_role_select import _fill_room_via_orm
|
|
||||||
|
|
||||||
|
|
||||||
# ── Significator Selection ────────────────────────────────────────────────────
|
# ── Significator Selection ────────────────────────────────────────────────────
|
||||||
#
|
#
|
||||||
@@ -23,71 +23,6 @@ from .test_room_role_select import _fill_room_via_orm
|
|||||||
#
|
#
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
SIG_SEAT_ORDER = ["PC", "NC", "EC", "SC", "AC", "BC"]
|
|
||||||
|
|
||||||
|
|
||||||
def _assign_all_roles(room, role_order=None):
|
|
||||||
"""Assign roles to all slots, reveal them, and advance to SIG_SELECT.
|
|
||||||
Also ensures all gamers have an equipped_deck (required for sig_deck_cards)."""
|
|
||||||
if role_order is None:
|
|
||||||
role_order = SIG_SEAT_ORDER[:]
|
|
||||||
earthman, _ = DeckVariant.objects.get_or_create(
|
|
||||||
slug="earthman",
|
|
||||||
defaults={"name": "Earthman Deck", "card_count": 108, "is_default": True},
|
|
||||||
)
|
|
||||||
# Seed the 18 sig deck cards (migration data is flushed in TransactionTestCase FTs).
|
|
||||||
# _sig_unique_cards() filters arcana=MIDDLE, suits BRANDS/CROWNS/BLADES/GRAILS (Earthman).
|
|
||||||
_NAME = {11: "Maid", 12: "Jack", 13: "Queen", 14: "King"}
|
|
||||||
for suit in ("BRANDS", "CROWNS", "BLADES", "GRAILS"):
|
|
||||||
for number in (11, 12, 13, 14):
|
|
||||||
TarotCard.objects.get_or_create(
|
|
||||||
deck_variant=earthman,
|
|
||||||
slug=f"{_NAME[number].lower()}-of-{suit.lower()}-em",
|
|
||||||
defaults={"arcana": "MIDDLE", "suit": suit, "number": number,
|
|
||||||
"name": f"{_NAME[number]} of {suit.capitalize()}",
|
|
||||||
"levity_qualifier": "Elevated",
|
|
||||||
"gravity_qualifier": "Graven"},
|
|
||||||
)
|
|
||||||
# Numbers 0–1 are the sig deck's Major Arcana (unlocked via Note).
|
|
||||||
# Seed them with correct Earthman names and qualifiers, then unlock for all gamers.
|
|
||||||
from django.utils import timezone
|
|
||||||
for number, name, slug in [
|
|
||||||
(0, "The Nomad", "the-nomad"),
|
|
||||||
(1, "The Schizo", "the-schizo"),
|
|
||||||
]:
|
|
||||||
TarotCard.objects.get_or_create(
|
|
||||||
deck_variant=earthman,
|
|
||||||
slug=slug,
|
|
||||||
defaults={"arcana": "MAJOR", "number": number, "name": name,
|
|
||||||
"levity_qualifier": "Enlightened",
|
|
||||||
"gravity_qualifier": "Engraven"},
|
|
||||||
)
|
|
||||||
for slot in room.gate_slots.order_by("slot_number"):
|
|
||||||
if slot.gamer:
|
|
||||||
Note.objects.get_or_create(
|
|
||||||
user=slot.gamer, slug="super-nomad",
|
|
||||||
defaults={"earned_at": timezone.now()},
|
|
||||||
)
|
|
||||||
Note.objects.get_or_create(
|
|
||||||
user=slot.gamer, slug="super-schizo",
|
|
||||||
defaults={"earned_at": timezone.now()},
|
|
||||||
)
|
|
||||||
for slot in room.gate_slots.order_by("slot_number"):
|
|
||||||
if slot.gamer and not slot.gamer.equipped_deck:
|
|
||||||
slot.gamer.equipped_deck = earthman
|
|
||||||
slot.gamer.save(update_fields=["equipped_deck"])
|
|
||||||
TableSeat.objects.update_or_create(
|
|
||||||
room=room,
|
|
||||||
slot_number=slot.slot_number,
|
|
||||||
defaults={
|
|
||||||
"gamer": slot.gamer,
|
|
||||||
"role": role_order[slot.slot_number - 1],
|
|
||||||
"role_revealed": True,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
room.table_status = Room.SIG_SELECT
|
|
||||||
room.save()
|
|
||||||
|
|
||||||
|
|
||||||
class SigSelectTest(FunctionalTest):
|
class SigSelectTest(FunctionalTest):
|
||||||
"""Significator Selection — non-WebSocket tests."""
|
"""Significator Selection — non-WebSocket tests."""
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ from django.test import tag
|
|||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
|
|
||||||
from .base import FunctionalTest
|
from .base import FunctionalTest
|
||||||
from .test_room_role_select import _fill_room_via_orm
|
from .room_page import _assign_all_roles, _fill_room_via_orm
|
||||||
from .test_room_sig_select import _assign_all_roles
|
|
||||||
from apps.epic.models import Room
|
from apps.epic.models import Room
|
||||||
from apps.lyric.models import User
|
from apps.lyric.models import User
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user