Implements comprehensive dice rolling system for gameplay: ## New Features - `/roll` and `!roll` commands for XdY dice notation with multiple roll support - `/ab` and `!atbat` commands for baseball at-bat dice shortcuts (1d6;2d6;1d20) - `/fielding` and `!f` commands for Super Advanced fielding with full position charts ## Technical Implementation - Complete dice command package in commands/dice/ - Full range and error charts for all 8 defensive positions (1B,2B,3B,SS,LF,RF,CF,C) - Pre-populated position choices for user-friendly slash command interface - Backwards compatibility with prefix commands (!roll, !r, !dice, !ab, !atbat, !f, !fielding, !saf) - Type-safe implementation following "Raise or Return" pattern ## Testing & Quality - 30 comprehensive tests with 100% pass rate - Complete test coverage for all dice functionality, parsing, validation, and error handling - Integration with bot.py command loading system - Maintainable data structures replacing verbose original implementation ## User Experience - Consistent embed formatting across all commands - Detailed fielding results with range and error analysis - Support for complex dice combinations and multiple roll formats - Clear error messages for invalid inputs 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
596 lines
24 KiB
Python
596 lines
24 KiB
Python
"""
|
|
Tests for Transaction Embed Views
|
|
|
|
Validates Discord UI components, modals, and interactive elements.
|
|
"""
|
|
import pytest
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
import discord
|
|
|
|
from views.transaction_embed import (
|
|
TransactionEmbedView,
|
|
RemoveMoveView,
|
|
RemoveMoveSelect,
|
|
PlayerSelectionModal,
|
|
SubmitConfirmationModal,
|
|
create_transaction_embed,
|
|
create_preview_embed
|
|
)
|
|
from services.transaction_builder import (
|
|
TransactionBuilder,
|
|
TransactionMove,
|
|
RosterValidationResult
|
|
)
|
|
from models.team import Team, RosterType
|
|
from models.player import Player
|
|
|
|
|
|
class TestTransactionEmbedView:
|
|
"""Test TransactionEmbedView Discord UI component."""
|
|
|
|
@pytest.fixture
|
|
def mock_builder(self):
|
|
"""Create mock TransactionBuilder."""
|
|
team = Team(id=499, abbrev='WV', sname='Black Bears', lname='West Virginia Black Bears', season=12)
|
|
builder = MagicMock(spec=TransactionBuilder)
|
|
builder.team = team
|
|
builder.user_id = 123456789
|
|
builder.season = 12
|
|
builder.is_empty = False
|
|
builder.move_count = 2
|
|
builder.moves = []
|
|
builder.created_at = MagicMock()
|
|
builder.created_at.strftime.return_value = "10:30:15"
|
|
return builder
|
|
|
|
# Don't create view as fixture - create in test methods to ensure event loop is running
|
|
|
|
@pytest.fixture
|
|
def mock_interaction(self):
|
|
"""Create mock Discord interaction."""
|
|
interaction = AsyncMock()
|
|
interaction.user = MagicMock()
|
|
interaction.user.id = 123456789
|
|
interaction.response = AsyncMock()
|
|
interaction.followup = AsyncMock()
|
|
interaction.client = MagicMock()
|
|
interaction.channel = MagicMock()
|
|
return interaction
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_interaction_check_correct_user(self, mock_builder, mock_interaction):
|
|
"""Test interaction check passes for correct user."""
|
|
view = TransactionEmbedView(mock_builder, user_id=123456789)
|
|
result = await view.interaction_check(mock_interaction)
|
|
assert result is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_interaction_check_wrong_user(self, mock_builder, mock_interaction):
|
|
"""Test interaction check fails for wrong user."""
|
|
view = TransactionEmbedView(mock_builder, user_id=123456789)
|
|
mock_interaction.user.id = 999999999 # Different user
|
|
|
|
result = await view.interaction_check(mock_interaction)
|
|
|
|
assert result is False
|
|
mock_interaction.response.send_message.assert_called_once()
|
|
call_args = mock_interaction.response.send_message.call_args
|
|
assert "don't have permission" in call_args[0][0]
|
|
assert call_args[1]['ephemeral'] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_add_move_button_click(self, mock_builder, mock_interaction):
|
|
"""Test add move button click opens modal."""
|
|
view = TransactionEmbedView(mock_builder, user_id=123456789)
|
|
await view.add_move_button.callback(mock_interaction)
|
|
|
|
# Should send modal
|
|
mock_interaction.response.send_modal.assert_called_once()
|
|
|
|
# Check that modal is PlayerSelectionModal
|
|
modal_arg = mock_interaction.response.send_modal.call_args[0][0]
|
|
assert isinstance(modal_arg, PlayerSelectionModal)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_remove_move_button_empty_builder(self, mock_builder, mock_interaction):
|
|
"""Test remove move button with empty builder."""
|
|
view = TransactionEmbedView(mock_builder, user_id=123456789)
|
|
view.builder.is_empty = True
|
|
|
|
await view.remove_move_button.callback(mock_interaction)
|
|
|
|
mock_interaction.response.send_message.assert_called_once()
|
|
call_args = mock_interaction.response.send_message.call_args
|
|
assert "No moves to remove" in call_args[0][0]
|
|
assert call_args[1]['ephemeral'] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_remove_move_button_with_moves(self, mock_builder, mock_interaction):
|
|
"""Test remove move button with moves available."""
|
|
view = TransactionEmbedView(mock_builder, user_id=123456789)
|
|
view.builder.is_empty = False
|
|
|
|
with patch('views.transaction_embed.create_transaction_embed') as mock_create_embed:
|
|
mock_create_embed.return_value = MagicMock()
|
|
|
|
await view.remove_move_button.callback(mock_interaction)
|
|
|
|
mock_interaction.response.edit_message.assert_called_once()
|
|
|
|
# Check that view is RemoveMoveView
|
|
call_args = mock_interaction.response.edit_message.call_args
|
|
view_arg = call_args[1]['view']
|
|
assert isinstance(view_arg, RemoveMoveView)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_preview_button_empty_builder(self, mock_builder, mock_interaction):
|
|
"""Test preview button with empty builder."""
|
|
view = TransactionEmbedView(mock_builder, user_id=123456789)
|
|
view.builder.is_empty = True
|
|
|
|
await view.preview_button.callback(mock_interaction)
|
|
|
|
mock_interaction.response.send_message.assert_called_once()
|
|
call_args = mock_interaction.response.send_message.call_args
|
|
assert "No moves to preview" in call_args[0][0]
|
|
assert call_args[1]['ephemeral'] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_preview_button_with_moves(self, mock_builder, mock_interaction):
|
|
"""Test preview button with moves available."""
|
|
view = TransactionEmbedView(mock_builder, user_id=123456789)
|
|
view.builder.is_empty = False
|
|
|
|
with patch('views.transaction_embed.create_preview_embed') as mock_create_preview:
|
|
mock_create_preview.return_value = MagicMock()
|
|
|
|
await view.preview_button.callback(mock_interaction)
|
|
|
|
mock_interaction.response.send_message.assert_called_once()
|
|
call_args = mock_interaction.response.send_message.call_args
|
|
assert call_args[1]['ephemeral'] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_submit_button_empty_builder(self, mock_builder, mock_interaction):
|
|
"""Test submit button with empty builder."""
|
|
view = TransactionEmbedView(mock_builder, user_id=123456789)
|
|
view.builder.is_empty = True
|
|
|
|
await view.submit_button.callback(mock_interaction)
|
|
|
|
mock_interaction.response.send_message.assert_called_once()
|
|
call_args = mock_interaction.response.send_message.call_args
|
|
assert "Cannot submit empty transaction" in call_args[0][0]
|
|
assert call_args[1]['ephemeral'] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_submit_button_illegal_transaction(self, mock_builder, mock_interaction):
|
|
"""Test submit button with illegal transaction."""
|
|
view = TransactionEmbedView(mock_builder, user_id=123456789)
|
|
view.builder.is_empty = False
|
|
view.builder.validate_transaction = AsyncMock(return_value=RosterValidationResult(
|
|
is_legal=False,
|
|
major_league_count=26,
|
|
minor_league_count=10,
|
|
warnings=[],
|
|
errors=["Too many players"],
|
|
suggestions=["Drop 1 player"]
|
|
))
|
|
|
|
await view.submit_button.callback(mock_interaction)
|
|
|
|
mock_interaction.response.send_message.assert_called_once()
|
|
call_args = mock_interaction.response.send_message.call_args
|
|
message = call_args[0][0]
|
|
assert "Cannot submit illegal transaction" in message
|
|
assert "Too many players" in message
|
|
assert "Drop 1 player" in message
|
|
assert call_args[1]['ephemeral'] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_submit_button_legal_transaction(self, mock_builder, mock_interaction):
|
|
"""Test submit button with legal transaction."""
|
|
view = TransactionEmbedView(mock_builder, user_id=123456789)
|
|
view.builder.is_empty = False
|
|
view.builder.validate_transaction = AsyncMock(return_value=RosterValidationResult(
|
|
is_legal=True,
|
|
major_league_count=25,
|
|
minor_league_count=10,
|
|
warnings=[],
|
|
errors=[],
|
|
suggestions=[]
|
|
))
|
|
|
|
await view.submit_button.callback(mock_interaction)
|
|
|
|
# Should send confirmation modal
|
|
mock_interaction.response.send_modal.assert_called_once()
|
|
modal_arg = mock_interaction.response.send_modal.call_args[0][0]
|
|
assert isinstance(modal_arg, SubmitConfirmationModal)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cancel_button(self, mock_builder, mock_interaction):
|
|
"""Test cancel button clears moves and disables view."""
|
|
view = TransactionEmbedView(mock_builder, user_id=123456789)
|
|
with patch('views.transaction_embed.create_transaction_embed') as mock_create_embed:
|
|
mock_create_embed.return_value = MagicMock()
|
|
|
|
await view.cancel_button.callback(mock_interaction)
|
|
|
|
# Should clear moves
|
|
view.builder.clear_moves.assert_called_once()
|
|
|
|
# Should edit message with disabled view
|
|
mock_interaction.response.edit_message.assert_called_once()
|
|
call_args = mock_interaction.response.edit_message.call_args
|
|
assert "Transaction cancelled" in call_args[1]['content']
|
|
|
|
|
|
class TestPlayerSelectionModal:
|
|
"""Test PlayerSelectionModal functionality."""
|
|
|
|
@pytest.fixture
|
|
def mock_builder(self):
|
|
"""Create mock TransactionBuilder."""
|
|
team = Team(id=499, abbrev='WV', sname='Black Bears', lname='West Virginia Black Bears', season=12)
|
|
builder = MagicMock(spec=TransactionBuilder)
|
|
builder.team = team
|
|
builder.season = 12
|
|
builder.add_move.return_value = True
|
|
return builder
|
|
|
|
# Don't create modal as fixture - create in test methods to ensure event loop is running
|
|
|
|
@pytest.fixture
|
|
def mock_interaction(self):
|
|
"""Create mock Discord interaction."""
|
|
interaction = AsyncMock()
|
|
interaction.user = MagicMock()
|
|
interaction.user.id = 123456789
|
|
interaction.response = AsyncMock()
|
|
interaction.followup = AsyncMock()
|
|
interaction.client = MagicMock()
|
|
interaction.channel = MagicMock()
|
|
|
|
# Mock message history
|
|
mock_message = MagicMock()
|
|
mock_message.author = interaction.client.user
|
|
mock_message.embeds = [MagicMock()]
|
|
mock_message.embeds[0].title = "📋 Transaction Builder"
|
|
mock_message.edit = AsyncMock()
|
|
|
|
interaction.channel.history.return_value.__aiter__ = AsyncMock(return_value=iter([mock_message]))
|
|
|
|
return interaction
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_modal_initialization(self, mock_builder):
|
|
"""Test modal initialization."""
|
|
modal = PlayerSelectionModal(mock_builder)
|
|
assert modal.title == f"Add Move - {mock_builder.team.abbrev}"
|
|
assert len(modal.children) == 3 # player_name, action, destination
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_modal_submit_success(self, mock_builder, mock_interaction):
|
|
"""Test successful modal submission."""
|
|
modal = PlayerSelectionModal(mock_builder)
|
|
# Mock the TextInput values
|
|
modal.player_name = MagicMock()
|
|
modal.player_name.value = 'Mike Trout'
|
|
modal.action = MagicMock()
|
|
modal.action.value = 'add'
|
|
modal.destination = MagicMock()
|
|
modal.destination.value = 'ml'
|
|
|
|
mock_player = Player(id=123, name='Mike Trout', wara=2.5, season=12, pos_1='CF')
|
|
|
|
with patch('services.player_service.player_service') as mock_service:
|
|
mock_service.get_players_by_name.return_value = [mock_player]
|
|
|
|
await modal.on_submit(mock_interaction)
|
|
|
|
# Should defer response
|
|
mock_interaction.response.defer.assert_called_once()
|
|
|
|
# Should search for player
|
|
mock_service.get_players_by_name.assert_called_once_with('Mike Trout', 12)
|
|
|
|
# Should add move to builder
|
|
modal.builder.add_move.assert_called_once()
|
|
|
|
# Should send success message
|
|
mock_interaction.followup.send.assert_called_once()
|
|
call_args = mock_interaction.followup.send.call_args
|
|
assert "✅ Added:" in call_args[0][0]
|
|
assert call_args[1]['ephemeral'] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_modal_submit_invalid_action(self, mock_builder, mock_interaction):
|
|
"""Test modal submission with invalid action."""
|
|
modal = PlayerSelectionModal(mock_builder)
|
|
# Mock the TextInput values
|
|
modal.player_name = MagicMock()
|
|
modal.player_name.value = 'Mike Trout'
|
|
modal.action = MagicMock()
|
|
modal.action.value = 'invalid'
|
|
modal.destination = MagicMock()
|
|
modal.destination.value = 'ml'
|
|
|
|
await modal.on_submit(mock_interaction)
|
|
|
|
mock_interaction.followup.send.assert_called_once()
|
|
call_args = mock_interaction.followup.send.call_args
|
|
assert "Invalid action 'invalid'" in call_args[0][0]
|
|
assert call_args[1]['ephemeral'] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_modal_submit_player_not_found(self, mock_builder, mock_interaction):
|
|
"""Test modal submission when player not found."""
|
|
modal = PlayerSelectionModal(mock_builder)
|
|
# Mock the TextInput values
|
|
modal.player_name = MagicMock()
|
|
modal.player_name.value = 'Nonexistent Player'
|
|
modal.action = MagicMock()
|
|
modal.action.value = 'add'
|
|
modal.destination = MagicMock()
|
|
modal.destination.value = 'ml'
|
|
|
|
with patch('services.player_service.player_service') as mock_service:
|
|
mock_service.get_players_by_name.return_value = []
|
|
|
|
await modal.on_submit(mock_interaction)
|
|
|
|
mock_interaction.followup.send.assert_called_once()
|
|
call_args = mock_interaction.followup.send.call_args
|
|
assert "No players found matching" in call_args[0][0]
|
|
assert call_args[1]['ephemeral'] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_modal_submit_move_add_fails(self, mock_builder, mock_interaction):
|
|
"""Test modal submission when move addition fails."""
|
|
modal = PlayerSelectionModal(mock_builder)
|
|
# Mock the TextInput values
|
|
modal.player_name = MagicMock()
|
|
modal.player_name.value = 'Mike Trout'
|
|
modal.action = MagicMock()
|
|
modal.action.value = 'add'
|
|
modal.destination = MagicMock()
|
|
modal.destination.value = 'ml'
|
|
modal.builder.add_move.return_value = False # Simulate failure
|
|
|
|
mock_player = Player(id=123, name='Mike Trout', wara=2.5, season=12, pos_1='CF')
|
|
|
|
with patch('services.player_service.player_service') as mock_service:
|
|
mock_service.get_players_by_name.return_value = [mock_player]
|
|
|
|
await modal.on_submit(mock_interaction)
|
|
|
|
mock_interaction.followup.send.assert_called_once()
|
|
call_args = mock_interaction.followup.send.call_args
|
|
assert "Could not add move" in call_args[0][0]
|
|
assert "already be in this transaction" in call_args[0][0]
|
|
|
|
|
|
class TestSubmitConfirmationModal:
|
|
"""Test SubmitConfirmationModal functionality."""
|
|
|
|
@pytest.fixture
|
|
def mock_builder(self):
|
|
"""Create mock TransactionBuilder."""
|
|
team = Team(id=499, abbrev='WV', sname='Black Bears', lname='West Virginia Black Bears', season=12)
|
|
builder = MagicMock(spec=TransactionBuilder)
|
|
builder.team = team
|
|
builder.moves = []
|
|
return builder
|
|
|
|
@pytest.fixture
|
|
def modal(self, mock_builder):
|
|
"""Create SubmitConfirmationModal instance."""
|
|
return SubmitConfirmationModal(mock_builder)
|
|
|
|
@pytest.fixture
|
|
def mock_interaction(self):
|
|
"""Create mock Discord interaction."""
|
|
interaction = AsyncMock()
|
|
interaction.user = MagicMock()
|
|
interaction.user.id = 123456789
|
|
interaction.response = AsyncMock()
|
|
interaction.followup = AsyncMock()
|
|
interaction.client = MagicMock()
|
|
interaction.channel = MagicMock()
|
|
|
|
# Mock message history
|
|
mock_message = MagicMock()
|
|
mock_message.author = interaction.client.user
|
|
mock_message.embeds = [MagicMock()]
|
|
mock_message.embeds[0].title = "📋 Transaction Builder"
|
|
mock_message.edit = AsyncMock()
|
|
|
|
interaction.channel.history.return_value.__aiter__ = AsyncMock(return_value=iter([mock_message]))
|
|
|
|
return interaction
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_modal_submit_wrong_confirmation(self, mock_builder, mock_interaction):
|
|
"""Test modal submission with wrong confirmation text."""
|
|
modal = SubmitConfirmationModal(mock_builder)
|
|
# Mock the TextInput values
|
|
modal.confirmation = MagicMock()
|
|
modal.confirmation.value = 'WRONG'
|
|
|
|
await modal.on_submit(mock_interaction)
|
|
|
|
mock_interaction.response.send_message.assert_called_once()
|
|
call_args = mock_interaction.response.send_message.call_args
|
|
assert "must type 'CONFIRM' exactly" in call_args[0][0]
|
|
assert call_args[1]['ephemeral'] is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_modal_submit_correct_confirmation(self, mock_builder, mock_interaction):
|
|
"""Test modal submission with correct confirmation."""
|
|
modal = SubmitConfirmationModal(mock_builder)
|
|
# Mock the TextInput values
|
|
modal.confirmation = MagicMock()
|
|
modal.confirmation.value = 'CONFIRM'
|
|
|
|
mock_transaction = MagicMock()
|
|
mock_transaction.moveid = 'Season-012-Week-11-123456789'
|
|
mock_transaction.week = 11
|
|
|
|
with patch('services.league_service.LeagueService') as mock_league_service_class:
|
|
mock_league_service = MagicMock()
|
|
mock_league_service_class.return_value = mock_league_service
|
|
|
|
mock_current_state = MagicMock()
|
|
mock_current_state.week = 10
|
|
mock_league_service.get_current_state.return_value = mock_current_state
|
|
|
|
modal.builder.submit_transaction.return_value = [mock_transaction]
|
|
|
|
with patch('services.transaction_builder.clear_transaction_builder') as mock_clear:
|
|
await modal.on_submit(mock_interaction)
|
|
|
|
# Should defer response
|
|
mock_interaction.response.defer.assert_called_once_with(ephemeral=True)
|
|
|
|
# Should get current state
|
|
mock_league_service.get_current_state.assert_called_once()
|
|
|
|
# Should submit transaction for next week
|
|
modal.builder.submit_transaction.assert_called_once_with(week=11)
|
|
|
|
# Should clear builder
|
|
mock_clear.assert_called_once_with(123456789)
|
|
|
|
# Should send success message
|
|
mock_interaction.followup.send.assert_called_once()
|
|
call_args = mock_interaction.followup.send.call_args
|
|
assert "Transaction Submitted Successfully" in call_args[0][0]
|
|
assert mock_transaction.moveid in call_args[0][0]
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_modal_submit_no_current_state(self, mock_builder, mock_interaction):
|
|
"""Test modal submission when current state unavailable."""
|
|
modal = SubmitConfirmationModal(mock_builder)
|
|
# Mock the TextInput values
|
|
modal.confirmation = MagicMock()
|
|
modal.confirmation.value = 'CONFIRM'
|
|
|
|
with patch('services.league_service.LeagueService') as mock_league_service_class:
|
|
mock_league_service = MagicMock()
|
|
mock_league_service_class.return_value = mock_league_service
|
|
mock_league_service.get_current_state.return_value = None
|
|
|
|
await modal.on_submit(mock_interaction)
|
|
|
|
mock_interaction.followup.send.assert_called_once()
|
|
call_args = mock_interaction.followup.send.call_args
|
|
assert "Could not get current league state" in call_args[0][0]
|
|
assert call_args[1]['ephemeral'] is True
|
|
|
|
|
|
class TestEmbedCreation:
|
|
"""Test embed creation functions."""
|
|
|
|
@pytest.fixture
|
|
def mock_builder_empty(self):
|
|
"""Create empty mock TransactionBuilder."""
|
|
team = Team(id=499, abbrev='WV', sname='Black Bears', lname='West Virginia Black Bears', season=12)
|
|
builder = MagicMock(spec=TransactionBuilder)
|
|
builder.team = team
|
|
builder.is_empty = True
|
|
builder.move_count = 0
|
|
builder.moves = []
|
|
builder.created_at = MagicMock()
|
|
builder.created_at.strftime.return_value = "10:30:15"
|
|
builder.validate_transaction = AsyncMock(return_value=RosterValidationResult(
|
|
is_legal=True,
|
|
major_league_count=24,
|
|
minor_league_count=10,
|
|
warnings=[],
|
|
errors=[],
|
|
suggestions=["Add player moves to build your transaction"]
|
|
))
|
|
return builder
|
|
|
|
@pytest.fixture
|
|
def mock_builder_with_moves(self):
|
|
"""Create mock TransactionBuilder with moves."""
|
|
team = Team(id=499, abbrev='WV', sname='Black Bears', lname='West Virginia Black Bears', season=12)
|
|
builder = MagicMock(spec=TransactionBuilder)
|
|
builder.team = team
|
|
builder.is_empty = False
|
|
builder.move_count = 2
|
|
|
|
mock_moves = []
|
|
for i in range(2):
|
|
move = MagicMock()
|
|
move.description = f"Move {i+1}: Player → Team"
|
|
mock_moves.append(move)
|
|
builder.moves = mock_moves
|
|
|
|
builder.created_at = MagicMock()
|
|
builder.created_at.strftime.return_value = "10:30:15"
|
|
builder.validate_transaction = AsyncMock(return_value=RosterValidationResult(
|
|
is_legal=False,
|
|
major_league_count=26,
|
|
minor_league_count=10,
|
|
warnings=["Warning message"],
|
|
errors=["Error message"],
|
|
suggestions=["Suggestion message"]
|
|
))
|
|
return builder
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_transaction_embed_empty(self, mock_builder_empty):
|
|
"""Test creating embed for empty transaction."""
|
|
embed = await create_transaction_embed(mock_builder_empty)
|
|
|
|
assert isinstance(embed, discord.Embed)
|
|
assert "Transaction Builder - WV" in embed.title
|
|
assert "📋" in embed.title
|
|
|
|
# Should have fields for empty state
|
|
field_names = [field.name for field in embed.fields]
|
|
assert "Current Moves" in field_names
|
|
assert "Roster Status" in field_names
|
|
assert "Suggestions" in field_names
|
|
|
|
# Check empty moves message
|
|
moves_field = next(field for field in embed.fields if field.name == "Current Moves")
|
|
assert "No moves yet" in moves_field.value
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_transaction_embed_with_moves(self, mock_builder_with_moves):
|
|
"""Test creating embed for transaction with moves."""
|
|
embed = await create_transaction_embed(mock_builder_with_moves)
|
|
|
|
assert isinstance(embed, discord.Embed)
|
|
assert "Transaction Builder - WV" in embed.title
|
|
|
|
# Should have all fields
|
|
field_names = [field.name for field in embed.fields]
|
|
assert "Current Moves (2)" in field_names
|
|
assert "Roster Status" in field_names
|
|
assert "❌ Errors" in field_names
|
|
assert "Suggestions" in field_names
|
|
|
|
# Check moves content
|
|
moves_field = next(field for field in embed.fields if "Current Moves" in field.name)
|
|
assert "Move 1: Player → Team" in moves_field.value
|
|
assert "Move 2: Player → Team" in moves_field.value
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_preview_embed(self, mock_builder_with_moves):
|
|
"""Test creating preview embed."""
|
|
embed = await create_preview_embed(mock_builder_with_moves)
|
|
|
|
assert isinstance(embed, discord.Embed)
|
|
assert "Transaction Preview - WV" in embed.title
|
|
assert "📋" in embed.title
|
|
|
|
# Should have preview-specific fields
|
|
field_names = [field.name for field in embed.fields]
|
|
assert "All Moves (2)" in field_names
|
|
assert "Final Roster Status" in field_names
|
|
assert "❌ Validation Issues" in field_names |