Add test for config and repair flow

This commit is contained in:
Jules 2024-01-08 21:32:28 +01:00
parent 2cca89f5ba
commit e53f9aded4
Signed by: jdejaegh
GPG key ID: 99D6D184CA66933A
5 changed files with 255 additions and 4 deletions

View file

@ -88,6 +88,6 @@ async def async_create_fix_flow(
hass: HomeAssistant,
issue_id: str,
data: dict[str, str | int | float | None] | None,
) -> RepairsFlow:
) -> OutOfBeneluxRepairFlow:
"""Create flow."""
return OutOfBeneluxRepairFlow(data)

View file

@ -14,6 +14,11 @@
"use_deprecated_forecast_attribute": "Use the deprecated forecat attribute"
}
}
},
"error": {
"out_of_benelux": "{zone} is out of Benelux. Pick a zone in Benelux.",
"api_error": "Could not get data from the API",
"zone_not_exist": "{zone} does not exist"
}
},
"selector": {
@ -57,7 +62,7 @@
"fix_flow": {
"step": {
"confirm": {
"title": "Title for the confirm step",
"title": "Repair: {zone} is outside of Benelux",
"description": "This integration can only get data for location in the Benelux. Move the zone or delete this configuration entry."
}
},

View file

@ -85,6 +85,14 @@ def mock_get_forecast_api_error():
return
@pytest.fixture
def mock_get_forecast_api_error_repair():
"""Mock a call to IrmKmiApiClient.get_forecasts_coord() so that it raises an error"""
with patch("custom_components.irm_kmi.repairs.IrmKmiApiClient.get_forecasts_coord",
side_effet=IrmKmiApiError):
return
@pytest.fixture()
def mock_irm_kmi_api(request: pytest.FixtureRequest) -> Generator[None, MagicMock, None]:
"""Return a mocked IrmKmi api client."""
@ -100,7 +108,7 @@ def mock_irm_kmi_api(request: pytest.FixtureRequest) -> Generator[None, MagicMoc
@pytest.fixture()
def mock_irm_kmi_api_out_benelux(request: pytest.FixtureRequest) -> Generator[None, MagicMock, None]:
def mock_irm_kmi_api_coordinator_out_benelux(request: pytest.FixtureRequest) -> Generator[None, MagicMock, None]:
"""Return a mocked IrmKmi api client."""
fixture: str = "forecast_out_of_benelux.json"
@ -113,6 +121,34 @@ def mock_irm_kmi_api_out_benelux(request: pytest.FixtureRequest) -> Generator[No
yield irm_kmi
@pytest.fixture()
def mock_irm_kmi_api_repair_in_benelux(request: pytest.FixtureRequest) -> Generator[None, MagicMock, None]:
"""Return a mocked IrmKmi api client."""
fixture: str = "forecast.json"
forecast = json.loads(load_fixture(fixture))
with patch(
"custom_components.irm_kmi.repairs.IrmKmiApiClient", autospec=True
) as irm_kmi_api_mock:
irm_kmi = irm_kmi_api_mock.return_value
irm_kmi.get_forecasts_coord.return_value = forecast
yield irm_kmi
@pytest.fixture()
def mock_irm_kmi_api_repair_out_of_benelux(request: pytest.FixtureRequest) -> Generator[None, MagicMock, None]:
"""Return a mocked IrmKmi api client."""
fixture: str = "forecast_out_of_benelux.json"
forecast = json.loads(load_fixture(fixture))
with patch(
"custom_components.irm_kmi.repairs.IrmKmiApiClient", autospec=True
) as irm_kmi_api_mock:
irm_kmi = irm_kmi_api_mock.return_value
irm_kmi.get_forecasts_coord.return_value = forecast
yield irm_kmi
@pytest.fixture()
def mock_exception_irm_kmi_api(request: pytest.FixtureRequest) -> Generator[None, MagicMock, None]:
"""Return a mocked IrmKmi api client."""

View file

@ -13,7 +13,7 @@ from custom_components.irm_kmi import async_migrate_entry
from custom_components.irm_kmi.const import (
CONF_DARK_MODE, CONF_STYLE, CONF_USE_DEPRECATED_FORECAST,
CONFIG_FLOW_VERSION, DOMAIN, OPTION_DEPRECATED_FORECAST_NOT_USED,
OPTION_STYLE_STD)
OPTION_STYLE_SATELLITE, OPTION_STYLE_STD)
async def test_full_user_flow(
@ -86,6 +86,53 @@ async def test_config_flow_with_api_error(
assert 'base' in result2.get('errors')
async def test_config_flow_unknown_zone(hass: HomeAssistant) -> None:
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_ZONE: "zone.what",
CONF_STYLE: OPTION_STYLE_STD,
CONF_DARK_MODE: False},
)
assert result2.get("type") == FlowResultType.FORM
assert result2.get("step_id") == "user"
assert CONF_ZONE in result2.get('errors')
async def test_option_flow(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry
) -> None:
mock_config_entry.add_to_hass(hass)
assert not mock_config_entry.options
result = await hass.config_entries.options.async_init(mock_config_entry.entry_id, data=None)
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "init"
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={
CONF_STYLE: OPTION_STYLE_SATELLITE,
CONF_DARK_MODE: True,
CONF_USE_DEPRECATED_FORECAST: OPTION_DEPRECATED_FORECAST_NOT_USED
}
)
assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["data"] == {
CONF_STYLE: OPTION_STYLE_SATELLITE,
CONF_DARK_MODE: True,
CONF_USE_DEPRECATED_FORECAST: OPTION_DEPRECATED_FORECAST_NOT_USED
}
async def test_config_entry_migration(hass: HomeAssistant) -> None:
"""Ensure that config entry migration takes the configuration to the latest version"""
entry = MockConfigEntry(

163
tests/test_repairs.py Normal file
View file

@ -0,0 +1,163 @@
import logging
from unittest.mock import MagicMock
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers import issue_registry
from pytest_homeassistant_custom_component.common import MockConfigEntry
from custom_components.irm_kmi import DOMAIN, IrmKmiCoordinator
from custom_components.irm_kmi.const import (REPAIR_OPT_DELETE,
REPAIR_OPT_MOVE, REPAIR_SOLUTION)
from custom_components.irm_kmi.repairs import (OutOfBeneluxRepairFlow,
async_create_fix_flow)
_LOGGER = logging.getLogger(__name__)
async def get_repair_flow(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry
) -> OutOfBeneluxRepairFlow:
hass.states.async_set(
"zone.home",
0,
{"latitude": 50.738681639, "longitude": 4.054077148},
)
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
coordinator = IrmKmiCoordinator(hass, mock_config_entry)
await coordinator._async_update_data()
ir = issue_registry.async_get(hass)
issue = ir.async_get_issue(DOMAIN, "zone_moved")
repair_flow = await async_create_fix_flow(hass, issue.issue_id, issue.data)
repair_flow.hass = hass
return repair_flow
async def test_repair_triggers_when_out_of_benelux(
hass: HomeAssistant,
mock_irm_kmi_api_coordinator_out_benelux: MagicMock,
mock_config_entry: MockConfigEntry
) -> None:
hass.states.async_set(
"zone.home",
0,
{"latitude": 50.738681639, "longitude": 4.054077148},
)
mock_config_entry.add_to_hass(hass)
coordinator = IrmKmiCoordinator(hass, mock_config_entry)
await coordinator._async_update_data()
ir = issue_registry.async_get(hass)
issue = ir.async_get_issue(DOMAIN, "zone_moved")
assert issue is not None
assert issue.data == {'config_entry_id': mock_config_entry.entry_id, 'zone': "zone.home"}
assert issue.translation_key == "zone_moved"
assert issue.is_fixable
assert issue.translation_placeholders == {'zone': "zone.home"}
async def test_repair_flow(
hass: HomeAssistant,
mock_irm_kmi_api_coordinator_out_benelux: MagicMock,
mock_irm_kmi_api_repair_in_benelux: MagicMock,
mock_config_entry: MockConfigEntry
) -> None:
repair_flow = await get_repair_flow(hass, mock_config_entry)
result = await repair_flow.async_step_init()
assert result['type'] == FlowResultType.FORM
assert result['errors'] == {}
assert result['description_placeholders'] == {"zone": "zone.home"}
user_input = {REPAIR_SOLUTION: REPAIR_OPT_MOVE}
result = await repair_flow.async_step_confirm(user_input)
assert result['type'] == FlowResultType.CREATE_ENTRY
assert result['title'] == ""
assert result['data'] == {}
async def test_repair_flow_invalid_choice(
hass: HomeAssistant,
mock_irm_kmi_api_coordinator_out_benelux: MagicMock,
mock_irm_kmi_api_repair_in_benelux: MagicMock,
mock_config_entry: MockConfigEntry
) -> None:
repair_flow = await get_repair_flow(hass, mock_config_entry)
result = await repair_flow.async_step_init()
assert result['type'] == FlowResultType.FORM
user_input = {REPAIR_SOLUTION: "whut?"}
result = await repair_flow.async_step_confirm(user_input)
assert result['type'] == FlowResultType.FORM
assert REPAIR_SOLUTION in result['errors']
assert result['errors'][REPAIR_SOLUTION] == 'invalid_choice'
async def test_repair_flow_api_error(
hass: HomeAssistant,
mock_irm_kmi_api_coordinator_out_benelux: MagicMock,
mock_get_forecast_api_error_repair: MagicMock,
mock_config_entry: MockConfigEntry
) -> None:
repair_flow = await get_repair_flow(hass, mock_config_entry)
result = await repair_flow.async_step_init()
assert result['type'] == FlowResultType.FORM
user_input = {REPAIR_SOLUTION: REPAIR_OPT_MOVE}
result = await repair_flow.async_step_confirm(user_input)
assert result['type'] == FlowResultType.FORM
assert REPAIR_SOLUTION in result['errors']
assert result['errors'][REPAIR_SOLUTION] == 'api_error'
async def test_repair_flow_out_of_benelux(
hass: HomeAssistant,
mock_irm_kmi_api_coordinator_out_benelux: MagicMock,
mock_irm_kmi_api_repair_out_of_benelux: MagicMock,
mock_config_entry: MockConfigEntry
) -> None:
repair_flow = await get_repair_flow(hass, mock_config_entry)
result = await repair_flow.async_step_init()
assert result['type'] == FlowResultType.FORM
user_input = {REPAIR_SOLUTION: REPAIR_OPT_MOVE}
result = await repair_flow.async_step_confirm(user_input)
assert result['type'] == FlowResultType.FORM
assert REPAIR_SOLUTION in result['errors']
assert result['errors'][REPAIR_SOLUTION] == 'out_of_benelux'
async def test_repair_flow_delete_entry(
hass: HomeAssistant,
mock_irm_kmi_api_coordinator_out_benelux: MagicMock,
mock_config_entry: MockConfigEntry
) -> None:
repair_flow = await get_repair_flow(hass, mock_config_entry)
result = await repair_flow.async_step_init()
assert result['type'] == FlowResultType.FORM
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert hass.config_entries.async_entries(DOMAIN)[0].entry_id == mock_config_entry.entry_id
user_input = {REPAIR_SOLUTION: REPAIR_OPT_DELETE}
result = await repair_flow.async_step_confirm(user_input)
assert result['type'] == FlowResultType.CREATE_ENTRY
assert result['title'] == ""
assert result['data'] == {}
assert len(hass.config_entries.async_entries(DOMAIN)) == 0