diff --git a/homeassistant/components/html5/__init__.py b/homeassistant/components/html5/__init__.py
index 4b85bf8ab8cd3..26d7b50992145 100644
--- a/homeassistant/components/html5/__init__.py
+++ b/homeassistant/components/html5/__init__.py
@@ -3,14 +3,18 @@
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
-from homeassistant.helpers import discovery
+from homeassistant.helpers import config_validation as cv, discovery
from .const import DOMAIN
+CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
+
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up HTML5 from a config entry."""
- await discovery.async_load_platform(
- hass, Platform.NOTIFY, DOMAIN, dict(entry.data), {}
+ hass.async_create_task(
+ discovery.async_load_platform(
+ hass, Platform.NOTIFY, DOMAIN, dict(entry.data), {}
+ )
)
return True
diff --git a/homeassistant/components/html5/config_flow.py b/homeassistant/components/html5/config_flow.py
index def9d74b5d4b8..ae409d1366edf 100644
--- a/homeassistant/components/html5/config_flow.py
+++ b/homeassistant/components/html5/config_flow.py
@@ -17,7 +17,6 @@
from homeassistant.core import callback
from .const import ATTR_VAPID_EMAIL, ATTR_VAPID_PRV_KEY, ATTR_VAPID_PUB_KEY, DOMAIN
-from .issues import async_create_html5_issue
def vapid_generate_private_key() -> str:
@@ -92,14 +91,3 @@ async def async_step_user(
),
errors=errors,
)
-
- async def async_step_import(
- self: HTML5ConfigFlow, import_config: dict
- ) -> ConfigFlowResult:
- """Handle config import from yaml."""
- _, flow_result = self._async_create_html5_entry(import_config)
- if not flow_result:
- async_create_html5_issue(self.hass, False)
- return self.async_abort(reason="invalid_config")
- async_create_html5_issue(self.hass, True)
- return flow_result
diff --git a/homeassistant/components/html5/issues.py b/homeassistant/components/html5/issues.py
deleted file mode 100644
index 8892562d347e5..0000000000000
--- a/homeassistant/components/html5/issues.py
+++ /dev/null
@@ -1,50 +0,0 @@
-"""Issues utility for HTML5."""
-
-import logging
-
-from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant, callback
-from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
-
-from .const import DOMAIN
-
-_LOGGER = logging.getLogger(__name__)
-
-SUCCESSFUL_IMPORT_TRANSLATION_KEY = "deprecated_yaml"
-FAILED_IMPORT_TRANSLATION_KEY = "deprecated_yaml_import_issue"
-
-INTEGRATION_TITLE = "HTML5 Push Notifications"
-
-
-@callback
-def async_create_html5_issue(hass: HomeAssistant, import_success: bool) -> None:
- """Create issues for HTML5."""
- if import_success:
- async_create_issue(
- hass,
- HOMEASSISTANT_DOMAIN,
- f"deprecated_yaml_{DOMAIN}",
- breaks_in_ha_version="2025.4.0",
- is_fixable=False,
- issue_domain=DOMAIN,
- severity=IssueSeverity.WARNING,
- translation_key="deprecated_yaml",
- translation_placeholders={
- "domain": DOMAIN,
- "integration_title": INTEGRATION_TITLE,
- },
- )
- else:
- async_create_issue(
- hass,
- DOMAIN,
- f"deprecated_yaml_{DOMAIN}",
- breaks_in_ha_version="2025.4.0",
- is_fixable=False,
- issue_domain=DOMAIN,
- severity=IssueSeverity.WARNING,
- translation_key="deprecated_yaml_import_issue",
- translation_placeholders={
- "domain": DOMAIN,
- "integration_title": INTEGRATION_TITLE,
- },
- )
diff --git a/homeassistant/components/html5/notify.py b/homeassistant/components/html5/notify.py
index 859a7b7e5678a..f38ff0dce1d77 100644
--- a/homeassistant/components/html5/notify.py
+++ b/homeassistant/components/html5/notify.py
@@ -27,10 +27,8 @@
ATTR_TARGET,
ATTR_TITLE,
ATTR_TITLE_DEFAULT,
- PLATFORM_SCHEMA as NOTIFY_PLATFORM_SCHEMA,
BaseNotificationService,
)
-from homeassistant.config_entries import SOURCE_IMPORT
from homeassistant.const import ATTR_NAME, URL_ROOT
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.exceptions import HomeAssistantError
@@ -47,23 +45,12 @@
DOMAIN,
SERVICE_DISMISS,
)
-from .issues import async_create_html5_issue
_LOGGER = logging.getLogger(__name__)
REGISTRATIONS_FILE = "html5_push_registrations.conf"
-PLATFORM_SCHEMA = NOTIFY_PLATFORM_SCHEMA.extend(
- {
- vol.Optional("gcm_sender_id"): cv.string,
- vol.Optional("gcm_api_key"): cv.string,
- vol.Required(ATTR_VAPID_PUB_KEY): cv.string,
- vol.Required(ATTR_VAPID_PRV_KEY): cv.string,
- vol.Required(ATTR_VAPID_EMAIL): cv.string,
- }
-)
-
ATTR_SUBSCRIPTION = "subscription"
ATTR_BROWSER = "browser"
@@ -166,17 +153,7 @@ async def async_get_service(
) -> HTML5NotificationService | None:
"""Get the HTML5 push notification service."""
if config:
- existing_config_entry = hass.config_entries.async_entries(DOMAIN)
- if existing_config_entry:
- async_create_html5_issue(hass, True)
- return None
- hass.async_create_task(
- hass.config_entries.flow.async_init(
- DOMAIN, context={"source": SOURCE_IMPORT}, data=config
- )
- )
return None
-
if discovery_info is None:
return None
diff --git a/homeassistant/components/zwave_js/fan.py b/homeassistant/components/zwave_js/fan.py
index 8e47cbbeb1ddb..710c052327131 100644
--- a/homeassistant/components/zwave_js/fan.py
+++ b/homeassistant/components/zwave_js/fan.py
@@ -267,22 +267,10 @@ def percentage_to_zwave_speed(self, percentage: int) -> int:
if percentage == 0:
return 0
- # Since the percentage steps are computed with rounding, we have to
- # search to find the appropriate speed.
- for speed_range in self.fan_value_mapping.speeds:
- (_, max_speed) = speed_range
- step_percentage = self.zwave_speed_to_percentage(max_speed)
-
- # zwave_speed_to_percentage will only return None if
- # `self.fan_value_mapping.speeds` doesn't contain the
- # specified speed. This can't happen here, because
- # the input is coming from the same data structure.
- assert step_percentage
-
- if percentage <= step_percentage:
- break
-
- return max_speed
+ speed_level = math.ceil(
+ percentage_to_ranged_value((1, self.speed_count), percentage)
+ )
+ return self.fan_value_mapping.speeds[speed_level - 1][1]
def zwave_speed_to_percentage(self, zwave_speed: int) -> int | None:
"""Convert a Zwave speed to a percentage.
@@ -293,15 +281,9 @@ def zwave_speed_to_percentage(self, zwave_speed: int) -> int | None:
if zwave_speed == 0:
return 0
- percentage = 0.0
- for speed_range in self.fan_value_mapping.speeds:
- (min_speed, max_speed) = speed_range
- percentage += self.percentage_step
+ for index, (min_speed, max_speed) in enumerate(self.fan_value_mapping.speeds):
if min_speed <= zwave_speed <= max_speed:
- # This choice of rounding function is to provide consistency with how
- # the UI handles steps e.g., for a 3-speed fan, you get steps at 33,
- # 67, and 100.
- return round(percentage)
+ return ranged_value_to_percentage((1, self.speed_count), index + 1)
# The specified Z-Wave device value doesn't map to a defined speed.
return None
diff --git a/tests/components/html5/conftest.py b/tests/components/html5/conftest.py
new file mode 100644
index 0000000000000..9c5322b94a67a
--- /dev/null
+++ b/tests/components/html5/conftest.py
@@ -0,0 +1,47 @@
+"""Common fixtures for html5 integration."""
+
+from collections.abc import Generator
+from unittest.mock import MagicMock
+
+import pytest
+
+from homeassistant.components.html5.const import (
+ ATTR_VAPID_EMAIL,
+ ATTR_VAPID_PRV_KEY,
+ ATTR_VAPID_PUB_KEY,
+ DOMAIN,
+)
+from homeassistant.const import CONF_NAME
+
+from tests.common import MockConfigEntry, patch
+
+MOCK_CONF = {
+ ATTR_VAPID_EMAIL: "test@example.com",
+ ATTR_VAPID_PRV_KEY: "h6acSRds8_KR8hT9djD8WucTL06Gfe29XXyZ1KcUjN8",
+}
+MOCK_CONF_PUB_KEY = "BIUtPN7Rq_8U7RBEqClZrfZ5dR9zPCfvxYPtLpWtRVZTJEc7lzv2dhzDU6Aw1m29Ao0-UA1Uq6XO9Df8KALBKqA"
+
+
+@pytest.fixture(name="config_entry")
+def mock_config_entry() -> MockConfigEntry:
+ """Mock ntfy configuration entry."""
+ return MockConfigEntry(
+ domain=DOMAIN,
+ title="HTML5",
+ data={
+ ATTR_VAPID_PRV_KEY: MOCK_CONF[ATTR_VAPID_PRV_KEY],
+ ATTR_VAPID_PUB_KEY: MOCK_CONF_PUB_KEY,
+ ATTR_VAPID_EMAIL: MOCK_CONF[ATTR_VAPID_EMAIL],
+ CONF_NAME: DOMAIN,
+ },
+ )
+
+
+@pytest.fixture(name="load_config")
+def mock_load_config() -> Generator[MagicMock]:
+ """Mock load config."""
+
+ with patch(
+ "homeassistant.components.html5.notify._load_config", return_value={}
+ ) as mock_load_config:
+ yield mock_load_config
diff --git a/tests/components/html5/test_config_flow.py b/tests/components/html5/test_config_flow.py
index 3cde435771ef2..9019d321eecf5 100644
--- a/tests/components/html5/test_config_flow.py
+++ b/tests/components/html5/test_config_flow.py
@@ -11,19 +11,10 @@
ATTR_VAPID_PUB_KEY,
DOMAIN,
)
-from homeassistant.components.html5.issues import (
- FAILED_IMPORT_TRANSLATION_KEY,
- SUCCESSFUL_IMPORT_TRANSLATION_KEY,
-)
from homeassistant.const import CONF_NAME
-from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
-from homeassistant.helpers import issue_registry as ir
+from homeassistant.core import HomeAssistant
-MOCK_CONF = {
- ATTR_VAPID_EMAIL: "test@example.com",
- ATTR_VAPID_PRV_KEY: "h6acSRds8_KR8hT9djD8WucTL06Gfe29XXyZ1KcUjN8",
-}
-MOCK_CONF_PUB_KEY = "BIUtPN7Rq_8U7RBEqClZrfZ5dR9zPCfvxYPtLpWtRVZTJEc7lzv2dhzDU6Aw1m29Ao0-UA1Uq6XO9Df8KALBKqA"
+from .conftest import MOCK_CONF, MOCK_CONF_PUB_KEY
async def test_step_user_success(hass: HomeAssistant) -> None:
@@ -127,77 +118,3 @@ async def test_step_user_form_invalid_key(
)
assert result["type"] is data_entry_flow.FlowResultType.CREATE_ENTRY
assert mock_setup_entry.call_count == 1
-
-
-async def test_step_import_good(
- hass: HomeAssistant,
- issue_registry: ir.IssueRegistry,
-) -> None:
- """Test valid import input."""
-
- with (
- patch(
- "homeassistant.components.html5.async_setup_entry",
- return_value=True,
- ) as mock_setup_entry,
- ):
- conf = MOCK_CONF.copy()
- conf[ATTR_VAPID_PUB_KEY] = MOCK_CONF_PUB_KEY
- conf["random_key"] = "random_value"
-
- result = await hass.config_entries.flow.async_init(
- DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=conf
- )
-
- await hass.async_block_till_done()
-
- assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
- assert result["data"] == {
- ATTR_VAPID_PRV_KEY: conf[ATTR_VAPID_PRV_KEY],
- ATTR_VAPID_PUB_KEY: MOCK_CONF_PUB_KEY,
- ATTR_VAPID_EMAIL: conf[ATTR_VAPID_EMAIL],
- CONF_NAME: DOMAIN,
- }
-
- assert mock_setup_entry.call_count == 1
- assert len(issue_registry.issues) == 1
- issue = issue_registry.async_get_issue(
- HOMEASSISTANT_DOMAIN, f"deprecated_yaml_{DOMAIN}"
- )
- assert issue
- assert issue.translation_key == SUCCESSFUL_IMPORT_TRANSLATION_KEY
-
-
-@pytest.mark.parametrize(
- ("key", "value"),
- [
- (ATTR_VAPID_PRV_KEY, "invalid"),
- ],
-)
-async def test_step_import_bad(
- hass: HomeAssistant, issue_registry: ir.IssueRegistry, key: str, value: str
-) -> None:
- """Test invalid import input."""
-
- with (
- patch(
- "homeassistant.components.html5.async_setup_entry",
- return_value=True,
- ) as mock_setup_entry,
- ):
- bad_conf = MOCK_CONF.copy()
- bad_conf[key] = value
-
- result = await hass.config_entries.flow.async_init(
- DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=bad_conf
- )
-
- await hass.async_block_till_done()
-
- assert result["type"] == data_entry_flow.FlowResultType.ABORT
- assert mock_setup_entry.call_count == 0
-
- assert len(issue_registry.issues) == 1
- issue = issue_registry.async_get_issue(DOMAIN, f"deprecated_yaml_{DOMAIN}")
- assert issue
- assert issue.translation_key == FAILED_IMPORT_TRANSLATION_KEY
diff --git a/tests/components/html5/test_init.py b/tests/components/html5/test_init.py
index 840890f18d198..51f34b50f4c3f 100644
--- a/tests/components/html5/test_init.py
+++ b/tests/components/html5/test_init.py
@@ -1,44 +1,16 @@
"""Test the HTML5 setup."""
+from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
-from homeassistant.helpers import issue_registry as ir
-from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry
-NOTIFY_CONF = {
- "notify": [
- {
- "platform": "html5",
- "name": "html5",
- "vapid_pub_key": "BIUtPN7Rq_8U7RBEqClZrfZ5dR9zPCfvxYPtLpWtRVZTJEc7lzv2dhzDU6Aw1m29Ao0-UA1Uq6XO9Df8KALBKqA",
- "vapid_prv_key": "h6acSRds8_KR8hT9djD8WucTL06Gfe29XXyZ1KcUjN8",
- "vapid_email": "test@example.com",
- }
- ]
-}
-
-async def test_setup_entry(
- hass: HomeAssistant,
- issue_registry: ir.IssueRegistry,
-) -> None:
+async def test_setup_entry(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
"""Test setup of a good config entry."""
- config_entry = MockConfigEntry(domain="html5", data={})
- config_entry.add_to_hass(hass)
- assert await async_setup_component(hass, "html5", {})
-
- assert len(issue_registry.issues) == 0
-
-async def test_setup_entry_issue(
- hass: HomeAssistant,
- issue_registry: ir.IssueRegistry,
-) -> None:
- """Test setup of an imported config entry with deprecated YAML."""
- config_entry = MockConfigEntry(domain="html5", data={})
config_entry.add_to_hass(hass)
- assert await async_setup_component(hass, "notify", NOTIFY_CONF)
- assert await async_setup_component(hass, "html5", NOTIFY_CONF)
+ assert await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
- assert len(issue_registry.issues) == 1
+ assert config_entry.state is ConfigEntryState.LOADED
diff --git a/tests/components/html5/test_notify.py b/tests/components/html5/test_notify.py
index f602a8f380765..d1d37cc0e164d 100644
--- a/tests/components/html5/test_notify.py
+++ b/tests/components/html5/test_notify.py
@@ -2,17 +2,18 @@
from http import HTTPStatus
import json
-from typing import Any
-from unittest.mock import mock_open, patch
+from unittest.mock import MagicMock, mock_open, patch
from aiohttp.hdrs import AUTHORIZATION
-from aiohttp.test_utils import TestClient
+import pytest
from homeassistant.components.html5 import notify as html5
+from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.setup import async_setup_component
+from tests.common import MockConfigEntry
from tests.typing import ClientSessionGenerator
CONFIG_FILE = "file.conf"
@@ -71,24 +72,6 @@
PUBLISH_URL = "/api/notify.html5/callback"
-async def mock_client(
- hass: HomeAssistant,
- hass_client: ClientSessionGenerator,
- registrations: dict[str, Any] | None = None,
-) -> TestClient:
- """Create a test client for HTML5 views."""
- if registrations is None:
- registrations = {}
-
- with patch(
- "homeassistant.components.html5.notify._load_config", return_value=registrations
- ):
- await async_setup_component(hass, "notify", {"notify": VAPID_CONF})
- await hass.async_block_till_done()
-
- return await hass_client()
-
-
async def test_get_service_with_no_json(hass: HomeAssistant) -> None:
"""Test empty json file."""
await async_setup_component(hass, "http", {})
@@ -259,11 +242,22 @@ async def test_fcm_additional_data(mock_wp, hass: HomeAssistant) -> None:
assert mock_wp.mock_calls[3][2]["headers"]["priority"] == "normal"
+@pytest.mark.usefixtures("load_config")
async def test_registering_new_device_view(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
) -> None:
"""Test that the HTML view works."""
- client = await mock_client(hass, hass_client)
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
with patch("homeassistant.components.html5.notify.save_json") as mock_save:
resp = await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_1))
@@ -273,11 +267,22 @@ async def test_registering_new_device_view(
assert mock_save.mock_calls[0][1][1] == {"unnamed device": SUBSCRIPTION_1}
+@pytest.mark.usefixtures("load_config")
async def test_registering_new_device_view_with_name(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
) -> None:
"""Test that the HTML view works with name attribute."""
- client = await mock_client(hass, hass_client)
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
SUB_WITH_NAME = SUBSCRIPTION_1.copy()
SUB_WITH_NAME["name"] = "test device"
@@ -290,11 +295,22 @@ async def test_registering_new_device_view_with_name(
assert mock_save.mock_calls[0][1][1] == {"test device": SUBSCRIPTION_1}
+@pytest.mark.usefixtures("load_config")
async def test_registering_new_device_expiration_view(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
) -> None:
"""Test that the HTML view works."""
- client = await mock_client(hass, hass_client)
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
with patch("homeassistant.components.html5.notify.save_json") as mock_save:
resp = await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_4))
@@ -303,13 +319,22 @@ async def test_registering_new_device_expiration_view(
assert mock_save.mock_calls[0][1][1] == {"unnamed device": SUBSCRIPTION_4}
+@pytest.mark.usefixtures("load_config")
async def test_registering_new_device_fails_view(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
) -> None:
"""Test subs. are not altered when registering a new device fails."""
- registrations = {}
- client = await mock_client(hass, hass_client, registrations)
+ await async_setup_component(hass, "http", {})
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
with patch(
"homeassistant.components.html5.notify.save_json",
side_effect=HomeAssistantError(),
@@ -317,31 +342,51 @@ async def test_registering_new_device_fails_view(
resp = await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_4))
assert resp.status == HTTPStatus.INTERNAL_SERVER_ERROR
- assert registrations == {}
+@pytest.mark.usefixtures("load_config")
async def test_registering_existing_device_view(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
) -> None:
"""Test subscription is updated when registering existing device."""
- registrations = {}
- client = await mock_client(hass, hass_client, registrations)
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
with patch("homeassistant.components.html5.notify.save_json") as mock_save:
await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_1))
resp = await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_4))
assert resp.status == HTTPStatus.OK
- assert mock_save.mock_calls[0][1][1] == {"unnamed device": SUBSCRIPTION_4}
- assert registrations == {"unnamed device": SUBSCRIPTION_4}
+ mock_save.assert_called_with(
+ hass.config.path(html5.REGISTRATIONS_FILE), {"unnamed device": SUBSCRIPTION_4}
+ )
+@pytest.mark.usefixtures("load_config")
async def test_registering_existing_device_view_with_name(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
) -> None:
"""Test subscription is updated when reg'ing existing device with name."""
- registrations = {}
- client = await mock_client(hass, hass_client, registrations)
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
SUB_WITH_NAME = SUBSCRIPTION_1.copy()
SUB_WITH_NAME["name"] = "test device"
@@ -351,16 +396,28 @@ async def test_registering_existing_device_view_with_name(
resp = await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_4))
assert resp.status == HTTPStatus.OK
- assert mock_save.mock_calls[0][1][1] == {"test device": SUBSCRIPTION_4}
- assert registrations == {"test device": SUBSCRIPTION_4}
+
+ mock_save.assert_called_with(
+ hass.config.path(html5.REGISTRATIONS_FILE), {"test device": SUBSCRIPTION_4}
+ )
+@pytest.mark.usefixtures("load_config")
async def test_registering_existing_device_fails_view(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
) -> None:
"""Test sub. is not updated when registering existing device fails."""
- registrations = {}
- client = await mock_client(hass, hass_client, registrations)
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
with patch("homeassistant.components.html5.notify.save_json") as mock_save:
await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_1))
@@ -368,14 +425,24 @@ async def test_registering_existing_device_fails_view(
resp = await client.post(REGISTER_URL, data=json.dumps(SUBSCRIPTION_4))
assert resp.status == HTTPStatus.INTERNAL_SERVER_ERROR
- assert registrations == {"unnamed device": SUBSCRIPTION_1}
+@pytest.mark.usefixtures("load_config")
async def test_registering_new_device_validation(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
) -> None:
"""Test various errors when registering a new device."""
- client = await mock_client(hass, hass_client)
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
resp = await client.post(
REGISTER_URL,
@@ -395,11 +462,25 @@ async def test_registering_new_device_validation(
async def test_unregistering_device_view(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
+ load_config: MagicMock,
) -> None:
"""Test that the HTML unregister view works."""
- registrations = {"some device": SUBSCRIPTION_1, "other device": SUBSCRIPTION_2}
- client = await mock_client(hass, hass_client, registrations)
+ load_config.return_value = {
+ "some device": SUBSCRIPTION_1,
+ "other device": SUBSCRIPTION_2,
+ }
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
with patch("homeassistant.components.html5.notify.save_json") as mock_save:
resp = await client.delete(
@@ -409,15 +490,27 @@ async def test_unregistering_device_view(
assert resp.status == HTTPStatus.OK
assert len(mock_save.mock_calls) == 1
- assert registrations == {"other device": SUBSCRIPTION_2}
+ mock_save.assert_called_once_with(
+ hass.config.path(html5.REGISTRATIONS_FILE), {"other device": SUBSCRIPTION_2}
+ )
+@pytest.mark.usefixtures("load_config")
async def test_unregister_device_view_handle_unknown_subscription(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
) -> None:
"""Test that the HTML unregister view handles unknown subscriptions."""
- registrations = {}
- client = await mock_client(hass, hass_client, registrations)
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
with patch("homeassistant.components.html5.notify.save_json") as mock_save:
resp = await client.delete(
@@ -426,16 +519,29 @@ async def test_unregister_device_view_handle_unknown_subscription(
)
assert resp.status == HTTPStatus.OK, resp.response
- assert registrations == {}
assert len(mock_save.mock_calls) == 0
async def test_unregistering_device_view_handles_save_error(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
+ load_config: MagicMock,
) -> None:
"""Test that the HTML unregister view handles save errors."""
- registrations = {"some device": SUBSCRIPTION_1, "other device": SUBSCRIPTION_2}
- client = await mock_client(hass, hass_client, registrations)
+ load_config.return_value = {
+ "some device": SUBSCRIPTION_1,
+ "other device": SUBSCRIPTION_2,
+ }
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
with patch(
"homeassistant.components.html5.notify.save_json",
@@ -447,17 +553,24 @@ async def test_unregistering_device_view_handles_save_error(
)
assert resp.status == HTTPStatus.INTERNAL_SERVER_ERROR, resp.response
- assert registrations == {
- "some device": SUBSCRIPTION_1,
- "other device": SUBSCRIPTION_2,
- }
+@pytest.mark.usefixtures("load_config")
async def test_callback_view_no_jwt(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
) -> None:
"""Test that the notification callback view works without JWT."""
- client = await mock_client(hass, hass_client)
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
resp = await client.post(
PUBLISH_URL,
data=json.dumps(
@@ -469,11 +582,22 @@ async def test_callback_view_no_jwt(
async def test_callback_view_with_jwt(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ hass_client: ClientSessionGenerator,
+ config_entry: MockConfigEntry,
+ load_config: MagicMock,
) -> None:
"""Test that the notification callback view works with JWT."""
- registrations = {"device": SUBSCRIPTION_1}
- client = await mock_client(hass, hass_client, registrations)
+ load_config.return_value = {"device": SUBSCRIPTION_1}
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
+ client = await hass_client()
with patch("homeassistant.components.html5.notify.WebPusher") as mock_wp:
mock_wp().send().status_code = 201
@@ -507,11 +631,20 @@ async def test_callback_view_with_jwt(
async def test_send_fcm_without_targets(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ config_entry: MockConfigEntry,
+ load_config: MagicMock,
) -> None:
"""Test that the notification is send with FCM without targets."""
- registrations = {"device": SUBSCRIPTION_5}
- await mock_client(hass, hass_client, registrations)
+ load_config.return_value = {"device": SUBSCRIPTION_5}
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
+
with patch("homeassistant.components.html5.notify.WebPusher") as mock_wp:
mock_wp().send().status_code = 201
await hass.services.async_call(
@@ -528,15 +661,23 @@ async def test_send_fcm_without_targets(
async def test_send_fcm_expired(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ config_entry: MockConfigEntry,
+ load_config: MagicMock,
) -> None:
"""Test that the FCM target is removed when expired."""
- registrations = {"device": SUBSCRIPTION_5}
- await mock_client(hass, hass_client, registrations)
+ load_config.return_value = {"device": SUBSCRIPTION_5}
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
with (
patch("homeassistant.components.html5.notify.WebPusher") as mock_wp,
- patch("homeassistant.components.html5.notify.save_json"),
+ patch("homeassistant.components.html5.notify.save_json") as mock_save,
):
mock_wp().send().status_code = 410
await hass.services.async_call(
@@ -546,15 +687,24 @@ async def test_send_fcm_expired(
blocking=True,
)
# "device" should be removed when expired.
- assert "device" not in registrations
+ mock_save.assert_called_once_with(hass.config.path(html5.REGISTRATIONS_FILE), {})
async def test_send_fcm_expired_save_fails(
- hass: HomeAssistant, hass_client: ClientSessionGenerator
+ hass: HomeAssistant,
+ config_entry: MockConfigEntry,
+ load_config: MagicMock,
+ caplog: pytest.LogCaptureFixture,
) -> None:
"""Test that the FCM target remains after expiry if save_json fails."""
- registrations = {"device": SUBSCRIPTION_5}
- await mock_client(hass, hass_client, registrations)
+ load_config.return_value = {"device": SUBSCRIPTION_5}
+ await async_setup_component(hass, "http", {})
+
+ config_entry.add_to_hass(hass)
+ await hass.config_entries.async_setup(config_entry.entry_id)
+ await hass.async_block_till_done()
+
+ assert config_entry.state is ConfigEntryState.LOADED
with (
patch("homeassistant.components.html5.notify.WebPusher") as mock_wp,
@@ -564,6 +714,7 @@ async def test_send_fcm_expired_save_fails(
),
):
mock_wp().send().status_code = 410
+
await hass.services.async_call(
"notify",
"html5",
@@ -571,4 +722,4 @@ async def test_send_fcm_expired_save_fails(
blocking=True,
)
# "device" should still exist if save fails.
- assert "device" in registrations
+ assert "Error saving registration" in caplog.text
diff --git a/tests/components/zwave_js/test_fan.py b/tests/components/zwave_js/test_fan.py
index f57f412f2ad0f..15d41ba4b8d51 100644
--- a/tests/components/zwave_js/test_fan.py
+++ b/tests/components/zwave_js/test_fan.py
@@ -281,8 +281,8 @@ async def get_percentage_from_zwave_speed(zwave_speed):
percentages_to_zwave_speeds = [
[[0], [0]],
[range(1, 34), range(1, 34)],
- [range(34, 68), range(34, 67)],
- [range(68, 101), range(67, 100)],
+ [range(34, 67), range(34, 67)],
+ [range(67, 101), range(67, 100)],
]
for percentages, zwave_speeds in percentages_to_zwave_speeds:
@@ -407,8 +407,8 @@ async def get_percentage_from_zwave_speed(zwave_speed):
percentages_to_zwave_speeds = [
[[0], [0]],
[range(1, 34), range(1, 34)],
- [range(34, 68), range(34, 68)],
- [range(68, 101), range(68, 100)],
+ [range(34, 67), range(34, 68)],
+ [range(67, 101), range(68, 100)],
]
for percentages, zwave_speeds in percentages_to_zwave_speeds:
@@ -500,8 +500,8 @@ async def get_percentage_from_zwave_speed(zwave_speed):
percentages_to_zwave_speeds = [
[[0], [0]],
[range(1, 34), range(1, 33)], # percentages 1-33 → zwave 1-32
- [range(34, 68), range(33, 67)], # percentages 34-67 → zwave 33-66
- [range(68, 101), range(67, 100)], # percentages 68-100 → zwave 67-99
+ [range(34, 67), range(33, 67)], # percentages 34-66 → zwave 33-66
+ [range(67, 101), range(67, 100)], # percentages 67-100 → zwave 67-99
]
for percentages, zwave_speeds in percentages_to_zwave_speeds:
@@ -597,8 +597,8 @@ async def get_percentage_from_zwave_speed(zwave_speed):
percentages_to_zwave_speeds = [
[[0], [0]],
[range(1, 34), range(2, 34)],
- [range(34, 68), range(34, 67)],
- [range(68, 101), range(67, 100)],
+ [range(34, 67), range(34, 67)],
+ [range(67, 101), range(67, 100)],
]
for percentages, zwave_speeds in percentages_to_zwave_speeds:
@@ -1106,8 +1106,8 @@ async def get_percentage_from_zwave_speed(zwave_speed):
percentages_to_zwave_speeds = [
[[0], [0]],
[range(1, 34), range(1, 33)],
- [range(34, 68), range(33, 67)],
- [range(68, 101), range(67, 100)],
+ [range(34, 67), range(33, 67)],
+ [range(67, 101), range(67, 100)],
]
for percentages, zwave_speeds in percentages_to_zwave_speeds: