Files
trello-plugin/tests/test_cards.py
T
Marko (Hermes Implementer) 034ed2c928 feat: implement Trello card management
Add 12 card management tools:
- trello_create_card — create a card on a list
- trello_card_details — view card with members, checklists, comments
- trello_update_card — update title, description, due date
- trello_move_card — move card to a different list
- trello_archive_card — archive a card
- trello_assign_member / trello_remove_member — member management
- trello_add_comment / trello_delete_comment — comments
- trello_add_checklist_item / trello_toggle_checklist_item / trello_delete_checklist_item

Also adds _delete() helper on TrelloClient for DELETE verbs.

73 total tests — all passing.

Issue: #4
2026-05-26 22:42:50 +00:00

313 lines
16 KiB
Python

"""Tests for the Trello plugin — card management feature."""
from __future__ import annotations
import json
import os
from typing import Any
import pytest
pytestmark = pytest.mark.usefixtures("clear_env")
@pytest.fixture(autouse=True)
def clear_env(monkeypatch: pytest.MonkeyPatch) -> Any:
monkeypatch.delenv("TRELLO_API_KEY", raising=False)
monkeypatch.delenv("TRELLO_TOKEN", raising=False)
# ---------------------------------------------------------------------------
# TrelloClient — create_card
# ---------------------------------------------------------------------------
class TestCreateCard:
def test_success(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.post("https://api.trello.com/1/cards", json={"id": "c1", "name": "My Card", "url": "https://trello.com/c/c1", "shortUrl": "https://trello.com/c/abc", "idList": "l1"})
client = TrelloClient(api_key="k", token="t")
result = client.create_card(name="My Card", list_id="l1")
assert result["success"]
assert result["card"]["name"] == "My Card"
def test_with_description_and_due(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.post("https://api.trello.com/1/cards", json={"id": "c1", "name": "Card", "url": "", "shortUrl": "", "idList": "l1"})
client = TrelloClient(api_key="k", token="t")
result = client.create_card(name="Card", list_id="l1", desc="Desc", due="2026-06-01T00:00:00Z")
assert result["success"]
def test_missing_credentials(self) -> None:
from trello_plugin.client import TrelloClient
client = TrelloClient(api_key="", token="")
result = client.create_card(name="Card", list_id="l1")
assert not result["success"]
assert "TRELLO_API_KEY" in result["message"]
# ---------------------------------------------------------------------------
# TrelloClient — card_details
# ---------------------------------------------------------------------------
class TestCardDetails:
def test_success(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.get(
"https://api.trello.com/1/cards/c1",
json={
"id": "c1", "name": "My Card", "desc": "Description", "due": None,
"dueComplete": False, "url": "https://trello.com/c/c1", "shortUrl": "https://trello.com/c/abc",
"idList": "l1", "closed": False, "list": {"id": "l1", "name": "To Do"},
"members": [{"id": "m1", "username": "user1", "fullName": "User One"}],
"checklists": [{"id": "cl1", "name": "Checklist", "checkItems": [{"id": "ci1", "name": "Item", "state": "incomplete"}]}],
"actions": [{"id": "a1", "type": "commentCard", "data": {"text": "Nice card"}, "memberCreator": {"username": "user1"}, "date": "2026-05-01T00:00:00Z"}],
},
)
client = TrelloClient(api_key="k", token="t")
result = client.card_details(card_id="c1")
assert result["success"]
assert result["card"]["name"] == "My Card"
assert len(result["card"]["members"]) == 1
assert len(result["card"]["checklists"]) == 1
assert len(result["card"]["comments"]) == 1
# ---------------------------------------------------------------------------
# TrelloClient — update_card
# ---------------------------------------------------------------------------
class TestUpdateCard:
def test_update_name(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.put("https://api.trello.com/1/cards/c1", json={"id": "c1", "name": "Updated", "desc": "", "due": None})
client = TrelloClient(api_key="k", token="t")
result = client.update_card(card_id="c1", name="Updated")
assert result["success"]
assert result["card"]["name"] == "Updated"
def test_no_changes(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
client = TrelloClient(api_key="k", token="t")
result = client.update_card(card_id="c1")
assert result["success"]
assert "No changes" in result["message"]
# ---------------------------------------------------------------------------
# TrelloClient — move_card, archive_card
# ---------------------------------------------------------------------------
class TestMoveCard:
def test_success(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.put("https://api.trello.com/1/cards/c1", json={"id": "c1", "name": "Card", "idList": "l2"})
client = TrelloClient(api_key="k", token="t")
result = client.move_card(card_id="c1", list_id="l2")
assert result["success"]
class TestArchiveCard:
def test_success(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.put("https://api.trello.com/1/cards/c1", json={"id": "c1", "name": "Card", "closed": True})
client = TrelloClient(api_key="k", token="t")
result = client.archive_card(card_id="c1")
assert result["success"]
# ---------------------------------------------------------------------------
# TrelloClient — member operations
# ---------------------------------------------------------------------------
class TestMemberOps:
def test_assign_member(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.post("https://api.trello.com/1/cards/c1/idMembers", json={"id": "c1"}, status_code=200)
client = TrelloClient(api_key="k", token="t")
result = client.assign_member(card_id="c1", member_id="m1")
assert result["success"]
def test_remove_member(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.delete("https://api.trello.com/1/cards/c1/idMembers/m1", status_code=200, json={})
client = TrelloClient(api_key="k", token="t")
result = client.remove_member(card_id="c1", member_id="m1")
assert result["success"]
# ---------------------------------------------------------------------------
# TrelloClient — comments
# ---------------------------------------------------------------------------
class TestComments:
def test_add_comment(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.post("https://api.trello.com/1/cards/c1/actions/comments", json={"id": "a1", "data": {"text": "Great!"}})
client = TrelloClient(api_key="k", token="t")
result = client.add_comment(card_id="c1", text="Great!")
assert result["success"]
assert result["comment"]["id"] == "a1"
def test_delete_comment(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.delete("https://api.trello.com/1/cards/c1/actions/a1/comments", status_code=200, json={})
client = TrelloClient(api_key="k", token="t")
result = client.delete_comment(card_id="c1", comment_id="a1")
assert result["success"]
# ---------------------------------------------------------------------------
# TrelloClient — checklists
# ---------------------------------------------------------------------------
class TestChecklistItems:
def test_add_item_with_checklist_id(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.post("https://api.trello.com/1/cards/c1/checklistItems", json={"id": "ci1", "name": "Task", "state": "incomplete", "idChecklist": "cl1"})
client = TrelloClient(api_key="k", token="t")
result = client.add_checklist_item(card_id="c1", name="Task", checklist_id="cl1")
assert result["success"]
assert result["item"]["name"] == "Task"
def test_add_item_auto_discover(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
# card_details call for auto-discover
requests_mock.get(
"https://api.trello.com/1/cards/c1",
json={
"id": "c1", "name": "Card", "desc": "", "due": None,
"dueComplete": False, "url": "", "shortUrl": "", "idList": "l1", "closed": False,
"list": {"id": "l1", "name": "List"},
"members": [], "checklists": [{"id": "cl1", "name": "Checklist", "checkItems": []}],
"actions": [],
},
)
requests_mock.post("https://api.trello.com/1/cards/c1/checklistItems", json={"id": "ci1", "name": "Auto", "state": "incomplete", "idChecklist": "cl1"})
client = TrelloClient(api_key="k", token="t")
result = client.add_checklist_item(card_id="c1", name="Auto")
assert result["success"]
def test_toggle_complete(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.put("https://api.trello.com/1/cards/c1/checklistItem/ci1", json={"id": "ci1", "name": "Task", "state": "complete"})
client = TrelloClient(api_key="k", token="t")
result = client.toggle_checklist_item(card_id="c1", item_id="ci1", checked=True)
assert result["success"]
assert result["item"]["state"] == "complete"
def test_toggle_incomplete(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.put("https://api.trello.com/1/cards/c1/checklistItem/ci1", json={"id": "ci1", "name": "Task", "state": "incomplete"})
client = TrelloClient(api_key="k", token="t")
result = client.toggle_checklist_item(card_id="c1", item_id="ci1", checked=False)
assert result["success"]
assert result["item"]["state"] == "incomplete"
def test_delete_item(self, requests_mock: Any) -> None:
from trello_plugin.client import TrelloClient
requests_mock.delete("https://api.trello.com/1/cards/c1/checklistItems/ci1", status_code=200, json={})
client = TrelloClient(api_key="k", token="t")
result = client.delete_checklist_item(card_id="c1", item_id="ci1")
assert result["success"]
# ---------------------------------------------------------------------------
# Tool functions
# ---------------------------------------------------------------------------
class TestCardToolFunctions:
def test_trello_create_card_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_create_card
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.post("https://api.trello.com/1/cards", json={"id": "c1", "name": "Card", "url": "", "shortUrl": "", "idList": "l1"})
result = json.loads(trello_create_card(name="Card", list_id="l1"))
assert result["success"]
def test_trello_card_details_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_card_details
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.get("https://api.trello.com/1/cards/c1", json={"id": "c1", "name": "Card", "desc": "", "due": None, "dueComplete": False, "url": "", "shortUrl": "", "idList": "l1", "closed": False, "list": {"id": "l1", "name": "List"}, "members": [], "checklists": [], "actions": []})
result = json.loads(trello_card_details(card_id="c1"))
assert result["success"]
def test_trello_update_card_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_update_card
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.put("https://api.trello.com/1/cards/c1", json={"id": "c1", "name": "New", "desc": "", "due": None})
result = json.loads(trello_update_card(card_id="c1", name="New"))
assert result["success"]
def test_trello_move_card_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_move_card
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.put("https://api.trello.com/1/cards/c1", json={"id": "c1", "name": "Card", "idList": "l2"})
result = json.loads(trello_move_card(card_id="c1", list_id="l2"))
assert result["success"]
def test_trello_archive_card_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_archive_card
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.put("https://api.trello.com/1/cards/c1", json={"id": "c1", "name": "Card", "closed": True})
result = json.loads(trello_archive_card(card_id="c1"))
assert result["success"]
def test_trello_assign_member_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_assign_member
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.post("https://api.trello.com/1/cards/c1/idMembers", json={}, status_code=200)
result = json.loads(trello_assign_member(card_id="c1", member_id="m1"))
assert result["success"]
def test_trello_remove_member_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_remove_member
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.delete("https://api.trello.com/1/cards/c1/idMembers/m1", status_code=200, json={})
result = json.loads(trello_remove_member(card_id="c1", member_id="m1"))
assert result["success"]
def test_trello_add_comment_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_add_comment
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.post("https://api.trello.com/1/cards/c1/actions/comments", json={"id": "a1", "data": {"text": "Nice"}})
result = json.loads(trello_add_comment(card_id="c1", text="Nice"))
assert result["success"]
def test_trello_delete_comment_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_delete_comment
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.delete("https://api.trello.com/1/cards/c1/actions/a1/comments", status_code=200, json={})
result = json.loads(trello_delete_comment(card_id="c1", comment_id="a1"))
assert result["success"]
def test_trello_add_checklist_item_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_add_checklist_item
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.post("https://api.trello.com/1/cards/c1/checklistItems", json={"id": "ci1", "name": "Task", "state": "incomplete", "idChecklist": "cl1"})
result = json.loads(trello_add_checklist_item(card_id="c1", name="Task", checklist_id="cl1"))
assert result["success"]
def test_trello_toggle_checklist_item_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_toggle_checklist_item
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.put("https://api.trello.com/1/cards/c1/checklistItem/ci1", json={"id": "ci1", "name": "Task", "state": "complete"})
result = json.loads(trello_toggle_checklist_item(card_id="c1", item_id="ci1", checked=True))
assert result["success"]
def test_trello_delete_checklist_item_tool(self, requests_mock: Any) -> None:
from trello_plugin.tools import trello_delete_checklist_item
os.environ["TRELLO_API_KEY"] = "k"
os.environ["TRELLO_TOKEN"] = "t"
requests_mock.delete("https://api.trello.com/1/cards/c1/checklistItems/ci1", status_code=200, json={})
result = json.loads(trello_delete_checklist_item(card_id="c1", item_id="ci1"))
assert result["success"]