"""
Tests for the Unified Card Tool with ModuleWrapper Integration.
This module tests the functionality of the unified_card_tool.py module,
which provides a dynamic card creation and sending capability using
the ModuleWrapper adapter.
"""
"""Test unified card tool providing consolidated card functionality.
๐ง MCP Tools Used:
- Unified card interface: Single tool for all card types
- Card type detection: Automatically detect appropriate card type
- Multi-format support: Support various input formats for card generation
- Card conversion: Convert between different card formats
๐งช What's Being Tested:
- Unified interface for all card generation workflows
- Automatic card type detection and selection
- Multi-format input handling (JSON, natural language, templates)
- Card format conversion and compatibility
- Simplified API for complex card operations
- Backward compatibility with existing card tools
- Performance optimization through unified processing
๐ Potential Duplications:
- Consolidates functionality from multiple other card tests
- Very high overlap with test_send_dynamic_card.py, test_smart_card_tool.py
- Unified approach may duplicate patterns from test_chat_app_tools.py
- Format conversion might overlap with general data transformation tests
"""
import os
import pytest
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
# Server configuration from environment variables with defaults
SERVER_HOST = os.getenv("MCP_SERVER_HOST", "localhost")
SERVER_PORT = os.getenv("MCP_SERVER_PORT", os.getenv("SERVER_PORT", "8002"))
# FastMCP servers in HTTP mode use the /mcp/ endpoint
SERVER_URL = os.getenv("MCP_SERVER_URL", f"http://{SERVER_HOST}:{SERVER_PORT}/mcp/")
# Test email address from environment variable - using your configured variable
TEST_EMAIL = os.getenv("TEST_CHAT_WEBHOOK_EMAIL", "srivers@groupon.com")
# Test space ID for Google Chat - extract from your configured webhook space or use full format
TEST_SPACE_ID = f"spaces/{os.getenv('TEST_CHAT_WEBHOOK_SPACE', 'AAAAWvjq2HE')}"
# Test webhook URL for Google Chat - using your configured variable
TEST_WEBHOOK_URL = os.getenv(
"TEST_CHAT_WEBHOOK",
"https://chat.googleapis.com/v1/spaces/AAAAWvjq2HE/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=mfrR_lwMjDtMA6qVGp0C0Hlu8jFvaYEpFrfIaKJJroQ",
)
class TestUnifiedCardTool:
"""Test the Unified Card Tool using the FastMCP Client."""
# Use standardized client fixture from conftest.py
@pytest.mark.asyncio
async def test_send_dynamic_card_tool_available(self, client):
"""Test that the send_dynamic_card tool is available."""
tools = await client.list_tools()
tool_names = [tool.name for tool in tools]
# Check for the main tool we're testing
assert (
"send_dynamic_card" in tool_names
), "Tool 'send_dynamic_card' not found in available tools"
print("โ
send_dynamic_card tool is available")
@pytest.mark.asyncio
async def test_send_dynamic_card_simple(self, client):
"""Test sending a simple dynamic card."""
# Skip if no webhook URL is available
if not TEST_WEBHOOK_URL:
pytest.skip("No webhook URL available for testing send_dynamic_card")
try:
# Call the tool with a simple card description
result = await client.call_tool(
"send_dynamic_card",
{
"user_google_email": TEST_EMAIL,
"space_id": TEST_SPACE_ID,
"card_description": "simple card with title and text",
"card_params": {
"title": "Simple Test Card",
"text": "This is a simple test card sent by the unified card tool",
"subtitle": "Simple Test",
},
"webhook_url": TEST_WEBHOOK_URL,
},
)
# Simple optimistic approach
assert len(result.content) > 0
content = result.content[0].text
# Check result
assert (
"successfully" in content.lower() or "sent" in content.lower()
), f"Failed to send card: {content}"
print(f"Simple card sending result: {content}")
except Exception as e:
# Handle server errors gracefully
print(f"Error during test_send_dynamic_card_simple: {str(e)}")
# Don't fail the test if there's a server-side error
pytest.skip(f"Server error occurred: {str(e)}")
@pytest.mark.asyncio
async def test_send_dynamic_card_with_image(self, client):
"""Test sending a dynamic card with an image."""
# Skip if no webhook URL is available
if not TEST_WEBHOOK_URL:
pytest.skip("No webhook URL available for testing send_dynamic_card")
try:
# Call the tool with a card description that includes an image
result = await client.call_tool(
"send_dynamic_card",
{
"user_google_email": TEST_EMAIL,
"space_id": TEST_SPACE_ID,
"card_description": "card with title, text and image",
"card_params": {
"title": "Image Test Card",
"text": "This card includes an image",
"subtitle": "Image Test",
"image_url": "https://picsum.photos/200/300",
},
"webhook_url": TEST_WEBHOOK_URL,
},
)
# Simple optimistic approach
assert len(result.content) > 0
content = result.content[0].text
# Check result
assert (
"successfully" in content.lower() or "sent" in content.lower()
), f"Failed to send card with image: {content}"
print(f"Card with image sending result: {content}")
except Exception as e:
# Handle server errors gracefully
print(f"Error during test_send_dynamic_card_with_image: {str(e)}")
# Don't fail the test if there's a server-side error
pytest.skip(f"Server error occurred: {str(e)}")
@pytest.mark.asyncio
async def test_send_dynamic_card_interactive(self, client):
"""Test sending an interactive dynamic card with buttons."""
# Skip if no webhook URL is available
if not TEST_WEBHOOK_URL:
pytest.skip("No webhook URL available for testing send_dynamic_card")
try:
# Call the tool with an interactive card description
result = await client.call_tool(
"send_dynamic_card",
{
"user_google_email": TEST_EMAIL,
"space_id": TEST_SPACE_ID,
"card_description": "interactive card with buttons",
"card_params": {
"title": "Interactive Test Card",
"text": "This card has interactive buttons",
"buttons": [
{"text": "Visit Google", "url": "https://www.google.com"},
{"text": "Visit GitHub", "url": "https://www.github.com"},
],
},
"webhook_url": TEST_WEBHOOK_URL,
},
)
# Simple optimistic approach
assert len(result.content) > 0
content = result.content[0].text
# Check result
assert (
"successfully" in content.lower() or "sent" in content.lower()
), f"Failed to send interactive card: {content}"
print(f"Interactive card sending result: {content}")
except Exception as e:
# Handle server errors gracefully
print(f"Error during test_send_dynamic_card_interactive: {str(e)}")
# Don't fail the test if there's a server-side error
pytest.skip(f"Server error occurred: {str(e)}")
@pytest.mark.asyncio
async def test_send_dynamic_card_with_natural_language(self, client):
"""Test sending a dynamic card using complex natural language description."""
# Skip if no webhook URL is available
if not TEST_WEBHOOK_URL:
pytest.skip("No webhook URL available for testing send_dynamic_card")
try:
# Call the tool with a complex natural language description
result = await client.call_tool(
"send_dynamic_card",
{
"user_google_email": TEST_EMAIL,
"space_id": TEST_SPACE_ID,
"card_description": "create a rich card with a header, some formatted text, and a button to visit a website",
"card_params": {
"title": "Natural Language Card",
"text": "This card was created using a complex natural language description",
"subtitle": "Demonstrates ModuleWrapper's semantic search",
"image_url": "https://picsum.photos/200/300",
"buttons": [
{
"text": "Learn More",
"url": "https://cloud.google.com/chat",
}
],
},
"webhook_url": TEST_WEBHOOK_URL,
},
)
# Simple optimistic approach
assert len(result.content) > 0
content = result.content[0].text
# Check result
assert (
"successfully" in content.lower() or "sent" in content.lower()
), f"Failed to send card with natural language: {content}"
print(f"Natural language card sending result: {content}")
except Exception as e:
# Handle server errors gracefully
print(
f"Error during test_send_dynamic_card_with_natural_language: {str(e)}"
)
# Don't fail the test if there's a server-side error
pytest.skip(f"Server error occurred: {str(e)}")
@pytest.mark.asyncio
async def test_send_dynamic_card_fallback(self, client):
"""Test the fallback behavior when card description doesn't match any component."""
# Skip if no webhook URL is available
if not TEST_WEBHOOK_URL:
pytest.skip("No webhook URL available for testing send_dynamic_card")
try:
# Call the tool with an unusual description that might not match any component
result = await client.call_tool(
"send_dynamic_card",
{
"user_google_email": TEST_EMAIL,
"space_id": TEST_SPACE_ID,
"card_description": "something completely unusual that doesn't match any card type",
"card_params": {
"title": "Fallback Test",
"text": "Testing fallback behavior",
},
"webhook_url": TEST_WEBHOOK_URL,
},
)
# Simple optimistic approach
assert len(result.content) > 0
content = result.content[0].text
# We should either get a fallback to a simple card or an error message
# Either way, the test should not fail with an exception
print(f"Fallback test result: {content}")
except Exception as e:
# Handle server errors gracefully
print(f"Error during test_send_dynamic_card_fallback: {str(e)}")
# Don't fail the test if there's a server-side error
pytest.skip(f"Server error occurred: {str(e)}")