test(contacts): address PR #719 review feedback

- Type-annotate _wrap_contact_field signature; drop stale "url" mention
  from its docstring (url is handled by the list-coercion helper, not
  this one).
- Split the shape-coercion helper so comma-splitting only applies to
  categories: _as_str_list (no split) for org/nickname/url,
  _split_categories (comma split) for CATEGORIES. Fixes the case where
  organization="Smith, Jones & Associates" was mangled into a two-
  component ORG.
- Share _normalize_contact_data between create and update so
  _merge_vcard_properties only sees canonical keys; add URL handlers in
  both update branches so the primary update path no longer drops URL
  silently.
- Annotate the Contact(**kwargs) type:ignore with the reason
  (pythonvCard4 typeshed doesn't accept **dict[str, Any]).
- Add tests/unit/client/test_contacts.py (pure unit, no HTTP) covering
  the #716 round-trip, comma-in-org regression, invalid-bday warning,
  tel/phone precedence, categories string-vs-list behaviour, and direct
  _normalize_contact_data cases.
- Extend the MCP workflow test with an update-with-url step asserting
  the URL handler in _merge_vcard_properties.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-04-23 07:44:05 +02:00
co-authored by Claude Opus 4.7
parent 5f0576ac09
commit 0186b494f1
3 changed files with 283 additions and 31 deletions
+18
View File
@@ -62,6 +62,24 @@ async def test_mcp_contacts_workflow(
assert "ORG:MCP Test Corp" in raw_vcard
assert f"NOTE:Created by test {unique_suffix}" in raw_vcard
# 4b. Update with a URL — regression guard for PR #719 review:
# _merge_vcard_properties previously had no URL handler, silently dropping it.
update_result = await nc_mcp_client.call_tool(
"nc_contacts_update_contact",
{
"addressbook": addressbook_name,
"uid": contact_uid,
"contact_data": {"url": "https://mcp-test.example.com"},
},
)
assert update_result.isError is False
contacts = await nc_client.contacts.list_contacts(addressbook=addressbook_name)
updated = next(c for c in contacts if c["vcard_id"] == contact_uid)
updated_vcard = updated.get("addressdata", "")
assert "mcp-test.example.com" in updated_vcard
# Prior properties must not have been clobbered by the merge.
assert "ORG:MCP Test Corp" in updated_vcard
# 5. Delete contact via MCP
logger.info(f"Deleting contact {contact_uid} via MCP")
delete_c_result = await nc_mcp_client.call_tool(