tabras / tests /test_app.py
Codex
Polish demo: boss reveal screen, portraits, varied packs, paced draft, title copy
39c3669
Raw
History Blame Contribute Delete
5.17 kB
import forge
from app import (
CSS,
background_selector_html,
refresh_screen,
school_asset_name,
school_selector_html,
show_background,
show_draft_from_rules,
show_name,
show_school,
start_rules,
)
from ui import new_run_shell
class AppPackClient:
# Return one deterministic draft pack for app-flow tests.
def __init__(self) -> None:
self.calls = 0
# Return a three-card model payload.
def create_pack(self, payload):
self.calls += 1
card = lambda index: {
"name": f"Flow Card {self.calls}-{index}",
"flavor": "The table waits.",
"art_prompt": "glowing spell on a wooden desk",
"effects": [{"primitive_id": "deal", "weight": 1}],
}
return {"cards": [card(index) for index in range(payload["pack_size"])]}
class AppArtClient:
# Count image requests made after card text is forged.
def __init__(self) -> None:
self.calls = 0
# Return a deterministic image URI.
def create_art(self, prompt: str) -> str:
self.calls += 1
return f"uri:{prompt}"
# Verify setup advances through one prompt per screen.
def test_setup_screen_steps() -> None:
assert show_name()[1] == "name"
assert show_background()[1] == "background"
assert show_school()[1] == "school"
# Verify the title CTA stays compact instead of full-width.
def test_play_now_button_is_compact() -> None:
assert "#play-now-btn" in CSS
assert "max-width: 220px" in CSS
assert "#start-draft-btn" in CSS
assert "max-width: 200px" in CSS
# Verify draft cards are compact enough for the draft table.
def test_draft_cards_are_compact() -> None:
assert "minmax(0, 300px)" in CSS
assert "min-height: 405px" in CSS
# Verify setup selectors are image-backed clickable panels with hover copy.
def test_setup_selectors_use_image_panels() -> None:
background = background_selector_html()
school = school_selector_html()
assert "selector-panel" in background
assert "selector-image" in background
assert "selector-copy" in background
assert "background-btn-dark-fantasy" in background
assert "You are a mage" in background
assert "school-btn-fire" in school
assert "school-btn-ice" in school
assert "school-btn-earth" in school
# Verify selector art resolves to the bundled user-provided filenames.
def test_setup_selectors_use_bundled_assets() -> None:
background = background_selector_html()
assert "data:image/png;base64" in background
assert school_asset_name("dark-fantasy", "fire") == "darkFantasyFire.png"
assert school_asset_name("dark-fantasy", "ice") == "darkFantasyIce.png"
assert school_asset_name("dark-fantasy", "earth") == "darkFantasyEarth.png"
assert school_asset_name("cyberpunk", "fire") == "cyberpunkFire.png"
assert school_asset_name("cyberpunk", "ice") == "cyberpunkice.png"
assert school_asset_name("cyberpunk", "earth") == "cyberpunkEarth.png"
assert school_asset_name("anime", "fire") == "animeFire.png"
assert school_asset_name("anime", "ice") == "animeIce.png"
assert school_asset_name("anime", "earth") == "animeEarth.png"
assert "data:image/png;base64" in school_selector_html("Cyberpunk")
# Verify the rules screen starts deck generation in the background.
def test_start_rules_queues_deck_generation(monkeypatch) -> None:
forge.reset()
client = AppPackClient()
monkeypatch.setattr("app.card_client_from_env", lambda: client)
monkeypatch.setattr("app.art_client_from_env", lambda: None)
output = start_rules("Ada", "ice", "Anime")
state = output[0]
# start_rules now lands on the boss reveal screen (rules follow on Continue).
assert output[1] == "reveal"
assert state.player_name == "Ada"
assert state.school == "ice"
assert "reveal-screen" in output[10]
assert "The Necrolich" in output[10]
forge.drain()
refresh_screen(state, "rules")
assert client.calls > 0
# Verify the rules screen starts image work once card text is ready.
def test_rules_screen_starts_art_generation(monkeypatch) -> None:
monkeypatch.setattr("ui.MIN_DRAFT_LOADING_SECONDS", 0.0)
forge.reset()
client = AppPackClient()
art_client = AppArtClient()
monkeypatch.setattr("app.card_client_from_env", lambda: client)
monkeypatch.setattr("app.art_client_from_env", lambda: art_client)
state = start_rules("Ada", "fire", "Cyberpunk")[0]
forge.drain()
state = refresh_screen(state, "rules")[0]
forge.drain()
refresh_screen(state, "rules")
assert art_client.calls >= 3
# Verify skipping rules shows a deck-loading draft state if the pack is still pending.
def test_skip_rules_shows_loading_deck(monkeypatch) -> None:
forge.reset()
monkeypatch.setattr("app.card_client_from_env", lambda: None)
monkeypatch.setattr("app.art_client_from_env", lambda: None)
state = new_run_shell("Ada", "Anime", "fire", seed=1)
output = show_draft_from_rules(state)
assert output[1] == "draft"
assert output[0].loading == "Loading your deck"
assert "Loading your deck" in output[12]