diff --git a/tests/conftest.py b/tests/conftest.py index 0d9db39..715c025 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,8 +3,6 @@ from unittest.mock import AsyncMock, patch from pathlib import Path -# from asynctest import CoroutineMock, MagicMock, patch -# import aiohttp import json import pytest from typing import Generator @@ -20,8 +18,18 @@ def __getitem__(self, name): def __getattr__(self, name): name, ext = name.rsplit("_", 1) + parse = False - return FIXTURES_DIR.joinpath(f"{name}.{ext}").read_text() + if ext == "obj": + parse = True + ext = "json" + + data = FIXTURES_DIR.joinpath(f"{name}.{ext}").read_text() + + if parse: + data = json.loads(data) + + return data @pytest.fixture @@ -68,3 +76,25 @@ def mock_aiohttp_session() -> Generator[dict[str, AsyncMock], None, None]: ) yield session + + +@pytest.fixture +def mock_watersmart_client() -> Generator[AsyncMock, None, None]: + """Mock a WaterSmart client.""" + + hourly_data = FixtureLoader().realtime_api_response_obj["data"]["series"] + + with ( + patch( + "custom_components.watersmart.client.WaterSmartClient", autospec=True + ) as mock_client, + patch( + "custom_components.watersmart.config_flow.WaterSmartClient", + new=mock_client, + ), + ): + client = mock_client.return_value + client.async_get_account_number.return_value = "1234567-8900" + client.async_get_account_number.async_get_hourly_data = hourly_data + + yield client diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py new file mode 100644 index 0000000..af1a8de --- /dev/null +++ b/tests/test_config_flow.py @@ -0,0 +1,154 @@ +"""Test the Simple Integration config flow.""" + +from unittest.mock import patch + +from homeassistant import config_entries, setup +from homeassistant.core import HomeAssistant +from custom_components.watersmart.const import DOMAIN +from custom_components.watersmart.client import AuthenticationError + + +async def test_successful_flow(hass: HomeAssistant, mock_watersmart_client): + """Test we get the form.""" + + await setup.async_setup_component(hass, "persistent_notification", {}) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + assert result["type"] == "form" + assert result["errors"] == {} + + with patch( + "custom_components.watersmart.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + configured_result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + "host": "test", + "username": "test@home-assistant.io", + "password": "Passw0rd", + }, + ) + + assert configured_result["type"] == "create_entry" + assert configured_result["title"] == "test (test@home-assistant.io)" + assert configured_result["data"] == { + "host": "test", + "username": "test@home-assistant.io", + "password": "Passw0rd", + } + await hass.async_block_till_done() + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_client_timeout(hass: HomeAssistant, mock_watersmart_client): + """Test we get the form.""" + + mock_watersmart_client.async_get_account_number.side_effect = TimeoutError( + "timeout" + ) + + await setup.async_setup_component(hass, "persistent_notification", {}) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + assert result["type"] == "form" + assert result["errors"] == {} + + with patch( + "custom_components.watersmart.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + configured_result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + "host": "test", + "username": "test@home-assistant.io", + "password": "Passw0rd", + }, + ) + + assert "title" not in configured_result + assert "data" not in configured_result + + assert configured_result["type"] == "form" + assert configured_result["errors"] == { + "base": "cannot_connect", + } + await hass.async_block_till_done() + assert len(mock_setup_entry.mock_calls) == 0 + + +async def test_auth_error(hass: HomeAssistant, mock_watersmart_client): + """Test we get the form.""" + + mock_watersmart_client.async_get_account_number.side_effect = AuthenticationError( + "invalid credentials" + ) + + await setup.async_setup_component(hass, "persistent_notification", {}) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + assert result["type"] == "form" + assert result["errors"] == {} + + with patch( + "custom_components.watersmart.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + configured_result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + "host": "test", + "username": "test@home-assistant.io", + "password": "Passw0rd", + }, + ) + + assert "title" not in configured_result + assert "data" not in configured_result + + assert configured_result["type"] == "form" + assert configured_result["errors"] == { + "base": "invalid_auth", + } + await hass.async_block_till_done() + assert len(mock_setup_entry.mock_calls) == 0 + + +async def test_no_account_number(hass: HomeAssistant, mock_watersmart_client): + """Test we get the form.""" + + mock_watersmart_client.async_get_account_number.return_value = None + + await setup.async_setup_component(hass, "persistent_notification", {}) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + assert result["type"] == "form" + assert result["errors"] == {} + + with patch( + "custom_components.watersmart.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + configured_result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + "host": "test", + "username": "test@home-assistant.io", + "password": "Passw0rd", + }, + ) + + assert "title" not in configured_result + assert "data" not in configured_result + + assert configured_result["type"] == "form" + assert configured_result["errors"] == { + "base": "invalid_auth", + } + await hass.async_block_till_done() + assert len(mock_setup_entry.mock_calls) == 0