test_categories.py•7.17 kB
"""
Test category-related MCP tools.
"""
from unittest.mock import MagicMock
import ynab
from assertions import assert_pagination_info, extract_response_data
from conftest import create_ynab_category
from fastmcp.client import Client, FastMCPTransport
async def test_list_categories_success(
mock_repository: MagicMock, mcp_client: Client[FastMCPTransport]
) -> None:
"""Test successful category listing."""
visible_category = create_ynab_category(
id="cat-1",
name="Groceries",
note="Food shopping",
goal_type="TB",
goal_target=100_000,
goal_percentage_complete=50,
)
hidden_category = create_ynab_category(
id="cat-hidden",
name="Hidden Category",
hidden=True, # Should be excluded
budgeted=10_000,
activity=0,
balance=10_000,
)
category_group = ynab.CategoryGroupWithCategories(
id="group-1",
name="Monthly Bills",
hidden=False,
deleted=False,
categories=[visible_category, hidden_category],
)
# Mock repository to return category groups
mock_repository.get_category_groups.return_value = [category_group]
result = await mcp_client.call_tool("list_categories", {})
response_data = extract_response_data(result)
# Should only include visible category
categories = response_data["categories"]
assert len(categories) == 1
assert categories[0]["id"] == "cat-1"
assert categories[0]["name"] == "Groceries"
assert categories[0]["category_group_name"] == "Monthly Bills"
assert_pagination_info(
response_data["pagination"],
total_count=1,
limit=50,
has_more=False,
)
async def test_list_category_groups_success(
mock_repository: MagicMock, mcp_client: Client[FastMCPTransport]
) -> None:
"""Test successful category group listing."""
category = ynab.Category(
id="cat-1",
category_group_id="group-1",
category_group_name="Monthly Bills",
name="Test Category",
hidden=False,
original_category_group_id=None,
note=None,
budgeted=50000,
activity=-30000,
balance=20000,
goal_type=None,
goal_needs_whole_amount=None,
goal_day=None,
goal_cadence=None,
goal_cadence_frequency=None,
goal_creation_month=None,
goal_target=None,
goal_target_month=None,
goal_percentage_complete=None,
goal_months_to_budget=None,
goal_under_funded=None,
goal_overall_funded=None,
goal_overall_left=None,
deleted=False,
)
category_group = ynab.CategoryGroupWithCategories(
id="group-1",
name="Monthly Bills",
hidden=False,
deleted=False,
categories=[category],
)
# Mock repository to return category groups
mock_repository.get_category_groups.return_value = [category_group]
result = await mcp_client.call_tool("list_category_groups", {})
groups_data = extract_response_data(result)
# Should return a list of category groups
assert isinstance(groups_data, list)
assert len(groups_data) == 1
group = groups_data[0]
assert group["id"] == "group-1"
assert group["name"] == "Monthly Bills"
async def test_list_categories_filters_deleted_and_hidden(
mock_repository: MagicMock, mcp_client: Client[FastMCPTransport]
) -> None:
"""Test that list_categories automatically filters out deleted and hidden."""
# Active category (should be included)
mock_active_category = ynab.Category(
id="cat-active",
name="Active Category",
category_group_id="group-1",
hidden=False,
deleted=False,
note="Active",
budgeted=10000,
activity=-5000,
balance=5000,
goal_type=None,
goal_target=None,
goal_percentage_complete=None,
goal_under_funded=None,
goal_creation_month=None,
goal_target_month=None,
goal_overall_funded=None,
goal_overall_left=None,
)
# Hidden category (should be excluded)
mock_hidden_category = ynab.Category(
id="cat-hidden",
name="Hidden Category",
category_group_id="group-1",
hidden=True,
deleted=False,
note="Hidden",
budgeted=0,
activity=0,
balance=0,
goal_type=None,
goal_target=None,
goal_percentage_complete=None,
goal_under_funded=None,
goal_creation_month=None,
goal_target_month=None,
goal_overall_funded=None,
goal_overall_left=None,
)
# Deleted category (should be excluded)
mock_deleted_category = ynab.Category(
id="cat-deleted",
name="Deleted Category",
category_group_id="group-1",
hidden=False,
deleted=True,
note="Deleted",
budgeted=0,
activity=0,
balance=0,
goal_type=None,
goal_target=None,
goal_percentage_complete=None,
goal_under_funded=None,
goal_creation_month=None,
goal_target_month=None,
goal_overall_funded=None,
goal_overall_left=None,
)
category_group = ynab.CategoryGroupWithCategories(
id="group-1",
name="Monthly Bills",
hidden=False,
deleted=False,
categories=[
mock_active_category,
mock_hidden_category,
mock_deleted_category,
],
)
# Mock repository to return category groups
mock_repository.get_category_groups.return_value = [category_group]
result = await mcp_client.call_tool("list_categories", {})
response_data = extract_response_data(result)
# Should only include the active category
assert len(response_data["categories"]) == 1
assert response_data["categories"][0]["id"] == "cat-active"
assert response_data["categories"][0]["name"] == "Active Category"
async def test_list_category_groups_filters_deleted(
mock_repository: MagicMock, mcp_client: Client[FastMCPTransport]
) -> None:
"""Test that list_category_groups automatically filters out deleted groups."""
# Active group (should be included)
active_group = ynab.CategoryGroupWithCategories(
id="group-active",
name="Active Group",
hidden=False,
deleted=False,
categories=[],
)
# Deleted group (should be excluded)
deleted_group = ynab.CategoryGroupWithCategories(
id="group-deleted",
name="Deleted Group",
hidden=False,
deleted=True,
categories=[],
)
# Mock repository to return category groups
mock_repository.get_category_groups.return_value = [active_group, deleted_group]
result = await mcp_client.call_tool("list_category_groups", {})
response_data = extract_response_data(result)
# Should only include the active group
assert isinstance(response_data, list)
assert len(response_data) == 1
group = response_data[0]
assert group["id"] == "group-active"
assert group["name"] == "Active Group"