mirror of
https://github.com/home-assistant/core.git
synced 2026-09-16 21:48:38 +01:00
268 lines
8.3 KiB
Python
268 lines
8.3 KiB
Python
"""The tests for the Select component."""
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
from homeassistant.components.select import (
|
|
ATTR_CYCLE,
|
|
ATTR_OPTION,
|
|
ATTR_OPTIONS,
|
|
DOMAIN,
|
|
SERVICE_SELECT_FIRST,
|
|
SERVICE_SELECT_LAST,
|
|
SERVICE_SELECT_NEXT,
|
|
SERVICE_SELECT_OPTION,
|
|
SERVICE_SELECT_PREVIOUS,
|
|
SelectEntity,
|
|
)
|
|
from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM, STATE_UNKNOWN
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import ServiceValidationError
|
|
from homeassistant.setup import async_setup_component
|
|
|
|
from tests.common import setup_test_component_platform
|
|
|
|
|
|
class MockSelectEntity(SelectEntity):
|
|
"""Mock SelectEntity to use in tests."""
|
|
|
|
_attr_current_option = "option_one"
|
|
_attr_options = ["option_one", "option_two", "option_three"]
|
|
|
|
|
|
class MockSelectEntityWithoutOptions(MockSelectEntity):
|
|
"""Mock SelectEntity without any options to use in tests."""
|
|
|
|
_attr_name = "select without options"
|
|
_attr_options: list[str] = []
|
|
|
|
|
|
async def test_select(hass: HomeAssistant) -> None:
|
|
"""Test getting data from the mocked select entity."""
|
|
select = MockSelectEntity()
|
|
assert select.current_option == "option_one"
|
|
assert select.state == "option_one"
|
|
assert select.options == ["option_one", "option_two", "option_three"]
|
|
|
|
# Test none selected
|
|
select._attr_current_option = None
|
|
assert select.current_option is None
|
|
assert select.state is None
|
|
|
|
# Test none existing selected
|
|
select._attr_current_option = "option_four"
|
|
assert select.current_option == "option_four"
|
|
assert select.state is None
|
|
|
|
select.hass = hass
|
|
|
|
with pytest.raises(NotImplementedError):
|
|
await select.async_first()
|
|
|
|
with pytest.raises(NotImplementedError):
|
|
await select.async_last()
|
|
|
|
with pytest.raises(NotImplementedError):
|
|
await select.async_next(cycle=False)
|
|
|
|
with pytest.raises(NotImplementedError):
|
|
await select.async_previous(cycle=False)
|
|
|
|
with pytest.raises(NotImplementedError):
|
|
await select.async_select_option("option_one")
|
|
|
|
select.select_option = MagicMock()
|
|
select._attr_current_option = None
|
|
|
|
await select.async_first()
|
|
assert select.select_option.call_args[0][0] == "option_one"
|
|
|
|
await select.async_last()
|
|
assert select.select_option.call_args[0][0] == "option_three"
|
|
|
|
await select.async_next(cycle=False)
|
|
assert select.select_option.call_args[0][0] == "option_one"
|
|
|
|
await select.async_previous(cycle=False)
|
|
assert select.select_option.call_args[0][0] == "option_three"
|
|
|
|
await select.async_select_option("option_two")
|
|
assert select.select_option.call_args[0][0] == "option_two"
|
|
|
|
assert select.select_option.call_count == 5
|
|
|
|
assert select.capability_attributes[ATTR_OPTIONS] == [
|
|
"option_one",
|
|
"option_two",
|
|
"option_three",
|
|
]
|
|
|
|
|
|
async def test_custom_integration_and_validation(
|
|
hass: HomeAssistant,
|
|
mock_select_entities: list[MockSelectEntity],
|
|
) -> None:
|
|
"""Test we can only select valid options."""
|
|
setup_test_component_platform(hass, DOMAIN, mock_select_entities)
|
|
|
|
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.states.get("select.select_1").state == "option 1"
|
|
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_SELECT_OPTION,
|
|
{ATTR_OPTION: "option 2", ATTR_ENTITY_ID: "select.select_1"},
|
|
blocking=True,
|
|
)
|
|
|
|
hass.states.async_set("select.select_1", "option 2")
|
|
await hass.async_block_till_done()
|
|
assert hass.states.get("select.select_1").state == "option 2"
|
|
|
|
# test ServiceValidationError trigger
|
|
with pytest.raises(ServiceValidationError) as exc:
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_SELECT_OPTION,
|
|
{ATTR_OPTION: "option invalid", ATTR_ENTITY_ID: "select.select_1"},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert exc.value.translation_domain == DOMAIN
|
|
assert exc.value.translation_key == "not_valid_option"
|
|
|
|
assert hass.states.get("select.select_1").state == "option 2"
|
|
|
|
assert hass.states.get("select.select_2").state == STATE_UNKNOWN
|
|
|
|
with pytest.raises(ServiceValidationError):
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_SELECT_OPTION,
|
|
{ATTR_OPTION: "option invalid", ATTR_ENTITY_ID: "select.select_2"},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert hass.states.get("select.select_2").state == STATE_UNKNOWN
|
|
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_SELECT_OPTION,
|
|
{ATTR_OPTION: "option 3", ATTR_ENTITY_ID: "select.select_2"},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.states.get("select.select_2").state == "option 3"
|
|
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_SELECT_FIRST,
|
|
{ATTR_ENTITY_ID: "select.select_2"},
|
|
blocking=True,
|
|
)
|
|
assert hass.states.get("select.select_2").state == "option 1"
|
|
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_SELECT_LAST,
|
|
{ATTR_ENTITY_ID: "select.select_2"},
|
|
blocking=True,
|
|
)
|
|
assert hass.states.get("select.select_2").state == "option 3"
|
|
|
|
# Do no cycle
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_SELECT_NEXT,
|
|
{ATTR_ENTITY_ID: "select.select_2", ATTR_CYCLE: False},
|
|
blocking=True,
|
|
)
|
|
assert hass.states.get("select.select_2").state == "option 3"
|
|
|
|
# Do cycle (default behavior)
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_SELECT_NEXT,
|
|
{ATTR_ENTITY_ID: "select.select_2"},
|
|
blocking=True,
|
|
)
|
|
assert hass.states.get("select.select_2").state == "option 1"
|
|
|
|
# Do not cycle
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_SELECT_PREVIOUS,
|
|
{ATTR_ENTITY_ID: "select.select_2", ATTR_CYCLE: False},
|
|
blocking=True,
|
|
)
|
|
assert hass.states.get("select.select_2").state == "option 1"
|
|
|
|
# Do cycle (default behavior)
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_SELECT_PREVIOUS,
|
|
{ATTR_ENTITY_ID: "select.select_2"},
|
|
blocking=True,
|
|
)
|
|
assert hass.states.get("select.select_2").state == "option 3"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("service", "service_data"),
|
|
[
|
|
pytest.param(SERVICE_SELECT_FIRST, {}, id="first"),
|
|
pytest.param(SERVICE_SELECT_LAST, {}, id="last"),
|
|
pytest.param(SERVICE_SELECT_NEXT, {}, id="next_cycle"),
|
|
pytest.param(SERVICE_SELECT_NEXT, {ATTR_CYCLE: False}, id="next_no_cycle"),
|
|
pytest.param(SERVICE_SELECT_PREVIOUS, {}, id="previous_cycle"),
|
|
pytest.param(
|
|
SERVICE_SELECT_PREVIOUS, {ATTR_CYCLE: False}, id="previous_no_cycle"
|
|
),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"current_option",
|
|
[None, "option_one"],
|
|
ids=["without_current_option", "with_stale_current_option"],
|
|
)
|
|
async def test_navigation_services_without_options(
|
|
hass: HomeAssistant,
|
|
service: str,
|
|
service_data: dict[str, bool],
|
|
current_option: str | None,
|
|
) -> None:
|
|
"""Test the navigation actions on an entity which has no options."""
|
|
entity = MockSelectEntityWithoutOptions()
|
|
entity._attr_current_option = current_option
|
|
entity.select_option = MagicMock()
|
|
setup_test_component_platform(hass, DOMAIN, [entity])
|
|
|
|
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.states.get("select.select_without_options").state == STATE_UNKNOWN
|
|
|
|
with pytest.raises(ServiceValidationError) as exc:
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
service,
|
|
{ATTR_ENTITY_ID: "select.select_without_options"} | service_data,
|
|
blocking=True,
|
|
)
|
|
assert exc.value.translation_domain == DOMAIN
|
|
assert exc.value.translation_key == "no_options"
|
|
assert exc.value.translation_placeholders == {
|
|
"entity_id": "select.select_without_options"
|
|
}
|
|
assert (
|
|
str(exc.value)
|
|
== "Entity select.select_without_options has no options to select from"
|
|
)
|
|
|
|
entity.select_option.assert_not_called()
|
|
assert hass.states.get("select.select_without_options").state == STATE_UNKNOWN
|