test: Define expected partial update behavior for DeckClient.update_card

Refactor tests to assert what SHOULD happen (partial updates preserve
unchanged fields) rather than documenting current buggy behavior.

Tests will fail until fix is implemented in client or upstream.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2025-12-30 22:28:23 -06:00
co-authored by Claude Opus 4.5
parent 30d3d9f0cf
commit 71ace47197
+77 -83
View File
@@ -1,22 +1,16 @@
""" """
Integration tests for DeckClient.update_card API behavior. Integration tests for DeckClient.update_card API behavior.
This test suite documents the behavior of our DeckClient.update_card method These tests define the EXPECTED behavior for partial card updates:
and identifies bugs in how it handles partial updates. - Only fields explicitly passed should be modified
- All other fields should be preserved unchanged
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)
Related issues: 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 #3127: REST API Docs: missing parameter in "update cards"
- deck #4106: Provide a working example of API usage to update a cards details - deck #4106: Provide a working example of API usage to update a cards details
""" """
import httpx
import pytest import pytest
pytestmark = [pytest.mark.integration] pytestmark = [pytest.mark.integration]
@@ -48,22 +42,15 @@ async def deck_test_card(nc_client):
class TestDeckClientUpdateCard: 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: Expected: Only explicitly provided fields are updated, all others preserved.
1. Updating without title fails (400) - title is required but conditionally sent
2. Updating with title clears description - description should be preserved
""" """
async def test_update_title_only_clears_description( async def test_update_title_only_preserves_description(
self, nc_client, deck_test_card self, nc_client, deck_test_card
): ):
""" """Updating only the title should preserve the description."""
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.
"""
await nc_client.deck.update_card( await nc_client.deck.update_card(
board_id=deck_test_card["board_id"], board_id=deck_test_card["board_id"],
stack_id=deck_test_card["stack_id"], stack_id=deck_test_card["stack_id"],
@@ -77,28 +64,27 @@ class TestDeckClientUpdateCard:
deck_test_card["card_id"], deck_test_card["card_id"],
) )
assert updated.title == "New Title" assert updated.title == "New Title"
# BUG: Description was cleared instead of preserved assert updated.description == "Original description"
assert updated.description == "" # Should be "Original description"
async def test_update_description_only_fails(self, nc_client, deck_test_card): async def test_update_description_only(self, nc_client, deck_test_card):
""" """Updating only the description should work and preserve other fields."""
BUG: Updating only the description fails with 400. 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. updated = await nc_client.deck.get_card(
Our client doesn't send title when not explicitly provided. deck_test_card["board_id"],
""" deck_test_card["stack_id"],
with pytest.raises(httpx.HTTPStatusError) as exc_info: deck_test_card["card_id"],
await nc_client.deck.update_card( )
board_id=deck_test_card["board_id"], assert updated.title == "Original Title"
stack_id=deck_test_card["stack_id"], assert updated.description == "New description only"
card_id=deck_test_card["card_id"],
description="New description only",
)
assert exc_info.value.response.status_code == 400
async def test_update_title_and_description(self, nc_client, deck_test_card): 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( await nc_client.deck.update_card(
board_id=deck_test_card["board_id"], board_id=deck_test_card["board_id"],
stack_id=deck_test_card["stack_id"], stack_id=deck_test_card["stack_id"],
@@ -115,40 +101,62 @@ class TestDeckClientUpdateCard:
assert updated.title == "New Title" assert updated.title == "New Title"
assert updated.description == "New description" assert updated.description == "New description"
async def test_update_duedate_only_fails(self, nc_client, deck_test_card): async def test_update_duedate_only(self, nc_client, deck_test_card):
""" """Updating only the duedate should work and preserve other fields."""
BUG: Updating only the duedate fails with 400. 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. updated = await nc_client.deck.get_card(
""" deck_test_card["board_id"],
with pytest.raises(httpx.HTTPStatusError) as exc_info: deck_test_card["stack_id"],
await nc_client.deck.update_card( deck_test_card["card_id"],
board_id=deck_test_card["board_id"], )
stack_id=deck_test_card["stack_id"], assert updated.title == "Original Title"
card_id=deck_test_card["card_id"], assert updated.description == "Original description"
duedate="2025-12-31T23:59:59+00:00", 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): updated = await nc_client.deck.get_card(
""" deck_test_card["board_id"],
BUG: Updating only the archived status fails with 400. 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. async def test_update_order_only(self, nc_client, deck_test_card):
""" """Updating only the order should work and preserve other fields."""
with pytest.raises(httpx.HTTPStatusError) as exc_info: await nc_client.deck.update_card(
await nc_client.deck.update_card( board_id=deck_test_card["board_id"],
board_id=deck_test_card["board_id"], stack_id=deck_test_card["stack_id"],
stack_id=deck_test_card["stack_id"], card_id=deck_test_card["card_id"],
card_id=deck_test_card["card_id"], order=99,
archived=True, )
)
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): 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"] original = deck_test_card["card"]
await nc_client.deck.update_card( await nc_client.deck.update_card(
@@ -164,9 +172,10 @@ class TestDeckClientUpdateCard:
deck_test_card["card_id"], deck_test_card["card_id"],
) )
assert updated.type == original.type assert updated.type == original.type
assert updated.description == "Original description"
async def test_update_preserves_owner(self, nc_client, deck_test_card): 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"] original = deck_test_card["card"]
await nc_client.deck.update_card( await nc_client.deck.update_card(
@@ -182,19 +191,4 @@ class TestDeckClientUpdateCard:
deck_test_card["card_id"], deck_test_card["card_id"],
) )
assert updated.owner == original.owner assert updated.owner == original.owner
assert updated.description == "Original description"
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