From 55e0af04bc5552ba1217d3360dc671cc264101a5 Mon Sep 17 00:00:00 2001 From: Hmmbob Date: Mon, 12 Oct 2026 14:56:37 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=A7=AA=20Fix=20PoolLab=20translation?= =?UTF-8?q?=20validation=20and=20current=20HA=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/tests.yaml | 8 +- custom_components/poollab/config_flow.py | 4 + .../poollab/translations/en.json | 4 +- tests/test_config_flow.py | 76 ++++++++++++------- tests/test_coordinator.py | 50 +++--------- 5 files changed, 69 insertions(+), 73 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 05b8ea1..030a9ab 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -5,16 +5,22 @@ on: pull_request: paths: - '**.py' + - 'custom_components/**/*.json' + - 'requirements.test.txt' + - '.github/workflows/tests.yaml' push: paths: - '**.py' + - 'custom_components/**/*.json' + - 'requirements.test.txt' + - '.github/workflows/tests.yaml' jobs: tests: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.12'] + python-version: ['3.12', '3.14'] steps: - uses: actions/checkout@v4 diff --git a/custom_components/poollab/config_flow.py b/custom_components/poollab/config_flow.py index 4bf0921..ad6ca33 100644 --- a/custom_components/poollab/config_flow.py +++ b/custom_components/poollab/config_flow.py @@ -18,6 +18,8 @@ _LOGGER = logging.getLogger(__name__) +API_KEY_URL = "https://labcom.cloud/pages/user-setting" + class PoolLabConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """PoolLab config flow.""" @@ -84,6 +86,7 @@ async def async_step_user( step_id="user", data_schema=user_schema, errors=errors, + description_placeholders={"api_key_url": API_KEY_URL}, ) async def async_step_reconfigure( @@ -129,6 +132,7 @@ async def async_step_reconfigure( step_id="reconfigure", data_schema=user_schema, errors=errors, + description_placeholders={"api_key_url": API_KEY_URL}, ) async def async_step_import(self, import_data) -> FlowResult: diff --git a/custom_components/poollab/translations/en.json b/custom_components/poollab/translations/en.json index 0c8ffd1..67dfc1a 100644 --- a/custom_components/poollab/translations/en.json +++ b/custom_components/poollab/translations/en.json @@ -3,7 +3,7 @@ "step": { "user": { "title": "PoolLab", - "description": "Setup a PoolLab integration, get key from https://labcom.cloud/pages/user-setting", + "description": "Setup a PoolLab integration, get key from {api_key_url}", "data": { "api_key": "API key", "url": "API endpoint URL", @@ -12,7 +12,7 @@ }, "reconfigure": { "title": "PoolLab", - "description": "Reconfigure a PoolLab integration, get key from https://labcom.cloud/pages/user-setting", + "description": "Reconfigure a PoolLab integration, get key from {api_key_url}", "data": { "api_key": "API key", "url": "API endpoint URL", diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py index d3e250b..af4f902 100644 --- a/tests/test_config_flow.py +++ b/tests/test_config_flow.py @@ -1,33 +1,51 @@ -"""config_flow tests.""" +"""Tests for PoolLab configuration forms.""" -from unittest import mock +import json +from pathlib import Path -from custom_components.poollab import config_flow import pytest +from pytest_homeassistant_custom_component.common import MockConfigEntry + +from homeassistant.config_entries import SOURCE_RECONFIGURE, SOURCE_USER +from homeassistant.const import CONF_API_KEY, CONF_SSL, CONF_URL +from homeassistant.data_entry_flow import FlowResultType + +from custom_components.poollab import config_flow +from custom_components.poollab.const import DOMAIN +from custom_components.poollab.poollab import API_ENDPOINT + + +@pytest.mark.parametrize("source", [SOURCE_USER, SOURCE_RECONFIGURE]) +async def test_config_form_api_key_link(hass, source): + """Both forms must supply a working URL for their translated description.""" + context = {"source": source} + if source == SOURCE_RECONFIGURE: + entry = MockConfigEntry( + domain=DOMAIN, + title="PoolLab", + unique_id="test-api-key", + version=config_flow.PoolLabConfigFlow.VERSION, + minor_version=config_flow.PoolLabConfigFlow.MINOR_VERSION, + data={ + CONF_API_KEY: "test-api-key", + CONF_URL: API_ENDPOINT, + CONF_SSL: True, + }, + ) + entry.add_to_hass(hass) + context["entry_id"] = entry.entry_id + + result = await hass.config_entries.flow.async_init(DOMAIN, context=context) + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == source + assert result["errors"] == {} -# from pytest_homeassistant_custom_component.async_mock import patch -import voluptuous as vol - -from homeassistant import config_entries -from homeassistant.const import ATTR_NAME, ATTR_UNIT_OF_MEASUREMENT -from homeassistant.helpers import selector - - -# @pytest.mark.asyncio -# async def test_flow_init(hass): -# """Test the initial flow.""" -# result = await hass.config_entries.flow.async_init( -# config_flow.DOMAIN, context={"source": "user"} -# ) - -# expected = { -# "data_schema": SCHEMA_COPY, -# # "data_schema": config_flow.DATA_SCHEMA, -# "description_placeholders": None, -# "errors": {}, -# "flow_id": mock.ANY, -# "handler": "poollab", -# "step_id": "user", -# "type": "form", -# } -# assert expected == result + translations = json.loads( + (Path(config_flow.__file__).parent / "translations" / "en.json").read_text() + ) + description = translations["config"]["step"][source]["description"] + assert "https://" not in description + rendered_description = description.format(**result["description_placeholders"]) + assert "https://labcom.cloud/pages/user-setting" in rendered_description + hass.config_entries.flow.async_abort(result["flow_id"]) diff --git a/tests/test_coordinator.py b/tests/test_coordinator.py index 5dfd9b8..ea6ed03 100644 --- a/tests/test_coordinator.py +++ b/tests/test_coordinator.py @@ -1,48 +1,16 @@ -"""planner tests.""" +"""Tests for the PoolLab coordinator.""" -from unittest import mock +from datetime import timedelta -# from custom_components.poollab.poollab import PoolLabApi -# from pytest_homeassistant_custom_component.async_mock import patch -# from pytest_homeassistant_custom_component.common import ( -# MockModule, -# MockPlatform, -# mock_integration, -# mock_platform, -# ) -from custom_components.poollab import DOMAIN, PoolLabCoordinator +from custom_components.poollab import PoolLabCoordinator from custom_components.poollab.poollab import PoolLabApi -import pytest -from homeassistant import config_entries -from homeassistant.const import ATTR_NAME -# from homeassistant.components import sensor -# from homeassistant.core import HomeAssistant -from homeassistant.helpers.entity_platform import AddEntitiesCallback - -NAME = "My balancer" - -CONF_ENTRY = config_entries.ConfigEntry( - data={ - ATTR_NAME: NAME, - "api_key": 5, - }, - options={}, - domain=DOMAIN, - version=1, - minor_version=0, - source="user", - title=NAME, - unique_id="123456", - discovery_keys=None, -) - - -@pytest.mark.asyncio async def test_coordinator_init(hass): - """Test the coordinator initialization.""" - - coordinator = PoolLabCoordinator(hass, PoolLabApi("API_TOKEN")) + """Initialize the coordinator with its API and polling interval.""" + api = PoolLabApi("API_TOKEN") + coordinator = PoolLabCoordinator(hass, api) - # assert coordinator.name == NAME + assert coordinator.api is api + assert coordinator.name == "PoolLab API" + assert coordinator.update_interval == timedelta(seconds=30) From 5168c52020686fc029c4aa6879c41a0092ce459d Mon Sep 17 00:00:00 2001 From: Hmmbob Date: Mon, 12 Oct 2026 16:38:40 +0200 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=A7=AA=20Keep=20initialization=20test?= =?UTF-8?q?s=20independent=20of=20polling=20policy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_coordinator.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_coordinator.py b/tests/test_coordinator.py index ea6ed03..ab0f231 100644 --- a/tests/test_coordinator.py +++ b/tests/test_coordinator.py @@ -1,16 +1,13 @@ """Tests for the PoolLab coordinator.""" -from datetime import timedelta - from custom_components.poollab import PoolLabCoordinator from custom_components.poollab.poollab import PoolLabApi async def test_coordinator_init(hass): - """Initialize the coordinator with its API and polling interval.""" + """Initialize the coordinator with its API and name.""" api = PoolLabApi("API_TOKEN") coordinator = PoolLabCoordinator(hass, api) assert coordinator.api is api assert coordinator.name == "PoolLab API" - assert coordinator.update_interval == timedelta(seconds=30)