diff --git a/tests/client/deck/test_deck_update_card_api.py b/tests/client/deck/test_deck_update_card_api.py index cf772e5..d110d9f 100644 --- a/tests/client/deck/test_deck_update_card_api.py +++ b/tests/client/deck/test_deck_update_card_api.py @@ -1,22 +1,16 @@ """ Integration tests for DeckClient.update_card API behavior. -This test suite documents the behavior of our DeckClient.update_card method -and identifies bugs in how it handles partial updates. - -FINDINGS: -The Deck API PUT endpoint is a FULL REPLACEMENT, not a partial update. -Fields not included in the request body are either: -- Required and cause 400 error (title, type, owner) -- Optional but get CLEARED if not sent (description) +These tests define the EXPECTED behavior for partial card updates: +- Only fields explicitly passed should be modified +- All other fields should be preserved unchanged Related issues: -- nextcloud-mcp-server #452: DeckClient.update_card always sets owner/type +- nextcloud-mcp-server #452: DeckClient.update_card partial update bugs - deck #3127: REST API Docs: missing parameter in "update cards" - deck #4106: Provide a working example of API usage to update a cards details """ -import httpx import pytest pytestmark = [pytest.mark.integration] @@ -48,22 +42,15 @@ async def deck_test_card(nc_client): class TestDeckClientUpdateCard: """ - Test DeckClient.update_card() method behavior with various parameter combinations. + Test DeckClient.update_card() partial update behavior. - These tests document the current buggy behavior where: - 1. Updating without title fails (400) - title is required but conditionally sent - 2. Updating with title clears description - description should be preserved + Expected: Only explicitly provided fields are updated, all others preserved. """ - async def test_update_title_only_clears_description( + async def test_update_title_only_preserves_description( self, nc_client, deck_test_card ): - """ - BUG: Updating only the title clears the description. - - The Deck PUT API is a full replacement. Our client doesn't send - description when not explicitly provided, so it gets cleared. - """ + """Updating only the title should preserve the description.""" await nc_client.deck.update_card( board_id=deck_test_card["board_id"], stack_id=deck_test_card["stack_id"], @@ -77,28 +64,27 @@ class TestDeckClientUpdateCard: deck_test_card["card_id"], ) assert updated.title == "New Title" - # BUG: Description was cleared instead of preserved - assert updated.description == "" # Should be "Original description" + assert updated.description == "Original description" - async def test_update_description_only_fails(self, nc_client, deck_test_card): - """ - BUG: Updating only the description fails with 400. + async def test_update_description_only(self, nc_client, deck_test_card): + """Updating only the description should work and preserve other fields.""" + await nc_client.deck.update_card( + board_id=deck_test_card["board_id"], + stack_id=deck_test_card["stack_id"], + card_id=deck_test_card["card_id"], + description="New description only", + ) - The Deck PUT API requires title, type, and owner. - Our client doesn't send title when not explicitly provided. - """ - with pytest.raises(httpx.HTTPStatusError) as exc_info: - await nc_client.deck.update_card( - board_id=deck_test_card["board_id"], - stack_id=deck_test_card["stack_id"], - card_id=deck_test_card["card_id"], - description="New description only", - ) - - assert exc_info.value.response.status_code == 400 + updated = await nc_client.deck.get_card( + deck_test_card["board_id"], + deck_test_card["stack_id"], + deck_test_card["card_id"], + ) + assert updated.title == "Original Title" + assert updated.description == "New description only" async def test_update_title_and_description(self, nc_client, deck_test_card): - """Updating title and description together works correctly.""" + """Updating title and description together should work.""" await nc_client.deck.update_card( board_id=deck_test_card["board_id"], stack_id=deck_test_card["stack_id"], @@ -115,40 +101,62 @@ class TestDeckClientUpdateCard: assert updated.title == "New Title" assert updated.description == "New description" - async def test_update_duedate_only_fails(self, nc_client, deck_test_card): - """ - BUG: Updating only the duedate fails with 400. + async def test_update_duedate_only(self, nc_client, deck_test_card): + """Updating only the duedate should work and preserve other fields.""" + await nc_client.deck.update_card( + board_id=deck_test_card["board_id"], + stack_id=deck_test_card["stack_id"], + card_id=deck_test_card["card_id"], + duedate="2025-12-31T23:59:59+00:00", + ) - title is required but not sent when not explicitly provided. - """ - with pytest.raises(httpx.HTTPStatusError) as exc_info: - await nc_client.deck.update_card( - board_id=deck_test_card["board_id"], - stack_id=deck_test_card["stack_id"], - card_id=deck_test_card["card_id"], - duedate="2025-12-31T23:59:59+00:00", - ) + updated = await nc_client.deck.get_card( + deck_test_card["board_id"], + deck_test_card["stack_id"], + deck_test_card["card_id"], + ) + assert updated.title == "Original Title" + assert updated.description == "Original description" + assert updated.duedate is not None - assert exc_info.value.response.status_code == 400 + async def test_update_archived_only(self, nc_client, deck_test_card): + """Updating only the archived status should work and preserve other fields.""" + await nc_client.deck.update_card( + board_id=deck_test_card["board_id"], + stack_id=deck_test_card["stack_id"], + card_id=deck_test_card["card_id"], + archived=True, + ) - async def test_update_archived_only_fails(self, nc_client, deck_test_card): - """ - BUG: Updating only the archived status fails with 400. + updated = await nc_client.deck.get_card( + deck_test_card["board_id"], + deck_test_card["stack_id"], + deck_test_card["card_id"], + ) + assert updated.title == "Original Title" + assert updated.description == "Original description" + assert updated.archived is True - title is required but not sent when not explicitly provided. - """ - with pytest.raises(httpx.HTTPStatusError) as exc_info: - await nc_client.deck.update_card( - board_id=deck_test_card["board_id"], - stack_id=deck_test_card["stack_id"], - card_id=deck_test_card["card_id"], - archived=True, - ) + async def test_update_order_only(self, nc_client, deck_test_card): + """Updating only the order should work and preserve other fields.""" + await nc_client.deck.update_card( + board_id=deck_test_card["board_id"], + stack_id=deck_test_card["stack_id"], + card_id=deck_test_card["card_id"], + order=99, + ) - assert exc_info.value.response.status_code == 400 + updated = await nc_client.deck.get_card( + deck_test_card["board_id"], + deck_test_card["stack_id"], + deck_test_card["card_id"], + ) + assert updated.title == "Original Title" + assert updated.description == "Original description" + assert updated.order == 99 async def test_update_preserves_type(self, nc_client, deck_test_card): - """Type is correctly preserved (already always sent in current implementation).""" + """Type should be preserved when not explicitly changed.""" original = deck_test_card["card"] await nc_client.deck.update_card( @@ -164,9 +172,10 @@ class TestDeckClientUpdateCard: deck_test_card["card_id"], ) assert updated.type == original.type + assert updated.description == "Original description" async def test_update_preserves_owner(self, nc_client, deck_test_card): - """Owner is correctly preserved (already always sent in current implementation).""" + """Owner should be preserved when not explicitly changed.""" original = deck_test_card["card"] await nc_client.deck.update_card( @@ -182,19 +191,4 @@ class TestDeckClientUpdateCard: deck_test_card["card_id"], ) assert updated.owner == original.owner - - async def test_update_order_only_fails(self, nc_client, deck_test_card): - """ - BUG: Updating only the order fails with 400. - - title is required but not sent when not explicitly provided. - """ - with pytest.raises(httpx.HTTPStatusError) as exc_info: - await nc_client.deck.update_card( - board_id=deck_test_card["board_id"], - stack_id=deck_test_card["stack_id"], - card_id=deck_test_card["card_id"], - order=1, - ) - - assert exc_info.value.response.status_code == 400 + assert updated.description == "Original description"