diff --git a/tests/components/tplink/__init__.py b/tests/components/tplink/__init__.py index e322cf9f5de..4107610c121 100644 --- a/tests/components/tplink/__init__.py +++ b/tests/components/tplink/__init__.py @@ -6,174 +6,36 @@ from datetime import datetime from typing import Any from unittest.mock import AsyncMock, MagicMock, patch -from kasa import ( - BaseProtocol, - Device, - DeviceConfig, - DeviceConnectionParameters, - DeviceEncryptionType, - DeviceFamily, - DeviceType, - Feature, - KasaException, - Module, -) +from kasa import BaseProtocol, Device, DeviceType, Feature, KasaException, Module from kasa.interfaces import Fan, Light, LightEffect, LightState from kasa.smart.modules.alarm import Alarm from kasa.smartcam.modules.camera import LOCAL_STREAMING_PORT, Camera from syrupy import SnapshotAssertion from homeassistant.components.automation import DOMAIN as AUTOMATION_DOMAIN -from homeassistant.components.tplink import ( - CONF_AES_KEYS, - CONF_ALIAS, - CONF_CAMERA_CREDENTIALS, - CONF_CONNECTION_PARAMETERS, - CONF_CREDENTIALS_HASH, - CONF_HOST, - CONF_LIVE_VIEW, - CONF_MODEL, - CONF_USES_HTTP, - Credentials, -) from homeassistant.components.tplink.const import DOMAIN from homeassistant.config_entries import ConfigEntry -from homeassistant.const import Platform +from homeassistant.const import CONF_HOST, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.translation import async_get_translations from homeassistant.helpers.typing import UNDEFINED from homeassistant.setup import async_setup_component +from .const import ( + ALIAS, + CREDENTIALS_HASH_LEGACY, + DEVICE_CONFIG_LEGACY, + DEVICE_ID, + IP_ADDRESS, + MAC_ADDRESS, + MODEL, +) + from tests.common import MockConfigEntry, load_json_value_fixture ColorTempRange = namedtuple("ColorTempRange", ["min", "max"]) # noqa: PYI024 -MODULE = "homeassistant.components.tplink" -MODULE_CONFIG_FLOW = "homeassistant.components.tplink.config_flow" -IP_ADDRESS = "127.0.0.1" -IP_ADDRESS2 = "127.0.0.2" -IP_ADDRESS3 = "127.0.0.3" -ALIAS = "My Bulb" -ALIAS_CAMERA = "My Camera" -MODEL = "HS100" -MODEL_CAMERA = "C210" -MAC_ADDRESS = "aa:bb:cc:dd:ee:ff" -DEVICE_ID = "123456789ABCDEFGH" -DEVICE_ID_MAC = "AA:BB:CC:DD:EE:FF" -DHCP_FORMATTED_MAC_ADDRESS = MAC_ADDRESS.replace(":", "") -MAC_ADDRESS2 = "11:22:33:44:55:66" -MAC_ADDRESS3 = "66:55:44:33:22:11" -DEFAULT_ENTRY_TITLE = f"{ALIAS} {MODEL}" -DEFAULT_ENTRY_TITLE_CAMERA = f"{ALIAS_CAMERA} {MODEL_CAMERA}" -CREDENTIALS_HASH_LEGACY = "" -CONN_PARAMS_LEGACY = DeviceConnectionParameters( - DeviceFamily.IotSmartPlugSwitch, DeviceEncryptionType.Xor -) -DEVICE_CONFIG_LEGACY = DeviceConfig(IP_ADDRESS) -DEVICE_CONFIG_DICT_LEGACY = { - k: v for k, v in DEVICE_CONFIG_LEGACY.to_dict().items() if k != "credentials" -} -CREDENTIALS = Credentials("foo", "bar") -CREDENTIALS_HASH_AES = "AES/abcdefghijklmnopqrstuvabcdefghijklmnopqrstuv==" -CREDENTIALS_HASH_KLAP = "KLAP/abcdefghijklmnopqrstuv==" -CONN_PARAMS_KLAP = DeviceConnectionParameters( - DeviceFamily.SmartTapoPlug, DeviceEncryptionType.Klap -) -DEVICE_CONFIG_KLAP = DeviceConfig( - IP_ADDRESS, - credentials=CREDENTIALS, - connection_type=CONN_PARAMS_KLAP, - uses_http=True, -) -CONN_PARAMS_AES = DeviceConnectionParameters( - DeviceFamily.SmartTapoPlug, DeviceEncryptionType.Aes -) -_test_privkey = ( - "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKLJKmBWGj6WYo9sewI8vkqar" - "Ed5H1JUr8Jj/LEWLTtV6+Mm4mfyEk6YKFHSmIG4AGgrVsGK/EbEkTZk9CwtixNQpBVc36oN2R" - "vuWWV38YnP4vI63mNxTA/gQonCsahjN4HfwE87pM7O5z39aeunoYm6Be663t33DbJH1ZUbZjm" - "tAgMBAAECgYB1Bn1KaFvRprcQOIJt51E9vNghQbf8rhj0fIEKpdC6mVhNIoUdCO+URNqnh+hP" - "SQIx4QYreUlHbsSeABFxOQSDJm6/kqyQsp59nCVDo/bXTtlvcSJ/sU3riqJNxYqEU1iJ0xMvU" - "N1VKKTmik89J8e5sN9R0AFfUSJIk7MpdOoD2QJBANTbV27nenyvbqee/ul4frdt2rrPGcGpcV" - "QmY87qbbrZgqgL5LMHHD7T/v/I8D1wRog1sBz/AiZGcnv/ox8dHKsCQQDDx8DCGPySSVqKVua" - "yUkBNpglN83wiCXZjyEtWIt+aB1A2n5ektE/o8oHnnOuvMdooxvtid7Mdapi2VLHV7VMHAkAE" - "d0GjWwnv2cJpk+VnQpbuBEkFiFjS/loZWODZM4Pv2qZqHi3DL9AA5XPBLBcWQufH7dBvG06RP" - "QMj5N4oRfUXAkEAuJJkVliqHNvM4OkGewzyFII4+WVYHNqg43dcFuuvtA27AJQ6qYtYXrvp3k" - "phI3yzOIhHTNCea1goepSkR5ODFwJBAJCTRbB+P47aEr/xA51ZFHE6VefDBJG9yg6yK4jcOxg" - "5ficXEpx8442okNtlzwa+QHpm/L3JOFrHwiEeVqXtiqY=" -) -_test_pubkey = ( - "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiySpgVho+lmKPbHsCPL5KmqxHeR9SVK/CY" - "/yxFi07VevjJuJn8hJOmChR0piBuABoK1bBivxGxJE2ZPQsLYsTUKQVXN+qDdkb7llld/GJz+" - "LyOt5jcUwP4EKJwrGoYzeB38BPO6TOzuc9/Wnrp6GJugXuut7d9w2yR9WVG2Y5rQIDAQAB" -) -AES_KEYS = {"private": _test_privkey, "public": _test_pubkey} -DEVICE_CONFIG_AES = DeviceConfig( - IP_ADDRESS2, - credentials=CREDENTIALS, - connection_type=CONN_PARAMS_AES, - uses_http=True, - aes_keys=AES_KEYS, -) -CONN_PARAMS_AES_CAMERA = DeviceConnectionParameters( - DeviceFamily.SmartIpCamera, DeviceEncryptionType.Aes, https=True, login_version=2 -) -DEVICE_CONFIG_AES_CAMERA = DeviceConfig( - IP_ADDRESS3, - credentials=CREDENTIALS, - connection_type=CONN_PARAMS_AES_CAMERA, - uses_http=True, -) - -DEVICE_CONFIG_DICT_KLAP = { - k: v for k, v in DEVICE_CONFIG_KLAP.to_dict().items() if k != "credentials" -} -DEVICE_CONFIG_DICT_AES = { - k: v for k, v in DEVICE_CONFIG_AES.to_dict().items() if k != "credentials" -} -CREATE_ENTRY_DATA_LEGACY = { - CONF_HOST: IP_ADDRESS, - CONF_ALIAS: ALIAS, - CONF_MODEL: MODEL, - CONF_CONNECTION_PARAMETERS: CONN_PARAMS_LEGACY.to_dict(), - CONF_USES_HTTP: False, -} - -CREATE_ENTRY_DATA_KLAP = { - CONF_HOST: IP_ADDRESS, - CONF_ALIAS: ALIAS, - CONF_MODEL: MODEL, - CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_KLAP, - CONF_CONNECTION_PARAMETERS: CONN_PARAMS_KLAP.to_dict(), - CONF_USES_HTTP: True, -} -CREATE_ENTRY_DATA_AES = { - CONF_HOST: IP_ADDRESS2, - CONF_ALIAS: ALIAS, - CONF_MODEL: MODEL, - CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_AES, - CONF_CONNECTION_PARAMETERS: CONN_PARAMS_AES.to_dict(), - CONF_USES_HTTP: True, - CONF_AES_KEYS: AES_KEYS, -} -CREATE_ENTRY_DATA_AES_CAMERA = { - CONF_HOST: IP_ADDRESS3, - CONF_ALIAS: ALIAS_CAMERA, - CONF_MODEL: MODEL_CAMERA, - CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_AES, - CONF_CONNECTION_PARAMETERS: CONN_PARAMS_AES_CAMERA.to_dict(), - CONF_USES_HTTP: True, - CONF_LIVE_VIEW: True, - CONF_CAMERA_CREDENTIALS: {"username": "camuser", "password": "campass"}, -} -SMALLEST_VALID_JPEG = ( - "ffd8ffe000104a46494600010101004800480000ffdb00430003020202020203020202030303030406040404040408060" - "6050609080a0a090809090a0c0f0c0a0b0e0b09090d110d0e0f101011100a0c12131210130f101010ffc9000b08000100" - "0101011100ffcc000600101005ffda0008010100003f00d2cf20ffd9" -) -SMALLEST_VALID_JPEG_BYTES = bytes.fromhex(SMALLEST_VALID_JPEG) - def _load_feature_fixtures(): fixtures = load_json_value_fixture("features.json", DOMAIN) @@ -201,7 +63,7 @@ async def setup_platform_for_device( _patch_discovery(device=device), _patch_connect(device=device), ): - await async_setup_component(hass, DOMAIN, {DOMAIN: {}}) + await hass.config_entries.async_setup(config_entry.entry_id) # Good practice to wait background tasks in tests see PR #112726 await hass.async_block_till_done(wait_background_tasks=True) diff --git a/tests/components/tplink/conftest.py b/tests/components/tplink/conftest.py index f1bbb80b80c..19cd5aa9acf 100644 --- a/tests/components/tplink/conftest.py +++ b/tests/components/tplink/conftest.py @@ -10,7 +10,8 @@ import pytest from homeassistant.components.tplink import DOMAIN from homeassistant.core import HomeAssistant -from . import ( +from . import _mocked_device +from .const import ( ALIAS_CAMERA, CREATE_ENTRY_DATA_AES_CAMERA, CREATE_ENTRY_DATA_LEGACY, @@ -26,7 +27,6 @@ from . import ( MAC_ADDRESS2, MAC_ADDRESS3, MODEL_CAMERA, - _mocked_device, ) from tests.common import MockConfigEntry @@ -115,8 +115,12 @@ def mock_setup_entry() -> Generator[AsyncMock]: @pytest.fixture -def mock_init() -> Generator[AsyncMock]: - """Override async_setup_entry.""" +def mock_init() -> Generator[dict[str, AsyncMock]]: + """Override async_setup and async_setup_entry. + + This fixture must be declared before the hass fixture to avoid errors + in the logs during teardown of the hass fixture which calls async_unload. + """ with patch.multiple( "homeassistant.components.tplink", async_setup=DEFAULT, diff --git a/tests/components/tplink/const.py b/tests/components/tplink/const.py new file mode 100644 index 00000000000..57829a7aa34 --- /dev/null +++ b/tests/components/tplink/const.py @@ -0,0 +1,146 @@ +"""Constants for the tplink component tests.""" + +from kasa import ( + DeviceConfig, + DeviceConnectionParameters, + DeviceEncryptionType, + DeviceFamily, +) + +from homeassistant.components.tplink import ( + CONF_AES_KEYS, + CONF_ALIAS, + CONF_CAMERA_CREDENTIALS, + CONF_CONNECTION_PARAMETERS, + CONF_CREDENTIALS_HASH, + CONF_HOST, + CONF_LIVE_VIEW, + CONF_MODEL, + CONF_USES_HTTP, + Credentials, +) + +MODULE = "homeassistant.components.tplink" +MODULE_CONFIG_FLOW = "homeassistant.components.tplink.config_flow" +IP_ADDRESS = "127.0.0.1" +IP_ADDRESS2 = "127.0.0.2" +IP_ADDRESS3 = "127.0.0.3" +ALIAS = "My Bulb" +ALIAS_CAMERA = "My Camera" +MODEL = "HS100" +MODEL_CAMERA = "C210" +MAC_ADDRESS = "aa:bb:cc:dd:ee:ff" +DEVICE_ID = "123456789ABCDEFGH" +DEVICE_ID_MAC = "AA:BB:CC:DD:EE:FF" +DHCP_FORMATTED_MAC_ADDRESS = MAC_ADDRESS.replace(":", "") +MAC_ADDRESS2 = "11:22:33:44:55:66" +MAC_ADDRESS3 = "66:55:44:33:22:11" +DEFAULT_ENTRY_TITLE = f"{ALIAS} {MODEL}" +DEFAULT_ENTRY_TITLE_CAMERA = f"{ALIAS_CAMERA} {MODEL_CAMERA}" +CREDENTIALS_HASH_LEGACY = "" +CONN_PARAMS_LEGACY = DeviceConnectionParameters( + DeviceFamily.IotSmartPlugSwitch, DeviceEncryptionType.Xor +) +DEVICE_CONFIG_LEGACY = DeviceConfig(IP_ADDRESS) +DEVICE_CONFIG_DICT_LEGACY = { + k: v for k, v in DEVICE_CONFIG_LEGACY.to_dict().items() if k != "credentials" +} +CREDENTIALS = Credentials("foo", "bar") +CREDENTIALS_HASH_AES = "AES/abcdefghijklmnopqrstuvabcdefghijklmnopqrstuv==" +CREDENTIALS_HASH_KLAP = "KLAP/abcdefghijklmnopqrstuv==" +CONN_PARAMS_KLAP = DeviceConnectionParameters( + DeviceFamily.SmartTapoPlug, DeviceEncryptionType.Klap +) +DEVICE_CONFIG_KLAP = DeviceConfig( + IP_ADDRESS, + credentials=CREDENTIALS, + connection_type=CONN_PARAMS_KLAP, + uses_http=True, +) +CONN_PARAMS_AES = DeviceConnectionParameters( + DeviceFamily.SmartTapoPlug, DeviceEncryptionType.Aes +) +_test_privkey = ( + "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKLJKmBWGj6WYo9sewI8vkqar" + "Ed5H1JUr8Jj/LEWLTtV6+Mm4mfyEk6YKFHSmIG4AGgrVsGK/EbEkTZk9CwtixNQpBVc36oN2R" + "vuWWV38YnP4vI63mNxTA/gQonCsahjN4HfwE87pM7O5z39aeunoYm6Be663t33DbJH1ZUbZjm" + "tAgMBAAECgYB1Bn1KaFvRprcQOIJt51E9vNghQbf8rhj0fIEKpdC6mVhNIoUdCO+URNqnh+hP" + "SQIx4QYreUlHbsSeABFxOQSDJm6/kqyQsp59nCVDo/bXTtlvcSJ/sU3riqJNxYqEU1iJ0xMvU" + "N1VKKTmik89J8e5sN9R0AFfUSJIk7MpdOoD2QJBANTbV27nenyvbqee/ul4frdt2rrPGcGpcV" + "QmY87qbbrZgqgL5LMHHD7T/v/I8D1wRog1sBz/AiZGcnv/ox8dHKsCQQDDx8DCGPySSVqKVua" + "yUkBNpglN83wiCXZjyEtWIt+aB1A2n5ektE/o8oHnnOuvMdooxvtid7Mdapi2VLHV7VMHAkAE" + "d0GjWwnv2cJpk+VnQpbuBEkFiFjS/loZWODZM4Pv2qZqHi3DL9AA5XPBLBcWQufH7dBvG06RP" + "QMj5N4oRfUXAkEAuJJkVliqHNvM4OkGewzyFII4+WVYHNqg43dcFuuvtA27AJQ6qYtYXrvp3k" + "phI3yzOIhHTNCea1goepSkR5ODFwJBAJCTRbB+P47aEr/xA51ZFHE6VefDBJG9yg6yK4jcOxg" + "5ficXEpx8442okNtlzwa+QHpm/L3JOFrHwiEeVqXtiqY=" +) +_test_pubkey = ( + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiySpgVho+lmKPbHsCPL5KmqxHeR9SVK/CY" + "/yxFi07VevjJuJn8hJOmChR0piBuABoK1bBivxGxJE2ZPQsLYsTUKQVXN+qDdkb7llld/GJz+" + "LyOt5jcUwP4EKJwrGoYzeB38BPO6TOzuc9/Wnrp6GJugXuut7d9w2yR9WVG2Y5rQIDAQAB" +) +AES_KEYS = {"private": _test_privkey, "public": _test_pubkey} +DEVICE_CONFIG_AES = DeviceConfig( + IP_ADDRESS2, + credentials=CREDENTIALS, + connection_type=CONN_PARAMS_AES, + uses_http=True, + aes_keys=AES_KEYS, +) +CONN_PARAMS_AES_CAMERA = DeviceConnectionParameters( + DeviceFamily.SmartIpCamera, DeviceEncryptionType.Aes, https=True, login_version=2 +) +DEVICE_CONFIG_AES_CAMERA = DeviceConfig( + IP_ADDRESS3, + credentials=CREDENTIALS, + connection_type=CONN_PARAMS_AES_CAMERA, + uses_http=True, +) + +DEVICE_CONFIG_DICT_KLAP = { + k: v for k, v in DEVICE_CONFIG_KLAP.to_dict().items() if k != "credentials" +} +DEVICE_CONFIG_DICT_AES = { + k: v for k, v in DEVICE_CONFIG_AES.to_dict().items() if k != "credentials" +} +CREATE_ENTRY_DATA_LEGACY = { + CONF_HOST: IP_ADDRESS, + CONF_ALIAS: ALIAS, + CONF_MODEL: MODEL, + CONF_CONNECTION_PARAMETERS: CONN_PARAMS_LEGACY.to_dict(), + CONF_USES_HTTP: False, +} + +CREATE_ENTRY_DATA_KLAP = { + CONF_HOST: IP_ADDRESS, + CONF_ALIAS: ALIAS, + CONF_MODEL: MODEL, + CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_KLAP, + CONF_CONNECTION_PARAMETERS: CONN_PARAMS_KLAP.to_dict(), + CONF_USES_HTTP: True, +} +CREATE_ENTRY_DATA_AES = { + CONF_HOST: IP_ADDRESS2, + CONF_ALIAS: ALIAS, + CONF_MODEL: MODEL, + CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_AES, + CONF_CONNECTION_PARAMETERS: CONN_PARAMS_AES.to_dict(), + CONF_USES_HTTP: True, + CONF_AES_KEYS: AES_KEYS, +} +CREATE_ENTRY_DATA_AES_CAMERA = { + CONF_HOST: IP_ADDRESS3, + CONF_ALIAS: ALIAS_CAMERA, + CONF_MODEL: MODEL_CAMERA, + CONF_CREDENTIALS_HASH: CREDENTIALS_HASH_AES, + CONF_CONNECTION_PARAMETERS: CONN_PARAMS_AES_CAMERA.to_dict(), + CONF_USES_HTTP: True, + CONF_LIVE_VIEW: True, + CONF_CAMERA_CREDENTIALS: {"username": "camuser", "password": "campass"}, +} +SMALLEST_VALID_JPEG = ( + "ffd8ffe000104a46494600010101004800480000ffdb00430003020202020203020202030303030406040404040408060" + "6050609080a0a090809090a0c0f0c0a0b0e0b09090d110d0e0f101011100a0c12131210130f101010ffc9000b08000100" + "0101011100ffcc000600101005ffda0008010100003f00d2cf20ffd9" +) +SMALLEST_VALID_JPEG_BYTES = bytes.fromhex(SMALLEST_VALID_JPEG) diff --git a/tests/components/tplink/test_binary_sensor.py b/tests/components/tplink/test_binary_sensor.py index e2b9cd08d13..b487fa51baf 100644 --- a/tests/components/tplink/test_binary_sensor.py +++ b/tests/components/tplink/test_binary_sensor.py @@ -4,18 +4,14 @@ from kasa import Feature import pytest from syrupy.assertion import SnapshotAssertion -from homeassistant.components import tplink from homeassistant.components.tplink.binary_sensor import BINARY_SENSOR_DESCRIPTIONS from homeassistant.components.tplink.const import DOMAIN from homeassistant.components.tplink.entity import EXCLUDED_FEATURES from homeassistant.const import CONF_HOST, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er -from homeassistant.setup import async_setup_component from . import ( - DEVICE_ID, - MAC_ADDRESS, _mocked_device, _mocked_feature, _mocked_strip_children, @@ -24,6 +20,7 @@ from . import ( setup_platform_for_device, snapshot_platform, ) +from .const import DEVICE_ID, MAC_ADDRESS from tests.common import MockConfigEntry @@ -47,7 +44,7 @@ async def test_states( device_registry: dr.DeviceRegistry, snapshot: SnapshotAssertion, ) -> None: - """Test a sensor unique ids.""" + """Test binary sensor states.""" features = {description.key for description in BINARY_SENSOR_DESCRIPTIONS} features.update(EXCLUDED_FEATURES) device = _mocked_device(alias="my_device", features=features) @@ -68,7 +65,7 @@ async def test_binary_sensor( entity_registry: er.EntityRegistry, mocked_feature_binary_sensor: Feature, ) -> None: - """Test a sensor unique ids.""" + """Test binary sensor unique ids.""" mocked_feature = mocked_feature_binary_sensor already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS @@ -77,7 +74,7 @@ async def test_binary_sensor( plug = _mocked_device(alias="my_plug", features=[mocked_feature]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() # The entity_id is based on standard name from core. @@ -93,7 +90,7 @@ async def test_binary_sensor_children( device_registry: dr.DeviceRegistry, mocked_feature_binary_sensor: Feature, ) -> None: - """Test a sensor unique ids.""" + """Test binary sensor children.""" mocked_feature = mocked_feature_binary_sensor already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS @@ -105,7 +102,7 @@ async def test_binary_sensor_children( children=_mocked_strip_children(features=[mocked_feature]), ) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "binary_sensor.my_plug_overheated" diff --git a/tests/components/tplink/test_button.py b/tests/components/tplink/test_button.py index a3eb8950336..c36d08337a7 100644 --- a/tests/components/tplink/test_button.py +++ b/tests/components/tplink/test_button.py @@ -4,7 +4,6 @@ from kasa import Feature import pytest from syrupy.assertion import SnapshotAssertion -from homeassistant.components import tplink from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS from homeassistant.components.tplink.button import BUTTON_DESCRIPTIONS from homeassistant.components.tplink.const import DOMAIN @@ -16,11 +15,8 @@ from homeassistant.helpers import ( entity_registry as er, issue_registry as ir, ) -from homeassistant.setup import async_setup_component from . import ( - DEVICE_ID, - MAC_ADDRESS, _mocked_device, _mocked_feature, _mocked_strip_children, @@ -30,6 +26,7 @@ from . import ( setup_platform_for_device, snapshot_platform, ) +from .const import DEVICE_ID, MAC_ADDRESS from tests.common import MockConfigEntry @@ -83,7 +80,7 @@ def create_deprecated_child_button_entities( @pytest.fixture def mocked_feature_button() -> Feature: - """Return mocked tplink binary sensor feature.""" + """Return mocked tplink button feature.""" return _mocked_feature( "test_alarm", value="", @@ -101,7 +98,7 @@ async def test_states( snapshot: SnapshotAssertion, create_deprecated_button_entities, ) -> None: - """Test a sensor unique ids.""" + """Test button states.""" features = {description.key for description in BUTTON_DESCRIPTIONS} features.update(EXCLUDED_FEATURES) device = _mocked_device(alias="my_device", features=features) @@ -118,14 +115,15 @@ async def test_states( async def test_button( hass: HomeAssistant, entity_registry: er.EntityRegistry, + mock_config_entry: MockConfigEntry, mocked_feature_button: Feature, create_deprecated_button_entities, ) -> None: - """Test a sensor unique ids.""" + """Test button unique ids.""" mocked_feature = mocked_feature_button plug = _mocked_device(alias="my_device", features=[mocked_feature]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() # The entity_id is based on standard name from core. @@ -139,11 +137,12 @@ async def test_button_children( hass: HomeAssistant, entity_registry: er.EntityRegistry, device_registry: dr.DeviceRegistry, + mock_config_entry: MockConfigEntry, mocked_feature_button: Feature, create_deprecated_button_entities, create_deprecated_child_button_entities, ) -> None: - """Test a sensor unique ids.""" + """Test button children.""" mocked_feature = mocked_feature_button plug = _mocked_device( alias="my_device", @@ -151,7 +150,7 @@ async def test_button_children( children=_mocked_strip_children(features=[mocked_feature]), ) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() entity_id = "button.my_device_test_alarm" @@ -173,6 +172,7 @@ async def test_button_children( async def test_button_press( hass: HomeAssistant, entity_registry: er.EntityRegistry, + mock_config_entry: MockConfigEntry, mocked_feature_button: Feature, create_deprecated_button_entities, ) -> None: @@ -180,7 +180,7 @@ async def test_button_press( mocked_feature = mocked_feature_button plug = _mocked_device(alias="my_device", features=[mocked_feature]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() entity_id = "button.my_device_test_alarm" @@ -213,7 +213,7 @@ async def test_button_not_exists_with_deprecation( mocked_feature = mocked_feature_button dev = _mocked_device(alias="my_device", features=[mocked_feature]) with _patch_discovery(device=dev), _patch_connect(device=dev): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert not entity_registry.async_get(entity_id) @@ -265,7 +265,7 @@ async def test_button_exists_with_deprecation( mocked_feature = mocked_feature_button dev = _mocked_device(alias="my_device", features=[mocked_feature]) with _patch_discovery(device=dev), _patch_connect(device=dev): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() entity = entity_registry.async_get(entity_id) diff --git a/tests/components/tplink/test_camera.py b/tests/components/tplink/test_camera.py index aa83ae659fb..ceb74e3a61a 100644 --- a/tests/components/tplink/test_camera.py +++ b/tests/components/tplink/test_camera.py @@ -11,6 +11,9 @@ from syrupy.assertion import SnapshotAssertion from homeassistant.components import stream from homeassistant.components.camera import ( + DOMAIN as CAMERA_DOMAIN, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, CameraEntityFeature, StreamType, async_get_image, @@ -23,15 +26,8 @@ from homeassistant.const import Platform from homeassistant.core import HomeAssistant, HomeAssistantError from homeassistant.helpers import device_registry as dr, entity_registry as er -from . import ( - DEVICE_ID, - IP_ADDRESS3, - MAC_ADDRESS3, - SMALLEST_VALID_JPEG_BYTES, - _mocked_device, - setup_platform_for_device, - snapshot_platform, -) +from . import _mocked_device, setup_platform_for_device, snapshot_platform +from .const import DEVICE_ID, IP_ADDRESS3, MAC_ADDRESS3, SMALLEST_VALID_JPEG_BYTES from tests.common import MockConfigEntry, async_fire_time_changed from tests.typing import WebSocketGenerator @@ -44,7 +40,7 @@ async def test_states( device_registry: dr.DeviceRegistry, snapshot: SnapshotAssertion, ) -> None: - """Test states.""" + """Test camera states.""" mock_camera_config_entry.add_to_hass(hass) mock_device = _mocked_device( @@ -73,6 +69,7 @@ async def test_camera_unique_id( hass: HomeAssistant, mock_camera_config_entry: MockConfigEntry, device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, ) -> None: """Test camera unique id.""" mock_device = _mocked_device( @@ -92,14 +89,13 @@ async def test_camera_unique_id( ) assert device_entries entity_id = "camera.my_camera_live_view" - entity_registry = er.async_get(hass) + assert entity_registry.async_get(entity_id).unique_id == f"{DEVICE_ID}-live_view" async def test_handle_mjpeg_stream( hass: HomeAssistant, mock_camera_config_entry: MockConfigEntry, - freezer: FrozenDateTimeFactory, ) -> None: """Test handle_async_mjpeg_stream.""" mock_device = _mocked_device( @@ -126,7 +122,6 @@ async def test_handle_mjpeg_stream( async def test_handle_mjpeg_stream_not_supported( hass: HomeAssistant, mock_camera_config_entry: MockConfigEntry, - freezer: FrozenDateTimeFactory, ) -> None: """Test handle_async_mjpeg_stream.""" mock_device = _mocked_device( @@ -216,7 +211,7 @@ async def test_no_camera_image_when_streaming( mock_camera_config_entry: MockConfigEntry, freezer: FrozenDateTimeFactory, ) -> None: - """Test async_get_image.""" + """Test no camera image when streaming.""" mock_device = _mocked_device( modules=[Module.Camera], alias="my_camera", @@ -272,9 +267,8 @@ async def test_no_camera_image_when_streaming( async def test_no_concurrent_camera_image( hass: HomeAssistant, mock_camera_config_entry: MockConfigEntry, - freezer: FrozenDateTimeFactory, ) -> None: - """Test async_get_image.""" + """Test async_get_image doesn't make concurrent requests.""" mock_device = _mocked_device( modules=[Module.Camera], alias="my_camera", @@ -321,7 +315,7 @@ async def test_camera_image_auth_error( mock_connect: AsyncMock, mock_discovery: AsyncMock, ) -> None: - """Test async_get_image.""" + """Test async_get_image auth error.""" mock_device = _mocked_device( modules=[Module.Camera], alias="my_camera", @@ -367,7 +361,7 @@ async def test_camera_stream_source( mock_camera_config_entry: MockConfigEntry, hass_ws_client: WebSocketGenerator, ) -> None: - """Test async_get_image. + """Test camera stream source. This test would fail if the integration didn't properly put stream in the dependencies. @@ -444,16 +438,16 @@ async def test_camera_turn_on_off( assert state is not None await hass.services.async_call( - "camera", - "turn_on", + CAMERA_DOMAIN, + SERVICE_TURN_ON, {"entity_id": "camera.my_camera_live_view"}, blocking=True, ) mock_camera.set_state.assert_called_with(True) await hass.services.async_call( - "camera", - "turn_off", + CAMERA_DOMAIN, + SERVICE_TURN_OFF, {"entity_id": "camera.my_camera_live_view"}, blocking=True, ) diff --git a/tests/components/tplink/test_climate.py b/tests/components/tplink/test_climate.py index 3a54048e1d6..b1c8abd3a9b 100644 --- a/tests/components/tplink/test_climate.py +++ b/tests/components/tplink/test_climate.py @@ -27,12 +27,12 @@ from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.util import dt as dt_util from . import ( - DEVICE_ID, _mocked_device, _mocked_feature, setup_platform_for_device, snapshot_platform, ) +from .const import DEVICE_ID from tests.common import MockConfigEntry, async_fire_time_changed @@ -41,7 +41,7 @@ ENTITY_ID = "climate.thermostat" @pytest.fixture async def mocked_hub(hass: HomeAssistant) -> Device: - """Return mocked tplink binary sensor feature.""" + """Return mocked tplink hub.""" features = [ _mocked_feature( @@ -166,7 +166,8 @@ async def test_set_hvac_mode( ) mocked_state.set_value.assert_called_with(True) - with pytest.raises(ServiceValidationError): + msg = "Tried to set unsupported mode: dry" + with pytest.raises(ServiceValidationError, match=msg): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, diff --git a/tests/components/tplink/test_config_flow.py b/tests/components/tplink/test_config_flow.py index 14f1260e2ec..08903e29a71 100644 --- a/tests/components/tplink/test_config_flow.py +++ b/tests/components/tplink/test_config_flow.py @@ -37,7 +37,9 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType -from . import ( +from . import _mocked_device, _patch_connect, _patch_discovery, _patch_single_discovery +from .conftest import override_side_effect +from .const import ( AES_KEYS, ALIAS, ALIAS_CAMERA, @@ -67,12 +69,7 @@ from . import ( MODEL_CAMERA, MODULE, SMALLEST_VALID_JPEG_BYTES, - _mocked_device, - _patch_connect, - _patch_discovery, - _patch_single_discovery, ) -from .conftest import override_side_effect from tests.common import MockConfigEntry @@ -168,8 +165,11 @@ async def test_discovery( assert result2["reason"] == "no_devices_found" +@pytest.mark.usefixtures("mock_init") async def test_discovery_camera( - hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, mock_init + hass: HomeAssistant, + mock_discovery: AsyncMock, + mock_connect: AsyncMock, ) -> None: """Test authenticated discovery for camera with stream.""" mock_device = _mocked_device( @@ -228,8 +228,11 @@ async def test_discovery_camera( assert result["context"]["unique_id"] == MAC_ADDRESS3 +@pytest.mark.usefixtures("mock_init") async def test_discovery_pick_device_camera( - hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, mock_init + hass: HomeAssistant, + mock_discovery: AsyncMock, + mock_connect: AsyncMock, ) -> None: """Test authenticated discovery for camera with stream.""" mock_device = _mocked_device( @@ -293,8 +296,11 @@ async def test_discovery_pick_device_camera( assert result["context"]["unique_id"] == MAC_ADDRESS3 +@pytest.mark.usefixtures("mock_init") async def test_discovery_auth( - hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, mock_init + hass: HomeAssistant, + mock_discovery: AsyncMock, + mock_connect: AsyncMock, ) -> None: """Test authenticated discovery.""" mock_device = _mocked_device( @@ -336,8 +342,11 @@ async def test_discovery_auth( assert result2["context"]["unique_id"] == MAC_ADDRESS +@pytest.mark.usefixtures("mock_init") async def test_discovery_auth_camera( - hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, mock_init + hass: HomeAssistant, + mock_discovery: AsyncMock, + mock_connect: AsyncMock, ) -> None: """Test authenticated discovery for camera with stream.""" mock_device = _mocked_device( @@ -407,13 +416,13 @@ async def test_discovery_auth_camera( ], ids=["invalid-auth", "unknown-error"], ) +@pytest.mark.usefixtures("mock_init") async def test_discovery_auth_errors( hass: HomeAssistant, mock_connect: AsyncMock, - mock_init, - error_type, - errors_msg, - error_placement, + error_type: Exception, + errors_msg: str, + error_placement: str, ) -> None: """Test handling of discovery authentication errors. @@ -465,10 +474,10 @@ async def test_discovery_auth_errors( assert result3["context"]["unique_id"] == MAC_ADDRESS +@pytest.mark.usefixtures("mock_init") async def test_discovery_new_credentials( hass: HomeAssistant, mock_connect: AsyncMock, - mock_init, ) -> None: """Test setting up discovery with new credentials.""" mock_device = mock_connect["mock_devices"][IP_ADDRESS] @@ -514,10 +523,10 @@ async def test_discovery_new_credentials( assert result3["context"]["unique_id"] == MAC_ADDRESS +@pytest.mark.usefixtures("mock_init") async def test_discovery_new_credentials_invalid( hass: HomeAssistant, mock_connect: AsyncMock, - mock_init, ) -> None: """Test setting up discovery with new invalid credentials.""" mock_device = mock_connect["mock_devices"][IP_ADDRESS] @@ -977,11 +986,11 @@ async def test_manual_no_capabilities(hass: HomeAssistant) -> None: assert result["context"]["unique_id"] == MAC_ADDRESS +@pytest.mark.usefixtures("mock_init") async def test_manual_auth( hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, - mock_init, ) -> None: """Test manually setup.""" result = await hass.config_entries.flow.async_init( @@ -1083,14 +1092,14 @@ async def test_manual_auth_camera( ], ids=["invalid-auth", "unknown-error"], ) +@pytest.mark.usefixtures("mock_init") async def test_manual_auth_errors( hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, - mock_init, - error_type, - errors_msg, - error_placement, + error_type: Exception, + errors_msg: str, + error_placement: str, ) -> None: """Test manually setup auth errors.""" result = await hass.config_entries.flow.async_init( @@ -1150,9 +1159,9 @@ async def test_manual_port_override( hass: HomeAssistant, mock_connect: AsyncMock, mock_discovery: AsyncMock, - host_str, - host, - port, + host_str: str, + host: str, + port: int, ) -> None: """Test manually setup.""" config = DeviceConfig( @@ -1342,7 +1351,7 @@ async def test_discovered_by_discovery_and_dhcp(hass: HomeAssistant) -> None: ], ) async def test_discovered_by_dhcp_or_discovery( - hass: HomeAssistant, source, data + hass: HomeAssistant, source: str, data: dict ) -> None: """Test we can setup when discovered from dhcp or discovery.""" @@ -1396,7 +1405,7 @@ async def test_discovered_by_dhcp_or_discovery( ], ) async def test_discovered_by_dhcp_or_discovery_failed_to_get_device( - hass: HomeAssistant, source, data + hass: HomeAssistant, source: str, data: dict ) -> None: """Test we abort if we cannot get the unique id when discovered from dhcp.""" @@ -1419,7 +1428,7 @@ async def test_integration_discovery_with_ip_change( mock_discovery: AsyncMock, mock_connect: AsyncMock, ) -> None: - """Test reauth flow.""" + """Test integration updates ip address from discovery.""" mock_config_entry.add_to_hass(hass) with ( patch("homeassistant.components.tplink.Discover.discover", return_value={}), @@ -1670,7 +1679,7 @@ async def test_reauth_camera( mock_discovery: AsyncMock, mock_connect: AsyncMock, ) -> None: - """Test async_get_image.""" + """Test reauth flow on invalid camera credentials.""" mock_device = mock_connect["mock_devices"][IP_ADDRESS3] mock_camera_config_entry.add_to_hass(hass) mock_camera_config_entry.async_start_reauth( @@ -1762,7 +1771,7 @@ async def test_reauth_try_connect_all_fail( override_side_effect(mock_discovery["discover_single"], TimeoutError), override_side_effect(mock_discovery["try_connect_all"], lambda *_, **__: None), ): - result2 = await hass.config_entries.flow.async_configure( + result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={ CONF_USERNAME: "fake_username", @@ -1774,7 +1783,23 @@ async def test_reauth_try_connect_all_fail( IP_ADDRESS, credentials=credentials, port=None ) mock_discovery["try_connect_all"].assert_called_once() - assert result2["errors"] == {"base": "cannot_connect"} + assert result["errors"] == {"base": "cannot_connect"} + + mock_discovery["try_connect_all"].reset_mock() + with ( + override_side_effect(mock_discovery["discover_single"], TimeoutError), + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={ + CONF_USERNAME: "fake_username", + CONF_PASSWORD: "fake_password", + }, + ) + + mock_discovery["try_connect_all"].assert_called_once() + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reauth_successful" async def test_reauth_update_with_encryption_change( @@ -2025,9 +2050,9 @@ async def test_reauth_errors( mock_added_config_entry: MockConfigEntry, mock_discovery: AsyncMock, mock_connect: AsyncMock, - error_type, - errors_msg, - error_placement, + error_type: Exception, + errors_msg: str, + error_placement: str, ) -> None: """Test reauth errors.""" mock_added_config_entry.async_start_reauth(hass) @@ -2089,8 +2114,8 @@ async def test_pick_device_errors( hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, - error_type, - expected_flow, + error_type: type[Exception], + expected_flow: FlowResultType, ) -> None: """Test errors on pick_device.""" result = await hass.config_entries.flow.async_init( @@ -2127,11 +2152,11 @@ async def test_pick_device_errors( assert result4["context"]["unique_id"] == MAC_ADDRESS +@pytest.mark.usefixtures("mock_init") async def test_discovery_timeout_try_connect_all( hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, - mock_init, ) -> None: """Test discovery tries legacy connect on timeout.""" result = await hass.config_entries.flow.async_init( @@ -2153,11 +2178,11 @@ async def test_discovery_timeout_try_connect_all( assert mock_connect["connect"].call_count == 1 +@pytest.mark.usefixtures("mock_init") async def test_discovery_timeout_try_connect_all_needs_creds( hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, - mock_init, ) -> None: """Test discovery tries legacy connect on timeout.""" result = await hass.config_entries.flow.async_init( @@ -2191,11 +2216,11 @@ async def test_discovery_timeout_try_connect_all_needs_creds( assert mock_connect["connect"].call_count == 1 +@pytest.mark.usefixtures("mock_init") async def test_discovery_timeout_try_connect_all_fail( hass: HomeAssistant, mock_discovery: AsyncMock, mock_connect: AsyncMock, - mock_init, ) -> None: """Test discovery tries legacy connect on timeout.""" result = await hass.config_entries.flow.async_init( diff --git a/tests/components/tplink/test_fan.py b/tests/components/tplink/test_fan.py index deba33abfa5..13a768f683c 100644 --- a/tests/components/tplink/test_fan.py +++ b/tests/components/tplink/test_fan.py @@ -2,8 +2,7 @@ from __future__ import annotations -from datetime import timedelta - +from freezegun.api import FrozenDateTimeFactory from kasa import Device, Module from syrupy.assertion import SnapshotAssertion @@ -11,13 +10,15 @@ from homeassistant.components.fan import ( ATTR_PERCENTAGE, DOMAIN as FAN_DOMAIN, SERVICE_SET_PERCENTAGE, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, ) from homeassistant.const import ATTR_ENTITY_ID, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er -import homeassistant.util.dt as dt_util -from . import DEVICE_ID, _mocked_device, setup_platform_for_device, snapshot_platform +from . import _mocked_device, setup_platform_for_device, snapshot_platform +from .const import DEVICE_ID from tests.common import MockConfigEntry, async_fire_time_changed @@ -56,6 +57,7 @@ async def test_fan_unique_id( hass: HomeAssistant, mock_config_entry: MockConfigEntry, device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, ) -> None: """Test a fan unique id.""" fan = _mocked_device(modules=[Module.Fan], alias="my_fan") @@ -66,12 +68,16 @@ async def test_fan_unique_id( ) assert device_entries entity_id = "fan.my_fan" - entity_registry = er.async_get(hass) + assert entity_registry.async_get(entity_id).unique_id == DEVICE_ID -async def test_fan(hass: HomeAssistant, mock_config_entry: MockConfigEntry) -> None: - """Test a color fan and that all transitions are correctly passed.""" +async def test_fan( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + freezer: FrozenDateTimeFactory, +) -> None: + """Test fan functionality.""" device = _mocked_device(modules=[Module.Fan], alias="my_fan") fan = device.modules[Module.Fan] fan.fan_speed_level = 0 @@ -83,26 +89,29 @@ async def test_fan(hass: HomeAssistant, mock_config_entry: MockConfigEntry) -> N assert state.state == "off" await hass.services.async_call( - FAN_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + FAN_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) fan.set_fan_speed_level.assert_called_once_with(4) fan.set_fan_speed_level.reset_mock() fan.fan_speed_level = 4 - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10)) + + freezer.tick(10) + async_fire_time_changed(hass) + await hass.async_block_till_done(wait_background_tasks=True) state = hass.states.get(entity_id) assert state.state == "on" await hass.services.async_call( - FAN_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True + FAN_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True ) fan.set_fan_speed_level.assert_called_once_with(0) fan.set_fan_speed_level.reset_mock() await hass.services.async_call( FAN_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_PERCENTAGE: 50}, blocking=True, ) diff --git a/tests/components/tplink/test_init.py b/tests/components/tplink/test_init.py index 59cdda3ad92..7dbd723aa2d 100644 --- a/tests/components/tplink/test_init.py +++ b/tests/components/tplink/test_init.py @@ -38,6 +38,14 @@ from homeassistant.setup import async_setup_component from homeassistant.util import dt as dt_util from . import ( + _mocked_device, + _mocked_feature, + _patch_connect, + _patch_discovery, + _patch_single_discovery, +) +from .conftest import override_side_effect +from .const import ( ALIAS, CREATE_ENTRY_DATA_AES, CREATE_ENTRY_DATA_KLAP, @@ -53,13 +61,7 @@ from . import ( IP_ADDRESS, MAC_ADDRESS, MODEL, - _mocked_device, - _mocked_feature, - _patch_connect, - _patch_discovery, - _patch_single_discovery, ) -from .conftest import override_side_effect from tests.common import MockConfigEntry, async_fire_time_changed @@ -98,7 +100,7 @@ async def test_config_entry_reload(hass: HomeAssistant) -> None: ) already_migrated_config_entry.add_to_hass(hass) with _patch_discovery(), _patch_single_discovery(), _patch_connect(): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() assert already_migrated_config_entry.state is ConfigEntryState.LOADED await hass.config_entries.async_unload(already_migrated_config_entry.entry_id) @@ -117,7 +119,7 @@ async def test_config_entry_retry(hass: HomeAssistant) -> None: _patch_single_discovery(no_device=True), _patch_connect(no_device=True), ): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() assert already_migrated_config_entry.state is ConfigEntryState.SETUP_RETRY @@ -175,7 +177,7 @@ async def test_config_entry_wrong_mac_Address( ) already_migrated_config_entry.add_to_hass(hass) with _patch_discovery(), _patch_single_discovery(), _patch_connect(): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() assert already_migrated_config_entry.state is ConfigEntryState.SETUP_RETRY @@ -309,7 +311,7 @@ async def test_plug_auth_fails(hass: HomeAssistant) -> None: config_entry.add_to_hass(hass) device = _mocked_device(alias="my_plug", features=["state"]) with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() entity_id = "switch.my_plug" @@ -355,7 +357,7 @@ async def test_update_attrs_fails_in_init( type(light_module).color_temp = p light.__str__ = lambda _: "MockLight" with _patch_discovery(device=light), _patch_connect(device=light): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -388,7 +390,7 @@ async def test_update_attrs_fails_on_update( light_module = light.modules[Module.Light] with _patch_discovery(device=light), _patch_connect(device=light): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -434,7 +436,7 @@ async def test_feature_no_category( ) dev.features["led"].category = Feature.Category.Unset with _patch_discovery(device=dev), _patch_connect(device=dev): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "switch.my_plug_led" diff --git a/tests/components/tplink/test_light.py b/tests/components/tplink/test_light.py index e19f2e11a40..565d4f1221a 100644 --- a/tests/components/tplink/test_light.py +++ b/tests/components/tplink/test_light.py @@ -20,6 +20,11 @@ from kasa.iot import IotDevice import pytest from homeassistant.components import tplink +from homeassistant.components.homeassistant.scene import ( + CONF_SCENE_ID, + CONF_SNAPSHOT, + SERVICE_CREATE, +) from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_COLOR_MODE, @@ -35,7 +40,10 @@ from homeassistant.components.light import ( ATTR_XY_COLOR, DOMAIN as LIGHT_DOMAIN, EFFECT_OFF, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, ) +from homeassistant.components.scene import DOMAIN as SCENE_DOMAIN from homeassistant.components.tplink.const import DOMAIN from homeassistant.components.tplink.light import ( SERVICE_RANDOM_EFFECT, @@ -56,14 +64,13 @@ from homeassistant.setup import async_setup_component import homeassistant.util.dt as dt_util from . import ( - DEVICE_ID, - MAC_ADDRESS, _mocked_device, _mocked_feature, _patch_connect, _patch_discovery, _patch_single_discovery, ) +from .const import DEVICE_ID, MAC_ADDRESS from tests.common import MockConfigEntry, async_fire_time_changed @@ -88,7 +95,7 @@ async def test_light_unique_id( light = _mocked_device(modules=[Module.Light], alias="my_light") light.device_type = device_type with _patch_discovery(device=light), _patch_connect(device=light): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -98,8 +105,11 @@ async def test_light_unique_id( ) -async def test_legacy_dimmer_unique_id(hass: HomeAssistant) -> None: - """Test a light unique id.""" +async def test_legacy_dimmer_unique_id( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, +) -> None: + """Test dimmer unique id.""" already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) @@ -113,16 +123,16 @@ async def test_legacy_dimmer_unique_id(hass: HomeAssistant) -> None: light.device_type = DeviceType.Dimmer with _patch_discovery(device=light), _patch_connect(device=light): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" - entity_registry = er.async_get(hass) + assert entity_registry.async_get(entity_id).unique_id == "aa:bb:cc:dd:ee:ff" @pytest.mark.parametrize( - ("device", "transition"), + ("device", "extra_data", "expected_transition"), [ ( _mocked_device( @@ -135,7 +145,138 @@ async def test_legacy_dimmer_unique_id(hass: HomeAssistant) -> None: ), ], ), - 2.0, + {ATTR_TRANSITION: 2.0}, + 2.0 * 1_000, + ), + ( + _mocked_device( + modules=[Module.Light], + features=[ + _mocked_feature("brightness", value=50), + _mocked_feature("hsv", value=(10, 30, 5)), + _mocked_feature( + "color_temp", value=4000, minimum_value=4000, maximum_value=9000 + ), + ], + ), + {}, + None, + ), + ], +) +async def test_color_light( + hass: HomeAssistant, + device: MagicMock, + extra_data: dict, + expected_transition: float | None, +) -> None: + """Test a color light and that all transitions are correctly passed.""" + already_migrated_config_entry = MockConfigEntry( + domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS + ) + already_migrated_config_entry.add_to_hass(hass) + light = device.modules[Module.Light] + + # Setting color_temp to None emulates a device without color temp + light.color_temp = None + + with _patch_discovery(device=device), _patch_connect(device=device): + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) + await hass.async_block_till_done() + + entity_id = "light.my_bulb" + + BASE_PAYLOAD = {ATTR_ENTITY_ID: entity_id} + BASE_PAYLOAD |= extra_data + + state = hass.states.get(entity_id) + assert state.state == "on" + attributes = state.attributes + assert attributes[ATTR_BRIGHTNESS] == 128 + assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs"] + + assert attributes.get(ATTR_EFFECT) is None + + assert attributes[ATTR_COLOR_MODE] == "hs" + assert attributes[ATTR_MIN_COLOR_TEMP_KELVIN] == 4000 + assert attributes[ATTR_MAX_COLOR_TEMP_KELVIN] == 9000 + assert attributes[ATTR_HS_COLOR] == (10, 30) + assert attributes[ATTR_RGB_COLOR] == (255, 191, 178) + assert attributes[ATTR_XY_COLOR] == (0.42, 0.336) + + await hass.services.async_call( + LIGHT_DOMAIN, SERVICE_TURN_OFF, BASE_PAYLOAD, blocking=True + ) + light.set_state.assert_called_once_with( + LightState(light_on=False, transition=expected_transition) + ) + light.set_state.reset_mock() + + await hass.services.async_call( + LIGHT_DOMAIN, SERVICE_TURN_ON, BASE_PAYLOAD, blocking=True + ) + light.set_state.assert_called_once_with( + LightState(light_on=True, transition=expected_transition) + ) + light.set_state.reset_mock() + + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {**BASE_PAYLOAD, ATTR_BRIGHTNESS: 100}, + blocking=True, + ) + light.set_brightness.assert_called_with(39, transition=expected_transition) + light.set_brightness.reset_mock() + + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {**BASE_PAYLOAD, ATTR_COLOR_TEMP_KELVIN: 6666}, + blocking=True, + ) + light.set_color_temp.assert_called_with( + 6666, brightness=None, transition=expected_transition + ) + light.set_color_temp.reset_mock() + + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {**BASE_PAYLOAD, ATTR_COLOR_TEMP_KELVIN: 6666}, + blocking=True, + ) + light.set_color_temp.assert_called_with( + 6666, brightness=None, transition=expected_transition + ) + light.set_color_temp.reset_mock() + + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {**BASE_PAYLOAD, ATTR_HS_COLOR: (10, 30)}, + blocking=True, + ) + light.set_hsv.assert_called_with(10, 30, None, transition=expected_transition) + light.set_hsv.reset_mock() + + +@pytest.mark.parametrize( + ("device", "extra_data", "expected_transition"), + [ + ( + _mocked_device( + modules=[Module.Light, Module.LightEffect], + features=[ + _mocked_feature("brightness", value=50), + _mocked_feature("hsv", value=(10, 30, 5)), + _mocked_feature( + "color_temp", value=4000, minimum_value=4000, maximum_value=9000 + ), + ], + ), + {ATTR_TRANSITION: 2.0}, + 2.0 * 1_000, ), ( _mocked_device( @@ -148,12 +289,16 @@ async def test_legacy_dimmer_unique_id(hass: HomeAssistant) -> None: ), ], ), + {}, None, ), ], ) -async def test_color_light( - hass: HomeAssistant, device: MagicMock, transition: float | None +async def test_color_light_with_active_effect( + hass: HomeAssistant, + device: MagicMock, + extra_data: dict, + expected_transition: float | None, ) -> None: """Test a color light and that all transitions are correctly passed.""" already_migrated_config_entry = MockConfigEntry( @@ -162,93 +307,84 @@ async def test_color_light( already_migrated_config_entry.add_to_hass(hass) light = device.modules[Module.Light] - # Setting color_temp to None emulates a device with active effects - light.color_temp = None - with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_bulb" - KASA_TRANSITION_VALUE = transition * 1_000 if transition is not None else None BASE_PAYLOAD = {ATTR_ENTITY_ID: entity_id} - if transition: - BASE_PAYLOAD[ATTR_TRANSITION] = transition + BASE_PAYLOAD |= extra_data state = hass.states.get(entity_id) assert state.state == "on" attributes = state.attributes assert attributes[ATTR_BRIGHTNESS] == 128 assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs"] + # If effect is active, only the brightness can be controlled - if attributes.get(ATTR_EFFECT) is not None: - assert attributes[ATTR_COLOR_MODE] == "brightness" - else: - assert attributes[ATTR_COLOR_MODE] == "hs" - assert attributes[ATTR_MIN_COLOR_TEMP_KELVIN] == 4000 - assert attributes[ATTR_MAX_COLOR_TEMP_KELVIN] == 9000 - assert attributes[ATTR_HS_COLOR] == (10, 30) - assert attributes[ATTR_RGB_COLOR] == (255, 191, 178) - assert attributes[ATTR_XY_COLOR] == (0.42, 0.336) + assert attributes.get(ATTR_EFFECT) is not None + assert attributes[ATTR_COLOR_MODE] == "brightness" await hass.services.async_call( - LIGHT_DOMAIN, "turn_off", BASE_PAYLOAD, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_OFF, BASE_PAYLOAD, blocking=True ) light.set_state.assert_called_once_with( - LightState(light_on=False, transition=KASA_TRANSITION_VALUE) + LightState(light_on=False, transition=expected_transition) ) light.set_state.reset_mock() - await hass.services.async_call(LIGHT_DOMAIN, "turn_on", BASE_PAYLOAD, blocking=True) + await hass.services.async_call( + LIGHT_DOMAIN, SERVICE_TURN_ON, BASE_PAYLOAD, blocking=True + ) light.set_state.assert_called_once_with( - LightState(light_on=True, transition=KASA_TRANSITION_VALUE) + LightState(light_on=True, transition=expected_transition) ) light.set_state.reset_mock() await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {**BASE_PAYLOAD, ATTR_BRIGHTNESS: 100}, blocking=True, ) - light.set_brightness.assert_called_with(39, transition=KASA_TRANSITION_VALUE) + light.set_brightness.assert_called_with(39, transition=expected_transition) light.set_brightness.reset_mock() await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {**BASE_PAYLOAD, ATTR_COLOR_TEMP_KELVIN: 6666}, blocking=True, ) light.set_color_temp.assert_called_with( - 6666, brightness=None, transition=KASA_TRANSITION_VALUE + 6666, brightness=None, transition=expected_transition ) light.set_color_temp.reset_mock() await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {**BASE_PAYLOAD, ATTR_COLOR_TEMP_KELVIN: 6666}, blocking=True, ) light.set_color_temp.assert_called_with( - 6666, brightness=None, transition=KASA_TRANSITION_VALUE + 6666, brightness=None, transition=expected_transition ) light.set_color_temp.reset_mock() await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {**BASE_PAYLOAD, ATTR_HS_COLOR: (10, 30)}, blocking=True, ) - light.set_hsv.assert_called_with(10, 30, None, transition=KASA_TRANSITION_VALUE) + light.set_hsv.assert_called_with(10, 30, None, transition=expected_transition) light.set_hsv.reset_mock() async def test_color_light_no_temp(hass: HomeAssistant) -> None: - """Test a light.""" + """Test a color light with no color temp.""" already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) @@ -263,7 +399,7 @@ async def test_color_light_no_temp(hass: HomeAssistant) -> None: type(light).color_temp = PropertyMock(side_effect=Exception) with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -279,20 +415,20 @@ async def test_color_light_no_temp(hass: HomeAssistant) -> None: assert attributes[ATTR_XY_COLOR] == (0.42, 0.336) await hass.services.async_call( - LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True ) light.set_state.assert_called_once() light.set_state.reset_mock() await hass.services.async_call( - LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) light.set_state.assert_called_once() light.set_state.reset_mock() await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100}, blocking=True, ) @@ -301,7 +437,7 @@ async def test_color_light_no_temp(hass: HomeAssistant) -> None: await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_HS_COLOR: (10, 30)}, blocking=True, ) @@ -309,51 +445,28 @@ async def test_color_light_no_temp(hass: HomeAssistant) -> None: light.set_hsv.reset_mock() -@pytest.mark.parametrize( - ("device", "is_color"), - [ - ( - _mocked_device( - modules=[Module.Light], - alias="my_light", - features=[ - _mocked_feature("brightness", value=50), - _mocked_feature("hsv", value=(10, 30, 5)), - _mocked_feature( - "color_temp", value=4000, minimum_value=4000, maximum_value=9000 - ), - ], +async def test_color_temp_light_color(hass: HomeAssistant) -> None: + """Test a color temp light with color.""" + device = _mocked_device( + modules=[Module.Light], + alias="my_light", + features=[ + _mocked_feature("brightness", value=50), + _mocked_feature("hsv", value=(10, 30, 5)), + _mocked_feature( + "color_temp", value=4000, minimum_value=4000, maximum_value=9000 ), - True, - ), - ( - _mocked_device( - modules=[Module.Light], - alias="my_light", - features=[ - _mocked_feature("brightness", value=50), - _mocked_feature( - "color_temp", value=4000, minimum_value=4000, maximum_value=9000 - ), - ], - ), - False, - ), - ], -) -async def test_color_temp_light( - hass: HomeAssistant, device: MagicMock, is_color: bool -) -> None: - """Test a light.""" + ], + ) already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) already_migrated_config_entry.add_to_hass(hass) - # device = _mocked_device(modules=[Module.Light], alias="my_light") + light = device.modules[Module.Light] with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -363,29 +476,24 @@ async def test_color_temp_light( attributes = state.attributes assert attributes[ATTR_BRIGHTNESS] == 128 assert attributes[ATTR_COLOR_MODE] == "color_temp" - if is_color: - assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs"] - else: - assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp"] - assert attributes[ATTR_MAX_COLOR_TEMP_KELVIN] == 9000 - assert attributes[ATTR_MIN_COLOR_TEMP_KELVIN] == 4000 - assert attributes[ATTR_COLOR_TEMP_KELVIN] == 4000 + + assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs"] await hass.services.async_call( - LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True ) light.set_state.assert_called_once() light.set_state.reset_mock() await hass.services.async_call( - LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) light.set_state.assert_called_once() light.set_state.reset_mock() await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100}, blocking=True, ) @@ -394,7 +502,7 @@ async def test_color_temp_light( await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 6666}, blocking=True, ) @@ -404,7 +512,7 @@ async def test_color_temp_light( # Verify color temp is clamped to the valid range await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 20000}, blocking=True, ) @@ -414,7 +522,94 @@ async def test_color_temp_light( # Verify color temp is clamped to the valid range await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 1}, + blocking=True, + ) + light.set_color_temp.assert_called_with(4000, brightness=None, transition=None) + light.set_color_temp.reset_mock() + + +async def test_color_temp_light_no_color(hass: HomeAssistant) -> None: + """Test a color temp light with no color.""" + device = _mocked_device( + modules=[Module.Light], + alias="my_light", + features=[ + _mocked_feature("brightness", value=50), + _mocked_feature( + "color_temp", value=4000, minimum_value=4000, maximum_value=9000 + ), + ], + ) + already_migrated_config_entry = MockConfigEntry( + domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS + ) + already_migrated_config_entry.add_to_hass(hass) + + light = device.modules[Module.Light] + + with _patch_discovery(device=device), _patch_connect(device=device): + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) + await hass.async_block_till_done() + + entity_id = "light.my_light" + + state = hass.states.get(entity_id) + assert state.state == "on" + attributes = state.attributes + assert attributes[ATTR_BRIGHTNESS] == 128 + assert attributes[ATTR_COLOR_MODE] == "color_temp" + + assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp"] + assert attributes[ATTR_MAX_COLOR_TEMP_KELVIN] == 9000 + assert attributes[ATTR_MIN_COLOR_TEMP_KELVIN] == 4000 + assert attributes[ATTR_COLOR_TEMP_KELVIN] == 4000 + + await hass.services.async_call( + LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True + ) + light.set_state.assert_called_once() + light.set_state.reset_mock() + + await hass.services.async_call( + LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True + ) + light.set_state.assert_called_once() + light.set_state.reset_mock() + + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100}, + blocking=True, + ) + light.set_brightness.assert_called_with(39, transition=None) + light.set_brightness.reset_mock() + + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 6666}, + blocking=True, + ) + light.set_color_temp.assert_called_with(6666, brightness=None, transition=None) + light.set_color_temp.reset_mock() + + # Verify color temp is clamped to the valid range + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 20000}, + blocking=True, + ) + light.set_color_temp.assert_called_with(9000, brightness=None, transition=None) + light.set_color_temp.reset_mock() + + # Verify color temp is clamped to the valid range + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 1}, blocking=True, ) @@ -423,7 +618,7 @@ async def test_color_temp_light( async def test_brightness_only_light(hass: HomeAssistant) -> None: - """Test a light.""" + """Test a light brightness.""" already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) @@ -435,7 +630,7 @@ async def test_brightness_only_light(hass: HomeAssistant) -> None: light = device.modules[Module.Light] with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -448,20 +643,20 @@ async def test_brightness_only_light(hass: HomeAssistant) -> None: assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["brightness"] await hass.services.async_call( - LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True ) light.set_state.assert_called_once() light.set_state.reset_mock() await hass.services.async_call( - LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) light.set_state.assert_called_once() light.set_state.reset_mock() await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100}, blocking=True, ) @@ -470,7 +665,7 @@ async def test_brightness_only_light(hass: HomeAssistant) -> None: async def test_on_off_light(hass: HomeAssistant) -> None: - """Test a light.""" + """Test a light turns on and off.""" already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) @@ -479,7 +674,7 @@ async def test_on_off_light(hass: HomeAssistant) -> None: light = device.modules[Module.Light] with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -490,20 +685,20 @@ async def test_on_off_light(hass: HomeAssistant) -> None: assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["onoff"] await hass.services.async_call( - LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True ) light.set_state.assert_called_once() light.set_state.reset_mock() await hass.services.async_call( - LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) light.set_state.assert_called_once() light.set_state.reset_mock() async def test_off_at_start_light(hass: HomeAssistant) -> None: - """Test a light.""" + """Test a light off at startup.""" already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) @@ -514,7 +709,7 @@ async def test_off_at_start_light(hass: HomeAssistant) -> None: light.state = LightState(light_on=False) with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -526,7 +721,7 @@ async def test_off_at_start_light(hass: HomeAssistant) -> None: async def test_dimmer_turn_on_fix(hass: HomeAssistant) -> None: - """Test a light.""" + """Test a dimmer turns on without brightness being set.""" already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) @@ -537,7 +732,7 @@ async def test_dimmer_turn_on_fix(hass: HomeAssistant) -> None: light.state = LightState(light_on=False) with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -546,7 +741,7 @@ async def test_dimmer_turn_on_fix(hass: HomeAssistant) -> None: assert state.state == "off" await hass.services.async_call( - LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) light.set_state.assert_called_once_with( LightState( @@ -587,7 +782,7 @@ async def test_smart_strip_effects( _patch_single_discovery(device=device), _patch_connect(device=device), ): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -601,7 +796,7 @@ async def test_smart_strip_effects( # is in progress calls set_effect to clear the effect await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP_KELVIN: 4000}, blocking=True, ) @@ -612,7 +807,7 @@ async def test_smart_strip_effects( await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "Effect2"}, blocking=True, ) @@ -629,7 +824,7 @@ async def test_smart_strip_effects( # Test setting light effect off await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "off"}, blocking=True, ) @@ -644,7 +839,7 @@ async def test_smart_strip_effects( caplog.clear() await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "Effect3"}, blocking=True, ) @@ -673,7 +868,7 @@ async def test_smart_strip_effects( await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True, ) @@ -703,7 +898,7 @@ async def test_smart_strip_custom_random_effect(hass: HomeAssistant) -> None: light_effect = device.modules[Module.LightEffect] with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -713,7 +908,7 @@ async def test_smart_strip_custom_random_effect(hass: HomeAssistant) -> None: await hass.services.async_call( DOMAIN, - "random_effect", + SERVICE_RANDOM_EFFECT, { ATTR_ENTITY_ID: entity_id, "init_states": [340, 20, 50], @@ -742,7 +937,7 @@ async def test_smart_strip_custom_random_effect(hass: HomeAssistant) -> None: await hass.services.async_call( DOMAIN, - "random_effect", + SERVICE_RANDOM_EFFECT, { ATTR_ENTITY_ID: entity_id, "init_states": [340, 20, 50], @@ -792,7 +987,7 @@ async def test_smart_strip_custom_random_effect(hass: HomeAssistant) -> None: await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True, ) @@ -801,7 +996,7 @@ async def test_smart_strip_custom_random_effect(hass: HomeAssistant) -> None: await hass.services.async_call( DOMAIN, - "random_effect", + SERVICE_RANDOM_EFFECT, { ATTR_ENTITY_ID: entity_id, "init_states": [340, 20, 50], @@ -875,7 +1070,7 @@ async def test_smart_strip_effect_service_error( service_params: dict, expected_extra_params: dict, ) -> None: - """Test smart strip custom random effects.""" + """Test smart strip effect service errors.""" already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) @@ -886,7 +1081,7 @@ async def test_smart_strip_effect_service_error( light_effect = device.modules[Module.LightEffect] with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -935,7 +1130,7 @@ async def test_smart_strip_custom_random_effect_at_start(hass: HomeAssistant) -> light_effect = device.modules[Module.LightEffect] light_effect.effect = LightEffect.LIGHT_EFFECTS_OFF with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -945,7 +1140,7 @@ async def test_smart_strip_custom_random_effect_at_start(hass: HomeAssistant) -> # fallback to set HSV when custom effect is not known so it does turn back on await hass.services.async_call( LIGHT_DOMAIN, - "turn_on", + SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True, ) @@ -965,7 +1160,7 @@ async def test_smart_strip_custom_sequence_effect(hass: HomeAssistant) -> None: light_effect = device.modules[Module.LightEffect] with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -975,7 +1170,7 @@ async def test_smart_strip_custom_sequence_effect(hass: HomeAssistant) -> None: await hass.services.async_call( DOMAIN, - "sequence_effect", + SERVICE_SEQUENCE_EFFECT, { ATTR_ENTITY_ID: entity_id, "sequence": [[340, 20, 50], [20, 50, 50], [0, 100, 50]], @@ -1040,7 +1235,7 @@ async def test_light_errors_when_turned_on( light.set_state.side_effect = exception_type(msg) with _patch_discovery(device=device), _patch_connect(device=device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_light" @@ -1051,7 +1246,7 @@ async def test_light_errors_when_turned_on( with pytest.raises(HomeAssistantError, match=msg): await hass.services.async_call( - LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) await hass.async_block_till_done() assert light.set_state.call_count == 1 @@ -1091,7 +1286,7 @@ async def test_light_child( ) with _patch_discovery(device=parent_device), _patch_connect(device=parent_device): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "light.my_device" @@ -1132,14 +1327,16 @@ async def test_scene_effect_light( light_effect.effect = LightEffect.LIGHT_EFFECTS_OFF with _patch_discovery(device=device), _patch_connect(device=device): - assert await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) - assert await async_setup_component(hass, "scene", {}) + assert await hass.config_entries.async_setup( + already_migrated_config_entry.entry_id + ) + assert await async_setup_component(hass, SCENE_DOMAIN, {}) await hass.async_block_till_done() entity_id = "light.my_light" await hass.services.async_call( - LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) await hass.async_block_till_done() freezer.tick(5) @@ -1151,9 +1348,9 @@ async def test_scene_effect_light( assert state.attributes["effect"] is EFFECT_OFF await hass.services.async_call( - "scene", - "create", - {"scene_id": "effect_off_scene", "snapshot_entities": [entity_id]}, + SCENE_DOMAIN, + SERVICE_CREATE, + {CONF_SCENE_ID: "effect_off_scene", CONF_SNAPSHOT: [entity_id]}, blocking=True, ) await hass.async_block_till_done() @@ -1161,7 +1358,7 @@ async def test_scene_effect_light( assert scene_state.state is STATE_UNKNOWN await hass.services.async_call( - LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True + LIGHT_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True ) await hass.async_block_till_done() freezer.tick(5) @@ -1172,10 +1369,10 @@ async def test_scene_effect_light( assert state.state is STATE_OFF await hass.services.async_call( - "scene", - "turn_on", + SCENE_DOMAIN, + SERVICE_TURN_ON, { - "entity_id": "scene.effect_off_scene", + ATTR_ENTITY_ID: "scene.effect_off_scene", }, blocking=True, ) diff --git a/tests/components/tplink/test_number.py b/tests/components/tplink/test_number.py index 865ce27ffc0..07d64178dfa 100644 --- a/tests/components/tplink/test_number.py +++ b/tests/components/tplink/test_number.py @@ -3,7 +3,6 @@ from kasa import Feature from syrupy.assertion import SnapshotAssertion -from homeassistant.components import tplink from homeassistant.components.number import ( ATTR_VALUE, DOMAIN as NUMBER_DOMAIN, @@ -15,11 +14,8 @@ from homeassistant.components.tplink.number import NUMBER_DESCRIPTIONS from homeassistant.const import ATTR_ENTITY_ID, CONF_HOST, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er -from homeassistant.setup import async_setup_component from . import ( - DEVICE_ID, - MAC_ADDRESS, _mocked_device, _mocked_feature, _mocked_strip_children, @@ -28,6 +24,7 @@ from . import ( setup_platform_for_device, snapshot_platform, ) +from .const import DEVICE_ID, MAC_ADDRESS from tests.common import MockConfigEntry @@ -39,7 +36,7 @@ async def test_states( device_registry: dr.DeviceRegistry, snapshot: SnapshotAssertion, ) -> None: - """Test a sensor unique ids.""" + """Test a number states.""" features = {description.key for description in NUMBER_DESCRIPTIONS} features.update(EXCLUDED_FEATURES) device = _mocked_device(alias="my_device", features=features) @@ -54,7 +51,7 @@ async def test_states( async def test_number(hass: HomeAssistant, entity_registry: er.EntityRegistry) -> None: - """Test a sensor unique ids.""" + """Test number unique ids.""" already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) @@ -70,7 +67,7 @@ async def test_number(hass: HomeAssistant, entity_registry: er.EntityRegistry) - ) plug = _mocked_device(alias="my_plug", features=[new_feature]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "number.my_plug_temperature_offset" @@ -84,7 +81,7 @@ async def test_number_children( entity_registry: er.EntityRegistry, device_registry: dr.DeviceRegistry, ) -> None: - """Test a sensor unique ids.""" + """Test number children.""" already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) @@ -104,7 +101,7 @@ async def test_number_children( children=_mocked_strip_children(features=[new_feature]), ) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "number.my_plug_temperature_offset" @@ -142,7 +139,7 @@ async def test_number_set( ) plug = _mocked_device(alias="my_plug", features=[new_feature]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "number.my_plug_temperature_offset" diff --git a/tests/components/tplink/test_select.py b/tests/components/tplink/test_select.py index 6c49185d91c..3b99412740a 100644 --- a/tests/components/tplink/test_select.py +++ b/tests/components/tplink/test_select.py @@ -4,7 +4,6 @@ from kasa import Feature import pytest from syrupy.assertion import SnapshotAssertion -from homeassistant.components import tplink from homeassistant.components.select import ( ATTR_OPTION, DOMAIN as SELECT_DOMAIN, @@ -16,11 +15,8 @@ from homeassistant.components.tplink.select import SELECT_DESCRIPTIONS from homeassistant.const import ATTR_ENTITY_ID, CONF_HOST, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er -from homeassistant.setup import async_setup_component from . import ( - DEVICE_ID, - MAC_ADDRESS, _mocked_device, _mocked_feature, _mocked_strip_children, @@ -29,13 +25,14 @@ from . import ( setup_platform_for_device, snapshot_platform, ) +from .const import DEVICE_ID, MAC_ADDRESS from tests.common import MockConfigEntry @pytest.fixture def mocked_feature_select() -> Feature: - """Return mocked tplink binary sensor feature.""" + """Return mocked tplink select feature.""" return _mocked_feature( "light_preset", value="First choice", @@ -53,7 +50,7 @@ async def test_states( device_registry: dr.DeviceRegistry, snapshot: SnapshotAssertion, ) -> None: - """Test a sensor unique ids.""" + """Test select states.""" features = {description.key for description in SELECT_DESCRIPTIONS} features.update(EXCLUDED_FEATURES) device = _mocked_device(alias="my_device", features=features) @@ -72,7 +69,7 @@ async def test_select( entity_registry: er.EntityRegistry, mocked_feature_select: Feature, ) -> None: - """Test a sensor unique ids.""" + """Test select unique ids.""" mocked_feature = mocked_feature_select already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS @@ -81,7 +78,7 @@ async def test_select( plug = _mocked_device(alias="my_plug", features=[mocked_feature]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() # The entity_id is based on standard name from core. @@ -97,7 +94,7 @@ async def test_select_children( device_registry: dr.DeviceRegistry, mocked_feature_select: Feature, ) -> None: - """Test a sensor unique ids.""" + """Test select children.""" mocked_feature = mocked_feature_select already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS @@ -109,7 +106,7 @@ async def test_select_children( children=_mocked_strip_children(features=[mocked_feature]), ) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "select.my_plug_light_preset" @@ -141,7 +138,7 @@ async def test_select_select( already_migrated_config_entry.add_to_hass(hass) plug = _mocked_device(alias="my_plug", features=[mocked_feature]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "select.my_plug_light_preset" diff --git a/tests/components/tplink/test_sensor.py b/tests/components/tplink/test_sensor.py index a53b59df0dc..857a2365527 100644 --- a/tests/components/tplink/test_sensor.py +++ b/tests/components/tplink/test_sensor.py @@ -4,18 +4,14 @@ from kasa import Device, Feature, Module import pytest from syrupy.assertion import SnapshotAssertion -from homeassistant.components import tplink from homeassistant.components.tplink.const import DOMAIN from homeassistant.components.tplink.entity import EXCLUDED_FEATURES from homeassistant.components.tplink.sensor import SENSOR_DESCRIPTIONS from homeassistant.const import CONF_HOST, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er -from homeassistant.setup import async_setup_component from . import ( - DEVICE_ID, - MAC_ADDRESS, _mocked_device, _mocked_energy_features, _mocked_feature, @@ -25,6 +21,7 @@ from . import ( setup_platform_for_device, snapshot_platform, ) +from .const import DEVICE_ID, MAC_ADDRESS from tests.common import MockConfigEntry @@ -36,7 +33,7 @@ async def test_states( device_registry: dr.DeviceRegistry, snapshot: SnapshotAssertion, ) -> None: - """Test a sensor unique ids.""" + """Test a sensor states.""" features = {description.key for description in SENSOR_DESCRIPTIONS} features.update(EXCLUDED_FEATURES) device = _mocked_device(alias="my_device", features=features) @@ -67,7 +64,7 @@ async def test_color_light_with_an_emeter(hass: HomeAssistant) -> None: alias="my_bulb", modules=[Module.Light], features=["state", *emeter_features] ) with _patch_discovery(device=bulb), _patch_connect(device=bulb): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() await hass.async_block_till_done() @@ -104,7 +101,7 @@ async def test_plug_with_an_emeter(hass: HomeAssistant) -> None: ) plug = _mocked_device(alias="my_plug", features=["state", *emeter_features]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() await hass.async_block_till_done() @@ -131,7 +128,7 @@ async def test_color_light_no_emeter(hass: HomeAssistant) -> None: bulb = _mocked_device(alias="my_bulb", modules=[Module.Light]) with _patch_discovery(device=bulb), _patch_connect(device=bulb): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() await hass.async_block_till_done() @@ -167,7 +164,7 @@ async def test_sensor_unique_id( ) plug = _mocked_device(alias="my_plug", features=emeter_features) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() expected = { @@ -202,7 +199,7 @@ async def test_undefined_sensor( ) plug = _mocked_device(alias="my_plug", features=[new_feature]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() msg = ( @@ -240,7 +237,7 @@ async def test_sensor_children_on_parent( device_type=Device.Type.WallSwitch, ) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "sensor.my_plug_this_month_s_consumption" @@ -288,7 +285,7 @@ async def test_sensor_children_on_child( device_type=Device.Type.Strip, ) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "sensor.my_plug_this_month_s_consumption" @@ -308,19 +305,18 @@ async def test_sensor_children_on_child( assert child_device.via_device_id == device.id -@pytest.mark.skip -async def test_new_datetime_sensor( +@pytest.mark.usefixtures("entity_registry_enabled_by_default") +async def test_datetime_sensor( hass: HomeAssistant, entity_registry: er.EntityRegistry ) -> None: - """Test a sensor unique ids.""" - # Skipped temporarily while datetime handling on hold. + """Test a timestamp sensor.""" already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) already_migrated_config_entry.add_to_hass(hass) plug = _mocked_device(alias="my_plug", features=["on_since"]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "sensor.my_plug_on_since" diff --git a/tests/components/tplink/test_switch.py b/tests/components/tplink/test_switch.py index 47b2e078f5a..bdf54f10e8b 100644 --- a/tests/components/tplink/test_switch.py +++ b/tests/components/tplink/test_switch.py @@ -9,7 +9,11 @@ import pytest from syrupy.assertion import SnapshotAssertion from homeassistant.components import tplink -from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN +from homeassistant.components.switch import ( + DOMAIN as SWITCH_DOMAIN, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, +) from homeassistant.components.tplink.const import DOMAIN from homeassistant.components.tplink.entity import EXCLUDED_FEATURES from homeassistant.components.tplink.switch import SWITCH_DESCRIPTIONS @@ -25,12 +29,9 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import device_registry as dr, entity_registry as er -from homeassistant.setup import async_setup_component from homeassistant.util import dt as dt_util, slugify from . import ( - DEVICE_ID, - MAC_ADDRESS, _mocked_device, _mocked_strip_children, _patch_connect, @@ -38,6 +39,7 @@ from . import ( setup_platform_for_device, snapshot_platform, ) +from .const import DEVICE_ID, MAC_ADDRESS from tests.common import MockConfigEntry, async_fire_time_changed @@ -49,7 +51,7 @@ async def test_states( device_registry: dr.DeviceRegistry, snapshot: SnapshotAssertion, ) -> None: - """Test a sensor unique ids.""" + """Test a switch states.""" features = {description.key for description in SWITCH_DESCRIPTIONS} features.update(EXCLUDED_FEATURES) device = _mocked_device(alias="my_device", features=features) @@ -72,7 +74,7 @@ async def test_plug(hass: HomeAssistant) -> None: plug = _mocked_device(alias="my_plug", features=["state"]) feat = plug.features["state"] with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "switch.my_plug" @@ -80,13 +82,13 @@ async def test_plug(hass: HomeAssistant) -> None: assert state.state == STATE_ON await hass.services.async_call( - SWITCH_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True + SWITCH_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True ) feat.set_value.assert_called_once() feat.set_value.reset_mock() await hass.services.async_call( - SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + SWITCH_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) feat.set_value.assert_called_once() feat.set_value.reset_mock() @@ -120,7 +122,7 @@ async def test_led_switch(hass: HomeAssistant, dev: Device, domain: str) -> None feat = dev.features["led"] already_migrated_config_entry.add_to_hass(hass) with _patch_discovery(device=dev), _patch_connect(device=dev): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_name = slugify(dev.alias) @@ -131,13 +133,13 @@ async def test_led_switch(hass: HomeAssistant, dev: Device, domain: str) -> None assert led_state.name == f"{dev.alias} LED" await hass.services.async_call( - SWITCH_DOMAIN, "turn_off", {ATTR_ENTITY_ID: led_entity_id}, blocking=True + SWITCH_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: led_entity_id}, blocking=True ) feat.set_value.assert_called_once_with(False) feat.set_value.reset_mock() await hass.services.async_call( - SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: led_entity_id}, blocking=True + SWITCH_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: led_entity_id}, blocking=True ) feat.set_value.assert_called_once_with(True) feat.set_value.reset_mock() @@ -153,7 +155,7 @@ async def test_plug_unique_id( already_migrated_config_entry.add_to_hass(hass) plug = _mocked_device(alias="my_plug", features=["state", "led"]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "switch.my_plug" @@ -168,7 +170,7 @@ async def test_plug_update_fails(hass: HomeAssistant) -> None: already_migrated_config_entry.add_to_hass(hass) plug = _mocked_device(alias="my_plug", features=["state", "led"]) with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "switch.my_plug" @@ -197,7 +199,7 @@ async def test_strip(hass: HomeAssistant) -> None: strip.children[0].features["state"].value = True strip.children[1].features["state"].value = False with _patch_discovery(device=strip), _patch_connect(device=strip): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "switch.my_strip_plug0" @@ -205,14 +207,14 @@ async def test_strip(hass: HomeAssistant) -> None: assert state.state == STATE_ON await hass.services.async_call( - SWITCH_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True + SWITCH_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True ) feat = strip.children[0].features["state"] feat.set_value.assert_called_once() feat.set_value.reset_mock() await hass.services.async_call( - SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + SWITCH_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) feat.set_value.assert_called_once() feat.set_value.reset_mock() @@ -222,14 +224,14 @@ async def test_strip(hass: HomeAssistant) -> None: assert state.state == STATE_OFF await hass.services.async_call( - SWITCH_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True + SWITCH_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}, blocking=True ) feat = strip.children[1].features["state"] feat.set_value.assert_called_once() feat.set_value.reset_mock() await hass.services.async_call( - SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + SWITCH_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) feat.set_value.assert_called_once() feat.set_value.reset_mock() @@ -249,7 +251,7 @@ async def test_strip_unique_ids( features=["state", "led"], ) with _patch_discovery(device=strip), _patch_connect(device=strip): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() for plug_id in range(2): @@ -264,7 +266,7 @@ async def test_strip_blank_alias( entity_registry: er.EntityRegistry, device_registry: dr.DeviceRegistry, ) -> None: - """Test a strip unique id.""" + """Test a strip with blank parent alias.""" already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS ) @@ -276,7 +278,7 @@ async def test_strip_blank_alias( features=["state", "led"], ) with _patch_discovery(device=strip), _patch_connect(device=strip): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() strip_entity_id = "switch.unnamed_ks123" @@ -338,7 +340,7 @@ async def test_plug_errors_when_turned_on( feat.set_value.side_effect = exception_type("test error") with _patch_discovery(device=plug), _patch_connect(device=plug): - await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.config_entries.async_setup(already_migrated_config_entry.entry_id) await hass.async_block_till_done() entity_id = "switch.my_plug" @@ -349,7 +351,7 @@ async def test_plug_errors_when_turned_on( with pytest.raises(HomeAssistantError, match=msg): await hass.services.async_call( - SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + SWITCH_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, blocking=True ) await hass.async_block_till_done() assert feat.set_value.call_count == 1