Refactor picnic tests (#181165)

This commit is contained in:
Joost Lekkerkerker
2026-09-03 13:22:55 +02:00
committed by GitHub
parent 038ca082c3
commit c740a9858e
3 changed files with 1219 additions and 579 deletions
+12
View File
@@ -1 +1,13 @@
"""Tests for the Picnic integration."""
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
"""Fixture for setting up the component."""
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
@@ -0,0 +1,883 @@
# serializer version: 1
# name: test_all_entities[sensor.mock_title_cart_items_count-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_cart_items_count',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Cart items count',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Cart items count',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'cart_items_count',
'unique_id': '295-6y3-1nf4.cart_items_count',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_cart_items_count-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Cart items count',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_cart_items_count',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '10',
})
# ---
# name: test_all_entities[sensor.mock_title_cart_total_price-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_cart_total_price',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Cart total price',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Cart total price',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'cart_total_price',
'unique_id': '295-6y3-1nf4.cart_total_price',
'unit_of_measurement': '€',
})
# ---
# name: test_all_entities[sensor.mock_title_cart_total_price-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Cart total price',
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: '€',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_cart_total_price',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '25.35',
})
# ---
# name: test_all_entities[sensor.mock_title_end_of_last_order_s_slot-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_end_of_last_order_s_slot',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': "End of last order's slot",
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': "End of last order's slot",
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'last_order_slot_end',
'unique_id': '295-6y3-1nf4.last_order_slot_end',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_end_of_last_order_s_slot-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: "Mock Title End of last order's slot",
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_end_of_last_order_s_slot',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2021-02-26T20:15:00+00:00',
})
# ---
# name: test_all_entities[sensor.mock_title_end_of_next_delivery_s_slot-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_end_of_next_delivery_s_slot',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': "End of next delivery's slot",
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': "End of next delivery's slot",
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'next_delivery_slot_end',
'unique_id': '295-6y3-1nf4.next_delivery_slot_end',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_end_of_next_delivery_s_slot-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: "Mock Title End of next delivery's slot",
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_end_of_next_delivery_s_slot',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_all_entities[sensor.mock_title_end_of_selected_slot-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_end_of_selected_slot',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'End of selected slot',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'End of selected slot',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'selected_slot_end',
'unique_id': '295-6y3-1nf4.selected_slot_end',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_end_of_selected_slot-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title End of selected slot',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_end_of_selected_slot',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2021-03-03T14:45:00+00:00',
})
# ---
# name: test_all_entities[sensor.mock_title_estimated_arrival_of_next_delivery-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_estimated_arrival_of_next_delivery',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Estimated arrival of next delivery',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Estimated arrival of next delivery',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'next_delivery_estimated_arrival',
'unique_id': '295-6y3-1nf4.next_delivery_estimated_arrival',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_estimated_arrival_of_next_delivery-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Estimated arrival of next delivery',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_estimated_arrival_of_next_delivery',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_all_entities[sensor.mock_title_expected_end_of_next_delivery-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_expected_end_of_next_delivery',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Expected end of next delivery',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Expected end of next delivery',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'next_delivery_eta_end',
'unique_id': '295-6y3-1nf4.next_delivery_eta_end',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_expected_end_of_next_delivery-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Expected end of next delivery',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_expected_end_of_next_delivery',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_all_entities[sensor.mock_title_expected_start_of_next_delivery-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_expected_start_of_next_delivery',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Expected start of next delivery',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Expected start of next delivery',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'next_delivery_eta_start',
'unique_id': '295-6y3-1nf4.next_delivery_eta_start',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_expected_start_of_next_delivery-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Expected start of next delivery',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_expected_start_of_next_delivery',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_all_entities[sensor.mock_title_last_order_delivery_time-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_last_order_delivery_time',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Last order delivery time',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last order delivery time',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'last_order_delivery_time',
'unique_id': '295-6y3-1nf4.last_order_delivery_time',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_last_order_delivery_time-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Last order delivery time',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_last_order_delivery_time',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2021-02-26T19:54:05+00:00',
})
# ---
# name: test_all_entities[sensor.mock_title_max_order_time_of_last_order-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_max_order_time_of_last_order',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Max order time of last order',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Max order time of last order',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'last_order_max_order_time',
'unique_id': '295-6y3-1nf4.last_order_max_order_time',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_max_order_time_of_last_order-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Max order time of last order',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_max_order_time_of_last_order',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2021-02-25T21:00:00+00:00',
})
# ---
# name: test_all_entities[sensor.mock_title_max_order_time_of_selected_slot-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_max_order_time_of_selected_slot',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Max order time of selected slot',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Max order time of selected slot',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'selected_slot_max_order_time',
'unique_id': '295-6y3-1nf4.selected_slot_max_order_time',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_max_order_time_of_selected_slot-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Max order time of selected slot',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_max_order_time_of_selected_slot',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2021-03-02T21:00:00+00:00',
})
# ---
# name: test_all_entities[sensor.mock_title_minimum_order_value_for_selected_slot-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_minimum_order_value_for_selected_slot',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Minimum order value for selected slot',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Minimum order value for selected slot',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'selected_slot_min_order_value',
'unique_id': '295-6y3-1nf4.selected_slot_min_order_value',
'unit_of_measurement': '€',
})
# ---
# name: test_all_entities[sensor.mock_title_minimum_order_value_for_selected_slot-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Minimum order value for selected slot',
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: '€',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_minimum_order_value_for_selected_slot',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '35.0',
})
# ---
# name: test_all_entities[sensor.mock_title_start_of_last_order_s_slot-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_start_of_last_order_s_slot',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': "Start of last order's slot",
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': "Start of last order's slot",
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'last_order_slot_start',
'unique_id': '295-6y3-1nf4.last_order_slot_start',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_start_of_last_order_s_slot-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: "Mock Title Start of last order's slot",
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_start_of_last_order_s_slot',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2021-02-26T19:15:00+00:00',
})
# ---
# name: test_all_entities[sensor.mock_title_start_of_next_delivery_s_slot-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_start_of_next_delivery_s_slot',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': "Start of next delivery's slot",
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': "Start of next delivery's slot",
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'next_delivery_slot_start',
'unique_id': '295-6y3-1nf4.next_delivery_slot_start',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_start_of_next_delivery_s_slot-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: "Mock Title Start of next delivery's slot",
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_start_of_next_delivery_s_slot',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_all_entities[sensor.mock_title_start_of_selected_slot-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_start_of_selected_slot',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Start of selected slot',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Start of selected slot',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'selected_slot_start',
'unique_id': '295-6y3-1nf4.selected_slot_start',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_start_of_selected_slot-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'timestamp',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Start of selected slot',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_start_of_selected_slot',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2021-03-03T13:45:00+00:00',
})
# ---
# name: test_all_entities[sensor.mock_title_status_of_last_order-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_status_of_last_order',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Status of last order',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Status of last order',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'last_order_status',
'unique_id': '295-6y3-1nf4.last_order_status',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.mock_title_status_of_last_order-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Status of last order',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_status_of_last_order',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'COMPLETED',
})
# ---
# name: test_all_entities[sensor.mock_title_total_price_of_last_order-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_total_price_of_last_order',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Total price of last order',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Total price of last order',
'platform': 'picnic',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'last_order_total_price',
'unique_id': '295-6y3-1nf4.last_order_total_price',
'unit_of_measurement': '€',
})
# ---
# name: test_all_entities[sensor.mock_title_total_price_of_last_order-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.ATTRIBUTION: 'attribution'>: 'Data provided by Picnic',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Mock Title Total price of last order',
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: '€',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_total_price_of_last_order',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '41.33',
})
# ---
+324 -579
View File
@@ -1,628 +1,373 @@
"""The tests for the Picnic sensor platform."""
import copy
from datetime import timedelta
import unittest
from unittest.mock import patch
from unittest.mock import MagicMock, patch
from freezegun.api import FrozenDateTimeFactory
import pytest
from python_picnic_api2.models import Cart, DeliverySummary, User
from python_picnic_api2.models import DeliverySummary, Eta
import requests
from syrupy.assertion import SnapshotAssertion
from homeassistant import config_entries
from homeassistant.components.picnic import const
from homeassistant.components.picnic.const import DOMAIN
from homeassistant.components.picnic.sensor import SENSOR_TYPES
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.components.picnic.const import DEFAULT_UPDATE_INTERVAL, DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import (
CONF_ACCESS_TOKEN,
CONF_COUNTRY_CODE,
CURRENCY_EURO,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.util import dt as dt_util
from tests.common import (
MockConfigEntry,
async_fire_time_changed,
async_test_home_assistant,
)
from . import setup_integration
DEFAULT_USER_RESPONSE = {
"user_id": "295-6y3-1nf4",
"firstname": "User",
"lastname": "Name",
"address": {
"house_number": 123,
"house_number_ext": "a",
"postcode": "4321 AB",
"street": "Commonstreet",
"city": "Somewhere",
},
"total_deliveries": 123,
"completed_deliveries": 112,
}
DEFAULT_CART_RESPONSE = {
"items": [],
"delivery_slots": [
{
"slot_id": "611a3b074872b23576bef456a",
"window_start": "2021-03-03T14:45:00.000+01:00",
"window_end": "2021-03-03T15:45:00.000+01:00",
"cut_off_time": "2021-03-02T22:00:00.000+01:00",
"minimum_order_value": 3500,
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
@pytest.fixture(autouse=True)
def enable_all_entities(entity_registry_enabled_by_default: None) -> None:
"""Make sure all entities are enabled."""
async def test_all_entities(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
entity_registry: er.EntityRegistry,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test all entities."""
with patch("homeassistant.components.picnic.PLATFORMS", [Platform.SENSOR]):
await setup_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
async def test_setup_platform_not_available(
hass: HomeAssistant,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test the set-up of the sensor platform if API is not available."""
mock_picnic_api.get_user.side_effect = requests.exceptions.ConnectionError
mock_picnic_api.get_cart.side_effect = requests.exceptions.ConnectionError
mock_picnic_api.get_deliveries.side_effect = requests.exceptions.ConnectionError
mock_picnic_api.get_delivery_position.side_effect = (
requests.exceptions.ConnectionError
)
await setup_integration(hass, mock_config_entry)
assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY
assert hass.states.get("sensor.mock_title_max_order_time_of_selected_slot") is None
assert hass.states.get("sensor.mock_title_status_of_last_order") is None
assert hass.states.get("sensor.mock_title_total_price_of_last_order") is None
async def test_sensors_no_selected_time_slot(
hass: HomeAssistant,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test sensor states with no explicit selected time slot."""
cart = mock_picnic_api.get_cart.return_value
cart.selected_slot.state = "IMPLICIT"
await setup_integration(hass, mock_config_entry)
assert (
hass.states.get("sensor.mock_title_start_of_selected_slot").state
== STATE_UNKNOWN
)
assert (
hass.states.get("sensor.mock_title_end_of_selected_slot").state == STATE_UNKNOWN
)
assert (
hass.states.get("sensor.mock_title_max_order_time_of_selected_slot").state
== STATE_UNKNOWN
)
assert (
hass.states.get("sensor.mock_title_minimum_order_value_for_selected_slot").state
== STATE_UNKNOWN
)
async def test_next_delivery_sensors(
hass: HomeAssistant,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test sensor states when last order is not yet delivered."""
delivery = mock_picnic_api.get_deliveries.return_value[0]
delivery.raw["delivery_time"] = None
delivery.status = "CURRENT"
await setup_integration(hass, mock_config_entry)
assert (
hass.states.get("sensor.mock_title_last_order_delivery_time").state
== STATE_UNKNOWN
)
assert (
hass.states.get("sensor.mock_title_expected_start_of_next_delivery").state
== "2021-02-26T19:54:00+00:00"
)
assert (
hass.states.get("sensor.mock_title_expected_end_of_next_delivery").state
== "2021-02-26T20:14:00+00:00"
)
assert (
hass.states.get("sensor.mock_title_start_of_next_delivery_s_slot").state
== "2021-02-26T19:15:00+00:00"
)
assert (
hass.states.get("sensor.mock_title_end_of_next_delivery_s_slot").state
== "2021-02-26T20:15:00+00:00"
)
async def test_sensors_eta_date_malformed(
hass: HomeAssistant,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test sensor states when last order eta dates are malformed."""
await setup_integration(hass, mock_config_entry)
delivery = mock_picnic_api.get_deliveries.return_value[0]
delivery.eta2 = Eta(start="wrong-time", end="other-malformed-datetime")
delivery.status = "CURRENT"
freezer.tick(DEFAULT_UPDATE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert (
hass.states.get("sensor.mock_title_expected_start_of_next_delivery").state
== STATE_UNKNOWN
)
assert (
hass.states.get("sensor.mock_title_expected_end_of_next_delivery").state
== STATE_UNKNOWN
)
async def test_sensors_use_detailed_eta_if_available(
hass: HomeAssistant,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test sensor states use the more precise delivery position ETA."""
await setup_integration(hass, mock_config_entry)
delivery = mock_picnic_api.get_deliveries.return_value[0]
delivery.raw["delivery_time"] = None
delivery.status = "CURRENT"
mock_picnic_api.get_delivery_position.return_value = {
"eta_window": {
"start": "2021-03-05T10:19:20.452+00:00",
"end": "2021-03-05T10:39:20.452+00:00",
},
],
"selected_slot": {"slot_id": "611a3b074872b23576bef456a", "state": "EXPLICIT"},
"total_count": 10,
"total_price": 2535,
}
DEFAULT_DELIVERY_RESPONSE = {
"delivery_id": "z28fjso23e",
"creation_time": "2021-02-24T21:48:46.395+01:00",
"slot": {
"slot_id": "602473859a40dc24c6b65879",
"hub_id": "AMS",
"window_start": "2021-02-26T20:15:00.000+01:00",
"window_end": "2021-02-26T21:15:00.000+01:00",
"cut_off_time": "2021-02-25T22:00:00.000+01:00",
"minimum_order_value": 3500,
},
"eta2": {
"start": "2021-02-26T20:54:00.000+01:00",
"end": "2021-02-26T21:14:00.000+01:00",
},
"status": "COMPLETED",
"delivery_time": {
"start": "2021-02-26T20:54:05.221+01:00",
"end": "2021-02-26T20:58:31.802+01:00",
},
"orders": [
{
"creation_time": "2021-02-24T21:48:46.418+01:00",
"total_price": 3597,
},
{
"creation_time": "2021-02-25T17:10:26.816+01:00",
"total_price": 536,
},
],
}
"eta": 1614941090000,
}
SENSOR_KEYS = [desc.key for desc in SENSOR_TYPES]
freezer.tick(DEFAULT_UPDATE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
mock_picnic_api.get_delivery_position.assert_called_with(delivery.delivery_id)
assert (
hass.states.get("sensor.mock_title_expected_start_of_next_delivery").state
== "2021-03-05T10:19:20+00:00"
)
assert (
hass.states.get("sensor.mock_title_expected_end_of_next_delivery").state
== "2021-03-05T10:39:20+00:00"
)
assert (
hass.states.get("sensor.mock_title_estimated_arrival_of_next_delivery").state
== "2021-03-05T10:44:50+00:00"
)
@pytest.mark.usefixtures("hass_storage")
class TestPicnicSensor(unittest.IsolatedAsyncioTestCase):
"""Test the Picnic sensor."""
async def test_sensors_no_data(
hass: HomeAssistant,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test sensor states when the api only returns empty objects."""
await setup_integration(hass, mock_config_entry)
async def asyncSetUp(self):
"""Set up things to be run when tests are started."""
self._manager = async_test_home_assistant()
self.hass = await self._manager.__aenter__()
self.entity_registry = er.async_get(self.hass)
mock_picnic_api.get_user.return_value = {}
mock_picnic_api.get_cart.return_value = None
mock_picnic_api.get_deliveries.return_value = None
mock_picnic_api.get_delivery_position.side_effect = ValueError
# Patch the api client
self.picnic_patcher = patch("homeassistant.components.picnic.PicnicAPI")
self.picnic_mock = self.picnic_patcher.start()
self.picnic_mock().session.auth_token = "3q29fpwhulzes"
freezer.tick(DEFAULT_UPDATE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
# Add a config entry and setup the integration
config_data = {
CONF_ACCESS_TOKEN: "x-original-picnic-auth-token",
CONF_COUNTRY_CODE: "NL",
}
self.config_entry = MockConfigEntry(
domain=const.DOMAIN,
data=config_data,
unique_id="295-6y3-1nf4",
)
self.config_entry.add_to_hass(self.hass)
async def asyncTearDown(self):
"""Tear down the test setup, stop hass/patchers."""
await self.hass.async_stop(force=True)
await self._manager.__aexit__(None, None, None)
self.picnic_patcher.stop()
@property
def _coordinator(self):
return self.config_entry.runtime_data
def _assert_sensor(self, name, state=None, cls=None, unit=None, disabled=False):
sensor = self.hass.states.get(name)
if disabled:
assert sensor is None
return
assert sensor.state == state
if cls:
assert sensor.attributes["device_class"] == cls
if unit:
assert sensor.attributes["unit_of_measurement"] == unit
assert sensor.attributes["attribution"] == "Data provided by Picnic"
async def _setup_platform(
self, use_default_responses=False, enable_all_sensors=True
for entity_id in (
"sensor.mock_title_cart_total_price",
"sensor.mock_title_start_of_selected_slot",
"sensor.mock_title_end_of_selected_slot",
"sensor.mock_title_max_order_time_of_selected_slot",
"sensor.mock_title_minimum_order_value_for_selected_slot",
"sensor.mock_title_max_order_time_of_last_order",
"sensor.mock_title_last_order_delivery_time",
"sensor.mock_title_expected_start_of_next_delivery",
"sensor.mock_title_expected_end_of_next_delivery",
):
"""Set up the Picnic sensor platform."""
if use_default_responses:
self.picnic_mock().get_user.return_value = User.from_api(
copy.deepcopy(DEFAULT_USER_RESPONSE)
)
self.picnic_mock().get_cart.return_value = Cart.from_api(
copy.deepcopy(DEFAULT_CART_RESPONSE)
)
self.picnic_mock().get_deliveries.return_value = [
DeliverySummary.from_api(copy.deepcopy(DEFAULT_DELIVERY_RESPONSE))
]
self.picnic_mock().get_delivery_position.return_value = {}
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
await self.hass.config_entries.async_setup(self.config_entry.entry_id)
await self.hass.async_block_till_done()
if enable_all_sensors:
await self._enable_all_sensors()
async def test_sensors_malformed_delivery_data(
hass: HomeAssistant,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test sensor states when the delivery api returns not a list."""
await setup_integration(hass, mock_config_entry)
async def _enable_all_sensors(self):
"""Enable all sensors of the Picnic integration."""
# Enable the sensors
for sensor_type in SENSOR_KEYS:
entry = self.entity_registry.async_get_or_create(
Platform.SENSOR, DOMAIN, f"{self.config_entry.unique_id}.{sensor_type}"
)
updated_entry = self.entity_registry.async_update_entity(
entry.entity_id, disabled_by=None
)
assert updated_entry.disabled is False
await self.hass.async_block_till_done()
mock_picnic_api.get_deliveries.return_value = {"error": "message"}
# Trigger a reload of the data
async_fire_time_changed(
self.hass,
dt_util.utcnow()
+ timedelta(seconds=config_entries.RELOAD_AFTER_UPDATE_DELAY + 1),
)
await self.hass.async_block_till_done()
freezer.tick(DEFAULT_UPDATE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
async def test_sensor_setup_platform_not_available(self):
"""Test the set-up of the sensor platform if API is not available."""
# Configure mock requests to yield exceptions
self.picnic_mock().get_user.side_effect = requests.exceptions.ConnectionError
self.picnic_mock().get_cart.side_effect = requests.exceptions.ConnectionError
self.picnic_mock().get_deliveries.side_effect = (
requests.exceptions.ConnectionError
)
self.picnic_mock().get_delivery_position.side_effect = (
requests.exceptions.ConnectionError
)
await self._setup_platform(enable_all_sensors=False)
for entity_id in (
"sensor.mock_title_max_order_time_of_last_order",
"sensor.mock_title_last_order_delivery_time",
"sensor.mock_title_expected_start_of_next_delivery",
"sensor.mock_title_expected_end_of_next_delivery",
):
assert hass.states.get(entity_id).state == STATE_UNKNOWN
# Assert that sensors are not set up
assert (
self.hass.states.get("sensor.mock_title_max_order_time_of_selected_slot")
is None
)
assert self.hass.states.get("sensor.mock_title_status_of_last_order") is None
assert (
self.hass.states.get("sensor.mock_title_total_price_of_last_order") is None
)
async def test_sensors_setup(self):
"""Test the default sensor setup behaviour."""
await self._setup_platform(use_default_responses=True)
async def test_sensors_malformed_response(
hass: HomeAssistant,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test sensors become unavailable when the API yields ValueError."""
await setup_integration(hass, mock_config_entry)
self._assert_sensor("sensor.mock_title_cart_items_count", "10")
self._assert_sensor(
"sensor.mock_title_cart_total_price",
"25.35",
unit=CURRENCY_EURO,
)
self._assert_sensor(
"sensor.mock_title_start_of_selected_slot",
"2021-03-03T13:45:00+00:00",
cls=SensorDeviceClass.TIMESTAMP,
)
self._assert_sensor(
"sensor.mock_title_end_of_selected_slot",
"2021-03-03T14:45:00+00:00",
cls=SensorDeviceClass.TIMESTAMP,
)
self._assert_sensor(
"sensor.mock_title_max_order_time_of_selected_slot",
"2021-03-02T21:00:00+00:00",
cls=SensorDeviceClass.TIMESTAMP,
)
self._assert_sensor(
"sensor.mock_title_minimum_order_value_for_selected_slot",
"35.0",
)
self._assert_sensor(
"sensor.mock_title_start_of_last_order_s_slot",
"2021-02-26T19:15:00+00:00",
cls=SensorDeviceClass.TIMESTAMP,
)
self._assert_sensor(
"sensor.mock_title_end_of_last_order_s_slot",
"2021-02-26T20:15:00+00:00",
cls=SensorDeviceClass.TIMESTAMP,
)
self._assert_sensor("sensor.mock_title_status_of_last_order", "COMPLETED")
self._assert_sensor(
"sensor.mock_title_max_order_time_of_last_order",
"2021-02-25T21:00:00+00:00",
cls=SensorDeviceClass.TIMESTAMP,
)
self._assert_sensor(
"sensor.mock_title_last_order_delivery_time",
"2021-02-26T19:54:05+00:00",
cls=SensorDeviceClass.TIMESTAMP,
)
self._assert_sensor(
"sensor.mock_title_total_price_of_last_order",
"41.33",
unit=CURRENCY_EURO,
)
self._assert_sensor(
"sensor.mock_title_expected_start_of_next_delivery",
"unknown",
cls=SensorDeviceClass.TIMESTAMP,
)
self._assert_sensor(
"sensor.mock_title_expected_end_of_next_delivery",
"unknown",
cls=SensorDeviceClass.TIMESTAMP,
)
self._assert_sensor(
"sensor.mock_title_start_of_next_delivery_s_slot",
"unknown",
cls=SensorDeviceClass.TIMESTAMP,
)
self._assert_sensor(
"sensor.mock_title_end_of_next_delivery_s_slot",
"unknown",
cls=SensorDeviceClass.TIMESTAMP,
)
mock_picnic_api.get_user.side_effect = ValueError
mock_picnic_api.get_cart.side_effect = ValueError
async def test_sensors_setup_disabled_by_default(self):
"""Test that some sensors are disabled by default."""
await self._setup_platform(use_default_responses=True, enable_all_sensors=False)
freezer.tick(DEFAULT_UPDATE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
self._assert_sensor("sensor.mock_title_cart_items_count", disabled=True)
self._assert_sensor(
"sensor.mock_title_start_of_last_order_s_slot", disabled=True
)
self._assert_sensor("sensor.mock_title_end_of_last_order_s_slot", disabled=True)
self._assert_sensor("sensor.mock_title_status_of_last_order", disabled=True)
self._assert_sensor(
"sensor.mock_title_total_price_of_last_order", disabled=True
)
self._assert_sensor(
"sensor.mock_title_start_of_next_delivery_s_slot",
disabled=True,
)
self._assert_sensor(
"sensor.mock_title_end_of_next_delivery_s_slot", disabled=True
)
assert (
hass.states.get("sensor.mock_title_cart_total_price").state == STATE_UNAVAILABLE
)
async def test_sensors_no_selected_time_slot(self):
"""Test sensor states with no explicit selected time slot."""
# Adjust cart response
cart_response = copy.deepcopy(DEFAULT_CART_RESPONSE)
cart_response["selected_slot"]["state"] = "IMPLICIT"
# Set mock responses
self.picnic_mock().get_user.return_value = User.from_api(
copy.deepcopy(DEFAULT_USER_RESPONSE)
)
self.picnic_mock().get_cart.return_value = Cart.from_api(cart_response)
self.picnic_mock().get_deliveries.return_value = [
DeliverySummary.from_api(copy.deepcopy(DEFAULT_DELIVERY_RESPONSE))
]
self.picnic_mock().get_delivery_position.return_value = {}
await self._setup_platform()
async def test_multiple_active_orders(
hass: HomeAssistant,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test sensor values with multiple active orders."""
completed = mock_picnic_api.get_deliveries.return_value[0]
# Assert sensors are unknown
self._assert_sensor("sensor.mock_title_start_of_selected_slot", STATE_UNKNOWN)
self._assert_sensor("sensor.mock_title_end_of_selected_slot", STATE_UNKNOWN)
self._assert_sensor(
"sensor.mock_title_max_order_time_of_selected_slot",
STATE_UNKNOWN,
)
self._assert_sensor(
"sensor.mock_title_minimum_order_value_for_selected_slot",
STATE_UNKNOWN,
)
def _undelivered(window_start: str, window_end: str, eta_start: str, eta_end: str):
order = DeliverySummary.from_api(completed.raw.copy())
order.raw["delivery_time"] = None
order.status = "CURRENT"
order.slot.window_start = window_start
order.slot.window_end = window_end
order.eta2 = Eta(start=eta_start, end=eta_end)
return order
async def test_next_delivery_sensors(self):
"""Test sensor states when last order is not yet delivered."""
# Adjust default delivery response
delivery_response = copy.deepcopy(DEFAULT_DELIVERY_RESPONSE)
del delivery_response["delivery_time"]
delivery_response["status"] = "CURRENT"
undelivered_order = _undelivered(
"2022-03-01T09:15:00.000+01:00",
"2022-03-01T10:15:00.000+01:00",
"2022-03-01T09:30:00.000+01:00",
"2022-03-01T09:45:00.000+01:00",
)
undelivered_order_2 = _undelivered(
"2022-03-08T13:15:00.000+01:00",
"2022-03-08T14:15:00.000+01:00",
"2022-03-08T13:30:00.000+01:00",
"2022-03-08T13:45:00.000+01:00",
)
# Set mock responses
self.picnic_mock().get_user.return_value = User.from_api(
copy.deepcopy(DEFAULT_USER_RESPONSE)
)
self.picnic_mock().get_cart.return_value = Cart.from_api(
copy.deepcopy(DEFAULT_CART_RESPONSE)
)
self.picnic_mock().get_deliveries.return_value = [
DeliverySummary.from_api(delivery_response)
]
self.picnic_mock().get_delivery_position.return_value = {}
await self._setup_platform()
mock_picnic_api.get_deliveries.return_value = [
undelivered_order_2,
undelivered_order,
completed,
]
mock_picnic_api.get_delivery_position.return_value = {}
# Assert delivery time is not available, but eta is
self._assert_sensor("sensor.mock_title_last_order_delivery_time", STATE_UNKNOWN)
self._assert_sensor(
"sensor.mock_title_expected_start_of_next_delivery",
"2021-02-26T19:54:00+00:00",
)
self._assert_sensor(
"sensor.mock_title_expected_end_of_next_delivery",
"2021-02-26T20:14:00+00:00",
)
self._assert_sensor(
"sensor.mock_title_start_of_next_delivery_s_slot",
"2021-02-26T19:15:00+00:00",
)
self._assert_sensor(
"sensor.mock_title_end_of_next_delivery_s_slot",
"2021-02-26T20:15:00+00:00",
)
await setup_integration(hass, mock_config_entry)
async def test_sensors_eta_date_malformed(self):
"""Test sensor states when last order eta dates are malformed."""
# Set-up platform with default mock responses
await self._setup_platform(use_default_responses=True)
assert (
hass.states.get("sensor.mock_title_start_of_last_order_s_slot").state
== "2022-03-08T12:15:00+00:00"
)
assert (
hass.states.get("sensor.mock_title_end_of_last_order_s_slot").state
== "2022-03-08T13:15:00+00:00"
)
assert (
hass.states.get("sensor.mock_title_start_of_next_delivery_s_slot").state
== "2022-03-01T08:15:00+00:00"
)
assert (
hass.states.get("sensor.mock_title_end_of_next_delivery_s_slot").state
== "2022-03-01T09:15:00+00:00"
)
assert (
hass.states.get("sensor.mock_title_expected_start_of_next_delivery").state
== "2022-03-01T08:30:00+00:00"
)
assert (
hass.states.get("sensor.mock_title_expected_end_of_next_delivery").state
== "2022-03-01T08:45:00+00:00"
)
# Set non-datetime strings as eta
eta_dates: dict[str, str] = {
"start": "wrong-time",
"end": "other-malformed-datetime",
}
delivery_response = copy.deepcopy(DEFAULT_DELIVERY_RESPONSE)
delivery_response["eta2"] = eta_dates
delivery_response["status"] = "CURRENT"
self.picnic_mock().get_deliveries.return_value = [
DeliverySummary.from_api(delivery_response)
]
await self._coordinator.async_refresh()
# Assert eta times are not available due to malformed date strings
self._assert_sensor(
"sensor.mock_title_expected_start_of_next_delivery",
STATE_UNKNOWN,
)
self._assert_sensor(
"sensor.mock_title_expected_end_of_next_delivery",
STATE_UNKNOWN,
)
async def test_device_registry_entry(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test if device registry entry is populated correctly."""
await setup_integration(hass, mock_config_entry)
async def test_sensors_use_detailed_eta_if_available(self):
"""Test sensor states when last order is not yet delivered."""
# Set-up platform with default mock responses
await self._setup_platform(use_default_responses=True)
picnic_service = device_registry.async_get_device_by_identifier(
(DOMAIN, "295-6y3-1nf4"),
mock_config_entry.entry_id,
)
assert picnic_service.model == "295-6y3-1nf4"
assert picnic_service.name == "Mock Title"
assert picnic_service.entry_type is dr.DeviceEntryType.SERVICE
# Provide a delivery position response with different ETA
# and remove delivery time from response
delivery_response = copy.deepcopy(DEFAULT_DELIVERY_RESPONSE)
del delivery_response["delivery_time"]
delivery_response["status"] = "CURRENT"
self.picnic_mock().get_deliveries.return_value = [
DeliverySummary.from_api(delivery_response)
]
self.picnic_mock().get_delivery_position.return_value = {
"eta_window": {
"start": "2021-03-05T10:19:20.452+00:00",
"end": "2021-03-05T10:39:20.452+00:00",
},
"eta": 1614941090000,
}
await self._coordinator.async_refresh()
# Assert detailed ETA is used
self.picnic_mock().get_delivery_position.assert_called_with(
delivery_response["delivery_id"]
)
self._assert_sensor(
"sensor.mock_title_expected_start_of_next_delivery",
"2021-03-05T10:19:20+00:00",
)
self._assert_sensor(
"sensor.mock_title_expected_end_of_next_delivery",
"2021-03-05T10:39:20+00:00",
)
self._assert_sensor(
"sensor.mock_title_estimated_arrival_of_next_delivery",
"2021-03-05T10:44:50+00:00",
)
async def test_auth_token_is_saved_on_update(
hass: HomeAssistant,
mock_picnic_api: MagicMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test auth-token changes are reflected by the config entry."""
await setup_integration(hass, mock_config_entry)
# The live estimate is cleared again once position data disappears
self.picnic_mock().get_delivery_position.return_value = {}
async_fire_time_changed(self.hass, dt_util.utcnow() + timedelta(minutes=31))
await self.hass.async_block_till_done(wait_background_tasks=True)
updated_auth_token = "x-updated-picnic-auth-token"
mock_picnic_api.session.auth_token = updated_auth_token
self._assert_sensor(
"sensor.mock_title_estimated_arrival_of_next_delivery",
STATE_UNKNOWN,
)
assert mock_config_entry.data.get(CONF_ACCESS_TOKEN) != updated_auth_token
async def test_sensors_no_data(self):
"""Test sensor states when the api only returns empty objects."""
# Setup platform with default responses
await self._setup_platform(use_default_responses=True)
freezer.tick(DEFAULT_UPDATE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
# Change mock responses to empty data and refresh the coordinator
self.picnic_mock().get_user.return_value = {}
self.picnic_mock().get_cart.return_value = None
self.picnic_mock().get_deliveries.return_value = None
self.picnic_mock().get_delivery_position.side_effect = ValueError
await self._coordinator.async_refresh()
# Assert all default-enabled sensors have STATE_UNAVAILABLE
# because the last update failed
assert self._coordinator.last_update_success is False
self._assert_sensor("sensor.mock_title_cart_total_price", STATE_UNAVAILABLE)
self._assert_sensor(
"sensor.mock_title_start_of_selected_slot", STATE_UNAVAILABLE
)
self._assert_sensor("sensor.mock_title_end_of_selected_slot", STATE_UNAVAILABLE)
self._assert_sensor(
"sensor.mock_title_max_order_time_of_selected_slot",
STATE_UNAVAILABLE,
)
self._assert_sensor(
"sensor.mock_title_minimum_order_value_for_selected_slot",
STATE_UNAVAILABLE,
)
self._assert_sensor(
"sensor.mock_title_max_order_time_of_last_order",
STATE_UNAVAILABLE,
)
self._assert_sensor(
"sensor.mock_title_last_order_delivery_time",
STATE_UNAVAILABLE,
)
self._assert_sensor(
"sensor.mock_title_expected_start_of_next_delivery",
STATE_UNAVAILABLE,
)
self._assert_sensor(
"sensor.mock_title_expected_end_of_next_delivery",
STATE_UNAVAILABLE,
)
async def test_sensors_malformed_delivery_data(self):
"""Test sensor states when the delivery api returns not a list."""
# Setup platform with default responses
await self._setup_platform(use_default_responses=True)
# Change mock responses to empty data and refresh the coordinator
self.picnic_mock().get_deliveries.return_value = {"error": "message"}
await self._coordinator.async_refresh()
# Assert all last-order sensors have STATE_UNAVAILABLE
# because the delivery info fetch failed
assert self._coordinator.last_update_success is True
self._assert_sensor(
"sensor.mock_title_max_order_time_of_last_order",
STATE_UNKNOWN,
)
self._assert_sensor("sensor.mock_title_last_order_delivery_time", STATE_UNKNOWN)
self._assert_sensor(
"sensor.mock_title_expected_start_of_next_delivery",
STATE_UNKNOWN,
)
self._assert_sensor(
"sensor.mock_title_expected_end_of_next_delivery",
STATE_UNKNOWN,
)
async def test_sensors_malformed_response(self):
"""Test coordinator update fails when API yields ValueError."""
# Setup platform with default responses
await self._setup_platform(use_default_responses=True)
# Change mock responses to empty data and refresh the coordinator
self.picnic_mock().get_user.side_effect = ValueError
self.picnic_mock().get_cart.side_effect = ValueError
await self._coordinator.async_refresh()
# Assert coordinator update failed
assert self._coordinator.last_update_success is False
async def test_multiple_active_orders(self):
"""Test sensor values with multiple active orders."""
# Create 2 undelivered orders
undelivered_order = copy.deepcopy(DEFAULT_DELIVERY_RESPONSE)
del undelivered_order["delivery_time"]
undelivered_order["status"] = "CURRENT"
undelivered_order["slot"]["window_start"] = "2022-03-01T09:15:00.000+01:00"
undelivered_order["slot"]["window_end"] = "2022-03-01T10:15:00.000+01:00"
undelivered_order["eta2"]["start"] = "2022-03-01T09:30:00.000+01:00"
undelivered_order["eta2"]["end"] = "2022-03-01T09:45:00.000+01:00"
undelivered_order_2 = copy.deepcopy(undelivered_order)
undelivered_order_2["slot"]["window_start"] = "2022-03-08T13:15:00.000+01:00"
undelivered_order_2["slot"]["window_end"] = "2022-03-08T14:15:00.000+01:00"
undelivered_order_2["eta2"]["start"] = "2022-03-08T13:30:00.000+01:00"
undelivered_order_2["eta2"]["end"] = "2022-03-08T13:45:00.000+01:00"
deliveries_response = [
DeliverySummary.from_api(undelivered_order_2),
DeliverySummary.from_api(undelivered_order),
DeliverySummary.from_api(copy.deepcopy(DEFAULT_DELIVERY_RESPONSE)),
]
# Set mock responses
self.picnic_mock().get_user.return_value = User.from_api(
copy.deepcopy(DEFAULT_USER_RESPONSE)
)
self.picnic_mock().get_cart.return_value = Cart.from_api(
copy.deepcopy(DEFAULT_CART_RESPONSE)
)
self.picnic_mock().get_deliveries.return_value = deliveries_response
self.picnic_mock().get_delivery_position.return_value = {}
await self._setup_platform()
self._assert_sensor(
"sensor.mock_title_start_of_last_order_s_slot",
"2022-03-08T12:15:00+00:00",
)
self._assert_sensor(
"sensor.mock_title_end_of_last_order_s_slot",
"2022-03-08T13:15:00+00:00",
)
self._assert_sensor(
"sensor.mock_title_start_of_next_delivery_s_slot",
"2022-03-01T08:15:00+00:00",
)
self._assert_sensor(
"sensor.mock_title_end_of_next_delivery_s_slot",
"2022-03-01T09:15:00+00:00",
)
self._assert_sensor(
"sensor.mock_title_expected_start_of_next_delivery",
"2022-03-01T08:30:00+00:00",
)
self._assert_sensor(
"sensor.mock_title_expected_end_of_next_delivery",
"2022-03-01T08:45:00+00:00",
)
async def test_device_registry_entry(self):
"""Test if device registry entry is populated correctly."""
# Setup platform and default mock responses
await self._setup_platform(use_default_responses=True)
device_registry = dr.async_get(self.hass) # pylint: disable=home-assistant-tests-registry-fixtures
picnic_service = device_registry.async_get_device_by_identifier(
(const.DOMAIN, DEFAULT_USER_RESPONSE["user_id"]),
self.config_entry.entry_id,
)
assert picnic_service.model == DEFAULT_USER_RESPONSE["user_id"]
assert picnic_service.name == "Mock Title"
assert picnic_service.entry_type is dr.DeviceEntryType.SERVICE
async def test_auth_token_is_saved_on_update(self):
"""Test auth-token changes are reflected by the config entry."""
# Setup platform and default mock responses
await self._setup_platform(use_default_responses=True)
# Set a different auth token in the session mock
updated_auth_token = "x-updated-picnic-auth-token"
self.picnic_mock().session.auth_token = updated_auth_token
# Verify the updated auth token is not set and fetch data using the coordinator
assert self.config_entry.data.get(CONF_ACCESS_TOKEN) != updated_auth_token
await self._coordinator.async_refresh()
# Verify that the updated auth token is saved in the config entry
assert self.config_entry.data.get(CONF_ACCESS_TOKEN) == updated_auth_token
assert mock_config_entry.data.get(CONF_ACCESS_TOKEN) == updated_auth_token