From a301a9c4b6f42daebd74f3eb6d1e4d4922a1faa8 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 13 Feb 2026 20:17:48 +0100 Subject: [PATCH] Always include homeassistant translations in tests (#162850) --- tests/components/easyenergy/test_services.py | 2 +- tests/components/sensibo/test_climate.py | 12 ++++--- .../components/transmission/test_services.py | 3 +- tests/conftest.py | 34 ++++++++++++++++--- tests/helpers/test_script.py | 5 --- tests/helpers/test_service.py | 3 -- tests/snapshots/test_config.ambr | 10 +++--- tests/test_config.py | 7 ---- tests/test_core.py | 18 +--------- 9 files changed, 47 insertions(+), 47 deletions(-) diff --git a/tests/components/easyenergy/test_services.py b/tests/components/easyenergy/test_services.py index 81c6fe57823..aaaf9b6d969 100644 --- a/tests/components/easyenergy/test_services.py +++ b/tests/components/easyenergy/test_services.py @@ -108,7 +108,7 @@ def config_entry_data( {"config_entry": "incorrect entry"}, {"incl_vat": True}, ServiceValidationError, - "service_config_entry_not_found", + "config entry with ID incorrect entry was not found", ), ( {"config_entry": True}, diff --git a/tests/components/sensibo/test_climate.py b/tests/components/sensibo/test_climate.py index e2216f0c8ef..0a8d3f7e5fa 100644 --- a/tests/components/sensibo/test_climate.py +++ b/tests/components/sensibo/test_climate.py @@ -174,13 +174,14 @@ async def test_climate_fan( async_fire_time_changed(hass) await hass.async_block_till_done() - with pytest.raises(HomeAssistantError, match="service_not_supported"): + with pytest.raises(HomeAssistantError) as err: await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_FAN_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_FAN_MODE: "low"}, blocking=True, ) + assert err.value.translation_key == "service_not_supported" state = hass.states.get("climate.hallway") assert "fan_mode" not in state.attributes @@ -255,13 +256,14 @@ async def test_climate_swing( async_fire_time_changed(hass) await hass.async_block_till_done() - with pytest.raises(HomeAssistantError, match="service_not_supported"): + with pytest.raises(HomeAssistantError) as err: await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_SWING_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_SWING_MODE: "fixedtop"}, blocking=True, ) + assert err.value.translation_key == "service_not_supported" state = hass.states.get("climate.hallway") assert "swing_mode" not in state.attributes @@ -341,7 +343,7 @@ async def test_climate_horizontal_swing( async_fire_time_changed(hass) await hass.async_block_till_done() - with pytest.raises(HomeAssistantError, match="service_not_supported"): + with pytest.raises(HomeAssistantError) as err: await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_SWING_HORIZONTAL_MODE, @@ -351,6 +353,7 @@ async def test_climate_horizontal_swing( }, blocking=True, ) + assert err.value.translation_key == "service_not_supported" state = hass.states.get("climate.hallway") assert "swing_horizontal_mode" not in state.attributes @@ -465,13 +468,14 @@ async def test_climate_temperatures( async_fire_time_changed(hass) await hass.async_block_till_done() - with pytest.raises(HomeAssistantError, match="service_not_supported"): + with pytest.raises(HomeAssistantError) as err: await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: state.entity_id, ATTR_TEMPERATURE: 20}, blocking=True, ) + assert err.value.translation_key == "service_not_supported" state = hass.states.get("climate.hallway") assert "temperature" not in state.attributes diff --git a/tests/components/transmission/test_services.py b/tests/components/transmission/test_services.py index 7d7683fbeec..d74fc641e79 100644 --- a/tests/components/transmission/test_services.py +++ b/tests/components/transmission/test_services.py @@ -37,7 +37,7 @@ async def test_service_config_entry_not_loaded_state( assert mock_config_entry.state is ConfigEntryState.NOT_LOADED - with pytest.raises(ServiceValidationError, match="service_not_found"): + with pytest.raises(ServiceValidationError) as err: await hass.services.async_call( DOMAIN, SERVICE_ADD_TORRENT, @@ -47,6 +47,7 @@ async def test_service_config_entry_not_loaded_state( }, blocking=True, ) + assert err.value.translation_key == "service_not_found" async def test_service_integration_not_found( diff --git a/tests/conftest.py b/tests/conftest.py index e596f955ed9..87973ce23d9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -626,6 +626,9 @@ async def hass( loop.set_exception_handler(exc_handle) frame.async_setup(hass) + # Ensure translations for "homeassistant" are always pre-loaded + await translation_helper.async_load_integrations(hass, {ha.DOMAIN}) + yield hass # Config entries are not normally unloaded on HA shutdown. They are unloaded here @@ -1296,10 +1299,33 @@ def translations_once() -> Generator[_patch]: def evict_faked_translations(translations_once) -> Generator[_patch]: """Clear translations for mocked integrations from the cache after each module.""" real_component_strings = translation_helper._async_get_component_strings - with patch( - "homeassistant.helpers.translation._async_get_component_strings", - wraps=real_component_strings, - ) as mock_component_strings: + + def _async_get_cached_translations( + _hass: HomeAssistant, + _language: str, + _category: str, + _integration: str | None = None, + ) -> dict[str, str]: + # Override default implementation to ensure "homeassistant" + # is always considered when getting "global" cached translations + cache = translation_helper._async_get_translations_cache(_hass) + _components = ( + {_integration} + if _integration + else _hass.config.top_level_components | {ha.DOMAIN} + ) + return cache.get_cached(_language, _category, _components) + + with ( + patch( + "homeassistant.helpers.translation.async_get_cached_translations", + _async_get_cached_translations, + ), + patch( + "homeassistant.helpers.translation._async_get_component_strings", + wraps=real_component_strings, + ) as mock_component_strings, + ): yield cache: _TranslationsCacheData = translations_once.kwargs["return_value"] component_paths = components.__path__ diff --git a/tests/helpers/test_script.py b/tests/helpers/test_script.py index 89d046ba628..c0eae410643 100644 --- a/tests/helpers/test_script.py +++ b/tests/helpers/test_script.py @@ -4019,7 +4019,6 @@ async def test_parallel_error( hass: HomeAssistant, caplog: pytest.LogCaptureFixture ) -> None: """Test parallel action failure handling.""" - await async_setup_component(hass, "homeassistant", {}) events = async_capture_events(hass, "test_event") sequence = cv.SCRIPT_SCHEMA( { @@ -4073,7 +4072,6 @@ async def test_last_triggered(hass: HomeAssistant) -> None: async def test_propagate_error_service_not_found(hass: HomeAssistant) -> None: """Test that a script aborts when a service is not found.""" - await async_setup_component(hass, "homeassistant", {}) event = "test_event" events = async_capture_events(hass, event) sequence = cv.SCRIPT_SCHEMA([{"action": "test.script"}, {"event": event}]) @@ -6291,7 +6289,6 @@ async def test_continue_on_error_with_stop(hass: HomeAssistant) -> None: async def test_continue_on_error_automation_issue(hass: HomeAssistant) -> None: """Test continue on error doesn't block action automation errors.""" - await async_setup_component(hass, "homeassistant", {}) sequence = cv.SCRIPT_SCHEMA( [ { @@ -6328,7 +6325,6 @@ async def test_continue_on_error_automation_issue(hass: HomeAssistant) -> None: async def test_continue_on_error_unknown_error(hass: HomeAssistant) -> None: """Test continue on error doesn't block unknown errors from e.g., libraries.""" - await async_setup_component(hass, "homeassistant", {}) class MyLibraryError(Exception): """My custom library error.""" @@ -6424,7 +6420,6 @@ async def test_disabled_actions( async def test_enabled_error_non_limited_template(hass: HomeAssistant) -> None: """Test that a script aborts when an action enabled uses non-limited template.""" - await async_setup_component(hass, "homeassistant", {}) event = "test_event" events = async_capture_events(hass, event) sequence = cv.SCRIPT_SCHEMA( diff --git a/tests/helpers/test_service.py b/tests/helpers/test_service.py index 3e1e4755033..9e798cccade 100644 --- a/tests/helpers/test_service.py +++ b/tests/helpers/test_service.py @@ -1511,7 +1511,6 @@ async def test_register_with_mixed_case(hass: HomeAssistant) -> None: async def test_call_with_required_features(hass: HomeAssistant, mock_entities) -> None: """Test service calls invoked only if entity has required features.""" # Set up homeassistant component to fetch the translations - await async_setup_component(hass, "homeassistant", {}) test_service_mock = AsyncMock(return_value=None) await service.entity_service_call( hass, @@ -1618,8 +1617,6 @@ async def test_call_with_device_class( unsupported_entity: str, ) -> None: """Test service calls invoked only if entity has required features.""" - # Set up homeassistant component to fetch the translations - await async_setup_component(hass, "homeassistant", {}) test_service_mock = AsyncMock(return_value=None) await service.entity_service_call( hass, diff --git a/tests/snapshots/test_config.ambr b/tests/snapshots/test_config.ambr index 7531bf5a663..60eab035d4c 100644 --- a/tests/snapshots/test_config.ambr +++ b/tests/snapshots/test_config.ambr @@ -78,7 +78,7 @@ }), dict({ 'has_exc_info': True, - 'message': 'config_validator_unknown_err', + 'message': 'Unknown error calling custom_validator_bad_2 config validator - broken', }), ]) # --- @@ -146,7 +146,7 @@ }), dict({ 'has_exc_info': True, - 'message': 'config_validator_unknown_err', + 'message': 'Unknown error calling custom_validator_bad_2 config validator - broken', }), ]) # --- @@ -262,7 +262,7 @@ }), dict({ 'has_exc_info': True, - 'message': 'config_validator_unknown_err', + 'message': 'Unknown error calling custom_validator_bad_2 config validator - broken', }), ]) # --- @@ -306,7 +306,7 @@ }), dict({ 'has_exc_info': True, - 'message': 'config_validator_unknown_err', + 'message': 'Unknown error calling custom_validator_bad_2 config validator - broken', }), dict({ 'has_exc_info': False, @@ -357,7 +357,7 @@ ''', "Invalid config for 'custom_validator_ok_2' at configuration.yaml, line 52: required key 'host' not provided, please check the docs at https://www.home-assistant.io/integrations/custom_validator_ok_2", "Invalid config for 'custom_validator_bad_1' at configuration.yaml, line 55: broken, please check the docs at https://www.home-assistant.io/integrations/custom_validator_bad_1", - 'config_validator_unknown_err', + 'Unknown error calling custom_validator_bad_2 config validator - broken', ]) # --- # name: test_individual_packages_schema_validation_errors[packages_dict] diff --git a/tests/test_config.py b/tests/test_config.py index 569af3238d0..99984f560fd 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -22,7 +22,6 @@ from homeassistant.exceptions import ConfigValidationError, HomeAssistantError from homeassistant.helpers import check_config, config_validation as cv from homeassistant.helpers.typing import ConfigType from homeassistant.loader import Integration, async_get_integration -from homeassistant.setup import async_setup_component from homeassistant.util.yaml import SECRET_YAML from homeassistant.util.yaml.objects import NodeDictClass @@ -852,9 +851,6 @@ async def test_component_config_exceptions( }, ) - # Make sure the exception translation cache is loaded - await async_setup_component(hass, "homeassistant", {}) - test_integration = Mock( domain="test_domain", async_get_component=AsyncMock(), @@ -1289,9 +1285,6 @@ async def test_component_config_error_processing( ) -> None: """Test component config error processing.""" - # Make sure the exception translation cache is loaded - await async_setup_component(hass, "homeassistant", {}) - test_integration = Mock( domain="test_domain", documentation="https://example.com", diff --git a/tests/test_core.py b/tests/test_core.py index 19ab0b8cace..d87a7aa7b11 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -58,7 +58,6 @@ from homeassistant.exceptions import ( ServiceValidationError, ) from homeassistant.helpers.json import json_dumps -from homeassistant.setup import async_setup_component from homeassistant.util import dt as dt_util from homeassistant.util.async_ import create_eager_task from homeassistant.util.read_only_dict import ReadOnlyDict @@ -1348,18 +1347,6 @@ async def test_eventbus_max_length_exceeded(hass: HomeAssistant) -> None: "this_event_exceeds_the_max_character_length_even_with_the_new_limit" ) - # Without cached translations the translation key is returned - with pytest.raises(MaxLengthExceeded) as exc_info: - hass.bus.async_fire(long_evt_name) - - assert str(exc_info.value) == "max_length_exceeded" - assert exc_info.value.property_name == "event_type" - assert exc_info.value.max_length == 64 - assert exc_info.value.value == long_evt_name - - # Fetch translations - await async_setup_component(hass, "homeassistant", {}) - # With cached translations the formatted message is returned with pytest.raises(MaxLengthExceeded) as exc_info: hass.bus.async_fire(long_evt_name) @@ -1368,6 +1355,7 @@ async def test_eventbus_max_length_exceeded(hass: HomeAssistant) -> None: str(exc_info.value) == f"Value {long_evt_name} for property event_type has a maximum length of 64 characters" ) + assert exc_info.value.translation_key == "max_length_exceeded" assert exc_info.value.property_name == "event_type" assert exc_info.value.max_length == 64 assert exc_info.value.value == long_evt_name @@ -1732,7 +1720,6 @@ async def test_serviceregistry_remove_service(hass: HomeAssistant) -> None: async def test_serviceregistry_service_that_not_exists(hass: HomeAssistant) -> None: """Test remove service that not exists.""" - await async_setup_component(hass, "homeassistant", {}) calls_remove = async_capture_events(hass, EVENT_SERVICE_REMOVED) assert not hass.services.has_service("test_xxx", "test_yyy") hass.services.async_remove("test_xxx", "test_yyy") @@ -1830,7 +1817,6 @@ async def test_services_call_return_response_requires_blocking( hass: HomeAssistant, ) -> None: """Test that non-blocking service calls cannot ask for response data.""" - await async_setup_component(hass, "homeassistant", {}) async_mock_service(hass, "test_domain", "test_service") with pytest.raises(ServiceValidationError, match="blocking=False") as exc: await hass.services.async_call( @@ -1860,7 +1846,6 @@ async def test_serviceregistry_return_response_invalid( hass: HomeAssistant, response_data: Any, expected_error: str ) -> None: """Test service call response data must be json serializable objects.""" - await async_setup_component(hass, "homeassistant", {}) def service_handler(call: ServiceCall) -> ServiceResponse: """Service handler coroutine.""" @@ -1897,7 +1882,6 @@ async def test_serviceregistry_return_response_arguments( expected_error: str, ) -> None: """Test service call response data invalid arguments.""" - await async_setup_component(hass, "homeassistant", {}) hass.services.async_register( "test_domain",