Add account selector to Anglian Water config flow (#158242)

This commit is contained in:
Jordan Harvey
2025-12-23 22:04:54 +01:00
committed by GitHub
parent 34db548725
commit b07b699e79
7 changed files with 307 additions and 39 deletions
+15 -5
View File
@@ -1,17 +1,19 @@
"""Common fixtures for the Anglian Water tests."""
from collections.abc import Generator
from collections.abc import AsyncGenerator, Generator
from unittest.mock import AsyncMock, MagicMock, patch
from pyanglianwater.api import API
from pyanglianwater.meter import SmartMeter
import pytest
from homeassistant.components.anglian_water.const import CONF_ACCOUNT_NUMBER, DOMAIN
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from .const import ACCESS_TOKEN, ACCOUNT_NUMBER, PASSWORD, USERNAME
from tests.common import MockConfigEntry
from tests.common import MockConfigEntry, async_load_json_object_fixture
@pytest.fixture
@@ -67,9 +69,11 @@ def mock_anglian_water_authenticator() -> Generator[MagicMock]:
@pytest.fixture
def mock_anglian_water_client(
mock_smart_meter: SmartMeter, mock_anglian_water_authenticator: MagicMock
) -> Generator[AsyncMock]:
async def mock_anglian_water_client(
hass: HomeAssistant,
mock_smart_meter: SmartMeter,
mock_anglian_water_authenticator: MagicMock,
) -> AsyncGenerator[AsyncMock]:
"""Mock a Anglian Water client."""
# Create a mock instance with our meters and config first.
with (
@@ -86,6 +90,12 @@ def mock_anglian_water_client(
mock_client.account_config = {"meter_type": "SmartMeter"}
mock_client.updated_data_callbacks = []
mock_client.validate_smart_meter.return_value = None
mock_client.api = AsyncMock(spec=API)
mock_client.api.get_associated_accounts.return_value = (
await async_load_json_object_fixture(
hass, "multi_associated_accounts.json", DOMAIN
)
)
yield mock_client
+1 -1
View File
@@ -1,6 +1,6 @@
"""Constants for the Anglian Water test suite."""
ACCOUNT_NUMBER = "12345678"
ACCOUNT_NUMBER = "171266493"
ACCESS_TOKEN = "valid_token"
USERNAME = "hello@example.com"
PASSWORD = "SecurePassword123"
@@ -0,0 +1,65 @@
{
"result": {
"property_count": 4,
"active": [
{
"business_partner_number": 906922831,
"account_number": 171266493,
"address": {
"company_name": "",
"building_name": "",
"sub_building_name": "",
"house_number": "10",
"street": "DOWNING STREET",
"locality": "",
"city": "LONDON",
"postcode": "SW1A 1AA"
}
},
{
"business_partner_number": 906922832,
"account_number": 171266494,
"address": {
"company_name": "",
"building_name": "Historic Building A",
"sub_building_name": "",
"house_number": "10",
"street": "DOWNING STREET",
"locality": "",
"city": "LONDON",
"postcode": "SW1A 1AA"
}
},
{
"business_partner_number": 906922832,
"account_number": 171266494,
"address": {
"company_name": "UK Government",
"building_name": "",
"sub_building_name": "",
"house_number": "10",
"street": "DOWNING STREET",
"locality": "",
"city": "LONDON",
"postcode": "SW1A 1AA"
}
}
],
"inactive": [
{
"business_partner_number": 100000000,
"account_number": 171200000,
"address": {
"company_name": "",
"building_name": "Finance Office",
"sub_building_name": "Heritage Wing",
"house_number": "50",
"street": "DOWNING STREET",
"locality": "",
"city": "LONDON",
"postcode": "SW1A 1AA"
}
}
]
}
}
@@ -0,0 +1,37 @@
{
"result": {
"property_count": 1,
"active": [
{
"business_partner_number": 906922831,
"account_number": 171266493,
"address": {
"company_name": "",
"building_name": "",
"sub_building_name": "",
"house_number": "10",
"street": "DOWNING STREET",
"locality": "",
"city": "LONDON",
"postcode": "SW1A 1AA"
}
}
],
"inactive": [
{
"business_partner_number": 100000000,
"account_number": 171200000,
"address": {
"company_name": "",
"building_name": "Finance Office",
"sub_building_name": "Heritage Wing",
"house_number": "50",
"street": "DOWNING STREET",
"locality": "",
"city": "LONDON",
"postcode": "SW1A 1AA"
}
}
]
}
}
@@ -18,16 +18,16 @@ from homeassistant.data_entry_flow import FlowResultType
from .const import ACCESS_TOKEN, ACCOUNT_NUMBER, PASSWORD, USERNAME
from tests.common import MockConfigEntry
from tests.common import MockConfigEntry, async_load_json_object_fixture
async def test_full_flow(
async def test_multiple_account_flow(
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
mock_anglian_water_authenticator: AsyncMock,
mock_anglian_water_client: AsyncMock,
) -> None:
"""Test a full and successful config flow."""
"""Test the config flow when there are multiple accounts."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@@ -40,6 +40,15 @@ async def test_full_flow(
user_input={
CONF_USERNAME: USERNAME,
CONF_PASSWORD: PASSWORD,
},
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "select_account"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_ACCOUNT_NUMBER: ACCOUNT_NUMBER,
},
)
@@ -53,6 +62,43 @@ async def test_full_flow(
assert result["result"].unique_id == ACCOUNT_NUMBER
async def test_single_account_flow(
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
mock_anglian_water_authenticator: AsyncMock,
mock_anglian_water_client: AsyncMock,
) -> None:
"""Test the config flow when there is just a single account."""
mock_anglian_water_client.api.get_associated_accounts.return_value = (
await async_load_json_object_fixture(
hass, "single_associated_accounts.json", DOMAIN
)
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result is not None
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_USERNAME: USERNAME,
CONF_PASSWORD: PASSWORD,
},
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == ACCOUNT_NUMBER
assert result["data"][CONF_USERNAME] == USERNAME
assert result["data"][CONF_PASSWORD] == PASSWORD
assert result["data"][CONF_ACCESS_TOKEN] == ACCESS_TOKEN
assert result["data"][CONF_ACCOUNT_NUMBER] == ACCOUNT_NUMBER
assert result["result"].unique_id == ACCOUNT_NUMBER
async def test_already_configured(
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
@@ -75,6 +121,15 @@ async def test_already_configured(
user_input={
CONF_USERNAME: USERNAME,
CONF_PASSWORD: PASSWORD,
},
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "select_account"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_ACCOUNT_NUMBER: ACCOUNT_NUMBER,
},
)
@@ -109,7 +164,6 @@ async def test_auth_recover_exception(
user_input={
CONF_USERNAME: USERNAME,
CONF_PASSWORD: PASSWORD,
CONF_ACCOUNT_NUMBER: ACCOUNT_NUMBER,
},
)
@@ -126,6 +180,15 @@ async def test_auth_recover_exception(
user_input={
CONF_USERNAME: USERNAME,
CONF_PASSWORD: PASSWORD,
},
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "select_account"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_ACCOUNT_NUMBER: ACCOUNT_NUMBER,
},
)
@@ -161,19 +224,28 @@ async def test_account_recover_exception(
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
mock_anglian_water_client.validate_smart_meter.side_effect = exception_type
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_USERNAME: USERNAME,
CONF_PASSWORD: PASSWORD,
},
)
mock_anglian_water_client.validate_smart_meter.side_effect = exception_type
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "select_account"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_ACCOUNT_NUMBER: ACCOUNT_NUMBER,
},
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
assert result["step_id"] == "select_account"
assert result["errors"] == {"base": expected_error}
# Now test we can recover
@@ -183,8 +255,6 @@ async def test_account_recover_exception(
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_USERNAME: USERNAME,
CONF_PASSWORD: PASSWORD,
CONF_ACCOUNT_NUMBER: ACCOUNT_NUMBER,
},
)