21e4d3effd
The reorder_card method was using the API route
/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/reorder
which has a parameter conflict: the URL's {stackId} (current stack)
overrides the body's stackId (target stack) in Nextcloud's routing.
This caused cards to stay in their original stack even when the API
reported success.
Switched to the non-API route /cards/{cardId}/reorder which correctly
reads stackId from the request body, matching the behavior of the
working curl command reported in the issue.
Also added the required OCS-APIRequest headers that were missing.
Fixes #469
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
178 lines
6.3 KiB
Python
178 lines
6.3 KiB
Python
"""Integration tests for Deck card reorder functionality.
|
|
|
|
Tests issue #469: Moving Deck card from one column (stack) to another not working.
|
|
https://github.com/cbcoutinho/nextcloud-mcp-server/issues/469
|
|
"""
|
|
|
|
import logging
|
|
import uuid
|
|
|
|
import pytest
|
|
|
|
from nextcloud_mcp_server.client import NextcloudClient
|
|
|
|
logger = logging.getLogger(__name__)
|
|
pytestmark = pytest.mark.integration
|
|
|
|
|
|
@pytest.fixture
|
|
async def board_with_two_stacks(nc_client: NextcloudClient):
|
|
"""Create a temporary board with two stacks for testing card movement.
|
|
|
|
Yields:
|
|
tuple: (board_data, source_stack_data, target_stack_data)
|
|
"""
|
|
unique_suffix = uuid.uuid4().hex[:8]
|
|
board_title = f"Reorder Test Board {unique_suffix}"
|
|
board = None
|
|
|
|
logger.info(f"Creating board with two stacks: {board_title}")
|
|
try:
|
|
board = await nc_client.deck.create_board(board_title, "0000FF")
|
|
board_id = board.id
|
|
|
|
# Create source stack (stack 1)
|
|
source_stack = await nc_client.deck.create_stack(
|
|
board_id, f"Source Stack {unique_suffix}", order=1
|
|
)
|
|
source_stack_data = {
|
|
"id": source_stack.id,
|
|
"title": source_stack.title,
|
|
"order": source_stack.order,
|
|
}
|
|
logger.info(f"Created source stack with ID: {source_stack.id}")
|
|
|
|
# Create target stack (stack 2)
|
|
target_stack = await nc_client.deck.create_stack(
|
|
board_id, f"Target Stack {unique_suffix}", order=2
|
|
)
|
|
target_stack_data = {
|
|
"id": target_stack.id,
|
|
"title": target_stack.title,
|
|
"order": target_stack.order,
|
|
}
|
|
logger.info(f"Created target stack with ID: {target_stack.id}")
|
|
|
|
board_data = {
|
|
"id": board_id,
|
|
"title": board.title,
|
|
"color": board.color,
|
|
}
|
|
|
|
yield (board_data, source_stack_data, target_stack_data)
|
|
|
|
finally:
|
|
if board:
|
|
logger.info(f"Cleaning up board ID: {board.id}")
|
|
try:
|
|
await nc_client.deck.delete_board(board.id)
|
|
except Exception as e:
|
|
logger.warning(f"Error cleaning up board: {e}")
|
|
|
|
|
|
async def test_reorder_card_move_to_different_stack(
|
|
nc_client: NextcloudClient, board_with_two_stacks: tuple
|
|
):
|
|
"""Test moving a card from one stack to another (issue #469).
|
|
|
|
This test reproduces the bug where the reorder_card API reports success
|
|
but the card doesn't actually move to the target stack.
|
|
"""
|
|
board_data, source_stack_data, target_stack_data = board_with_two_stacks
|
|
board_id = board_data["id"]
|
|
source_stack_id = source_stack_data["id"]
|
|
target_stack_id = target_stack_data["id"]
|
|
|
|
# Create a card in the source stack
|
|
unique_suffix = uuid.uuid4().hex[:8]
|
|
card_title = f"Test Card {unique_suffix}"
|
|
card = await nc_client.deck.create_card(
|
|
board_id, source_stack_id, card_title, description="Card to be moved"
|
|
)
|
|
card_id = card.id
|
|
logger.info(f"Created card ID: {card_id} in source stack ID: {source_stack_id}")
|
|
|
|
try:
|
|
# Verify card is in source stack
|
|
card_before = await nc_client.deck.get_card(board_id, source_stack_id, card_id)
|
|
assert card_before.stackId == source_stack_id, (
|
|
f"Card should start in source stack {source_stack_id}, "
|
|
f"but is in {card_before.stackId}"
|
|
)
|
|
logger.info(f"Verified card is in source stack: {source_stack_id}")
|
|
|
|
# Move card to target stack
|
|
logger.info(
|
|
f"Moving card {card_id} from stack {source_stack_id} "
|
|
f"to stack {target_stack_id}"
|
|
)
|
|
await nc_client.deck.reorder_card(
|
|
board_id=board_id,
|
|
stack_id=source_stack_id,
|
|
card_id=card_id,
|
|
order=0,
|
|
target_stack_id=target_stack_id,
|
|
)
|
|
logger.info("reorder_card API call completed")
|
|
|
|
# Verify card moved to target stack
|
|
# Note: After moving, the card should be accessible from the target stack
|
|
card_after = await nc_client.deck.get_card(board_id, target_stack_id, card_id)
|
|
assert card_after.stackId == target_stack_id, (
|
|
f"Card should have moved to target stack {target_stack_id}, "
|
|
f"but is in {card_after.stackId}"
|
|
)
|
|
logger.info(f"SUCCESS: Card moved to target stack {target_stack_id}")
|
|
|
|
finally:
|
|
# Clean up - try to delete from target stack first, then source
|
|
try:
|
|
await nc_client.deck.delete_card(board_id, target_stack_id, card_id)
|
|
except Exception:
|
|
try:
|
|
await nc_client.deck.delete_card(board_id, source_stack_id, card_id)
|
|
except Exception as e:
|
|
logger.warning(f"Error cleaning up card: {e}")
|
|
|
|
|
|
async def test_reorder_card_within_same_stack(
|
|
nc_client: NextcloudClient, board_with_two_stacks: tuple
|
|
):
|
|
"""Test reordering a card within the same stack (should work)."""
|
|
board_data, source_stack_data, _ = board_with_two_stacks
|
|
board_id = board_data["id"]
|
|
source_stack_id = source_stack_data["id"]
|
|
|
|
# Create two cards in the source stack
|
|
unique_suffix = uuid.uuid4().hex[:8]
|
|
card1 = await nc_client.deck.create_card(
|
|
board_id, source_stack_id, f"Card 1 {unique_suffix}", order=0
|
|
)
|
|
card2 = await nc_client.deck.create_card(
|
|
board_id, source_stack_id, f"Card 2 {unique_suffix}", order=1
|
|
)
|
|
logger.info(f"Created cards {card1.id} (order 0) and {card2.id} (order 1)")
|
|
|
|
try:
|
|
# Reorder card1 to position after card2
|
|
await nc_client.deck.reorder_card(
|
|
board_id=board_id,
|
|
stack_id=source_stack_id,
|
|
card_id=card1.id,
|
|
order=2, # Move to position 2
|
|
target_stack_id=source_stack_id, # Same stack
|
|
)
|
|
logger.info(f"Reordered card {card1.id} to order 2")
|
|
|
|
# Verify card is still in the same stack
|
|
card_after = await nc_client.deck.get_card(board_id, source_stack_id, card1.id)
|
|
assert card_after.stackId == source_stack_id
|
|
logger.info("Card reorder within same stack succeeded")
|
|
|
|
finally:
|
|
try:
|
|
await nc_client.deck.delete_card(board_id, source_stack_id, card1.id)
|
|
await nc_client.deck.delete_card(board_id, source_stack_id, card2.id)
|
|
except Exception as e:
|
|
logger.warning(f"Error cleaning up cards: {e}")
|