feat: implement Trello list management
Add 4 list management tools extending the Trello client: - trello_create_list — create a new list on a board - trello_rename_list — rename an existing list - trello_archive_list — archive a list - trello_move_list — move a list to a new position Also update the auth spec doc to reflect the PR #5 review fixes (TypedDict contracts, updated disconnect message). Issue: #3
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
"""Tests for the Trello plugin — list management feature."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.usefixtures("clear_env")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def clear_env(monkeypatch: pytest.MonkeyPatch) -> Any:
|
||||
"""Remove Trello env vars before each test so state is predictable."""
|
||||
monkeypatch.delenv("TRELLO_API_KEY", raising=False)
|
||||
monkeypatch.delenv("TRELLO_TOKEN", raising=False)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TrelloClient — create_list
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestCreateList:
|
||||
"""Tests for TrelloClient.create_list()."""
|
||||
|
||||
def test_success(self, requests_mock: Any) -> None:
|
||||
"""Happy path: creates a list and returns details."""
|
||||
from trello_plugin.client import TrelloClient
|
||||
|
||||
# Resolve board
|
||||
requests_mock.get(
|
||||
"https://api.trello.com/1/boards/b1",
|
||||
json={"id": "b1", "name": "My Board", "url": ""},
|
||||
)
|
||||
# Create list
|
||||
requests_mock.post(
|
||||
"https://api.trello.com/1/lists",
|
||||
json={"id": "l1", "name": "To Do", "idBoard": "b1"},
|
||||
)
|
||||
|
||||
client = TrelloClient(api_key="key", token="tok")
|
||||
result = client.create_list(name="To Do", board_id="b1")
|
||||
|
||||
assert result["success"] is True
|
||||
assert result["list"]["name"] == "To Do"
|
||||
assert result["list"]["id_board"] == "b1"
|
||||
|
||||
def test_board_not_found(self, requests_mock: Any) -> None:
|
||||
"""Non-existent board returns error."""
|
||||
from trello_plugin.client import TrelloClient
|
||||
|
||||
requests_mock.get(
|
||||
"https://api.trello.com/1/boards/nonexistent",
|
||||
status_code=404,
|
||||
)
|
||||
requests_mock.get(
|
||||
"https://api.trello.com/1/members/me/boards",
|
||||
json=[],
|
||||
)
|
||||
|
||||
client = TrelloClient(api_key="key", token="tok")
|
||||
result = client.create_list(name="List", board_id="nonexistent")
|
||||
|
||||
assert result["success"] is False
|
||||
assert "not found" in result["message"].lower()
|
||||
|
||||
def test_missing_credentials(self) -> None:
|
||||
"""Missing creds returns error before any network call."""
|
||||
from trello_plugin.client import TrelloClient
|
||||
|
||||
client = TrelloClient(api_key="", token="")
|
||||
result = client.create_list(name="List", board_id="b1")
|
||||
|
||||
assert result["success"] is False
|
||||
assert "TRELLO_API_KEY" in result["message"]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TrelloClient — rename_list
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestRenameList:
|
||||
"""Tests for TrelloClient.rename_list()."""
|
||||
|
||||
def test_success(self, requests_mock: Any) -> None:
|
||||
"""Renaming a list works."""
|
||||
from trello_plugin.client import TrelloClient
|
||||
|
||||
requests_mock.put(
|
||||
"https://api.trello.com/1/lists/l1",
|
||||
json={"id": "l1", "name": "Renamed List"},
|
||||
)
|
||||
|
||||
client = TrelloClient(api_key="key", token="tok")
|
||||
result = client.rename_list(list_id="l1", name="Renamed List")
|
||||
|
||||
assert result["success"] is True
|
||||
assert result["list"]["name"] == "Renamed List"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TrelloClient — archive_list
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestArchiveList:
|
||||
"""Tests for TrelloClient.archive_list()."""
|
||||
|
||||
def test_success(self, requests_mock: Any) -> None:
|
||||
"""Archiving a list returns success message."""
|
||||
from trello_plugin.client import TrelloClient
|
||||
|
||||
requests_mock.put(
|
||||
"https://api.trello.com/1/lists/l1",
|
||||
json={"id": "l1", "name": "My List", "closed": True},
|
||||
)
|
||||
|
||||
client = TrelloClient(api_key="key", token="tok")
|
||||
result = client.archive_list(list_id="l1")
|
||||
|
||||
assert result["success"] is True
|
||||
assert "archived" in result["message"].lower()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TrelloClient — move_list
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestMoveList:
|
||||
"""Tests for TrelloClient.move_list()."""
|
||||
|
||||
def test_success(self, requests_mock: Any) -> None:
|
||||
"""Moving a list returns success message."""
|
||||
from trello_plugin.client import TrelloClient
|
||||
|
||||
requests_mock.put(
|
||||
"https://api.trello.com/1/lists/l1",
|
||||
json={"id": "l1", "name": "My List", "pos": 1},
|
||||
)
|
||||
|
||||
client = TrelloClient(api_key="key", token="tok")
|
||||
result = client.move_list(list_id="l1", pos="top")
|
||||
|
||||
assert result["success"] is True
|
||||
assert "moved" in result["message"].lower()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tool functions
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestListToolFunctions:
|
||||
"""Tests for the Hermes list management tool wrappers."""
|
||||
|
||||
def test_trello_create_list_tool(self, requests_mock: Any) -> None:
|
||||
"""Create list tool returns valid JSON."""
|
||||
from trello_plugin.tools import trello_create_list
|
||||
|
||||
os.environ["TRELLO_API_KEY"] = "key"
|
||||
os.environ["TRELLO_TOKEN"] = "tok"
|
||||
|
||||
requests_mock.get(
|
||||
"https://api.trello.com/1/boards/b1",
|
||||
json={"id": "b1", "name": "Board", "url": ""},
|
||||
)
|
||||
requests_mock.post(
|
||||
"https://api.trello.com/1/lists",
|
||||
json={"id": "l1", "name": "New List", "idBoard": "b1"},
|
||||
)
|
||||
|
||||
result = json.loads(trello_create_list(name="New List", board_id="b1"))
|
||||
assert result["success"] is True
|
||||
assert result["list"]["name"] == "New List"
|
||||
|
||||
def test_trello_rename_list_tool(self, requests_mock: Any) -> None:
|
||||
"""Rename list tool returns valid JSON."""
|
||||
from trello_plugin.tools import trello_rename_list
|
||||
|
||||
os.environ["TRELLO_API_KEY"] = "key"
|
||||
os.environ["TRELLO_TOKEN"] = "tok"
|
||||
|
||||
requests_mock.put(
|
||||
"https://api.trello.com/1/lists/l1",
|
||||
json={"id": "l1", "name": "Renamed"},
|
||||
)
|
||||
|
||||
result = json.loads(trello_rename_list(list_id="l1", name="Renamed"))
|
||||
assert result["success"] is True
|
||||
assert result["list"]["name"] == "Renamed"
|
||||
|
||||
def test_trello_archive_list_tool(self, requests_mock: Any) -> None:
|
||||
"""Archive list tool returns valid JSON."""
|
||||
from trello_plugin.tools import trello_archive_list
|
||||
|
||||
os.environ["TRELLO_API_KEY"] = "key"
|
||||
os.environ["TRELLO_TOKEN"] = "tok"
|
||||
|
||||
requests_mock.put(
|
||||
"https://api.trello.com/1/lists/l1",
|
||||
json={"id": "l1", "name": "My List", "closed": True},
|
||||
)
|
||||
|
||||
result = json.loads(trello_archive_list(list_id="l1"))
|
||||
assert result["success"] is True
|
||||
assert "archived" in result["message"].lower()
|
||||
|
||||
def test_trello_move_list_tool(self, requests_mock: Any) -> None:
|
||||
"""Move list tool returns valid JSON."""
|
||||
from trello_plugin.tools import trello_move_list
|
||||
|
||||
os.environ["TRELLO_API_KEY"] = "key"
|
||||
os.environ["TRELLO_TOKEN"] = "tok"
|
||||
|
||||
requests_mock.put(
|
||||
"https://api.trello.com/1/lists/l1",
|
||||
json={"id": "l1", "name": "My List", "pos": 1},
|
||||
)
|
||||
|
||||
result = json.loads(trello_move_list(list_id="l1", pos="top"))
|
||||
assert result["success"] is True
|
||||
assert "moved" in result["message"].lower()
|
||||
Reference in New Issue
Block a user