feat: tier completion notification embeds (WP-14) (#79) #89

Merged
Claude merged 3 commits from ai/paper-dynasty-database-79 into main 2026-03-23 03:59:15 +00:00
2 changed files with 213 additions and 0 deletions

View File

@ -0,0 +1,154 @@
"""
Tests for evolution tier completion notification embeds (WP-14).
These are pure unit tests no database or Discord bot connection required.
Each test constructs embeds and asserts on title, description, color, and
footer to verify the notification design spec is met.
"""
import discord
from utilities.evolution_notifications import (
TIER_COLORS,
build_tier_embeds,
tier_up_embed,
)
class TestTierUpEmbed:
"""Unit tests for tier_up_embed() — standard (T1T3) and fully-evolved (T4) paths."""
def test_tier_up_title(self):
"""Standard tier-up embeds must use the 'Evolution Tier Up!' title."""
embed = tier_up_embed(
"Mike Trout", tier=2, tier_name="Rising", track_name="Batter"
)
assert embed.title == "Evolution Tier Up!"
def test_tier_up_description_format(self):
"""Description must include player name, tier number, tier name, and track name."""
embed = tier_up_embed(
"Mike Trout", tier=2, tier_name="Rising", track_name="Batter"
)
assert (
embed.description
== "Mike Trout reached Tier 2 (Rising) on the Batter track"
)
def test_tier_up_color_matches_tier(self):
"""Each tier must map to its specified embed color."""
for tier, expected_color in TIER_COLORS.items():
if tier == 4:
continue # T4 handled in fully-evolved tests
embed = tier_up_embed(
"Test Player", tier=tier, tier_name="Name", track_name="Batter"
)
assert embed.color.value == expected_color, f"Tier {tier} color mismatch"
def test_tier_up_no_footer_for_standard_tiers(self):
"""Standard tier-up embeds (T1T3) must not have a footer."""
for tier in (1, 2, 3):
embed = tier_up_embed(
"Test Player", tier=tier, tier_name="Name", track_name="Batter"
)
assert embed.footer.text is None
class TestFullyEvolvedEmbed:
"""Unit tests for the fully-evolved (T4) embed — distinct title, description, and footer."""
def test_fully_evolved_title(self):
"""T4 embeds must use the 'FULLY EVOLVED!' title."""
embed = tier_up_embed(
"Mike Trout", tier=4, tier_name="Legendary", track_name="Batter"
)
assert embed.title == "FULLY EVOLVED!"
def test_fully_evolved_description(self):
"""T4 description must indicate maximum evolution without mentioning tier number."""
embed = tier_up_embed(
"Mike Trout", tier=4, tier_name="Legendary", track_name="Batter"
)
assert (
embed.description
== "Mike Trout has reached maximum evolution on the Batter track"
)
def test_fully_evolved_footer(self):
"""T4 embeds must include the Phase 2 teaser footer."""
embed = tier_up_embed(
"Mike Trout", tier=4, tier_name="Legendary", track_name="Batter"
)
assert embed.footer.text == "Rating boosts coming in a future update!"
def test_fully_evolved_color(self):
"""T4 embed color must be teal."""
embed = tier_up_embed(
"Mike Trout", tier=4, tier_name="Legendary", track_name="Batter"
)
assert embed.color.value == TIER_COLORS[4]
class TestBuildTierEmbeds:
"""Unit tests for build_tier_embeds() — list construction and edge cases."""
def test_no_tier_ups_returns_empty_list(self):
"""When no tier-ups occurred, build_tier_embeds must return an empty list."""
result = build_tier_embeds([])
assert result == []
def test_single_tier_up_returns_one_embed(self):
"""A single tier-up event must produce exactly one embed."""
tier_ups = [
{
"player_name": "Mike Trout",
"tier": 2,
"tier_name": "Rising",
"track_name": "Batter",
}
]
result = build_tier_embeds(tier_ups)
assert len(result) == 1
assert isinstance(result[0], discord.Embed)
def test_multiple_tier_ups_return_separate_embeds(self):
"""Multiple tier-up events in one game must produce one embed per event."""
tier_ups = [
{
"player_name": "Mike Trout",
"tier": 2,
"tier_name": "Rising",
"track_name": "Batter",
},
{
"player_name": "Sandy Koufax",
"tier": 3,
"tier_name": "Elite",
"track_name": "Starter",
},
]
result = build_tier_embeds(tier_ups)
assert len(result) == 2
assert (
result[0].description
== "Mike Trout reached Tier 2 (Rising) on the Batter track"
)
assert (
result[1].description
== "Sandy Koufax reached Tier 3 (Elite) on the Starter track"
)
def test_fully_evolved_in_batch(self):
"""A T4 event in a batch must produce a fully-evolved embed, not a standard one."""
tier_ups = [
{
"player_name": "Babe Ruth",
"tier": 4,
"tier_name": "Legendary",
"track_name": "Batter",
}
]
result = build_tier_embeds(tier_ups)
assert len(result) == 1
assert result[0].title == "FULLY EVOLVED!"
assert result[0].footer.text == "Rating boosts coming in a future update!"

View File

@ -0,0 +1,59 @@
import discord
# Tier colors as Discord embed color integers
TIER_COLORS = {
1: 0x57F287, # green
2: 0xF1C40F, # gold
3: 0x9B59B6, # purple
4: 0x1ABC9C, # teal
}
MAX_TIER = 4
def tier_up_embed(
player_name: str, tier: int, tier_name: str, track_name: str
) -> discord.Embed:
"""
Build a Discord embed for a single evolution tier-up event.
For tier 4 (fully evolved), uses a distinct title, description, and footer.
For tiers 13, uses the standard tier-up format.
"""
color = TIER_COLORS.get(tier, 0xFFFFFF)
if tier == MAX_TIER:
embed = discord.Embed(
title="FULLY EVOLVED!",
description=f"{player_name} has reached maximum evolution on the {track_name} track",
color=color,
)
embed.set_footer(text="Rating boosts coming in a future update!")
else:
embed = discord.Embed(
title="Evolution Tier Up!",
description=f"{player_name} reached Tier {tier} ({tier_name}) on the {track_name} track",
color=color,
)
return embed
def build_tier_embeds(tier_ups: list) -> list:
"""
Build a list of Discord embeds for all tier-up events in a game.
Each item in tier_ups should be a dict with keys:
player_name (str), tier (int), tier_name (str), track_name (str)
Returns an empty list if there are no tier-ups.
"""
return [
tier_up_embed(
player_name=t["player_name"],
tier=t["tier"],
tier_name=t["tier_name"],
track_name=t["track_name"],
)
for t in tier_ups
]