From fbde3eeaa12f063136725c0b5b9e2effc6daf370 Mon Sep 17 00:00:00 2001 From: orchestrator-agent Date: Sat, 19 Sep 2026 14:20:13 -0400 Subject: [PATCH] Allow saving the empty default notify target An empty target means notifications are not configured yet and is the shipped default; only malformed strings (padded or whitespace-only) reject. --- custom_components/nestquest/options_flow.py | 12 ++++++++---- tests/test_options_flow.py | 17 +++++++++++++++-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/custom_components/nestquest/options_flow.py b/custom_components/nestquest/options_flow.py index 201d128..bf5c59f 100644 --- a/custom_components/nestquest/options_flow.py +++ b/custom_components/nestquest/options_flow.py @@ -98,11 +98,15 @@ def _async_validate(user_input: dict[str, Any]) -> dict[str, str]: ): errors[time_key] = "invalid_time" notify_target = user_input.get(CONF_NOTIFY_TARGET) - if notify_target is not None and ( - not isinstance(notify_target, str) - or not notify_target.strip() - or notify_target != notify_target.strip() + if notify_target is not None and not isinstance(notify_target, str): + errors[CONF_NOTIFY_TARGET] = "invalid" + elif isinstance(notify_target, str) and notify_target != ( + notify_target.strip() ): + # An EMPTY target is valid — it means "no notifications + # configured yet" and is the shipped default; a value that + # differs from its own trim (padded or whitespace-only) is + # malformed and rejected. errors[CONF_NOTIFY_TARGET] = "invalid" for toggle_key in ( CONF_MORNING_SUMMARY_ENABLED, diff --git a/tests/test_options_flow.py b/tests/test_options_flow.py index ba4dcc5..f0c8385 100644 --- a/tests/test_options_flow.py +++ b/tests/test_options_flow.py @@ -712,9 +712,22 @@ def test_options_flow_notification_times_must_be_strict_hh_mm() -> None: assert result["errors"] == {CONF_MORNING_SUMMARY_TIME: "invalid_time"} -def test_options_flow_notify_target_must_be_clean_nonempty_string() -> None: +def test_options_flow_notify_target_validation() -> None: + """The empty target is VALID (it is the shipped default and must be + savable); only malformed non-empty values reject.""" flow = _make_flow(_make_entry()) - for bad_target in ("", " notify.x ", 42): + # The empty default saves cleanly. + result = _run( + flow.async_step_init( + {**VALID_INPUT, CONF_NOTIFY_TARGET: ""} + ) + ) + assert result["type"] == "create_entry" + assert result["data"][CONF_NOTIFY_TARGET] == "" + + # Malformed non-empty values reject. + for bad_target in (" notify.x ", " ", 42): + flow = _make_flow(_make_entry()) result = _run( flow.async_step_init( {