core/tests/components/openweathermap/test_config_flow.py

306 lines
8.8 KiB
Python

"""Define tests for the OpenWeatherMap config flow."""
from datetime import UTC, datetime
from unittest.mock import AsyncMock, MagicMock, patch
from pyopenweathermap import (
CurrentWeather,
DailyTemperature,
DailyWeatherForecast,
MinutelyWeatherForecast,
RequestError,
WeatherCondition,
WeatherReport,
)
import pytest
from homeassistant.components.openweathermap.const import (
DEFAULT_LANGUAGE,
DEFAULT_OWM_MODE,
DOMAIN,
OWM_MODE_V25,
)
from homeassistant.config_entries import SOURCE_USER, ConfigEntryState
from homeassistant.const import (
CONF_API_KEY,
CONF_LANGUAGE,
CONF_LATITUDE,
CONF_LONGITUDE,
CONF_MODE,
CONF_NAME,
)
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
CONFIG = {
CONF_NAME: "openweathermap",
CONF_API_KEY: "foo",
CONF_LATITUDE: 50,
CONF_LONGITUDE: 40,
CONF_LANGUAGE: DEFAULT_LANGUAGE,
CONF_MODE: OWM_MODE_V25,
}
VALID_YAML_CONFIG = {CONF_API_KEY: "foo"}
def _create_mocked_owm_factory(is_valid: bool):
current_weather = CurrentWeather(
date_time=datetime.fromtimestamp(1714063536, tz=UTC),
temperature=6.84,
feels_like=2.07,
pressure=1000,
humidity=82,
dew_point=3.99,
uv_index=0.13,
cloud_coverage=75,
visibility=10000,
wind_speed=9.83,
wind_bearing=199,
wind_gust=None,
rain={},
snow={},
condition=WeatherCondition(
id=803,
main="Clouds",
description="broken clouds",
icon="04d",
),
)
daily_weather_forecast = DailyWeatherForecast(
date_time=datetime.fromtimestamp(1714063536, tz=UTC),
summary="There will be clear sky until morning, then partly cloudy",
temperature=DailyTemperature(
day=18.76,
min=8.11,
max=21.26,
night=13.06,
evening=20.51,
morning=8.47,
),
feels_like=DailyTemperature(
day=18.76,
min=8.11,
max=21.26,
night=13.06,
evening=20.51,
morning=8.47,
),
pressure=1015,
humidity=62,
dew_point=11.34,
wind_speed=8.14,
wind_bearing=168,
wind_gust=11.81,
condition=WeatherCondition(
id=803,
main="Clouds",
description="broken clouds",
icon="04d",
),
cloud_coverage=84,
precipitation_probability=0,
uv_index=4.06,
rain=0,
snow=0,
)
minutely_weather_forecast = MinutelyWeatherForecast(
date_time=1728672360, precipitation=2.54
)
weather_report = WeatherReport(
current_weather, [minutely_weather_forecast], [], [daily_weather_forecast]
)
mocked_owm_client = MagicMock()
mocked_owm_client.validate_key = AsyncMock(return_value=is_valid)
mocked_owm_client.get_weather = AsyncMock(return_value=weather_report)
return mocked_owm_client
@pytest.fixture(name="owm_client_mock")
def mock_owm_client():
"""Mock config_flow OWMClient."""
with patch(
"homeassistant.components.openweathermap.create_owm_client",
) as mock:
yield mock
@pytest.fixture(name="config_flow_owm_client_mock")
def mock_config_flow_owm_client():
"""Mock config_flow OWMClient."""
with patch(
"homeassistant.components.openweathermap.utils.create_owm_client",
) as mock:
yield mock
async def test_successful_config_flow(
hass: HomeAssistant,
owm_client_mock,
config_flow_owm_client_mock,
) -> None:
"""Test that the form is served with valid input."""
mock = _create_mocked_owm_factory(True)
owm_client_mock.return_value = mock
config_flow_owm_client_mock.return_value = mock
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {}
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
await hass.async_block_till_done()
conf_entries = hass.config_entries.async_entries(DOMAIN)
entry = conf_entries[0]
assert entry.state is ConfigEntryState.LOADED
await hass.config_entries.async_unload(conf_entries[0].entry_id)
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.NOT_LOADED
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == CONFIG[CONF_NAME]
assert result["data"][CONF_LATITUDE] == CONFIG[CONF_LATITUDE]
assert result["data"][CONF_LONGITUDE] == CONFIG[CONF_LONGITUDE]
assert result["data"][CONF_API_KEY] == CONFIG[CONF_API_KEY]
async def test_abort_config_flow(
hass: HomeAssistant,
owm_client_mock,
config_flow_owm_client_mock,
) -> None:
"""Test that the form is served with same data."""
mock = _create_mocked_owm_factory(True)
owm_client_mock.return_value = mock
config_flow_owm_client_mock.return_value = mock
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.ABORT
async def test_config_flow_options_change(
hass: HomeAssistant,
owm_client_mock,
config_flow_owm_client_mock,
) -> None:
"""Test that the options form."""
mock = _create_mocked_owm_factory(True)
owm_client_mock.return_value = mock
config_flow_owm_client_mock.return_value = mock
config_entry = MockConfigEntry(
domain=DOMAIN, unique_id="openweathermap_unique_id", data=CONFIG
)
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
result = await hass.config_entries.options.async_init(config_entry.entry_id)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "init"
new_language = "es"
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={CONF_MODE: DEFAULT_OWM_MODE, CONF_LANGUAGE: new_language},
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert config_entry.options == {
CONF_LANGUAGE: new_language,
CONF_MODE: DEFAULT_OWM_MODE,
}
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
result = await hass.config_entries.options.async_init(config_entry.entry_id)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "init"
updated_language = "es"
result = await hass.config_entries.options.async_configure(
result["flow_id"], user_input={CONF_LANGUAGE: updated_language}
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert config_entry.options == {
CONF_LANGUAGE: updated_language,
CONF_MODE: DEFAULT_OWM_MODE,
}
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
async def test_form_invalid_api_key(
hass: HomeAssistant,
config_flow_owm_client_mock,
) -> None:
"""Test that the form is served with no input."""
config_flow_owm_client_mock.return_value = _create_mocked_owm_factory(False)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {"base": "invalid_api_key"}
config_flow_owm_client_mock.return_value = _create_mocked_owm_factory(True)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=CONFIG
)
assert result["type"] is FlowResultType.CREATE_ENTRY
async def test_form_api_call_error(
hass: HomeAssistant,
config_flow_owm_client_mock,
) -> None:
"""Test setting up with api call error."""
config_flow_owm_client_mock.return_value = _create_mocked_owm_factory(True)
config_flow_owm_client_mock.side_effect = RequestError("oops")
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {"base": "cannot_connect"}
config_flow_owm_client_mock.side_effect = None
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=CONFIG
)
assert result["type"] is FlowResultType.CREATE_ENTRY