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:
Disco DeDisco
2026-05-12 19:23:08 -04:00
parent b97c4a0508
commit 8240de6b45
8 changed files with 124 additions and 121 deletions

View 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 01 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()

View File

@@ -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):

View File

@@ -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"

View File

@@ -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"

View File

@@ -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):

View File

@@ -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):

View File

@@ -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 01 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."""

View File

@@ -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