feat: tier completion notification embeds (WP-14) (#79) #89
154
tests/test_evolution_notifications.py
Normal file
154
tests/test_evolution_notifications.py
Normal 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 (T1–T3) 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 (T1–T3) 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!"
|
||||
59
utilities/evolution_notifications.py
Normal file
59
utilities/evolution_notifications.py
Normal 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 1–3, 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
|
||||
]
|
||||
Loading…
Reference in New Issue
Block a user