1
0
mirror of https://github.com/home-assistant/core.git synced 2026-04-02 08:26:41 +01:00
Files
core/tests/components/opendisplay/test_config_flow.py
g4bri3lDev bbe45e0759 Add OpenDisplay integration (#164048)
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2026-03-06 16:23:09 +01:00

245 lines
8.0 KiB
Python

"""Test the OpenDisplay config flow."""
from collections.abc import Generator
from unittest.mock import MagicMock, patch
from opendisplay import BLEConnectionError, BLETimeoutError, OpenDisplayError
import pytest
from homeassistant import config_entries
from homeassistant.components.opendisplay.const import DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from . import NOT_OPENDISPLAY_SERVICE_INFO, VALID_SERVICE_INFO
from tests.common import MockConfigEntry
@pytest.fixture(autouse=True)
def mock_setup_entry() -> Generator[None]:
"""Prevent the integration from actually setting up after config flow."""
with patch(
"homeassistant.components.opendisplay.async_setup_entry",
return_value=True,
):
yield
async def test_bluetooth_discovery(hass: HomeAssistant) -> None:
"""Test discovery via Bluetooth with a valid device."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_BLUETOOTH},
data=VALID_SERVICE_INFO,
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "bluetooth_confirm"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "OpenDisplay 1234"
assert result["data"] == {}
assert result["result"].unique_id == "AA:BB:CC:DD:EE:FF"
async def test_bluetooth_discovery_already_configured(
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test discovery aborts when device is already configured."""
mock_config_entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_BLUETOOTH},
data=VALID_SERVICE_INFO,
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"
async def test_bluetooth_discovery_already_in_progress(hass: HomeAssistant) -> None:
"""Test discovery aborts when same device flow is in progress."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_BLUETOOTH},
data=VALID_SERVICE_INFO,
)
assert result["type"] is FlowResultType.FORM
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_BLUETOOTH},
data=VALID_SERVICE_INFO,
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_in_progress"
@pytest.mark.parametrize(
("exception", "expected_reason"),
[
(BLEConnectionError("test"), "cannot_connect"),
(BLETimeoutError("test"), "cannot_connect"),
(OpenDisplayError("test"), "cannot_connect"),
(RuntimeError("test"), "unknown"),
],
)
async def test_bluetooth_confirm_connection_error(
hass: HomeAssistant,
mock_opendisplay_device: MagicMock,
exception: Exception,
expected_reason: str,
) -> None:
"""Test confirm step aborts when connection fails before showing the form."""
mock_opendisplay_device.__aenter__.side_effect = exception
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_BLUETOOTH},
data=VALID_SERVICE_INFO,
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == expected_reason
async def test_bluetooth_confirm_ble_device_not_found(
hass: HomeAssistant,
) -> None:
"""Test confirm step aborts when BLE device is not found."""
with patch(
"homeassistant.components.opendisplay.config_flow.async_ble_device_from_address",
return_value=None,
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_BLUETOOTH},
data=VALID_SERVICE_INFO,
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "cannot_connect"
async def test_user_step_with_devices(hass: HomeAssistant) -> None:
"""Test user step with discovered devices."""
with patch(
"homeassistant.components.opendisplay.config_flow.async_discovered_service_info",
return_value=[VALID_SERVICE_INFO],
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_USER},
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={"address": "AA:BB:CC:DD:EE:FF"},
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "OpenDisplay 1234"
assert result["data"] == {}
assert result["result"].unique_id == "AA:BB:CC:DD:EE:FF"
async def test_user_step_no_devices(hass: HomeAssistant) -> None:
"""Test user step when no devices are discovered."""
with patch(
"homeassistant.components.opendisplay.config_flow.async_discovered_service_info",
return_value=[],
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_USER},
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "no_devices_found"
async def test_user_step_filters_unsupported(hass: HomeAssistant) -> None:
"""Test user step filters out unsupported devices."""
with patch(
"homeassistant.components.opendisplay.config_flow.async_discovered_service_info",
return_value=[NOT_OPENDISPLAY_SERVICE_INFO],
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_USER},
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "no_devices_found"
@pytest.mark.parametrize(
("exception", "expected_error"),
[
(BLEConnectionError("test"), "cannot_connect"),
(BLETimeoutError("test"), "cannot_connect"),
(OpenDisplayError("test"), "cannot_connect"),
(RuntimeError("test"), "unknown"),
],
)
async def test_user_step_connection_error(
hass: HomeAssistant,
mock_opendisplay_device: MagicMock,
exception: Exception,
expected_error: str,
) -> None:
"""Test user step handles connection and unexpected errors."""
with patch(
"homeassistant.components.opendisplay.config_flow.async_discovered_service_info",
return_value=[VALID_SERVICE_INFO],
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_USER},
)
assert result["type"] is FlowResultType.FORM
mock_opendisplay_device.__aenter__.side_effect = exception
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={"address": "AA:BB:CC:DD:EE:FF"},
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {"base": expected_error}
mock_opendisplay_device.__aenter__.side_effect = None
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={"address": "AA:BB:CC:DD:EE:FF"},
)
assert result["type"] is FlowResultType.CREATE_ENTRY
async def test_user_step_already_configured(
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test user step aborts when device is already configured."""
mock_config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.opendisplay.config_flow.async_discovered_service_info",
return_value=[VALID_SERVICE_INFO],
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_USER},
)
# Device is filtered out since it's already configured
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "no_devices_found"