mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Ensure config_flow abort reasons have translations (#128140)
* Ensure config_flow abort reasons have translations * Ignore fake_integration in application_credentials * Mark gardena_bluetooth as needs fixing * Mark google as needs fixing * Mark google_assistant_sdk as needs fixing * Mark homewizard as needs fixing * Mark homeworks as needs fixing * Mark honeywell as needs fixing * Mark jewish_calendar as needs fixing * Mark lg_netcast as needs fixing * Mark lifx as needs fixing * Mark lyric as needs fixing * Mark madvr as needs fixing * Mark matter as needs fixing * Mark melcloud as needs fixing * Mark motioneye as needs fixing * Mark ollama as needs fixing * Mark philips_js as needs fixing * Mark spotify as needs fixing * Mark srp_energy as needs fixing * Mark subaru as needs fixing * Mark tplink as needs fixing * Mark yolink as needs fixing * Mark youtube as needs fixing * Fix incorrect comment
This commit is contained in:
parent
821d9abc56
commit
f41494b7cc
@ -48,6 +48,18 @@ NAME = "Name"
|
||||
TEST_DOMAIN = "fake_integration"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def ignore_translations() -> list[str]:
|
||||
"""Ignore specific translations.
|
||||
|
||||
We can ignore translations for the fake_integration we are testing with.
|
||||
"""
|
||||
return [
|
||||
f"component.{TEST_DOMAIN}.config.abort.missing_configuration",
|
||||
f"component.{TEST_DOMAIN}.config.abort.missing_credentials",
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def authorization_server() -> AuthorizationServer:
|
||||
"""Fixture AuthorizationServer for mock application_credentials integration."""
|
||||
|
@ -11,8 +11,16 @@ from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch
|
||||
from aiohasupervisor.models import Repository, StoreAddon, StoreInfo
|
||||
import pytest
|
||||
|
||||
from homeassistant.config_entries import (
|
||||
DISCOVERY_SOURCES,
|
||||
SOURCE_SYSTEM,
|
||||
ConfigEntriesFlowManager,
|
||||
FlowResult,
|
||||
)
|
||||
from homeassistant.const import STATE_OFF, STATE_ON
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowHandler, FlowManager, FlowResultType
|
||||
from homeassistant.helpers.translation import async_get_translations
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.components.hassio import AddonManager
|
||||
@ -456,3 +464,87 @@ def supervisor_client() -> Generator[AsyncMock]:
|
||||
),
|
||||
):
|
||||
yield supervisor_client
|
||||
|
||||
|
||||
async def _ensure_translation_exists(
|
||||
hass: HomeAssistant,
|
||||
ignore_translations: list[str],
|
||||
category: str,
|
||||
component: str,
|
||||
key: str,
|
||||
) -> None:
|
||||
"""Raise if translation doesn't exist."""
|
||||
full_key = f"component.{component}.{category}.{key}"
|
||||
if full_key in ignore_translations:
|
||||
return
|
||||
|
||||
translations = await async_get_translations(hass, "en", category, [component])
|
||||
if full_key in translations:
|
||||
return
|
||||
|
||||
key_parts = key.split(".")
|
||||
# Ignore step data translations if title or description exists
|
||||
if (
|
||||
len(key_parts) >= 3
|
||||
and key_parts[0] == "step"
|
||||
and key_parts[2] == "data"
|
||||
and (
|
||||
f"component.{component}.{category}.{key_parts[0]}.{key_parts[1]}.description"
|
||||
in translations
|
||||
or f"component.{component}.{category}.{key_parts[0]}.{key_parts[1]}.title"
|
||||
in translations
|
||||
)
|
||||
):
|
||||
return
|
||||
|
||||
raise ValueError(
|
||||
f"Translation not found for {component}: `{category}.{key}`. "
|
||||
f"Please add to homeassistant/components/{component}/strings.json"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def ignore_translations() -> list[str]:
|
||||
"""Ignore specific translations.
|
||||
|
||||
Override or parametrize this fixture with a fixture that returns,
|
||||
a list of translation that should be ignored.
|
||||
"""
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def check_config_translations(ignore_translations: list[str]) -> Generator[None]:
|
||||
"""Ensure config_flow translations are available."""
|
||||
_original = FlowManager._async_handle_step
|
||||
|
||||
async def _async_handle_step(
|
||||
self: FlowManager, flow: FlowHandler, *args
|
||||
) -> FlowResult:
|
||||
result = await _original(self, flow, *args)
|
||||
if isinstance(self, ConfigEntriesFlowManager):
|
||||
category = "config"
|
||||
component = flow.handler
|
||||
else:
|
||||
return result
|
||||
|
||||
if (
|
||||
result["type"] is FlowResultType.ABORT
|
||||
and flow.source != SOURCE_SYSTEM
|
||||
and flow.source not in DISCOVERY_SOURCES
|
||||
):
|
||||
await _ensure_translation_exists(
|
||||
flow.hass,
|
||||
ignore_translations,
|
||||
category,
|
||||
component,
|
||||
f"abort.{result["reason"]}",
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
with patch(
|
||||
"homeassistant.data_entry_flow.FlowManager._async_handle_step",
|
||||
_async_handle_step,
|
||||
):
|
||||
yield
|
||||
|
@ -138,7 +138,7 @@
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
# name: test_failed_connect
|
||||
# name: test_failed_connect[component.gardena_bluetooth.config.abort.cannot_connect]
|
||||
FlowResultSnapshot({
|
||||
'data_schema': list([
|
||||
dict({
|
||||
@ -163,7 +163,7 @@
|
||||
'type': <FlowResultType.FORM: 'form'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_failed_connect.1
|
||||
# name: test_failed_connect[component.gardena_bluetooth.config.abort.cannot_connect].1
|
||||
FlowResultSnapshot({
|
||||
'data_schema': None,
|
||||
'description_placeholders': dict({
|
||||
@ -178,7 +178,7 @@
|
||||
'type': <FlowResultType.FORM: 'form'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_failed_connect.2
|
||||
# name: test_failed_connect[component.gardena_bluetooth.config.abort.cannot_connect].2
|
||||
FlowResultSnapshot({
|
||||
'description_placeholders': dict({
|
||||
'error': 'something went wrong',
|
||||
|
@ -50,6 +50,10 @@ async def test_user_selection(
|
||||
assert result == snapshot
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.gardena_bluetooth.config.abort.cannot_connect"],
|
||||
)
|
||||
async def test_failed_connect(
|
||||
hass: HomeAssistant,
|
||||
mock_client: Mock,
|
||||
|
@ -437,6 +437,10 @@ async def test_multiple_config_entries(
|
||||
assert len(entries) == 2
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.google.config.abort.missing_credentials"],
|
||||
)
|
||||
async def test_missing_configuration(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
|
@ -157,6 +157,10 @@ async def test_reauth(
|
||||
assert config_entry.data["token"].get("refresh_token") == "mock-refresh-token"
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.google_assistant_sdk.config.abort.single_instance_allowed"],
|
||||
)
|
||||
@pytest.mark.usefixtures("current_request_with_host")
|
||||
async def test_single_instance_allowed(
|
||||
hass: HomeAssistant,
|
||||
|
@ -302,6 +302,10 @@ async def test_error_flow(
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.homewizard.config.abort.unsupported_api_version"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("exception", "reason"),
|
||||
[
|
||||
|
@ -235,6 +235,10 @@ async def test_user_flow_cannot_connect(
|
||||
assert result["step_id"] == "user"
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.homeworks.config.abort.reconfigure_successful"],
|
||||
)
|
||||
async def test_reconfigure_flow(
|
||||
hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_homeworks: MagicMock
|
||||
) -> None:
|
||||
@ -322,6 +326,10 @@ async def test_reconfigure_flow_flow_duplicate(
|
||||
assert result["errors"] == {"base": "duplicated_host_port"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.homeworks.config.abort.reconfigure_successful"],
|
||||
)
|
||||
async def test_reconfigure_flow_flow_no_change(
|
||||
hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_homeworks: MagicMock
|
||||
) -> None:
|
||||
|
@ -120,6 +120,10 @@ async def test_create_option_entry(
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.honeywell.config.abort.reauth_successful"],
|
||||
)
|
||||
async def test_reauth_flow(hass: HomeAssistant) -> None:
|
||||
"""Test a successful reauth flow."""
|
||||
|
||||
|
@ -166,6 +166,10 @@ async def test_options_reconfigure(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.jewish_calendar.config.abort.reconfigure_successful"],
|
||||
)
|
||||
async def test_reconfigure(
|
||||
hass: HomeAssistant, mock_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
|
@ -3,6 +3,8 @@
|
||||
from datetime import timedelta
|
||||
from unittest.mock import DEFAULT, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant.components.lg_netcast.const import DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
@ -112,6 +114,10 @@ async def test_manual_host_unsuccessful_details_response(hass: HomeAssistant) ->
|
||||
assert result["reason"] == "cannot_connect"
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.lg_netcast.config.abort.invalid_host"],
|
||||
)
|
||||
async def test_manual_host_no_unique_id_response(hass: HomeAssistant) -> None:
|
||||
"""Test manual host configuration."""
|
||||
with _patch_lg_netcast(no_unique_id=True):
|
||||
|
@ -101,6 +101,10 @@ async def test_discovery(hass: HomeAssistant) -> None:
|
||||
assert result2["reason"] == "no_devices_found"
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.lifx.config.abort.cannot_connect"],
|
||||
)
|
||||
async def test_discovery_but_cannot_connect(hass: HomeAssistant) -> None:
|
||||
"""Test we can discover the device but we cannot connect."""
|
||||
with _patch_discovery(), _patch_config_flow_try_connect(no_device=True):
|
||||
|
@ -36,6 +36,10 @@ async def mock_impl(hass: HomeAssistant) -> None:
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.lyric.config.abort.missing_credentials"],
|
||||
)
|
||||
async def test_abort_if_no_configuration(hass: HomeAssistant) -> None:
|
||||
"""Check flow abort when no configuration."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -165,6 +165,10 @@ async def test_reconfigure_flow(
|
||||
mock_madvr_client.async_cancel_tasks.assert_called()
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.madvr.config.abort.set_up_new_device"],
|
||||
)
|
||||
async def test_reconfigure_new_device(
|
||||
hass: HomeAssistant,
|
||||
mock_madvr_client: AsyncMock,
|
||||
|
@ -827,6 +827,10 @@ async def test_addon_running(
|
||||
assert setup_entry.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.matter.config.abort.cannot_connect"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
(
|
||||
"discovery_info",
|
||||
|
@ -73,6 +73,10 @@ async def test_form(hass: HomeAssistant, mock_login, mock_get_devices) -> None:
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.melcloud.config.abort.cannot_connect"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("error", "reason"),
|
||||
[(ClientError(), "cannot_connect"), (TimeoutError(), "cannot_connect")],
|
||||
@ -94,6 +98,15 @@ async def test_form_errors(
|
||||
assert result["reason"] == reason
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
[
|
||||
[
|
||||
"component.melcloud.config.abort.cannot_connect",
|
||||
"component.melcloud.config.abort.invalid_auth",
|
||||
],
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("error", "message"),
|
||||
[
|
||||
|
@ -7,6 +7,7 @@ from motioneye_client.client import (
|
||||
MotionEyeClientInvalidAuthError,
|
||||
MotionEyeClientRequestError,
|
||||
)
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.hassio import HassioServiceInfo
|
||||
@ -390,6 +391,10 @@ async def test_hassio_ignored(hass: HomeAssistant) -> None:
|
||||
assert result.get("reason") == "already_configured"
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.motioneye.config.abort.already_in_progress"],
|
||||
)
|
||||
async def test_hassio_abort_if_already_in_progress(hass: HomeAssistant) -> None:
|
||||
"""Test Supervisor discovered flow aborts if user flow in progress."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -204,6 +204,10 @@ async def test_form_errors(hass: HomeAssistant, side_effect, error) -> None:
|
||||
assert result2["errors"] == {"base": error}
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.ollama.config.abort.download_failed"],
|
||||
)
|
||||
async def test_download_error(hass: HomeAssistant) -> None:
|
||||
"""Test we handle errors while downloading a model."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -161,6 +161,10 @@ async def test_pairing(hass: HomeAssistant, mock_tv_pairable, mock_setup_entry)
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.philips_js.config.abort.pairing_failure"],
|
||||
)
|
||||
async def test_pair_request_failed(
|
||||
hass: HomeAssistant, mock_tv_pairable, mock_setup_entry
|
||||
) -> None:
|
||||
@ -188,6 +192,10 @@ async def test_pair_request_failed(
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.philips_js.config.abort.pairing_failure"],
|
||||
)
|
||||
async def test_pair_grant_failed(
|
||||
hass: HomeAssistant, mock_tv_pairable, mock_setup_entry
|
||||
) -> None:
|
||||
|
@ -29,6 +29,10 @@ BLANK_ZEROCONF_INFO = zeroconf.ZeroconfServiceInfo(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.spotify.config.abort.missing_credentials"],
|
||||
)
|
||||
async def test_abort_if_no_configuration(hass: HomeAssistant) -> None:
|
||||
"""Check flow aborts when no configuration is present."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -100,6 +100,10 @@ async def test_form_invalid_auth(
|
||||
assert result["errors"] == {"base": "invalid_auth"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.srp_energy.config.abort.unknown"],
|
||||
)
|
||||
async def test_form_unknown_error(
|
||||
hass: HomeAssistant,
|
||||
mock_srp_energy_config_flow: MagicMock,
|
||||
|
@ -192,6 +192,10 @@ async def test_two_factor_request_success(
|
||||
assert len(mock_two_factor_request.mock_calls) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.subaru.config.abort.two_factor_request_failed"],
|
||||
)
|
||||
async def test_two_factor_request_fail(
|
||||
hass: HomeAssistant, two_factor_start_form
|
||||
) -> None:
|
||||
|
@ -1348,6 +1348,10 @@ async def test_reauth_errors(
|
||||
assert result3["reason"] == "reauth_successful"
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.tplink.config.abort.cannot_connect"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("error_type", "expected_flow"),
|
||||
[
|
||||
|
@ -22,6 +22,10 @@ CLIENT_SECRET = "6789"
|
||||
DOMAIN = "yolink"
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.yolink.config.abort.missing_credentials"],
|
||||
)
|
||||
async def test_abort_if_no_configuration(hass: HomeAssistant) -> None:
|
||||
"""Check flow abort when no configuration."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -210,6 +210,10 @@ async def test_flow_http_error(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize( # Remove when translations fixed
|
||||
"ignore_translations",
|
||||
["component.youtube.config.abort.wrong_account"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("fixture", "abort_reason", "placeholders", "call_count", "access_token"),
|
||||
[
|
||||
|
Loading…
x
Reference in New Issue
Block a user