1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-24 12:59:34 +00:00

clean up velux test fixtures (#156554)

This commit is contained in:
wollew
2025-11-14 19:53:17 +01:00
committed by GitHub
parent 3aff225bc3
commit 84b0d39763
5 changed files with 429 additions and 113 deletions

View File

@@ -4,10 +4,10 @@ from collections.abc import Generator
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from pyvlx.lightening_device import LighteningDevice
from pyvlx.opening_device import Blind, Window
from homeassistant.components.velux import DOMAIN
from homeassistant.components.velux.binary_sensor import Window
from homeassistant.components.velux.light import LighteningDevice
from homeassistant.components.velux.scene import PyVLXScene as Scene
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PASSWORD, Platform
from homeassistant.core import HomeAssistant
@@ -26,22 +26,10 @@ def mock_setup_entry() -> Generator[AsyncMock]:
@pytest.fixture
def mock_velux_client() -> Generator[AsyncMock]:
"""Mock a Velux client."""
with (
patch(
"homeassistant.components.velux.config_flow.PyVLX",
autospec=True,
) as mock_client,
):
client = mock_client.return_value
yield client
@pytest.fixture
def mock_user_config_entry() -> MockConfigEntry:
"""Return the user config entry."""
def mock_config_entry() -> MockConfigEntry:
"""Return a mock config entry (unified fixture for all tests)."""
return MockConfigEntry(
entry_id="test_entry_id",
domain=DOMAIN,
title="127.0.0.1",
data={
@@ -66,7 +54,8 @@ def mock_discovered_config_entry() -> MockConfigEntry:
)
# fixtures for the binary sensor tests
# various types of fixtures for specific node types
# first the window
@pytest.fixture
def mock_window() -> AsyncMock:
"""Create a mock Velux window with a rain sensor."""
@@ -81,6 +70,27 @@ def mock_window() -> AsyncMock:
return window
# a blind
@pytest.fixture
def mock_blind() -> AsyncMock:
"""Create a mock Velux blind (cover with tilt)."""
blind = AsyncMock(spec=Blind, autospec=True)
blind.name = "Test Blind"
blind.serial_number = "4711"
# Standard cover position (used by current_cover_position)
blind.position = MagicMock(position_percent=40, closed=False)
blind.is_opening = False
blind.is_closing = False
# Orientation/tilt-related attributes and methods
blind.orientation = MagicMock(position_percent=25)
blind.open_orientation = AsyncMock()
blind.close_orientation = AsyncMock()
blind.stop_orientation = AsyncMock()
blind.set_orientation = AsyncMock()
return blind
# a light
@pytest.fixture
def mock_light() -> AsyncMock:
"""Create a mock Velux light."""
@@ -91,6 +101,56 @@ def mock_light() -> AsyncMock:
return light
# fixture to create all other cover types via parameterization
@pytest.fixture
def mock_cover_type(request: pytest.FixtureRequest) -> AsyncMock:
"""Create a mock Velux cover of specified type."""
cover = AsyncMock(spec=request.param, autospec=True)
cover.name = f"Test {request.param.__name__}"
cover.serial_number = f"serial_{request.param.__name__}"
cover.is_opening = False
cover.is_closing = False
cover.position = MagicMock(position_percent=30, closed=False)
return cover
@pytest.fixture
def mock_pyvlx(
mock_scene: AsyncMock,
mock_light: AsyncMock,
mock_window: AsyncMock,
mock_blind: AsyncMock,
request: pytest.FixtureRequest,
) -> Generator[MagicMock]:
"""Create the library mock and patch PyVLX in both component and config_flow.
Tests can parameterize this fixture with the name of a node fixture to include
(e.g., "mock_window", "mock_blind", "mock_light", or "mock_cover_type").
If no parameter is provided, an empty node list is used.
"""
pyvlx = MagicMock()
if hasattr(request, "param"):
pyvlx.nodes = [request.getfixturevalue(request.param)]
else:
pyvlx.nodes = [mock_light, mock_blind, mock_window, mock_cover_type]
pyvlx.scenes = [mock_scene]
# Async methods invoked by the integration/config flow
pyvlx.load_scenes = AsyncMock()
pyvlx.load_nodes = AsyncMock()
pyvlx.connect = AsyncMock()
pyvlx.disconnect = AsyncMock()
with (
patch("homeassistant.components.velux.PyVLX", return_value=pyvlx),
patch("homeassistant.components.velux.config_flow.PyVLX", return_value=pyvlx),
):
yield pyvlx
@pytest.fixture
def mock_scene() -> AsyncMock:
"""Create a mock Velux scene."""
@@ -101,40 +161,12 @@ def mock_scene() -> AsyncMock:
return scene
@pytest.fixture
def mock_pyvlx(
mock_window: MagicMock, mock_light: MagicMock, mock_scene: AsyncMock
) -> Generator[MagicMock]:
"""Create the library mock and patch PyVLX."""
pyvlx = MagicMock()
pyvlx.nodes = [mock_window, mock_light]
pyvlx.scenes = [mock_scene]
pyvlx.load_scenes = AsyncMock()
pyvlx.load_nodes = AsyncMock()
pyvlx.disconnect = AsyncMock()
with patch("homeassistant.components.velux.PyVLX", return_value=pyvlx):
yield pyvlx
@pytest.fixture
def mock_config_entry() -> MockConfigEntry:
"""Return a mock config entry."""
return MockConfigEntry(
entry_id="test_entry_id",
domain=DOMAIN,
data={
CONF_HOST: "testhost",
CONF_PASSWORD: "testpw",
},
)
# Fixture to set up the integration for testing, needs platform fixture, to be defined in each test file
@pytest.fixture
async def setup_integration(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_pyvlx: MagicMock,
mock_pyvlx: AsyncMock,
platform: Platform,
) -> None:
"""Set up the integration for testing."""

View File

@@ -1,5 +1,261 @@
# serializer version: 1
# name: test_cover_setup[cover.test_window-entry]
# name: test_blind_entity_setup[mock_blind][cover.test_blind-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'cover',
'entity_category': None,
'entity_id': 'cover.test_blind',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <CoverDeviceClass.BLIND: 'blind'>,
'original_icon': None,
'original_name': None,
'platform': 'velux',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <CoverEntityFeature: 255>,
'translation_key': None,
'unique_id': '4711',
'unit_of_measurement': None,
})
# ---
# name: test_blind_entity_setup[mock_blind][cover.test_blind-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'current_position': 60,
'current_tilt_position': 75,
'device_class': 'blind',
'friendly_name': 'Test Blind',
'supported_features': <CoverEntityFeature: 255>,
}),
'context': <ANY>,
'entity_id': 'cover.test_blind',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'open',
})
# ---
# name: test_cover_entity_setup[mock_cover_type-Awning][cover.test_awning-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'cover',
'entity_category': None,
'entity_id': 'cover.test_awning',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <CoverDeviceClass.AWNING: 'awning'>,
'original_icon': None,
'original_name': None,
'platform': 'velux',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <CoverEntityFeature: 15>,
'translation_key': None,
'unique_id': 'serial_Awning',
'unit_of_measurement': None,
})
# ---
# name: test_cover_entity_setup[mock_cover_type-Awning][cover.test_awning-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'current_position': 70,
'device_class': 'awning',
'friendly_name': 'Test Awning',
'supported_features': <CoverEntityFeature: 15>,
}),
'context': <ANY>,
'entity_id': 'cover.test_awning',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'open',
})
# ---
# name: test_cover_entity_setup[mock_cover_type-GarageDoor][cover.test_garagedoor-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'cover',
'entity_category': None,
'entity_id': 'cover.test_garagedoor',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <CoverDeviceClass.GARAGE: 'garage'>,
'original_icon': None,
'original_name': None,
'platform': 'velux',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <CoverEntityFeature: 15>,
'translation_key': None,
'unique_id': 'serial_GarageDoor',
'unit_of_measurement': None,
})
# ---
# name: test_cover_entity_setup[mock_cover_type-GarageDoor][cover.test_garagedoor-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'current_position': 70,
'device_class': 'garage',
'friendly_name': 'Test GarageDoor',
'supported_features': <CoverEntityFeature: 15>,
}),
'context': <ANY>,
'entity_id': 'cover.test_garagedoor',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'open',
})
# ---
# name: test_cover_entity_setup[mock_cover_type-Gate][cover.test_gate-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'cover',
'entity_category': None,
'entity_id': 'cover.test_gate',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <CoverDeviceClass.GATE: 'gate'>,
'original_icon': None,
'original_name': None,
'platform': 'velux',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <CoverEntityFeature: 15>,
'translation_key': None,
'unique_id': 'serial_Gate',
'unit_of_measurement': None,
})
# ---
# name: test_cover_entity_setup[mock_cover_type-Gate][cover.test_gate-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'current_position': 70,
'device_class': 'gate',
'friendly_name': 'Test Gate',
'supported_features': <CoverEntityFeature: 15>,
}),
'context': <ANY>,
'entity_id': 'cover.test_gate',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'open',
})
# ---
# name: test_cover_entity_setup[mock_cover_type-RollerShutter][cover.test_rollershutter-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'cover',
'entity_category': None,
'entity_id': 'cover.test_rollershutter',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <CoverDeviceClass.SHUTTER: 'shutter'>,
'original_icon': None,
'original_name': None,
'platform': 'velux',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <CoverEntityFeature: 15>,
'translation_key': None,
'unique_id': 'serial_RollerShutter',
'unit_of_measurement': None,
})
# ---
# name: test_cover_entity_setup[mock_cover_type-RollerShutter][cover.test_rollershutter-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'current_position': 70,
'device_class': 'shutter',
'friendly_name': 'Test RollerShutter',
'supported_features': <CoverEntityFeature: 15>,
}),
'context': <ANY>,
'entity_id': 'cover.test_rollershutter',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'open',
})
# ---
# name: test_cover_entity_setup[mock_cover_type-Window][cover.test_window-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -30,11 +286,11 @@
'suggested_object_id': None,
'supported_features': <CoverEntityFeature: 15>,
'translation_key': None,
'unique_id': '123456789',
'unique_id': 'serial_Window',
'unit_of_measurement': None,
})
# ---
# name: test_cover_setup[cover.test_window-state]
# name: test_cover_entity_setup[mock_cover_type-Window][cover.test_window-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'current_position': 70,

View File

@@ -1,6 +1,6 @@
"""Tests for the Velux binary sensor platform."""
from unittest.mock import MagicMock, patch
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
import pytest
@@ -16,22 +16,21 @@ from . import update_polled_entities
from tests.common import MockConfigEntry
@pytest.fixture
def platform() -> Platform:
"""Fixture to specify platform to test."""
return Platform.BINARY_SENSOR
@pytest.mark.usefixtures("setup_integration")
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@pytest.mark.usefixtures("mock_pyvlx")
async def test_rain_sensor_state(
hass: HomeAssistant,
mock_window: MagicMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test the rain sensor."""
mock_config_entry.add_to_hass(hass)
with patch("homeassistant.components.velux.PLATFORMS", [Platform.BINARY_SENSOR]):
# setup config entry
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
test_entity_id = "binary_sensor.test_window_rain_sensor"
# simulate no rain detected
@@ -62,8 +61,8 @@ async def test_rain_sensor_state(
assert state.state == STATE_OFF
@pytest.mark.usefixtures("setup_integration")
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@pytest.mark.usefixtures("mock_pyvlx")
async def test_rain_sensor_device_association(
hass: HomeAssistant,
mock_window: MagicMock,
@@ -73,11 +72,6 @@ async def test_rain_sensor_device_association(
) -> None:
"""Test the rain sensor is properly associated with its device."""
mock_config_entry.add_to_hass(hass)
with patch("homeassistant.components.velux.PLATFORMS", [Platform.BINARY_SENSOR]):
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
test_entity_id = "binary_sensor.test_window_rain_sensor"
# Verify entity exists

View File

@@ -26,7 +26,7 @@ DHCP_DISCOVERY = DhcpServiceInfo(
async def test_user_flow(
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
mock_velux_client: AsyncMock,
mock_pyvlx: AsyncMock,
) -> None:
"""Test starting a flow by user with valid values."""
result = await hass.config_entries.flow.async_init(
@@ -53,8 +53,8 @@ async def test_user_flow(
}
assert not result["result"].unique_id
mock_velux_client.disconnect.assert_called_once()
mock_velux_client.connect.assert_called_once()
mock_pyvlx.disconnect.assert_called_once()
mock_pyvlx.connect.assert_called_once()
@pytest.mark.parametrize(
@@ -66,14 +66,14 @@ async def test_user_flow(
)
async def test_user_errors(
hass: HomeAssistant,
mock_velux_client: AsyncMock,
mock_pyvlx: AsyncMock,
exception: Exception,
error: str,
mock_setup_entry: AsyncMock,
) -> None:
"""Test starting a flow by user but with exceptions."""
mock_velux_client.connect.side_effect = exception
mock_pyvlx.connect.side_effect = exception
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
@@ -95,9 +95,9 @@ async def test_user_errors(
assert result["step_id"] == "user"
assert result["errors"] == {"base": error}
mock_velux_client.connect.assert_called_once()
mock_pyvlx.connect.assert_called_once()
mock_velux_client.connect.side_effect = None
mock_pyvlx.connect.side_effect = None
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
@@ -112,11 +112,11 @@ async def test_user_errors(
async def test_user_flow_duplicate_entry(
hass: HomeAssistant,
mock_user_config_entry: MockConfigEntry,
mock_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
) -> None:
"""Test initialized flow with a duplicate entry."""
mock_user_config_entry.add_to_hass(hass)
mock_config_entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN,
@@ -140,7 +140,7 @@ async def test_user_flow_duplicate_entry(
async def test_dhcp_discovery(
hass: HomeAssistant,
mock_velux_client: AsyncMock,
mock_pyvlx: AsyncMock,
mock_setup_entry: AsyncMock,
) -> None:
"""Test we can setup from dhcp discovery."""
@@ -168,8 +168,8 @@ async def test_dhcp_discovery(
}
assert result["result"].unique_id == "VELUX_KLF_ABCD"
mock_velux_client.disconnect.assert_called()
mock_velux_client.connect.assert_called()
mock_pyvlx.disconnect.assert_called()
mock_pyvlx.connect.assert_called()
@pytest.mark.parametrize(
@@ -181,7 +181,7 @@ async def test_dhcp_discovery(
)
async def test_dhcp_discovery_errors(
hass: HomeAssistant,
mock_velux_client: AsyncMock,
mock_pyvlx: AsyncMock,
exception: Exception,
error: str,
mock_setup_entry: AsyncMock,
@@ -196,7 +196,7 @@ async def test_dhcp_discovery_errors(
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "discovery_confirm"
mock_velux_client.connect.side_effect = exception
mock_pyvlx.connect.side_effect = exception
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
@@ -207,7 +207,7 @@ async def test_dhcp_discovery_errors(
assert result["step_id"] == "discovery_confirm"
assert result["errors"] == {"base": error}
mock_velux_client.connect.side_effect = None
mock_pyvlx.connect.side_effect = None
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
@@ -226,7 +226,7 @@ async def test_dhcp_discovery_errors(
async def test_dhcp_discovery_already_configured(
hass: HomeAssistant,
mock_velux_client: AsyncMock,
mock_pyvlx: AsyncMock,
mock_discovered_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
) -> None:
@@ -245,15 +245,15 @@ async def test_dhcp_discovery_already_configured(
async def test_dhcp_discover_unique_id(
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
mock_velux_client: AsyncMock,
mock_user_config_entry: MockConfigEntry,
mock_pyvlx: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test dhcp discovery when already configured."""
mock_user_config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(mock_user_config_entry.entry_id)
mock_config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
assert mock_user_config_entry.state is ConfigEntryState.LOADED
assert mock_user_config_entry.unique_id is None
assert mock_config_entry.state is ConfigEntryState.LOADED
assert mock_config_entry.unique_id is None
result = await hass.config_entries.flow.async_init(
DOMAIN,
@@ -263,20 +263,20 @@ async def test_dhcp_discover_unique_id(
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"
assert mock_user_config_entry.unique_id == "VELUX_KLF_ABCD"
assert mock_config_entry.unique_id == "VELUX_KLF_ABCD"
async def test_dhcp_discovery_not_loaded(
hass: HomeAssistant,
mock_velux_client: AsyncMock,
mock_user_config_entry: MockConfigEntry,
mock_pyvlx: AsyncMock,
mock_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
) -> None:
"""Test dhcp discovery when entry with same host not loaded."""
mock_user_config_entry.add_to_hass(hass)
mock_config_entry.add_to_hass(hass)
assert mock_user_config_entry.state is not ConfigEntryState.LOADED
assert mock_user_config_entry.unique_id is None
assert mock_config_entry.state is not ConfigEntryState.LOADED
assert mock_config_entry.unique_id is None
result = await hass.config_entries.flow.async_init(
DOMAIN,
@@ -286,4 +286,4 @@ async def test_dhcp_discovery_not_loaded(
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"
assert mock_user_config_entry.unique_id is None
assert mock_config_entry.unique_id is None

View File

@@ -3,6 +3,7 @@
from unittest.mock import AsyncMock
import pytest
from pyvlx.opening_device import Awning, GarageDoor, Gate, RollerShutter, Window
from homeassistant.components.velux import DOMAIN
from homeassistant.const import STATE_CLOSED, STATE_OPEN, Platform
@@ -21,14 +22,14 @@ def platform() -> Platform:
@pytest.mark.usefixtures("setup_integration")
async def test_cover_setup(
@pytest.mark.parametrize("mock_pyvlx", ["mock_blind"], indirect=True)
async def test_blind_entity_setup(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
device_registry: dr.DeviceRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Snapshot the cover entity (registry + state)."""
"""Snapshot the entity and validate registry metadata."""
await snapshot_platform(
hass,
entity_registry,
@@ -36,31 +37,64 @@ async def test_cover_setup(
mock_config_entry.entry_id,
)
# Get the cover entity setup and test device association
@pytest.mark.usefixtures("setup_integration")
@pytest.mark.usefixtures("mock_cover_type")
@pytest.mark.parametrize(
"mock_cover_type", [Awning, GarageDoor, Gate, RollerShutter, Window], indirect=True
)
@pytest.mark.parametrize(
"mock_pyvlx",
["mock_cover_type"],
indirect=True,
)
async def test_cover_entity_setup(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Snapshot the entity and validate entity metadata."""
await snapshot_platform(
hass,
entity_registry,
snapshot,
mock_config_entry.entry_id,
)
@pytest.mark.usefixtures("setup_integration")
async def test_cover_device_association(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test the cover entity device association."""
entity_entries = er.async_entries_for_config_entry(
entity_registry, mock_config_entry.entry_id
)
assert len(entity_entries) == 1
entry = entity_entries[0]
assert len(entity_entries) >= 1
assert entry.device_id is not None
device_entry = device_registry.async_get(entry.device_id)
assert device_entry is not None
assert (DOMAIN, f"{123456789}") in device_entry.identifiers
assert device_entry.via_device_id is not None
via_device_entry = device_registry.async_get(device_entry.via_device_id)
assert via_device_entry is not None
assert (
DOMAIN,
f"gateway_{mock_config_entry.entry_id}",
) in via_device_entry.identifiers
for entry in entity_entries:
assert entry.device_id is not None
device_entry = device_registry.async_get(entry.device_id)
assert device_entry is not None
assert (DOMAIN, entry.unique_id) in device_entry.identifiers
assert device_entry.via_device_id is not None
via_device_entry = device_registry.async_get(device_entry.via_device_id)
assert via_device_entry is not None
assert (
DOMAIN,
f"gateway_{mock_config_entry.entry_id}",
) in via_device_entry.identifiers
@pytest.mark.usefixtures("setup_integration")
async def test_cover_closed(
hass: HomeAssistant,
mock_window: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test the cover closed state."""