Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ jobs:
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flake8 pytest homeassistant luxtronik==0.3.14 requests>=2.28.2 getmac==0.8.2
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f tests/requirements-dev.txt ]; then pip install -r tests/requirements-dev.txt; fi

- name: Set PYTHONPATH
run: echo "PYTHONPATH=$PYTHONPATH:$(pwd)" >> $GITHUB_ENV
- name: Lint with flake8
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Luxtronik Integration Tests

on:
workflow_dispatch:

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r tests/requirements-dev.txt

- name: Run tests with coverage
run: |
pytest --cov=custom_components.luxtronik --cov-report=xml --cov-report=term tests/

- name: Upload coverage report
uses: actions/upload-artifact@v3
with:
name: coverage-report
path: coverage.xml

4 changes: 4 additions & 0 deletions tests/requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pytest
pytest-asyncio
pytest-cov
pytest-homeassistant-custom-component
94 changes: 94 additions & 0 deletions tests/test_config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import pytest
pytestmark = pytest.mark.enable_custom_integrations

Check warning on line 2 in tests/test_config_flow.py

View workflow job for this annotation

GitHub Actions / build (3.13)

Unknown pytest.mark.enable_custom_integrations - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html

from unittest.mock import AsyncMock, MagicMock

from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.service_info.dhcp import DhcpServiceInfo
from homeassistant.const import CONF_HOST, CONF_PORT

from custom_components.luxtronik.config_flow import LuxtronikFlowHandler, LuxtronikOptionsFlowHandler
from custom_components.luxtronik.const import DOMAIN, DEFAULT_PORT


@pytest.fixture
def mock_hass():
hass = MagicMock(spec=HomeAssistant)
hass.async_add_executor_job = AsyncMock()
hass.config_entries.async_entries = MagicMock(return_value=[])
hass.config_entries.async_update_entry = AsyncMock()
hass.config_entries.async_reload = AsyncMock()
return hass

@pytest.fixture
def flow_handler(mock_hass):
handler = LuxtronikFlowHandler()
handler.hass = mock_hass
return handler

@pytest.mark.asyncio
async def test_async_step_user_with_available_devices(flow_handler):
flow_handler._async_current_entries = MagicMock(return_value=[])
flow_handler._discover_devices = AsyncMock(return_value=[("192.168.1.100", 8888)])

result = await flow_handler.async_step_user()

assert result["type"] == "form"
assert result["step_id"] == "select_devices"

Check failure on line 38 in tests/test_config_flow.py

View workflow job for this annotation

GitHub Actions / build (3.13)

test_async_step_user_with_available_devices AssertionError: assert 'user' == 'select_devices' - select_devices + user

@pytest.mark.asyncio
async def test_async_step_user_with_no_available_devices(flow_handler):
flow_handler._async_current_entries = MagicMock(return_value=[
MagicMock(data={CONF_HOST: "192.168.1.100", CONF_PORT: 8888})
])
flow_handler._discover_devices = AsyncMock(return_value=[("192.168.1.100", 8888)])

result = await flow_handler.async_step_user()

assert result["type"] == "form"
assert result["step_id"] == "manual_entry"

Check failure on line 50 in tests/test_config_flow.py

View workflow job for this annotation

GitHub Actions / build (3.13)

test_async_step_user_with_no_available_devices AssertionError: assert 'user' == 'manual_entry' - manual_entry + user

@pytest.mark.asyncio
async def test_async_step_select_devices_success(flow_handler):
flow_handler._connect_and_get_coordinator = AsyncMock(return_value=MagicMock(unique_id="123"))
flow_handler._set_unique_id_or_abort = AsyncMock(return_value=True)

result = await flow_handler.async_step_select_devices({"selected_devices": ["192.168.1.100:8888"]})

Check failure on line 57 in tests/test_config_flow.py

View workflow job for this annotation

GitHub Actions / build (3.13)

test_async_step_select_devices_success AttributeError: 'LuxtronikFlowHandler' object has no attribute 'async_step_select_devices'

assert result["type"] == "create_entry"
assert result["title"] == "192.168.1.100:8888"

@pytest.mark.asyncio
async def test_async_step_manual_entry_success(flow_handler):
flow_handler._connect_and_get_coordinator = AsyncMock(return_value=MagicMock(unique_id="123"))
flow_handler._set_unique_id_or_abort = AsyncMock(return_value=True)

result = await flow_handler.async_step_manual_entry({CONF_HOST: "192.168.1.100", CONF_PORT: 8888})

Check failure on line 67 in tests/test_config_flow.py

View workflow job for this annotation

GitHub Actions / build (3.13)

test_async_step_manual_entry_success AttributeError: 'LuxtronikFlowHandler' object has no attribute 'async_step_manual_entry'

assert result["type"] == "create_entry"
assert result["title"] == "192.168.1.100:8888"

@pytest.mark.asyncio
async def test_async_step_dhcp_success(flow_handler):
flow_handler._discover_devices = AsyncMock(return_value=[("192.168.1.100", 8888)])
flow_handler._connect_and_get_coordinator = AsyncMock(return_value=MagicMock(unique_id="123"))
flow_handler._set_unique_id_or_abort = AsyncMock(return_value=True)

dhcp_info = MagicMock(ip="192.168.1.100", hostname="luxtronik")
result = await flow_handler.async_step_dhcp(dhcp_info)

assert result["type"] == "create_entry"

Check failure on line 81 in tests/test_config_flow.py

View workflow job for this annotation

GitHub Actions / build (3.13)

test_async_step_dhcp_success TypeError: 'NoneType' object is not subscriptable
assert result["title"] == "192.168.1.100:8888"

@pytest.mark.asyncio
async def test_options_flow_update_options():
config_entry = MagicMock(data={CONF_HOST: "192.168.1.100", CONF_PORT: 8888}, options={})
handler = LuxtronikOptionsFlowHandler(config_entry)

Check failure on line 87 in tests/test_config_flow.py

View workflow job for this annotation

GitHub Actions / build (3.13)

test_options_flow_update_options RuntimeError: Frame helper not set up
handler.hass = MagicMock()
handler.hass.config_entries.async_update_entry = AsyncMock()
handler.hass.config_entries.async_reload = AsyncMock()

result = await handler.async_step_user({})

assert result["type"] == "create_entry"
65 changes: 65 additions & 0 deletions tests/test_options_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import pytest
pytestmark = pytest.mark.enable_custom_integrations

Check warning on line 2 in tests/test_options_flow.py

View workflow job for this annotation

GitHub Actions / build (3.13)

Unknown pytest.mark.enable_custom_integrations - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html

from homeassistant import data_entry_flow
from homeassistant.core import HomeAssistant
from homeassistant.const import CONF_HOST, CONF_PORT

from custom_components.luxtronik.config_flow import LuxtronikFlowHandler, LuxtronikOptionsFlowHandler
from custom_components.luxtronik.const import DOMAIN,CONF_HA_SENSOR_INDOOR_TEMPERATURE, DEFAULT_PORT


@pytest.fixture
def mock_config_entry():
class MockConfigEntry:
data = {
CONF_HOST: "192.168.1.100",
CONF_PORT: 8888,
}
options = {}
entry_id = "test_entry"
return MockConfigEntry()

@pytest.fixture
def mock_connect(monkeypatch):
class MockCoordinator:
manufacturer = "Luxtronik"
model = "HP"
serial_number = "123456789"
monkeypatch.setattr(
"custom_components.luxtronik.coordinator.LuxtronikCoordinator.connect",
lambda hass, config: MockCoordinator()
)
return MockCoordinator()

@pytest.mark.asyncio
async def test_options_flow_form_rendering(hass: HomeAssistant, mock_config_entry, mock_connect):
flow = LuxtronikOptionsFlowHandler(mock_config_entry)

Check failure on line 37 in tests/test_options_flow.py

View workflow job for this annotation

GitHub Actions / build (3.13)

test_options_flow_form_rendering RuntimeError: Frame helper not set up
flow.hass = hass

result = await flow.async_step_user()
assert result["type"] == data_entry_flow.FlowResultType.FORM
assert result["step_id"] == "user"
assert "data_schema" in result

@pytest.mark.asyncio
async def test_options_flow_updates_options(hass: HomeAssistant, mock_config_entry, mock_connect):
flow = LuxtronikOptionsFlowHandler(mock_config_entry)

Check failure on line 47 in tests/test_options_flow.py

View workflow job for this annotation

GitHub Actions / build (3.13)

test_options_flow_updates_options RuntimeError: Frame helper not set up
flow.hass = hass

user_input = {
CONF_HA_SENSOR_INDOOR_TEMPERATURE: "sensor.indoor_temp"
}

result = await flow.async_step_user(user_input)
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
assert result["data"] == {}

@pytest.mark.asyncio
async def test_options_flow_init_redirects_to_user(hass: HomeAssistant, mock_config_entry):
flow = LuxtronikOptionsFlowHandler(mock_config_entry)

Check failure on line 60 in tests/test_options_flow.py

View workflow job for this annotation

GitHub Actions / build (3.13)

test_options_flow_init_redirects_to_user RuntimeError: Frame helper not set up
flow.hass = hass

result = await flow.async_step_init()
assert result["type"] == data_entry_flow.FlowResultType.FORM
assert result["step_id"] == "user"
Loading