From 4d75758eb2f3df7b7d662603fccbc572d8e68d93 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Jul 2025 17:39:02 -0500 Subject: [PATCH] tests --- tests/integration/fixtures/entity_icon.yaml | 78 +++++++++++++++++ tests/integration/test_entity_icon.py | 97 +++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 tests/integration/fixtures/entity_icon.yaml create mode 100644 tests/integration/test_entity_icon.py diff --git a/tests/integration/fixtures/entity_icon.yaml b/tests/integration/fixtures/entity_icon.yaml new file mode 100644 index 0000000000..2ce633fe2c --- /dev/null +++ b/tests/integration/fixtures/entity_icon.yaml @@ -0,0 +1,78 @@ +esphome: + name: icon-test + +host: + +api: + +logger: + +# Test entities with custom icons +sensor: + - platform: template + name: "Sensor With Icon" + icon: "mdi:temperature-celsius" + unit_of_measurement: "°C" + update_interval: 1s + lambda: |- + return 25.5; + + - platform: template + name: "Sensor Without Icon" + unit_of_measurement: "%" + update_interval: 1s + lambda: |- + return 50.0; + +binary_sensor: + - platform: template + name: "Binary Sensor With Icon" + icon: "mdi:motion-sensor" + lambda: |- + return true; + + - platform: template + name: "Binary Sensor Without Icon" + lambda: |- + return false; + +text_sensor: + - platform: template + name: "Text Sensor With Icon" + icon: "mdi:text-box" + lambda: |- + return {"Hello Icons"}; + +switch: + - platform: template + name: "Switch With Icon" + icon: "mdi:toggle-switch" + optimistic: true + +button: + - platform: template + name: "Button With Icon" + icon: "mdi:gesture-tap-button" + on_press: + - logger.log: "Button with icon pressed" + +number: + - platform: template + name: "Number With Icon" + icon: "mdi:numeric" + initial_value: 42 + min_value: 0 + max_value: 100 + step: 1 + optimistic: true + +select: + - platform: template + name: "Select With Icon" + icon: "mdi:format-list-bulleted" + options: + - "Option A" + - "Option B" + - "Option C" + initial_option: "Option A" + optimistic: true diff --git a/tests/integration/test_entity_icon.py b/tests/integration/test_entity_icon.py new file mode 100644 index 0000000000..56e266b486 --- /dev/null +++ b/tests/integration/test_entity_icon.py @@ -0,0 +1,97 @@ +"""Integration test for entity icons with USE_ENTITY_ICON feature.""" + +from __future__ import annotations + +import asyncio + +from aioesphomeapi import EntityState +import pytest + +from .types import APIClientConnectedFactory, RunCompiledFunction + + +@pytest.mark.asyncio +async def test_entity_icon( + yaml_config: str, + run_compiled: RunCompiledFunction, + api_client_connected: APIClientConnectedFactory, +) -> None: + """Test that entities with custom icons work correctly with USE_ENTITY_ICON.""" + # Write, compile and run the ESPHome device, then connect to API + async with run_compiled(yaml_config), api_client_connected() as client: + # Get all entities + entities = await client.list_entities_services() + + # Create a map of entity names to entity info + entity_map = {entity.name: entity for entity in entities[0]} + + # Test entities with icons + icon_test_cases = [ + # (entity_name, expected_icon) + ("Sensor With Icon", "mdi:temperature-celsius"), + ("Binary Sensor With Icon", "mdi:motion-sensor"), + ("Text Sensor With Icon", "mdi:text-box"), + ("Switch With Icon", "mdi:toggle-switch"), + ("Button With Icon", "mdi:gesture-tap-button"), + ("Number With Icon", "mdi:numeric"), + ("Select With Icon", "mdi:format-list-bulleted"), + ] + + # Test entities without icons (should have empty string) + no_icon_test_cases = [ + "Sensor Without Icon", + "Binary Sensor Without Icon", + ] + + # Verify entities with icons + for entity_name, expected_icon in icon_test_cases: + assert entity_name in entity_map, ( + f"Entity '{entity_name}' not found in API response" + ) + entity = entity_map[entity_name] + + # Check icon field + assert hasattr(entity, "icon"), ( + f"{entity_name}: Entity should have icon attribute" + ) + assert entity.icon == expected_icon, ( + f"{entity_name}: icon mismatch - " + f"expected '{expected_icon}', got '{entity.icon}'" + ) + + # Verify entities without icons + for entity_name in no_icon_test_cases: + assert entity_name in entity_map, ( + f"Entity '{entity_name}' not found in API response" + ) + entity = entity_map[entity_name] + + # Check icon field is empty + assert hasattr(entity, "icon"), ( + f"{entity_name}: Entity should have icon attribute" + ) + assert entity.icon == "", ( + f"{entity_name}: icon should be empty string for entities without icons, " + f"got '{entity.icon}'" + ) + + # Subscribe to states to ensure everything works normally + states: dict[int, EntityState] = {} + state_received = asyncio.Event() + + def on_state(state: EntityState) -> None: + states[state.key] = state + state_received.set() + + client.subscribe_states(on_state) + + # Wait for states + try: + await asyncio.wait_for(state_received.wait(), timeout=5.0) + except asyncio.TimeoutError: + pytest.fail("No states received within 5 seconds") + + # Verify we received states + assert len(states) > 0, ( + "No states received - entities may not be working correctly" + )