mirror of
https://github.com/home-assistant/core.git
synced 2026-07-07 14:56:25 +01:00
9decee350f
Co-authored-by: Ariel Ebersberger <31776703+justanotherariel@users.noreply.github.com>
383 lines
13 KiB
Python
383 lines
13 KiB
Python
"""Test the National Weather Service (NWS) config flow."""
|
|
|
|
from unittest.mock import AsyncMock
|
|
|
|
import aiohttp
|
|
import pytest
|
|
|
|
from homeassistant import config_entries
|
|
from homeassistant.components.nws.const import (
|
|
CONF_LOCATION_ENTITY,
|
|
CONF_STATION,
|
|
DOMAIN,
|
|
)
|
|
from homeassistant.config_entries import ConfigFlowResult
|
|
from homeassistant.const import ATTR_LATITUDE, ATTR_LONGITUDE, CONF_API_KEY
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.data_entry_flow import FlowResultType
|
|
from homeassistant.helpers import entity_registry as er
|
|
|
|
|
|
async def _select_menu_option(
|
|
hass: HomeAssistant, flow_id: str, option: str
|
|
) -> ConfigFlowResult:
|
|
"""Select a menu option and return the resulting form."""
|
|
return await hass.config_entries.flow.async_configure(
|
|
flow_id, {"next_step_id": option}
|
|
)
|
|
|
|
|
|
async def test_menu_shown(hass: HomeAssistant, mock_simple_nws_config) -> None:
|
|
"""Test that the initial step shows a menu."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.MENU
|
|
assert result["menu_options"] == ["location", "entity"]
|
|
|
|
|
|
async def test_form_location(
|
|
hass: HomeAssistant, mock_simple_nws_config, mock_setup_entry: AsyncMock
|
|
) -> None:
|
|
"""Test the specific location configuration path."""
|
|
hass.config.latitude = 35
|
|
hass.config.longitude = -90
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
result2 = await _select_menu_option(hass, result["flow_id"], "location")
|
|
assert result2["type"] is FlowResultType.FORM
|
|
assert result2["step_id"] == "location"
|
|
assert result2["errors"] == {}
|
|
|
|
result3 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"], {CONF_API_KEY: "test"}
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result3["type"] is FlowResultType.CREATE_ENTRY
|
|
assert result3["title"] == "ABC"
|
|
assert result3["data"] == {
|
|
CONF_API_KEY: "test",
|
|
"latitude": 35,
|
|
"longitude": -90,
|
|
CONF_STATION: "ABC",
|
|
}
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
|
|
async def test_form_location_cannot_connect(
|
|
hass: HomeAssistant, mock_simple_nws_config
|
|
) -> None:
|
|
"""Test we handle cannot connect error in location path."""
|
|
mock_instance = mock_simple_nws_config.return_value
|
|
mock_instance.set_station.side_effect = aiohttp.ClientError
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "location")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test"},
|
|
)
|
|
|
|
assert result2["type"] is FlowResultType.FORM
|
|
assert result2["errors"] == {"base": "cannot_connect"}
|
|
|
|
|
|
async def test_form_location_unknown_error(
|
|
hass: HomeAssistant, mock_simple_nws_config
|
|
) -> None:
|
|
"""Test we handle unknown error in location path."""
|
|
mock_instance = mock_simple_nws_config.return_value
|
|
mock_instance.set_station.side_effect = ValueError
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "location")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test"},
|
|
)
|
|
|
|
assert result2["type"] is FlowResultType.FORM
|
|
assert result2["errors"] == {"base": "unknown"}
|
|
|
|
|
|
async def test_form_location_already_configured(
|
|
hass: HomeAssistant, mock_simple_nws_config, mock_setup_entry: AsyncMock
|
|
) -> None:
|
|
"""Test we handle duplicate location entries."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "location")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test"},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
mock_setup_entry.reset_mock()
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "location")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test"},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result2["type"] is FlowResultType.ABORT
|
|
assert result2["reason"] == "already_configured"
|
|
assert len(mock_setup_entry.mock_calls) == 0
|
|
|
|
|
|
async def test_form_entity(
|
|
hass: HomeAssistant,
|
|
mock_simple_nws_config,
|
|
entity_registry: er.EntityRegistry,
|
|
mock_setup_entry: AsyncMock,
|
|
) -> None:
|
|
"""Test the entity-based configuration path."""
|
|
entry = entity_registry.async_get_or_create("person", "person", "test_user")
|
|
entity_registry.async_get_or_create("person", "person", "other_user")
|
|
hass.states.async_set(
|
|
entry.entity_id,
|
|
"home",
|
|
{ATTR_LATITUDE: 40.0, ATTR_LONGITUDE: -80.0},
|
|
)
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "entity")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test", CONF_LOCATION_ENTITY: entry.entity_id},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
|
assert result2["title"] == "person.person_test_user"
|
|
assert result2["data"] == {
|
|
CONF_API_KEY: "test",
|
|
CONF_LOCATION_ENTITY: entry.id,
|
|
}
|
|
assert result2["result"].unique_id is None
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
|
|
async def test_form_entity_no_coordinates(
|
|
hass: HomeAssistant,
|
|
mock_simple_nws_config,
|
|
entity_registry: er.EntityRegistry,
|
|
) -> None:
|
|
"""Test entity path with entity that has no coordinates."""
|
|
entry = entity_registry.async_get_or_create("person", "person", "no_gps")
|
|
entity_registry.async_get_or_create("person", "person", "also_no_gps")
|
|
hass.states.async_set(entry.entity_id, "unknown", {})
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "entity")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test", CONF_LOCATION_ENTITY: entry.entity_id},
|
|
)
|
|
|
|
assert result2["type"] is FlowResultType.FORM
|
|
assert result2["errors"] == {"base": "entity_no_coordinates"}
|
|
|
|
|
|
async def test_form_entity_non_numeric_coordinates(
|
|
hass: HomeAssistant,
|
|
mock_simple_nws_config,
|
|
entity_registry: er.EntityRegistry,
|
|
) -> None:
|
|
"""Test entity path with entity that has non-numeric coordinates."""
|
|
entry = entity_registry.async_get_or_create("person", "person", "bad_gps")
|
|
entity_registry.async_get_or_create("person", "person", "other_user")
|
|
hass.states.async_set(
|
|
entry.entity_id,
|
|
"home",
|
|
{ATTR_LATITUDE: "not_a_number", ATTR_LONGITUDE: "also_not"},
|
|
)
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "entity")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test", CONF_LOCATION_ENTITY: entry.entity_id},
|
|
)
|
|
|
|
assert result2["type"] is FlowResultType.FORM
|
|
assert result2["errors"] == {"base": "entity_no_coordinates"}
|
|
|
|
|
|
async def test_form_entity_not_found(
|
|
hass: HomeAssistant, mock_simple_nws_config
|
|
) -> None:
|
|
"""Test entity path with entity not in registry."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "entity")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test", CONF_LOCATION_ENTITY: "person.nonexistent"},
|
|
)
|
|
|
|
assert result2["type"] is FlowResultType.FORM
|
|
assert result2["errors"] == {"base": "entity_not_found"}
|
|
|
|
|
|
async def test_form_entity_disabled(
|
|
hass: HomeAssistant,
|
|
mock_simple_nws_config,
|
|
entity_registry: er.EntityRegistry,
|
|
) -> None:
|
|
"""Test entity path with disabled entity."""
|
|
entry = entity_registry.async_get_or_create("person", "person", "disabled_user")
|
|
entity_registry.async_get_or_create("person", "person", "other_user")
|
|
entity_registry.async_update_entity(
|
|
entry.entity_id, disabled_by=er.RegistryEntryDisabler.USER
|
|
)
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "entity")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test", CONF_LOCATION_ENTITY: entry.entity_id},
|
|
)
|
|
|
|
assert result2["type"] is FlowResultType.FORM
|
|
assert result2["errors"] == {"base": "entity_disabled"}
|
|
|
|
|
|
async def test_form_entity_unknown_error(
|
|
hass: HomeAssistant,
|
|
mock_simple_nws_config,
|
|
entity_registry: er.EntityRegistry,
|
|
) -> None:
|
|
"""Test we handle unknown error in entity path."""
|
|
mock_instance = mock_simple_nws_config.return_value
|
|
mock_instance.set_station.side_effect = ValueError
|
|
|
|
entry = entity_registry.async_get_or_create("person", "person", "test_user")
|
|
entity_registry.async_get_or_create("person", "person", "other_user")
|
|
hass.states.async_set(
|
|
entry.entity_id,
|
|
"home",
|
|
{ATTR_LATITUDE: 40.0, ATTR_LONGITUDE: -80.0},
|
|
)
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "entity")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test", CONF_LOCATION_ENTITY: entry.entity_id},
|
|
)
|
|
|
|
assert result2["type"] is FlowResultType.FORM
|
|
assert result2["errors"] == {"base": "unknown"}
|
|
|
|
|
|
async def test_form_entity_cannot_connect(
|
|
hass: HomeAssistant,
|
|
mock_simple_nws_config,
|
|
entity_registry: er.EntityRegistry,
|
|
) -> None:
|
|
"""Test we handle cannot connect error in entity path."""
|
|
mock_instance = mock_simple_nws_config.return_value
|
|
mock_instance.set_station.side_effect = aiohttp.ClientError
|
|
|
|
entry = entity_registry.async_get_or_create("person", "person", "test_user")
|
|
entity_registry.async_get_or_create("person", "person", "other_user")
|
|
hass.states.async_set(
|
|
entry.entity_id,
|
|
"home",
|
|
{ATTR_LATITUDE: 40.0, ATTR_LONGITUDE: -80.0},
|
|
)
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "entity")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test", CONF_LOCATION_ENTITY: entry.entity_id},
|
|
)
|
|
|
|
assert result2["type"] is FlowResultType.FORM
|
|
assert result2["errors"] == {"base": "cannot_connect"}
|
|
|
|
|
|
@pytest.mark.usefixtures("mock_setup_entry")
|
|
async def test_form_entity_already_configured(
|
|
hass: HomeAssistant,
|
|
mock_simple_nws_config,
|
|
entity_registry: er.EntityRegistry,
|
|
) -> None:
|
|
"""Test we handle duplicate entity-based entries."""
|
|
entry = entity_registry.async_get_or_create("person", "person", "test_user")
|
|
entity_registry.async_get_or_create("person", "person", "other_user")
|
|
hass.states.async_set(
|
|
entry.entity_id,
|
|
"home",
|
|
{ATTR_LATITUDE: 40.0, ATTR_LONGITUDE: -80.0},
|
|
)
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "entity")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test", CONF_LOCATION_ENTITY: entry.entity_id},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
await _select_menu_option(hass, result["flow_id"], "entity")
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_API_KEY: "test", CONF_LOCATION_ENTITY: entry.entity_id},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result2["type"] is FlowResultType.ABORT
|
|
assert result2["reason"] == "already_configured"
|