Dynamically create and delete todo lists in mealie (#121710)
This commit is contained in:
parent
c223709c7c
commit
73475aa675
7 changed files with 255 additions and 190 deletions
|
@ -75,8 +75,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: MealieConfigEntry) -> bo
|
|||
shoppinglist_coordinator = MealieShoppingListCoordinator(hass, client)
|
||||
|
||||
await mealplan_coordinator.async_config_entry_first_refresh()
|
||||
|
||||
await shoppinglist_coordinator.async_get_shopping_lists()
|
||||
await shoppinglist_coordinator.async_config_entry_first_refresh()
|
||||
|
||||
entry.runtime_data = MealieData(
|
||||
|
|
|
@ -96,8 +96,16 @@ class MealieMealplanCoordinator(
|
|||
return res
|
||||
|
||||
|
||||
@dataclass
|
||||
class ShoppingListData:
|
||||
"""Data class for shopping list data."""
|
||||
|
||||
shopping_list: ShoppingList
|
||||
items: list[ShoppingItem]
|
||||
|
||||
|
||||
class MealieShoppingListCoordinator(
|
||||
MealieDataUpdateCoordinator[dict[str, list[ShoppingItem]]]
|
||||
MealieDataUpdateCoordinator[dict[str, ShoppingListData]]
|
||||
):
|
||||
"""Class to manage fetching Mealie Shopping list data."""
|
||||
|
||||
|
@ -109,36 +117,25 @@ class MealieShoppingListCoordinator(
|
|||
client=client,
|
||||
update_interval=timedelta(minutes=5),
|
||||
)
|
||||
self.shopping_lists: list[ShoppingList]
|
||||
|
||||
async def async_get_shopping_lists(self) -> list[ShoppingList]:
|
||||
"""Return shopping lists."""
|
||||
try:
|
||||
self.shopping_lists = (await self.client.get_shopping_lists()).items
|
||||
except MealieAuthenticationError as error:
|
||||
raise ConfigEntryAuthFailed from error
|
||||
except MealieConnectionError as error:
|
||||
raise UpdateFailed(error) from error
|
||||
return self.shopping_lists
|
||||
|
||||
async def _async_update_data(
|
||||
self,
|
||||
) -> dict[str, list[ShoppingItem]]:
|
||||
shopping_list_items: dict[str, list[ShoppingItem]] = {}
|
||||
|
||||
) -> dict[str, ShoppingListData]:
|
||||
shopping_list_items = {}
|
||||
try:
|
||||
for shopping_list in self.shopping_lists:
|
||||
shopping_lists = (await self.client.get_shopping_lists()).items
|
||||
for shopping_list in shopping_lists:
|
||||
shopping_list_id = shopping_list.list_id
|
||||
|
||||
shopping_items = (
|
||||
await self.client.get_shopping_items(shopping_list_id)
|
||||
).items
|
||||
|
||||
shopping_list_items[shopping_list_id] = shopping_items
|
||||
|
||||
shopping_list_items[shopping_list_id] = ShoppingListData(
|
||||
shopping_list=shopping_list, items=shopping_items
|
||||
)
|
||||
except MealieAuthenticationError as error:
|
||||
raise ConfigEntryAuthFailed from error
|
||||
except MealieConnectionError as error:
|
||||
raise UpdateFailed(error) from error
|
||||
|
||||
return shopping_list_items
|
||||
|
|
|
@ -25,7 +25,7 @@ async def async_get_config_entry_diagnostics(
|
|||
for entry_type, mealplans in data.mealplan_coordinator.data.items()
|
||||
},
|
||||
"shoppinglist": {
|
||||
list_id: [asdict(item) for item in shopping_list]
|
||||
list_id: asdict(shopping_list)
|
||||
for list_id, shopping_list in data.shoppinglist_coordinator.data.items()
|
||||
},
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ from __future__ import annotations
|
|||
from aiomealie import MealieError, MutateShoppingItem, ShoppingItem, ShoppingList
|
||||
|
||||
from homeassistant.components.todo import (
|
||||
DOMAIN as TODO_DOMAIN,
|
||||
TodoItem,
|
||||
TodoItemStatus,
|
||||
TodoListEntity,
|
||||
|
@ -12,6 +13,7 @@ from homeassistant.components.todo import (
|
|||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
|
@ -48,10 +50,36 @@ async def async_setup_entry(
|
|||
"""Set up the todo platform for entity."""
|
||||
coordinator = entry.runtime_data.shoppinglist_coordinator
|
||||
|
||||
async_add_entities(
|
||||
MealieShoppingListTodoListEntity(coordinator, shopping_list)
|
||||
for shopping_list in coordinator.shopping_lists
|
||||
)
|
||||
added_lists: set[str] = set()
|
||||
|
||||
assert entry.unique_id is not None
|
||||
|
||||
def _async_delete_entities(lists: set[str]) -> None:
|
||||
"""Delete entities for removed shopping lists."""
|
||||
entity_registry = er.async_get(hass)
|
||||
for list_id in lists:
|
||||
entity_id = entity_registry.async_get_entity_id(
|
||||
TODO_DOMAIN, DOMAIN, f"{entry.unique_id}_{list_id}"
|
||||
)
|
||||
if entity_id:
|
||||
entity_registry.async_remove(entity_id)
|
||||
|
||||
def _async_entity_listener() -> None:
|
||||
"""Handle additions/deletions of shopping lists."""
|
||||
received_lists = set(coordinator.data)
|
||||
new_lists = received_lists - added_lists
|
||||
removed_lists = added_lists - received_lists
|
||||
if new_lists:
|
||||
async_add_entities(
|
||||
MealieShoppingListTodoListEntity(coordinator, shopping_list_id)
|
||||
for shopping_list_id in new_lists
|
||||
)
|
||||
added_lists.update(new_lists)
|
||||
if removed_lists:
|
||||
_async_delete_entities(removed_lists)
|
||||
|
||||
coordinator.async_add_listener(_async_entity_listener)
|
||||
_async_entity_listener()
|
||||
|
||||
|
||||
class MealieShoppingListTodoListEntity(MealieEntity, TodoListEntity):
|
||||
|
@ -69,17 +97,22 @@ class MealieShoppingListTodoListEntity(MealieEntity, TodoListEntity):
|
|||
coordinator: MealieShoppingListCoordinator
|
||||
|
||||
def __init__(
|
||||
self, coordinator: MealieShoppingListCoordinator, shopping_list: ShoppingList
|
||||
self, coordinator: MealieShoppingListCoordinator, shopping_list_id: str
|
||||
) -> None:
|
||||
"""Create the todo entity."""
|
||||
super().__init__(coordinator, shopping_list.list_id)
|
||||
self._shopping_list = shopping_list
|
||||
self._attr_name = shopping_list.name
|
||||
super().__init__(coordinator, shopping_list_id)
|
||||
self._shopping_list_id = shopping_list_id
|
||||
self._attr_name = self.shopping_list.name
|
||||
|
||||
@property
|
||||
def shopping_list(self) -> ShoppingList:
|
||||
"""Get the shopping list."""
|
||||
return self.coordinator.data[self._shopping_list_id].shopping_list
|
||||
|
||||
@property
|
||||
def shopping_items(self) -> list[ShoppingItem]:
|
||||
"""Get the shopping items for this list."""
|
||||
return self.coordinator.data[self._shopping_list.list_id]
|
||||
return self.coordinator.data[self._shopping_list_id].items
|
||||
|
||||
@property
|
||||
def todo_items(self) -> list[TodoItem] | None:
|
||||
|
@ -93,7 +126,7 @@ class MealieShoppingListTodoListEntity(MealieEntity, TodoListEntity):
|
|||
position = self.shopping_items[-1].position + 1
|
||||
|
||||
new_shopping_item = MutateShoppingItem(
|
||||
list_id=self._shopping_list.list_id,
|
||||
list_id=self._shopping_list_id,
|
||||
note=item.summary.strip() if item.summary else item.summary,
|
||||
position=position,
|
||||
)
|
||||
|
@ -104,7 +137,7 @@ class MealieShoppingListTodoListEntity(MealieEntity, TodoListEntity):
|
|||
translation_domain=DOMAIN,
|
||||
translation_key="add_item_error",
|
||||
translation_placeholders={
|
||||
"shopping_list_name": self._shopping_list.name
|
||||
"shopping_list_name": self.shopping_list.name
|
||||
},
|
||||
) from exception
|
||||
finally:
|
||||
|
@ -164,7 +197,7 @@ class MealieShoppingListTodoListEntity(MealieEntity, TodoListEntity):
|
|||
translation_domain=DOMAIN,
|
||||
translation_key="update_item_error",
|
||||
translation_placeholders={
|
||||
"shopping_list_name": self._shopping_list.name
|
||||
"shopping_list_name": self.shopping_list.name
|
||||
},
|
||||
) from exception
|
||||
finally:
|
||||
|
@ -180,7 +213,7 @@ class MealieShoppingListTodoListEntity(MealieEntity, TodoListEntity):
|
|||
translation_domain=DOMAIN,
|
||||
translation_key="delete_item_error",
|
||||
translation_placeholders={
|
||||
"shopping_list_name": self._shopping_list.name
|
||||
"shopping_list_name": self.shopping_list.name
|
||||
},
|
||||
) from exception
|
||||
finally:
|
||||
|
@ -238,6 +271,4 @@ class MealieShoppingListTodoListEntity(MealieEntity, TodoListEntity):
|
|||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return False if shopping list no longer available."""
|
||||
return (
|
||||
super().available and self._shopping_list.list_id in self.coordinator.data
|
||||
)
|
||||
return super().available and self._shopping_list_id in self.coordinator.data
|
||||
|
|
|
@ -350,138 +350,156 @@
|
|||
]),
|
||||
}),
|
||||
'shoppinglist': dict({
|
||||
'27edbaab-2ec6-441f-8490-0283ea77585f': list([
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': True,
|
||||
'display': '2 Apples',
|
||||
'food_id': None,
|
||||
'is_food': False,
|
||||
'item_id': 'f45430f7-3edf-45a9-a50f-73bb375090be',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': 'Apples',
|
||||
'position': 0,
|
||||
'quantity': 2.0,
|
||||
'unit_id': None,
|
||||
'27edbaab-2ec6-441f-8490-0283ea77585f': dict({
|
||||
'items': list([
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': True,
|
||||
'display': '2 Apples',
|
||||
'food_id': None,
|
||||
'is_food': False,
|
||||
'item_id': 'f45430f7-3edf-45a9-a50f-73bb375090be',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': 'Apples',
|
||||
'position': 0,
|
||||
'quantity': 2.0,
|
||||
'unit_id': None,
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': '1 can acorn squash',
|
||||
'food_id': '09322430-d24c-4b1a-abb6-22b6ed3a88f5',
|
||||
'is_food': True,
|
||||
'item_id': '84d8fd74-8eb0-402e-84b6-71f251bfb7cc',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 1,
|
||||
'quantity': 1.0,
|
||||
'unit_id': '7bf539d4-fc78-48bc-b48e-c35ccccec34a',
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': 'aubergine',
|
||||
'food_id': '96801494-4e26-4148-849a-8155deb76327',
|
||||
'is_food': True,
|
||||
'item_id': '69913b9a-7c75-4935-abec-297cf7483f88',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 2,
|
||||
'quantity': 0.0,
|
||||
'unit_id': None,
|
||||
}),
|
||||
]),
|
||||
'shopping_list': dict({
|
||||
'list_id': '27edbaab-2ec6-441f-8490-0283ea77585f',
|
||||
'name': 'Supermarket',
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': '1 can acorn squash',
|
||||
'food_id': '09322430-d24c-4b1a-abb6-22b6ed3a88f5',
|
||||
'is_food': True,
|
||||
'item_id': '84d8fd74-8eb0-402e-84b6-71f251bfb7cc',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 1,
|
||||
'quantity': 1.0,
|
||||
'unit_id': '7bf539d4-fc78-48bc-b48e-c35ccccec34a',
|
||||
}),
|
||||
'e9d78ff2-4b23-4b77-a3a8-464827100b46': dict({
|
||||
'items': list([
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': True,
|
||||
'display': '2 Apples',
|
||||
'food_id': None,
|
||||
'is_food': False,
|
||||
'item_id': 'f45430f7-3edf-45a9-a50f-73bb375090be',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': 'Apples',
|
||||
'position': 0,
|
||||
'quantity': 2.0,
|
||||
'unit_id': None,
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': '1 can acorn squash',
|
||||
'food_id': '09322430-d24c-4b1a-abb6-22b6ed3a88f5',
|
||||
'is_food': True,
|
||||
'item_id': '84d8fd74-8eb0-402e-84b6-71f251bfb7cc',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 1,
|
||||
'quantity': 1.0,
|
||||
'unit_id': '7bf539d4-fc78-48bc-b48e-c35ccccec34a',
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': 'aubergine',
|
||||
'food_id': '96801494-4e26-4148-849a-8155deb76327',
|
||||
'is_food': True,
|
||||
'item_id': '69913b9a-7c75-4935-abec-297cf7483f88',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 2,
|
||||
'quantity': 0.0,
|
||||
'unit_id': None,
|
||||
}),
|
||||
]),
|
||||
'shopping_list': dict({
|
||||
'list_id': 'e9d78ff2-4b23-4b77-a3a8-464827100b46',
|
||||
'name': 'Freezer',
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': 'aubergine',
|
||||
'food_id': '96801494-4e26-4148-849a-8155deb76327',
|
||||
'is_food': True,
|
||||
'item_id': '69913b9a-7c75-4935-abec-297cf7483f88',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 2,
|
||||
'quantity': 0.0,
|
||||
'unit_id': None,
|
||||
}),
|
||||
'f8438635-8211-4be8-80d0-0aa42e37a5f2': dict({
|
||||
'items': list([
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': True,
|
||||
'display': '2 Apples',
|
||||
'food_id': None,
|
||||
'is_food': False,
|
||||
'item_id': 'f45430f7-3edf-45a9-a50f-73bb375090be',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': 'Apples',
|
||||
'position': 0,
|
||||
'quantity': 2.0,
|
||||
'unit_id': None,
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': '1 can acorn squash',
|
||||
'food_id': '09322430-d24c-4b1a-abb6-22b6ed3a88f5',
|
||||
'is_food': True,
|
||||
'item_id': '84d8fd74-8eb0-402e-84b6-71f251bfb7cc',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 1,
|
||||
'quantity': 1.0,
|
||||
'unit_id': '7bf539d4-fc78-48bc-b48e-c35ccccec34a',
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': 'aubergine',
|
||||
'food_id': '96801494-4e26-4148-849a-8155deb76327',
|
||||
'is_food': True,
|
||||
'item_id': '69913b9a-7c75-4935-abec-297cf7483f88',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 2,
|
||||
'quantity': 0.0,
|
||||
'unit_id': None,
|
||||
}),
|
||||
]),
|
||||
'shopping_list': dict({
|
||||
'list_id': 'f8438635-8211-4be8-80d0-0aa42e37a5f2',
|
||||
'name': 'Special groceries',
|
||||
}),
|
||||
]),
|
||||
'e9d78ff2-4b23-4b77-a3a8-464827100b46': list([
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': True,
|
||||
'display': '2 Apples',
|
||||
'food_id': None,
|
||||
'is_food': False,
|
||||
'item_id': 'f45430f7-3edf-45a9-a50f-73bb375090be',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': 'Apples',
|
||||
'position': 0,
|
||||
'quantity': 2.0,
|
||||
'unit_id': None,
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': '1 can acorn squash',
|
||||
'food_id': '09322430-d24c-4b1a-abb6-22b6ed3a88f5',
|
||||
'is_food': True,
|
||||
'item_id': '84d8fd74-8eb0-402e-84b6-71f251bfb7cc',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 1,
|
||||
'quantity': 1.0,
|
||||
'unit_id': '7bf539d4-fc78-48bc-b48e-c35ccccec34a',
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': 'aubergine',
|
||||
'food_id': '96801494-4e26-4148-849a-8155deb76327',
|
||||
'is_food': True,
|
||||
'item_id': '69913b9a-7c75-4935-abec-297cf7483f88',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 2,
|
||||
'quantity': 0.0,
|
||||
'unit_id': None,
|
||||
}),
|
||||
]),
|
||||
'f8438635-8211-4be8-80d0-0aa42e37a5f2': list([
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': True,
|
||||
'display': '2 Apples',
|
||||
'food_id': None,
|
||||
'is_food': False,
|
||||
'item_id': 'f45430f7-3edf-45a9-a50f-73bb375090be',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': 'Apples',
|
||||
'position': 0,
|
||||
'quantity': 2.0,
|
||||
'unit_id': None,
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': '1 can acorn squash',
|
||||
'food_id': '09322430-d24c-4b1a-abb6-22b6ed3a88f5',
|
||||
'is_food': True,
|
||||
'item_id': '84d8fd74-8eb0-402e-84b6-71f251bfb7cc',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 1,
|
||||
'quantity': 1.0,
|
||||
'unit_id': '7bf539d4-fc78-48bc-b48e-c35ccccec34a',
|
||||
}),
|
||||
dict({
|
||||
'checked': False,
|
||||
'disable_amount': False,
|
||||
'display': 'aubergine',
|
||||
'food_id': '96801494-4e26-4148-849a-8155deb76327',
|
||||
'is_food': True,
|
||||
'item_id': '69913b9a-7c75-4935-abec-297cf7483f88',
|
||||
'label_id': None,
|
||||
'list_id': '9ce096fe-ded2-4077-877d-78ba450ab13e',
|
||||
'note': '',
|
||||
'position': 2,
|
||||
'quantity': 0.0,
|
||||
'unit_id': None,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
|
|
|
@ -135,25 +135,3 @@ async def test_shoppingitems_initialization_failure(
|
|||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert mock_config_entry.state is state
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("exc", "state"),
|
||||
[
|
||||
(MealieConnectionError, ConfigEntryState.SETUP_ERROR),
|
||||
(MealieAuthenticationError, ConfigEntryState.SETUP_ERROR),
|
||||
],
|
||||
)
|
||||
async def test_shoppinglists_initialization_failure(
|
||||
hass: HomeAssistant,
|
||||
mock_mealie_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
exc: Exception,
|
||||
state: ConfigEntryState,
|
||||
) -> None:
|
||||
"""Test initialization failure."""
|
||||
mock_mealie_client.get_shopping_lists.side_effect = exc
|
||||
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert mock_config_entry.state is state
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
"""Tests for the Mealie todo."""
|
||||
|
||||
from datetime import timedelta
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aiomealie import ShoppingListsResponse
|
||||
from aiomealie.exceptions import MealieError
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.mealie import DOMAIN
|
||||
from homeassistant.components.todo import (
|
||||
ATTR_ITEM,
|
||||
ATTR_RENAME,
|
||||
|
@ -20,7 +24,12 @@ from homeassistant.helpers import entity_registry as er
|
|||
|
||||
from . import setup_integration
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_fire_time_changed,
|
||||
load_fixture,
|
||||
snapshot_platform,
|
||||
)
|
||||
|
||||
|
||||
async def test_entities(
|
||||
|
@ -153,3 +162,37 @@ async def test_delete_todo_list_item_error(
|
|||
target={ATTR_ENTITY_ID: "todo.mealie_supermarket"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
|
||||
async def test_runtime_management(
|
||||
hass: HomeAssistant,
|
||||
mock_mealie_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test for creating and deleting shopping lists."""
|
||||
response = ShoppingListsResponse.from_json(
|
||||
load_fixture("get_shopping_lists.json", DOMAIN)
|
||||
).items
|
||||
mock_mealie_client.get_shopping_lists.return_value = ShoppingListsResponse(
|
||||
items=[response[0]]
|
||||
)
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
assert hass.states.get("todo.mealie_supermarket") is not None
|
||||
assert hass.states.get("todo.mealie_special_groceries") is None
|
||||
|
||||
mock_mealie_client.get_shopping_lists.return_value = ShoppingListsResponse(
|
||||
items=response[0:2]
|
||||
)
|
||||
freezer.tick(timedelta(minutes=5))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get("todo.mealie_special_groceries") is not None
|
||||
|
||||
mock_mealie_client.get_shopping_lists.return_value = ShoppingListsResponse(
|
||||
items=[response[0]]
|
||||
)
|
||||
freezer.tick(timedelta(minutes=5))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get("todo.mealie_special_groceries") is None
|
||||
|
|
Loading…
Add table
Reference in a new issue