Fix tests

This commit is contained in:
Joostlek 2025-05-22 20:29:17 +02:00
parent 6e74df7d8c
commit f6f732b6a7
9 changed files with 211 additions and 82 deletions

View File

@ -28,13 +28,13 @@ class SmarlaConfigFlow(ConfigFlow, domain=DOMAIN):
conn = Connection(url=HOST, token_b64=token) conn = Connection(url=HOST, token_b64=token)
except ValueError: except ValueError:
errors["base"] = "malformed_token" errors["base"] = "malformed_token"
return (errors, None) return errors, None
if not await conn.refresh_token(): if not await conn.refresh_token():
errors["base"] = "invalid_auth" errors["base"] = "invalid_auth"
return (errors, None) return errors, None
return (errors, conn.token.serialNumber) return errors, conn.token.serialNumber
async def async_step_user( async def async_step_user(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None

View File

@ -1,20 +1,22 @@
"""Tests for the Smarla integration.""" """Tests for the Smarla integration."""
import base64 from typing import Any
import json from unittest.mock import AsyncMock
from homeassistant.const import CONF_ACCESS_TOKEN from homeassistant.core import HomeAssistant
MOCK_ACCESS_TOKEN_JSON = { from tests.common import MockConfigEntry
"refreshToken": "test",
"appIdentifier": "HA-test",
"serialNumber": "ABCD",
}
MOCK_SERIAL_NUMBER = MOCK_ACCESS_TOKEN_JSON["serialNumber"]
MOCK_ACCESS_TOKEN = base64.b64encode( async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
json.dumps(MOCK_ACCESS_TOKEN_JSON).encode() """Set up the component."""
).decode() config_entry.add_to_hass(hass)
MOCK_USER_INPUT = {CONF_ACCESS_TOKEN: MOCK_ACCESS_TOKEN} assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
async def update_property_listeners(mock: AsyncMock, value: Any = None) -> None:
"""Update the property listeners for the mock object."""
for call in mock.add_listener.call_args_list:
await call[0][0](value)

View File

@ -1,11 +0,0 @@
"""Common test utilities for entity component tests."""
from homeassistant.components.smarla.const import DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
def get_entity_id_by_unique_id(hass: HomeAssistant, platform: str, unique_id: str):
"""Get entity id by its unique id."""
registry = er.async_get(hass)
return registry.async_get_entity_id(platform, DOMAIN, unique_id)

View File

@ -6,12 +6,13 @@ from collections.abc import Generator
from unittest.mock import AsyncMock, MagicMock, patch from unittest.mock import AsyncMock, MagicMock, patch
from pysmarlaapi.classes import AuthToken from pysmarlaapi.classes import AuthToken
from pysmarlaapi.federwiege.classes import Property
import pytest import pytest
from homeassistant.components.smarla.const import DOMAIN from homeassistant.components.smarla.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER from homeassistant.config_entries import SOURCE_USER
from . import MOCK_ACCESS_TOKEN_JSON, MOCK_SERIAL_NUMBER, MOCK_USER_INPUT from .const import MOCK_ACCESS_TOKEN_JSON, MOCK_SERIAL_NUMBER, MOCK_USER_INPUT
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
@ -55,11 +56,22 @@ def mock_connection() -> Generator[MagicMock]:
@pytest.fixture @pytest.fixture
def mock_federwiege() -> Generator[MagicMock]: def mock_federwiege(
mock_connection: AsyncMock, mock_property: AsyncMock
) -> Generator[AsyncMock]:
"""Mock the Federwiege instance.""" """Mock the Federwiege instance."""
with patch( with patch(
"homeassistant.components.smarla.Federwiege", autospec=True "homeassistant.components.smarla.Federwiege", autospec=True
) as mock_federwiege: ) as mock_federwiege:
federwiege = mock_federwiege.return_value federwiege = mock_federwiege.return_value
federwiege.serial_number = MOCK_SERIAL_NUMBER federwiege.serial_number = MOCK_SERIAL_NUMBER
federwiege.get_property.return_value = mock_property
yield federwiege yield federwiege
@pytest.fixture
def mock_property() -> AsyncMock:
"""Mock the Federwiege instance."""
mock = AsyncMock(spec=Property)
mock.get.return_value = False
return mock

View File

@ -0,0 +1,20 @@
"""Constants for the Smarla integration tests."""
import base64
import json
from homeassistant.const import CONF_ACCESS_TOKEN
MOCK_ACCESS_TOKEN_JSON = {
"refreshToken": "test",
"appIdentifier": "HA-test",
"serialNumber": "ABCD",
}
MOCK_SERIAL_NUMBER = MOCK_ACCESS_TOKEN_JSON["serialNumber"]
MOCK_ACCESS_TOKEN = base64.b64encode(
json.dumps(MOCK_ACCESS_TOKEN_JSON).encode()
).decode()
MOCK_USER_INPUT = {CONF_ACCESS_TOKEN: MOCK_ACCESS_TOKEN}

View File

@ -0,0 +1,95 @@
# serializer version: 1
# name: test_entities[switch.smarla-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': 'switch',
'entity_category': None,
'entity_id': 'switch.smarla',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': None,
'platform': 'smarla',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'ABCD-swing_active',
'unit_of_measurement': None,
})
# ---
# name: test_entities[switch.smarla-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Smarla',
}),
'context': <ANY>,
'entity_id': 'switch.smarla',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_entities[switch.smarla_smart_mode-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': 'switch',
'entity_category': None,
'entity_id': 'switch.smarla_smart_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Smart Mode',
'platform': 'smarla',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'smart_mode',
'unique_id': 'ABCD-smart_mode',
'unit_of_measurement': None,
})
# ---
# name: test_entities[switch.smarla_smart_mode-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Smarla Smart Mode',
}),
'context': <ANY>,
'entity_id': 'switch.smarla_smart_mode',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---

View File

@ -7,7 +7,7 @@ from homeassistant.config_entries import SOURCE_USER
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
from . import MOCK_SERIAL_NUMBER, MOCK_USER_INPUT from .const import MOCK_SERIAL_NUMBER, MOCK_USER_INPUT
from tests.common import MockConfigEntry from tests.common import MockConfigEntry

View File

@ -1,7 +1,5 @@
"""Test switch platform for Swing2Sleep Smarla integration.""" """Test switch platform for Swing2Sleep Smarla integration."""
from unittest.mock import AsyncMock, patch
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -15,11 +13,9 @@ async def test_init_invalid_auth(
# Add the mock entry to hass # Add the mock entry to hass
mock_config_entry.add_to_hass(hass) mock_config_entry.add_to_hass(hass)
with patch.object( mock_connection.refresh_token.return_value = False
mock_connection, "refresh_token", new=AsyncMock(return_value=False) # Set up the platform
): await hass.config_entries.async_setup(mock_config_entry.entry_id)
# Set up the platform await hass.async_block_till_done()
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR

View File

@ -1,14 +1,13 @@
"""Test switch platform for Swing2Sleep Smarla integration.""" """Test switch platform for Swing2Sleep Smarla integration."""
from pysmarlaapi.federwiege.classes import Property from unittest.mock import AsyncMock, patch
import pytest
from homeassistant.components.smarla.switch import SWITCHES import pytest
from homeassistant.components.switch import ( from syrupy.assertion import SnapshotAssertion
DOMAIN as SWITCH_DOMAIN,
SwitchEntityDescription, from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
)
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
SERVICE_TURN_ON, SERVICE_TURN_ON,
STATE_OFF, STATE_OFF,
@ -16,57 +15,73 @@ from homeassistant.const import (
Platform, Platform,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import get_entity_id_by_unique_id from . import setup_integration, update_property_listeners
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, snapshot_platform
@pytest.mark.parametrize("switch_desc", SWITCHES) async def test_entities(
async def test_switch_behavior(
hass: HomeAssistant, hass: HomeAssistant,
switch_desc: SwitchEntityDescription, mock_federwiege: AsyncMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
mock_connection, entity_registry: er.EntityRegistry,
mock_federwiege, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test SmarlaSwitch on/off behavior.""" """Test the Spotify entities."""
# Assign switch property to federwiege with (
mock_property = Property[bool](None, False) patch("homeassistant.components.smarla.PLATFORMS", [Platform.SWITCH]),
mock_federwiege.get_property.return_value = mock_property ):
# Add the mock entry to hass await setup_integration(hass, mock_config_entry)
mock_config_entry.add_to_hass(hass)
# Set up the platform await snapshot_platform(
await hass.config_entries.async_setup(mock_config_entry.entry_id) hass, entity_registry, snapshot, mock_config_entry.entry_id
await hass.async_block_till_done() )
# Get entity id by unique id
unique_id = f"{mock_federwiege.serial_number}-{switch_desc.key}"
entity_id = get_entity_id_by_unique_id(hass, Platform.SWITCH, unique_id)
assert entity_id is not None
# Check entity initial state @pytest.mark.parametrize(
assert hass.states.get(entity_id).state == STATE_OFF ("service", "parameter"),
[
(SERVICE_TURN_ON, True),
(SERVICE_TURN_OFF, False),
],
)
async def test_switch_action(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_federwiege: AsyncMock,
mock_property: AsyncMock,
service: str,
parameter: bool,
) -> None:
"""Test Smarla Switch on/off behavior."""
await setup_integration(hass, mock_config_entry)
# Turn on # Turn on
await hass.services.async_call( await hass.services.async_call(
SWITCH_DOMAIN, SWITCH_DOMAIN,
SERVICE_TURN_ON, service,
{"entity_id": entity_id}, {ATTR_ENTITY_ID: "switch.smarla"},
blocking=True, blocking=True,
) )
mock_property.set(True, push=False) mock_property.set.assert_called_once_with(parameter)
await mock_property.notify_listeners()
assert hass.states.get(entity_id).state == STATE_ON
# Turn off
await hass.services.async_call( async def test_switch_state_update(
SWITCH_DOMAIN, hass: HomeAssistant,
SERVICE_TURN_OFF, mock_config_entry: MockConfigEntry,
{"entity_id": entity_id}, mock_federwiege: AsyncMock,
blocking=True, mock_property: AsyncMock,
) ) -> None:
mock_property.set(False, push=False) """Test Smarla Switch on/off behavior."""
await mock_property.notify_listeners() await setup_integration(hass, mock_config_entry)
assert hass.states.get(entity_id).state == STATE_OFF
assert hass.states.get("switch.smarla").state == STATE_OFF
mock_property.get.return_value = True
await update_property_listeners(mock_property)
await hass.async_block_till_done()
assert hass.states.get("switch.smarla").state == STATE_ON