mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Refactor todo services and their schema (#103079)
This commit is contained in:
parent
7319abcab0
commit
d97a030872
@ -43,14 +43,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
websocket_api.async_register_command(hass, websocket_handle_todo_item_move)
|
websocket_api.async_register_command(hass, websocket_handle_todo_item_move)
|
||||||
|
|
||||||
component.async_register_entity_service(
|
component.async_register_entity_service(
|
||||||
"create_item",
|
"add_item",
|
||||||
{
|
{
|
||||||
vol.Required("summary"): vol.All(cv.string, vol.Length(min=1)),
|
vol.Required("item"): vol.All(cv.string, vol.Length(min=1)),
|
||||||
vol.Optional("status", default=TodoItemStatus.NEEDS_ACTION): vol.In(
|
|
||||||
{TodoItemStatus.NEEDS_ACTION, TodoItemStatus.COMPLETED}
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
_async_create_todo_item,
|
_async_add_todo_item,
|
||||||
required_features=[TodoListEntityFeature.CREATE_TODO_ITEM],
|
required_features=[TodoListEntityFeature.CREATE_TODO_ITEM],
|
||||||
)
|
)
|
||||||
component.async_register_entity_service(
|
component.async_register_entity_service(
|
||||||
@ -58,30 +55,26 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
vol.All(
|
vol.All(
|
||||||
cv.make_entity_service_schema(
|
cv.make_entity_service_schema(
|
||||||
{
|
{
|
||||||
vol.Optional("uid"): cv.string,
|
vol.Required("item"): vol.All(cv.string, vol.Length(min=1)),
|
||||||
vol.Optional("summary"): vol.All(cv.string, vol.Length(min=1)),
|
vol.Optional("rename"): vol.All(cv.string, vol.Length(min=1)),
|
||||||
vol.Optional("status"): vol.In(
|
vol.Optional("status"): vol.In(
|
||||||
{TodoItemStatus.NEEDS_ACTION, TodoItemStatus.COMPLETED}
|
{TodoItemStatus.NEEDS_ACTION, TodoItemStatus.COMPLETED}
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
cv.has_at_least_one_key("uid", "summary"),
|
cv.has_at_least_one_key("rename", "status"),
|
||||||
),
|
),
|
||||||
_async_update_todo_item,
|
_async_update_todo_item,
|
||||||
required_features=[TodoListEntityFeature.UPDATE_TODO_ITEM],
|
required_features=[TodoListEntityFeature.UPDATE_TODO_ITEM],
|
||||||
)
|
)
|
||||||
component.async_register_entity_service(
|
component.async_register_entity_service(
|
||||||
"delete_item",
|
"remove_item",
|
||||||
vol.All(
|
|
||||||
cv.make_entity_service_schema(
|
cv.make_entity_service_schema(
|
||||||
{
|
{
|
||||||
vol.Optional("uid"): vol.All(cv.ensure_list, [cv.string]),
|
vol.Required("item"): vol.All(cv.ensure_list, [cv.string]),
|
||||||
vol.Optional("summary"): vol.All(cv.ensure_list, [cv.string]),
|
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
cv.has_at_least_one_key("uid", "summary"),
|
_async_remove_todo_items,
|
||||||
),
|
|
||||||
_async_delete_todo_items,
|
|
||||||
required_features=[TodoListEntityFeature.DELETE_TODO_ITEM],
|
required_features=[TodoListEntityFeature.DELETE_TODO_ITEM],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -114,13 +107,6 @@ class TodoItem:
|
|||||||
status: TodoItemStatus | None = None
|
status: TodoItemStatus | None = None
|
||||||
"""A status or confirmation of the To-do item."""
|
"""A status or confirmation of the To-do item."""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, obj: dict[str, Any]) -> "TodoItem":
|
|
||||||
"""Create a To-do Item from a dictionary parsed by schema validators."""
|
|
||||||
return cls(
|
|
||||||
summary=obj.get("summary"), status=obj.get("status"), uid=obj.get("uid")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TodoListEntity(Entity):
|
class TodoListEntity(Entity):
|
||||||
"""An entity that represents a To-do list."""
|
"""An entity that represents a To-do list."""
|
||||||
@ -232,39 +218,43 @@ async def websocket_handle_todo_item_move(
|
|||||||
connection.send_result(msg["id"])
|
connection.send_result(msg["id"])
|
||||||
|
|
||||||
|
|
||||||
def _find_by_summary(summary: str, items: list[TodoItem] | None) -> TodoItem | None:
|
def _find_by_uid_or_summary(
|
||||||
"""Find a To-do List item by summary name."""
|
value: str, items: list[TodoItem] | None
|
||||||
|
) -> TodoItem | None:
|
||||||
|
"""Find a To-do List item by uid or summary name."""
|
||||||
for item in items or ():
|
for item in items or ():
|
||||||
if item.summary == summary:
|
if value in (item.uid, item.summary):
|
||||||
return item
|
return item
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def _async_create_todo_item(entity: TodoListEntity, call: ServiceCall) -> None:
|
async def _async_add_todo_item(entity: TodoListEntity, call: ServiceCall) -> None:
|
||||||
"""Add an item to the To-do list."""
|
"""Add an item to the To-do list."""
|
||||||
await entity.async_create_todo_item(item=TodoItem.from_dict(call.data))
|
await entity.async_create_todo_item(
|
||||||
|
item=TodoItem(summary=call.data["item"], status=TodoItemStatus.NEEDS_ACTION)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _async_update_todo_item(entity: TodoListEntity, call: ServiceCall) -> None:
|
async def _async_update_todo_item(entity: TodoListEntity, call: ServiceCall) -> None:
|
||||||
"""Update an item in the To-do list."""
|
"""Update an item in the To-do list."""
|
||||||
item = TodoItem.from_dict(call.data)
|
item = call.data["item"]
|
||||||
if not item.uid:
|
found = _find_by_uid_or_summary(item, entity.todo_items)
|
||||||
found = _find_by_summary(call.data["summary"], entity.todo_items)
|
|
||||||
if not found:
|
if not found:
|
||||||
raise ValueError(f"Unable to find To-do item with summary '{item.summary}'")
|
raise ValueError(f"Unable to find To-do item '{item}'")
|
||||||
item.uid = found.uid
|
|
||||||
|
|
||||||
await entity.async_update_todo_item(item=item)
|
update_item = TodoItem(
|
||||||
|
uid=found.uid, summary=call.data.get("rename"), status=call.data.get("status")
|
||||||
|
)
|
||||||
|
|
||||||
|
await entity.async_update_todo_item(item=update_item)
|
||||||
|
|
||||||
|
|
||||||
async def _async_delete_todo_items(entity: TodoListEntity, call: ServiceCall) -> None:
|
async def _async_remove_todo_items(entity: TodoListEntity, call: ServiceCall) -> None:
|
||||||
"""Delete an item in the To-do list."""
|
"""Remove an item in the To-do list."""
|
||||||
uids = call.data.get("uid", [])
|
uids = []
|
||||||
if not uids:
|
for item in call.data.get("item", []):
|
||||||
summaries = call.data.get("summary", [])
|
found = _find_by_uid_or_summary(item, entity.todo_items)
|
||||||
for summary in summaries:
|
if not found or not found.uid:
|
||||||
item = _find_by_summary(summary, entity.todo_items)
|
raise ValueError(f"Unable to find To-do item '{item}")
|
||||||
if not item:
|
uids.append(found.uid)
|
||||||
raise ValueError(f"Unable to find To-do item with summary '{summary}")
|
|
||||||
uids.append(item.uid)
|
|
||||||
await entity.async_delete_todo_items(uids=uids)
|
await entity.async_delete_todo_items(uids=uids)
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
create_item:
|
add_item:
|
||||||
target:
|
target:
|
||||||
entity:
|
entity:
|
||||||
domain: todo
|
domain: todo
|
||||||
supported_features:
|
supported_features:
|
||||||
- todo.TodoListEntityFeature.CREATE_TODO_ITEM
|
- todo.TodoListEntityFeature.CREATE_TODO_ITEM
|
||||||
fields:
|
fields:
|
||||||
summary:
|
item:
|
||||||
required: true
|
required: true
|
||||||
example: "Submit income tax return"
|
example: "Submit income tax return"
|
||||||
selector:
|
selector:
|
||||||
text:
|
text:
|
||||||
status:
|
|
||||||
example: "needs_action"
|
|
||||||
selector:
|
|
||||||
select:
|
|
||||||
translation_key: status
|
|
||||||
options:
|
|
||||||
- needs_action
|
|
||||||
- completed
|
|
||||||
update_item:
|
update_item:
|
||||||
target:
|
target:
|
||||||
entity:
|
entity:
|
||||||
@ -25,11 +17,13 @@ update_item:
|
|||||||
supported_features:
|
supported_features:
|
||||||
- todo.TodoListEntityFeature.UPDATE_TODO_ITEM
|
- todo.TodoListEntityFeature.UPDATE_TODO_ITEM
|
||||||
fields:
|
fields:
|
||||||
uid:
|
item:
|
||||||
|
required: true
|
||||||
|
example: "Submit income tax return"
|
||||||
selector:
|
selector:
|
||||||
text:
|
text:
|
||||||
summary:
|
rename:
|
||||||
example: "Submit income tax return"
|
example: "Something else"
|
||||||
selector:
|
selector:
|
||||||
text:
|
text:
|
||||||
status:
|
status:
|
||||||
@ -40,16 +34,13 @@ update_item:
|
|||||||
options:
|
options:
|
||||||
- needs_action
|
- needs_action
|
||||||
- completed
|
- completed
|
||||||
delete_item:
|
remove_item:
|
||||||
target:
|
target:
|
||||||
entity:
|
entity:
|
||||||
domain: todo
|
domain: todo
|
||||||
supported_features:
|
supported_features:
|
||||||
- todo.TodoListEntityFeature.DELETE_TODO_ITEM
|
- todo.TodoListEntityFeature.DELETE_TODO_ITEM
|
||||||
fields:
|
fields:
|
||||||
uid:
|
item:
|
||||||
selector:
|
|
||||||
object:
|
|
||||||
summary:
|
|
||||||
selector:
|
selector:
|
||||||
object:
|
object:
|
||||||
|
@ -6,49 +6,41 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
"create_item": {
|
"add_item": {
|
||||||
"name": "Create to-do list item",
|
"name": "Add to-do list item",
|
||||||
"description": "Add a new to-do list item.",
|
"description": "Add a new to-do list item.",
|
||||||
"fields": {
|
"fields": {
|
||||||
"summary": {
|
"item": {
|
||||||
"name": "Summary",
|
"name": "Item name",
|
||||||
"description": "The short summary that represents the to-do item."
|
"description": "The name that represents the to-do item."
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "Status",
|
|
||||||
"description": "A status or confirmation of the to-do item."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"update_item": {
|
"update_item": {
|
||||||
"name": "Update to-do list item",
|
"name": "Update to-do list item",
|
||||||
"description": "Update an existing to-do list item based on either its unique ID or summary.",
|
"description": "Update an existing to-do list item based on its name.",
|
||||||
"fields": {
|
"fields": {
|
||||||
"uid": {
|
"item": {
|
||||||
"name": "To-do item unique ID",
|
"name": "Item name",
|
||||||
"description": "Unique identifier for the to-do list item."
|
"description": "The name for the to-do list item."
|
||||||
},
|
},
|
||||||
"summary": {
|
"rename": {
|
||||||
"name": "Summary",
|
"name": "Rename item",
|
||||||
"description": "The short summary that represents the to-do item."
|
"description": "The new name of the to-do item"
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"name": "Status",
|
"name": "Set status",
|
||||||
"description": "A status or confirmation of the to-do item."
|
"description": "A status or confirmation of the to-do item."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"delete_item": {
|
"remove_item": {
|
||||||
"name": "Delete a to-do list item",
|
"name": "Remove a to-do list item",
|
||||||
"description": "Delete an existing to-do list item either by its unique ID or summary.",
|
"description": "Remove an existing to-do list item by its name.",
|
||||||
"fields": {
|
"fields": {
|
||||||
"uid": {
|
"item": {
|
||||||
"name": "To-do item unique IDs",
|
"name": "Item name",
|
||||||
"description": "Unique identifiers for the to-do list items."
|
"description": "The name for the to-do list items."
|
||||||
},
|
|
||||||
"summary": {
|
|
||||||
"name": "Summary",
|
|
||||||
"description": "The short summary that represents the to-do item."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,28 +197,18 @@ async def test_unsupported_websocket(
|
|||||||
assert resp.get("error", {}).get("code") == "not_found"
|
assert resp.get("error", {}).get("code") == "not_found"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
async def test_add_item_service(
|
||||||
("item_data", "expected_status"),
|
|
||||||
[
|
|
||||||
({}, TodoItemStatus.NEEDS_ACTION),
|
|
||||||
({"status": "needs_action"}, TodoItemStatus.NEEDS_ACTION),
|
|
||||||
({"status": "completed"}, TodoItemStatus.COMPLETED),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
async def test_create_item_service(
|
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
item_data: dict[str, Any],
|
|
||||||
expected_status: TodoItemStatus,
|
|
||||||
test_entity: TodoListEntity,
|
test_entity: TodoListEntity,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test creating an item in a To-do list."""
|
"""Test adding an item in a To-do list."""
|
||||||
|
|
||||||
await create_mock_platform(hass, [test_entity])
|
await create_mock_platform(hass, [test_entity])
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"create_item",
|
"add_item",
|
||||||
{"summary": "New item", **item_data},
|
{"item": "New item"},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -229,14 +219,14 @@ async def test_create_item_service(
|
|||||||
assert item
|
assert item
|
||||||
assert item.uid is None
|
assert item.uid is None
|
||||||
assert item.summary == "New item"
|
assert item.summary == "New item"
|
||||||
assert item.status == expected_status
|
assert item.status == TodoItemStatus.NEEDS_ACTION
|
||||||
|
|
||||||
|
|
||||||
async def test_create_item_service_raises(
|
async def test_add_item_service_raises(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
test_entity: TodoListEntity,
|
test_entity: TodoListEntity,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test creating an item in a To-do list that raises an error."""
|
"""Test adding an item in a To-do list that raises an error."""
|
||||||
|
|
||||||
await create_mock_platform(hass, [test_entity])
|
await create_mock_platform(hass, [test_entity])
|
||||||
|
|
||||||
@ -244,8 +234,8 @@ async def test_create_item_service_raises(
|
|||||||
with pytest.raises(HomeAssistantError, match="Ooops"):
|
with pytest.raises(HomeAssistantError, match="Ooops"):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"create_item",
|
"add_item",
|
||||||
{"summary": "New item", "status": "needs_action"},
|
{"item": "New item"},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -255,27 +245,23 @@ async def test_create_item_service_raises(
|
|||||||
("item_data", "expected_error"),
|
("item_data", "expected_error"),
|
||||||
[
|
[
|
||||||
({}, "required key not provided"),
|
({}, "required key not provided"),
|
||||||
({"status": "needs_action"}, "required key not provided"),
|
({"item": ""}, "length of value must be at least 1"),
|
||||||
(
|
|
||||||
{"summary": "", "status": "needs_action"},
|
|
||||||
"length of value must be at least 1",
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_create_item_service_invalid_input(
|
async def test_add_item_service_invalid_input(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
test_entity: TodoListEntity,
|
test_entity: TodoListEntity,
|
||||||
item_data: dict[str, Any],
|
item_data: dict[str, Any],
|
||||||
expected_error: str,
|
expected_error: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test invalid input to the create item service."""
|
"""Test invalid input to the add item service."""
|
||||||
|
|
||||||
await create_mock_platform(hass, [test_entity])
|
await create_mock_platform(hass, [test_entity])
|
||||||
|
|
||||||
with pytest.raises(vol.Invalid, match=expected_error):
|
with pytest.raises(vol.Invalid, match=expected_error):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"create_item",
|
"add_item",
|
||||||
item_data,
|
item_data,
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
@ -293,7 +279,7 @@ async def test_update_todo_item_service_by_id(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"update_item",
|
"update_item",
|
||||||
{"uid": "item-1", "summary": "Updated item", "status": "completed"},
|
{"item": "1", "rename": "Updated item", "status": "completed"},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -302,7 +288,7 @@ async def test_update_todo_item_service_by_id(
|
|||||||
assert args
|
assert args
|
||||||
item = args.kwargs.get("item")
|
item = args.kwargs.get("item")
|
||||||
assert item
|
assert item
|
||||||
assert item.uid == "item-1"
|
assert item.uid == "1"
|
||||||
assert item.summary == "Updated item"
|
assert item.summary == "Updated item"
|
||||||
assert item.status == TodoItemStatus.COMPLETED
|
assert item.status == TodoItemStatus.COMPLETED
|
||||||
|
|
||||||
@ -318,7 +304,7 @@ async def test_update_todo_item_service_by_id_status_only(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"update_item",
|
"update_item",
|
||||||
{"uid": "item-1", "status": "completed"},
|
{"item": "1", "status": "completed"},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -327,12 +313,12 @@ async def test_update_todo_item_service_by_id_status_only(
|
|||||||
assert args
|
assert args
|
||||||
item = args.kwargs.get("item")
|
item = args.kwargs.get("item")
|
||||||
assert item
|
assert item
|
||||||
assert item.uid == "item-1"
|
assert item.uid == "1"
|
||||||
assert item.summary is None
|
assert item.summary is None
|
||||||
assert item.status == TodoItemStatus.COMPLETED
|
assert item.status == TodoItemStatus.COMPLETED
|
||||||
|
|
||||||
|
|
||||||
async def test_update_todo_item_service_by_id_summary_only(
|
async def test_update_todo_item_service_by_id_rename(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
test_entity: TodoListEntity,
|
test_entity: TodoListEntity,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -343,7 +329,7 @@ async def test_update_todo_item_service_by_id_summary_only(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"update_item",
|
"update_item",
|
||||||
{"uid": "item-1", "summary": "Updated item"},
|
{"item": "1", "rename": "Updated item"},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -352,7 +338,7 @@ async def test_update_todo_item_service_by_id_summary_only(
|
|||||||
assert args
|
assert args
|
||||||
item = args.kwargs.get("item")
|
item = args.kwargs.get("item")
|
||||||
assert item
|
assert item
|
||||||
assert item.uid == "item-1"
|
assert item.uid == "1"
|
||||||
assert item.summary == "Updated item"
|
assert item.summary == "Updated item"
|
||||||
assert item.status is None
|
assert item.status is None
|
||||||
|
|
||||||
@ -368,7 +354,7 @@ async def test_update_todo_item_service_raises(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"update_item",
|
"update_item",
|
||||||
{"uid": "item-1", "summary": "Updated item", "status": "completed"},
|
{"item": "1", "rename": "Updated item", "status": "completed"},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -378,7 +364,7 @@ async def test_update_todo_item_service_raises(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"update_item",
|
"update_item",
|
||||||
{"uid": "item-1", "summary": "Updated item", "status": "completed"},
|
{"item": "1", "rename": "Updated item", "status": "completed"},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -395,7 +381,7 @@ async def test_update_todo_item_service_by_summary(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"update_item",
|
"update_item",
|
||||||
{"summary": "Item #1", "status": "completed"},
|
{"item": "Item #1", "rename": "Something else", "status": "completed"},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -405,10 +391,35 @@ async def test_update_todo_item_service_by_summary(
|
|||||||
item = args.kwargs.get("item")
|
item = args.kwargs.get("item")
|
||||||
assert item
|
assert item
|
||||||
assert item.uid == "1"
|
assert item.uid == "1"
|
||||||
assert item.summary == "Item #1"
|
assert item.summary == "Something else"
|
||||||
assert item.status == TodoItemStatus.COMPLETED
|
assert item.status == TodoItemStatus.COMPLETED
|
||||||
|
|
||||||
|
|
||||||
|
async def test_update_todo_item_service_by_summary_only_status(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
test_entity: TodoListEntity,
|
||||||
|
) -> None:
|
||||||
|
"""Test updating an item in a To-do list by summary."""
|
||||||
|
|
||||||
|
await create_mock_platform(hass, [test_entity])
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
"update_item",
|
||||||
|
{"item": "Item #1", "rename": "Something else"},
|
||||||
|
target={"entity_id": "todo.entity1"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
args = test_entity.async_update_todo_item.call_args
|
||||||
|
assert args
|
||||||
|
item = args.kwargs.get("item")
|
||||||
|
assert item
|
||||||
|
assert item.uid == "1"
|
||||||
|
assert item.summary == "Something else"
|
||||||
|
assert item.status is None
|
||||||
|
|
||||||
|
|
||||||
async def test_update_todo_item_service_by_summary_not_found(
|
async def test_update_todo_item_service_by_summary_not_found(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
test_entity: TodoListEntity,
|
test_entity: TodoListEntity,
|
||||||
@ -421,7 +432,7 @@ async def test_update_todo_item_service_by_summary_not_found(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"update_item",
|
"update_item",
|
||||||
{"summary": "Item #7", "status": "completed"},
|
{"item": "Item #7", "status": "completed"},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -430,10 +441,11 @@ async def test_update_todo_item_service_by_summary_not_found(
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("item_data", "expected_error"),
|
("item_data", "expected_error"),
|
||||||
[
|
[
|
||||||
({}, "must contain at least one of"),
|
({}, r"required key not provided @ data\['item'\]"),
|
||||||
({"status": "needs_action"}, "must contain at least one of"),
|
({"status": "needs_action"}, r"required key not provided @ data\['item'\]"),
|
||||||
|
({"item": "Item #1"}, "must contain at least one of"),
|
||||||
(
|
(
|
||||||
{"summary": "", "status": "needs_action"},
|
{"item": "", "status": "needs_action"},
|
||||||
"length of value must be at least 1",
|
"length of value must be at least 1",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -458,32 +470,32 @@ async def test_update_item_service_invalid_input(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_delete_todo_item_service_by_id(
|
async def test_remove_todo_item_service_by_id(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
test_entity: TodoListEntity,
|
test_entity: TodoListEntity,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test deleting an item in a To-do list."""
|
"""Test removing an item in a To-do list."""
|
||||||
|
|
||||||
await create_mock_platform(hass, [test_entity])
|
await create_mock_platform(hass, [test_entity])
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"delete_item",
|
"remove_item",
|
||||||
{"uid": ["item-1", "item-2"]},
|
{"item": ["1", "2"]},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
args = test_entity.async_delete_todo_items.call_args
|
args = test_entity.async_delete_todo_items.call_args
|
||||||
assert args
|
assert args
|
||||||
assert args.kwargs.get("uids") == ["item-1", "item-2"]
|
assert args.kwargs.get("uids") == ["1", "2"]
|
||||||
|
|
||||||
|
|
||||||
async def test_delete_todo_item_service_raises(
|
async def test_remove_todo_item_service_raises(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
test_entity: TodoListEntity,
|
test_entity: TodoListEntity,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test deleting an item in a To-do list that raises an error."""
|
"""Test removing an item in a To-do list that raises an error."""
|
||||||
|
|
||||||
await create_mock_platform(hass, [test_entity])
|
await create_mock_platform(hass, [test_entity])
|
||||||
|
|
||||||
@ -491,43 +503,45 @@ async def test_delete_todo_item_service_raises(
|
|||||||
with pytest.raises(HomeAssistantError, match="Ooops"):
|
with pytest.raises(HomeAssistantError, match="Ooops"):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"delete_item",
|
"remove_item",
|
||||||
{"uid": ["item-1", "item-2"]},
|
{"item": ["1", "2"]},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_delete_todo_item_service_invalid_input(
|
async def test_remove_todo_item_service_invalid_input(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
test_entity: TodoListEntity,
|
test_entity: TodoListEntity,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test invalid input to the delete item service."""
|
"""Test invalid input to the remove item service."""
|
||||||
|
|
||||||
await create_mock_platform(hass, [test_entity])
|
await create_mock_platform(hass, [test_entity])
|
||||||
|
|
||||||
with pytest.raises(vol.Invalid, match="must contain at least one of"):
|
with pytest.raises(
|
||||||
|
vol.Invalid, match=r"required key not provided @ data\['item'\]"
|
||||||
|
):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"delete_item",
|
"remove_item",
|
||||||
{},
|
{},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_delete_todo_item_service_by_summary(
|
async def test_remove_todo_item_service_by_summary(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
test_entity: TodoListEntity,
|
test_entity: TodoListEntity,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test deleting an item in a To-do list by summary."""
|
"""Test removing an item in a To-do list by summary."""
|
||||||
|
|
||||||
await create_mock_platform(hass, [test_entity])
|
await create_mock_platform(hass, [test_entity])
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"delete_item",
|
"remove_item",
|
||||||
{"summary": ["Item #1"]},
|
{"item": ["Item #1"]},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -537,19 +551,19 @@ async def test_delete_todo_item_service_by_summary(
|
|||||||
assert args.kwargs.get("uids") == ["1"]
|
assert args.kwargs.get("uids") == ["1"]
|
||||||
|
|
||||||
|
|
||||||
async def test_delete_todo_item_service_by_summary_not_found(
|
async def test_remove_todo_item_service_by_summary_not_found(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
test_entity: TodoListEntity,
|
test_entity: TodoListEntity,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test deleting an item in a To-do list by summary which is not found."""
|
"""Test removing an item in a To-do list by summary which is not found."""
|
||||||
|
|
||||||
await create_mock_platform(hass, [test_entity])
|
await create_mock_platform(hass, [test_entity])
|
||||||
|
|
||||||
with pytest.raises(ValueError, match="Unable to find"):
|
with pytest.raises(ValueError, match="Unable to find"):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"delete_item",
|
"remove_item",
|
||||||
{"summary": ["Item #7"]},
|
{"item": ["Item #7"]},
|
||||||
target={"entity_id": "todo.entity1"},
|
target={"entity_id": "todo.entity1"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
@ -656,22 +670,22 @@ async def test_move_todo_item_service_invalid_input(
|
|||||||
("service_name", "payload"),
|
("service_name", "payload"),
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"create_item",
|
"add_item",
|
||||||
{
|
{
|
||||||
"summary": "New item",
|
"item": "New item",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"delete_item",
|
"remove_item",
|
||||||
{
|
{
|
||||||
"uid": ["1"],
|
"item": ["1"],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"update_item",
|
"update_item",
|
||||||
{
|
{
|
||||||
"uid": "1",
|
"item": "1",
|
||||||
"summary": "Updated item",
|
"rename": "Updated item",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user