diff --git a/homeassistant/components/melissa/__init__.py b/homeassistant/components/melissa/__init__.py index 93e26231005..9a9268e73d1 100644 --- a/homeassistant/components/melissa/__init__.py +++ b/homeassistant/components/melissa/__init__.py @@ -1,6 +1,6 @@ """Support for Melissa climate.""" -import melissa +from melissa import AsyncMelissa import voluptuous as vol from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform @@ -31,7 +31,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: conf = config[DOMAIN] username = conf.get(CONF_USERNAME) password = conf.get(CONF_PASSWORD) - api = melissa.AsyncMelissa(username=username, password=password) + api = AsyncMelissa(username=username, password=password) await api.async_connect() hass.data[DATA_MELISSA] = api diff --git a/homeassistant/components/melissa/climate.py b/homeassistant/components/melissa/climate.py index af59046c58b..73b04ff8c1d 100644 --- a/homeassistant/components/melissa/climate.py +++ b/homeassistant/components/melissa/climate.py @@ -50,7 +50,7 @@ async def async_setup_platform( if device["type"] == "melissa": all_devices.append(MelissaClimate(api, device["serial_number"], device)) - async_add_entities(all_devices) + async_add_entities(all_devices, True) class MelissaClimate(ClimateEntity): diff --git a/tests/components/melissa/__init__.py b/tests/components/melissa/__init__.py index c4caf0fe671..24b278b3c3a 100644 --- a/tests/components/melissa/__init__.py +++ b/tests/components/melissa/__init__.py @@ -1 +1,11 @@ """Tests for the melissa component.""" +from homeassistant.core import HomeAssistant +from homeassistant.setup import async_setup_component + +VALID_CONFIG = {"melissa": {"username": "********", "password": "********"}} + + +async def setup_integration(hass: HomeAssistant) -> None: + """Set up the melissa integration in Home Assistant.""" + assert await async_setup_component(hass, "melissa", VALID_CONFIG) + await hass.async_block_till_done() diff --git a/tests/components/melissa/conftest.py b/tests/components/melissa/conftest.py new file mode 100644 index 00000000000..6a6781263b5 --- /dev/null +++ b/tests/components/melissa/conftest.py @@ -0,0 +1,47 @@ +"""Melissa conftest.""" + +from unittest.mock import AsyncMock, patch + +import pytest + +from tests.common import load_json_object_fixture + + +@pytest.fixture +async def mock_melissa(): + """Mock the Melissa API.""" + with patch( + "homeassistant.components.melissa.AsyncMelissa", autospec=True + ) as mock_client: + mock_client.return_value.async_connect = AsyncMock() + mock_client.return_value.async_fetch_devices.return_value = ( + load_json_object_fixture("fetch_devices.json", "melissa") + ) + mock_client.return_value.async_status.return_value = load_json_object_fixture( + "status.json", "melissa" + ) + mock_client.return_value.async_cur_settings.return_value = ( + load_json_object_fixture("cur_settings.json", "melissa") + ) + + mock_client.return_value.STATE_OFF = 0 + mock_client.return_value.STATE_ON = 1 + mock_client.return_value.STATE_IDLE = 2 + + mock_client.return_value.MODE_AUTO = 0 + mock_client.return_value.MODE_FAN = 1 + mock_client.return_value.MODE_HEAT = 2 + mock_client.return_value.MODE_COOL = 3 + mock_client.return_value.MODE_DRY = 4 + + mock_client.return_value.FAN_AUTO = 0 + mock_client.return_value.FAN_LOW = 1 + mock_client.return_value.FAN_MEDIUM = 2 + mock_client.return_value.FAN_HIGH = 3 + + mock_client.return_value.STATE = "state" + mock_client.return_value.MODE = "mode" + mock_client.return_value.FAN = "fan" + mock_client.return_value.TEMP = "temp" + mock_client.return_value.HUMIDITY = "humidity" + yield mock_client diff --git a/tests/components/melissa/snapshots/test_climate.ambr b/tests/components/melissa/snapshots/test_climate.ambr new file mode 100644 index 00000000000..40e757d1561 --- /dev/null +++ b/tests/components/melissa/snapshots/test_climate.ambr @@ -0,0 +1,34 @@ +# serializer version: 1 +# name: test_setup_platform + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'current_humidity': 18.7, + 'current_temperature': 27.4, + 'fan_mode': 'low', + 'fan_modes': list([ + 'auto', + 'high', + 'medium', + 'low', + ]), + 'friendly_name': 'Melissa 12345678', + 'hvac_modes': list([ + , + , + , + , + , + ]), + 'max_temp': 30, + 'min_temp': 16, + 'supported_features': , + 'target_temp_step': 1, + 'temperature': 16, + }), + 'context': , + 'entity_id': 'climate.melissa_12345678', + 'last_changed': , + 'last_updated': , + 'state': 'heat', + }) +# --- diff --git a/tests/components/melissa/test_climate.py b/tests/components/melissa/test_climate.py index 7903744ff13..ff59f925961 100644 --- a/tests/components/melissa/test_climate.py +++ b/tests/components/melissa/test_climate.py @@ -1,368 +1,46 @@ """Test for Melissa climate component.""" -import json -from unittest.mock import AsyncMock, Mock, patch +from unittest.mock import AsyncMock + +from syrupy import SnapshotAssertion from homeassistant.components.climate import ( - FAN_HIGH, - FAN_LOW, - FAN_MEDIUM, - ClimateEntityFeature, - HVACMode, + DOMAIN as CLIMATE_DOMAIN, + SERVICE_SET_TEMPERATURE, ) -from homeassistant.components.melissa import DATA_MELISSA, climate as melissa -from homeassistant.components.melissa.climate import MelissaClimate -from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature +from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE from homeassistant.core import HomeAssistant +import homeassistant.helpers.entity_registry as er -from tests.common import load_fixture - -_SERIAL = "12345678" +from tests.components.melissa import setup_integration -def melissa_mock(): - """Use this to mock the melissa api.""" - api = Mock() - api.async_fetch_devices = AsyncMock( - return_value=json.loads(load_fixture("fetch_devices.json", "melissa")) - ) - api.async_status = AsyncMock( - return_value=json.loads(load_fixture("status.json", "melissa")) - ) - api.async_cur_settings = AsyncMock( - return_value=json.loads(load_fixture("cur_settings.json", "melissa")) - ) - - api.async_send = AsyncMock(return_value=True) - - api.STATE_OFF = 0 - api.STATE_ON = 1 - api.STATE_IDLE = 2 - - api.MODE_AUTO = 0 - api.MODE_FAN = 1 - api.MODE_HEAT = 2 - api.MODE_COOL = 3 - api.MODE_DRY = 4 - - api.FAN_AUTO = 0 - api.FAN_LOW = 1 - api.FAN_MEDIUM = 2 - api.FAN_HIGH = 3 - - api.STATE = "state" - api.MODE = "mode" - api.FAN = "fan" - api.TEMP = "temp" - return api - - -async def test_setup_platform(hass: HomeAssistant) -> None: +async def test_setup_platform( + hass: HomeAssistant, mock_melissa, snapshot: SnapshotAssertion +) -> None: """Test setup_platform.""" - with patch( - "homeassistant.components.melissa.climate.MelissaClimate" - ) as mocked_thermostat: - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = mocked_thermostat(api, device["serial_number"], device) - thermostats = [thermostat] + await setup_integration(hass) - hass.data[DATA_MELISSA] = api - - config = {} - add_entities = Mock() - discovery_info = {} - - await melissa.async_setup_platform(hass, config, add_entities, discovery_info) - add_entities.assert_called_once_with(thermostats) + assert hass.states.get("climate.melissa_12345678") == snapshot -async def test_get_name(hass: HomeAssistant) -> None: - """Test name property.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert thermostat.name == "Melissa 12345678" +async def test_actions( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + mock_melissa: AsyncMock, +) -> None: + """Test that the switch can be turned on and off.""" + await setup_integration(hass) + entity_id = "climate.melissa_12345678" -async def test_current_fan_mode(hass: HomeAssistant) -> None: - """Test current_fan_mode property.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - await thermostat.async_update() - assert thermostat.fan_mode == FAN_LOW + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_TEMPERATURE, + {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 25}, + blocking=True, + ) + await hass.async_block_till_done() - thermostat._cur_settings = None - assert thermostat.fan_mode is None - - -async def test_current_temperature(hass: HomeAssistant) -> None: - """Test current temperature.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert thermostat.current_temperature == 27.4 - - -async def test_current_temperature_no_data(hass: HomeAssistant) -> None: - """Test current temperature without data.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - thermostat._data = None - assert thermostat.current_temperature is None - - -async def test_target_temperature_step(hass: HomeAssistant) -> None: - """Test current target_temperature_step.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert thermostat.target_temperature_step == 1 - - -async def test_current_operation(hass: HomeAssistant) -> None: - """Test current operation.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - await thermostat.async_update() - assert thermostat.state == HVACMode.HEAT - - thermostat._cur_settings = None - assert thermostat.hvac_action is None - - -async def test_operation_list(hass: HomeAssistant) -> None: - """Test the operation list.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert [ - HVACMode.HEAT, - HVACMode.COOL, - HVACMode.DRY, - HVACMode.FAN_ONLY, - HVACMode.OFF, - ] == thermostat.hvac_modes - - -async def test_fan_modes(hass: HomeAssistant) -> None: - """Test the fan list.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert ["auto", FAN_HIGH, FAN_MEDIUM, FAN_LOW] == thermostat.fan_modes - - -async def test_target_temperature(hass: HomeAssistant) -> None: - """Test target temperature.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - await thermostat.async_update() - assert thermostat.target_temperature == 16 - - thermostat._cur_settings = None - assert thermostat.target_temperature is None - - -async def test_state(hass: HomeAssistant) -> None: - """Test state.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - await thermostat.async_update() - assert thermostat.state == HVACMode.HEAT - - thermostat._cur_settings = None - assert thermostat.state is None - - -async def test_temperature_unit(hass: HomeAssistant) -> None: - """Test temperature unit.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert thermostat.temperature_unit == UnitOfTemperature.CELSIUS - - -async def test_min_temp(hass: HomeAssistant) -> None: - """Test min temp.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert thermostat.min_temp == 16 - - -async def test_max_temp(hass: HomeAssistant) -> None: - """Test max temp.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert thermostat.max_temp == 30 - - -async def test_supported_features(hass: HomeAssistant) -> None: - """Test supported_features property.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - features = ( - ClimateEntityFeature.TARGET_TEMPERATURE - | ClimateEntityFeature.FAN_MODE - | ClimateEntityFeature.TURN_OFF - | ClimateEntityFeature.TURN_ON - ) - assert thermostat.supported_features == features - - -async def test_set_temperature(hass: HomeAssistant) -> None: - """Test set_temperature.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - await thermostat.async_update() - await thermostat.async_set_temperature(**{ATTR_TEMPERATURE: 25}) - assert thermostat.target_temperature == 25 - - -async def test_fan_mode(hass: HomeAssistant) -> None: - """Test set_fan_mode.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - await thermostat.async_update() - await hass.async_block_till_done() - await thermostat.async_set_fan_mode(FAN_HIGH) - await hass.async_block_till_done() - assert thermostat.fan_mode == FAN_HIGH - - -async def test_set_operation_mode(hass: HomeAssistant) -> None: - """Test set_operation_mode.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - await thermostat.async_update() - await hass.async_block_till_done() - await thermostat.async_set_hvac_mode(HVACMode.COOL) - await hass.async_block_till_done() - assert thermostat.hvac_mode == HVACMode.COOL - - -async def test_send(hass: HomeAssistant) -> None: - """Test send.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - await thermostat.async_update() - await hass.async_block_till_done() - await thermostat.async_send({"fan": api.FAN_MEDIUM}) - await hass.async_block_till_done() - assert thermostat.fan_mode == FAN_MEDIUM - api.async_send.return_value = AsyncMock(return_value=False) - thermostat._cur_settings = None - await thermostat.async_send({"fan": api.FAN_LOW}) - await hass.async_block_till_done() - assert thermostat.fan_mode != FAN_LOW - assert thermostat._cur_settings is None - - -async def test_update(hass: HomeAssistant) -> None: - """Test update.""" - with patch( - "homeassistant.components.melissa.climate._LOGGER.warning" - ) as mocked_warning, patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - await thermostat.async_update() - assert thermostat.fan_mode == FAN_LOW - assert thermostat.state == HVACMode.HEAT - api.async_status = AsyncMock(side_effect=KeyError("boom")) - await thermostat.async_update() - mocked_warning.assert_called_once_with( - "Unable to update entity %s", thermostat.entity_id - ) - - -async def test_melissa_op_to_hass(hass: HomeAssistant) -> None: - """Test for translate melissa operations to hass.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert thermostat.melissa_op_to_hass(1) == HVACMode.FAN_ONLY - assert thermostat.melissa_op_to_hass(2) == HVACMode.HEAT - assert thermostat.melissa_op_to_hass(3) == HVACMode.COOL - assert thermostat.melissa_op_to_hass(4) == HVACMode.DRY - assert thermostat.melissa_op_to_hass(5) is None - - -async def test_melissa_fan_to_hass(hass: HomeAssistant) -> None: - """Test for translate melissa fan state to hass.""" - with patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert thermostat.melissa_fan_to_hass(0) == "auto" - assert thermostat.melissa_fan_to_hass(1) == FAN_LOW - assert thermostat.melissa_fan_to_hass(2) == FAN_MEDIUM - assert thermostat.melissa_fan_to_hass(3) == FAN_HIGH - assert thermostat.melissa_fan_to_hass(4) is None - - -async def test_hass_mode_to_melissa(hass: HomeAssistant) -> None: - """Test for hass operations to melssa.""" - with patch( - "homeassistant.components.melissa.climate._LOGGER.warning" - ) as mocked_warning, patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert thermostat.hass_mode_to_melissa(HVACMode.FAN_ONLY) == 1 - assert thermostat.hass_mode_to_melissa(HVACMode.HEAT) == 2 - assert thermostat.hass_mode_to_melissa(HVACMode.COOL) == 3 - assert thermostat.hass_mode_to_melissa(HVACMode.DRY) == 4 - thermostat.hass_mode_to_melissa("test") - mocked_warning.assert_called_once_with( - "Melissa have no setting for %s mode", "test" - ) - - -async def test_hass_fan_to_melissa(hass: HomeAssistant) -> None: - """Test for translate melissa states to hass.""" - with patch( - "homeassistant.components.melissa.climate._LOGGER.warning" - ) as mocked_warning, patch("homeassistant.components.melissa"): - api = melissa_mock() - device = (await api.async_fetch_devices())[_SERIAL] - thermostat = MelissaClimate(api, _SERIAL, device) - assert thermostat.hass_fan_to_melissa("auto") == 0 - assert thermostat.hass_fan_to_melissa(FAN_LOW) == 1 - assert thermostat.hass_fan_to_melissa(FAN_MEDIUM) == 2 - assert thermostat.hass_fan_to_melissa(FAN_HIGH) == 3 - thermostat.hass_fan_to_melissa("test") - mocked_warning.assert_called_once_with( - "Melissa have no setting for %s fan mode", "test" - ) + assert len(mock_melissa.return_value.async_send.mock_calls) == 2 diff --git a/tests/components/melissa/test_init.py b/tests/components/melissa/test_init.py index 8f1e0c7a43c..6ad86ba4595 100644 --- a/tests/components/melissa/test_init.py +++ b/tests/components/melissa/test_init.py @@ -1,25 +1,13 @@ """The test for the Melissa Climate component.""" -from unittest.mock import AsyncMock, patch -from homeassistant.components import melissa from homeassistant.core import HomeAssistant -VALID_CONFIG = {"melissa": {"username": "********", "password": "********"}} +from tests.components.melissa import setup_integration -async def test_setup(hass: HomeAssistant) -> None: +async def test_setup(hass: HomeAssistant, mock_melissa) -> None: """Test setting up the Melissa component.""" - with patch("melissa.AsyncMelissa") as mocked_melissa, patch.object( - melissa, "async_load_platform" - ): - mocked_melissa.return_value.async_connect = AsyncMock() - await melissa.async_setup(hass, VALID_CONFIG) + await setup_integration(hass) - mocked_melissa.assert_called_with(username="********", password="********") - - assert melissa.DATA_MELISSA in hass.data - assert isinstance( - hass.data[melissa.DATA_MELISSA], - type(mocked_melissa.return_value), - ) + mock_melissa.assert_called_with(username="********", password="********")