diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 6f1c6f46599..6b0737ae346 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -888,9 +888,11 @@ def script_action(value: Any) -> dict: SCRIPT_SCHEMA = vol.All(ensure_list, [script_action]) +SCRIPT_ACTION_BASE_SCHEMA = {vol.Optional(CONF_ALIAS): string} + EVENT_SCHEMA = vol.Schema( { - vol.Optional(CONF_ALIAS): string, + **SCRIPT_ACTION_BASE_SCHEMA, vol.Required(CONF_EVENT): string, vol.Optional(CONF_EVENT_DATA): vol.All(dict, template_complex), vol.Optional(CONF_EVENT_DATA_TEMPLATE): vol.All(dict, template_complex), @@ -900,7 +902,7 @@ EVENT_SCHEMA = vol.Schema( SERVICE_SCHEMA = vol.All( vol.Schema( { - vol.Optional(CONF_ALIAS): string, + **SCRIPT_ACTION_BASE_SCHEMA, vol.Exclusive(CONF_SERVICE, "service name"): vol.Any( service, dynamic_template ), @@ -920,9 +922,12 @@ NUMERIC_STATE_THRESHOLD_SCHEMA = vol.Any( vol.Coerce(float), vol.All(str, entity_domain("input_number")) ) +CONDITION_BASE_SCHEMA = {vol.Optional(CONF_ALIAS): string} + NUMERIC_STATE_CONDITION_SCHEMA = vol.All( vol.Schema( { + **CONDITION_BASE_SCHEMA, vol.Required(CONF_CONDITION): "numeric_state", vol.Required(CONF_ENTITY_ID): entity_ids, vol.Optional(CONF_ATTRIBUTE): str, @@ -935,6 +940,7 @@ NUMERIC_STATE_CONDITION_SCHEMA = vol.All( ) STATE_CONDITION_BASE_SCHEMA = { + **CONDITION_BASE_SCHEMA, vol.Required(CONF_CONDITION): "state", vol.Required(CONF_ENTITY_ID): entity_ids, vol.Optional(CONF_ATTRIBUTE): str, @@ -975,6 +981,7 @@ def STATE_CONDITION_SCHEMA(value: Any) -> dict: # pylint: disable=invalid-name SUN_CONDITION_SCHEMA = vol.All( vol.Schema( { + **CONDITION_BASE_SCHEMA, vol.Required(CONF_CONDITION): "sun", vol.Optional("before"): sun_event, vol.Optional("before_offset"): time_period, @@ -989,6 +996,7 @@ SUN_CONDITION_SCHEMA = vol.All( TEMPLATE_CONDITION_SCHEMA = vol.Schema( { + **CONDITION_BASE_SCHEMA, vol.Required(CONF_CONDITION): "template", vol.Required(CONF_VALUE_TEMPLATE): template, } @@ -997,6 +1005,7 @@ TEMPLATE_CONDITION_SCHEMA = vol.Schema( TIME_CONDITION_SCHEMA = vol.All( vol.Schema( { + **CONDITION_BASE_SCHEMA, vol.Required(CONF_CONDITION): "time", "before": vol.Any(time, vol.All(str, entity_domain("input_datetime"))), "after": vol.Any(time, vol.All(str, entity_domain("input_datetime"))), @@ -1008,6 +1017,7 @@ TIME_CONDITION_SCHEMA = vol.All( ZONE_CONDITION_SCHEMA = vol.Schema( { + **CONDITION_BASE_SCHEMA, vol.Required(CONF_CONDITION): "zone", vol.Required(CONF_ENTITY_ID): entity_ids, "zone": entity_ids, @@ -1019,6 +1029,7 @@ ZONE_CONDITION_SCHEMA = vol.Schema( AND_CONDITION_SCHEMA = vol.Schema( { + **CONDITION_BASE_SCHEMA, vol.Required(CONF_CONDITION): "and", vol.Required(CONF_CONDITIONS): vol.All( ensure_list, @@ -1030,6 +1041,7 @@ AND_CONDITION_SCHEMA = vol.Schema( OR_CONDITION_SCHEMA = vol.Schema( { + **CONDITION_BASE_SCHEMA, vol.Required(CONF_CONDITION): "or", vol.Required(CONF_CONDITIONS): vol.All( ensure_list, @@ -1041,6 +1053,7 @@ OR_CONDITION_SCHEMA = vol.Schema( NOT_CONDITION_SCHEMA = vol.Schema( { + **CONDITION_BASE_SCHEMA, vol.Required(CONF_CONDITION): "not", vol.Required(CONF_CONDITIONS): vol.All( ensure_list, @@ -1052,6 +1065,7 @@ NOT_CONDITION_SCHEMA = vol.Schema( DEVICE_CONDITION_BASE_SCHEMA = vol.Schema( { + **CONDITION_BASE_SCHEMA, vol.Required(CONF_CONDITION): "device", vol.Required(CONF_DEVICE_ID): str, vol.Required(CONF_DOMAIN): str, @@ -1087,14 +1101,14 @@ TRIGGER_SCHEMA = vol.All( _SCRIPT_DELAY_SCHEMA = vol.Schema( { - vol.Optional(CONF_ALIAS): string, + **SCRIPT_ACTION_BASE_SCHEMA, vol.Required(CONF_DELAY): positive_time_period_template, } ) _SCRIPT_WAIT_TEMPLATE_SCHEMA = vol.Schema( { - vol.Optional(CONF_ALIAS): string, + **SCRIPT_ACTION_BASE_SCHEMA, vol.Required(CONF_WAIT_TEMPLATE): template, vol.Optional(CONF_TIMEOUT): positive_time_period_template, vol.Optional(CONF_CONTINUE_ON_TIMEOUT): boolean, @@ -1102,16 +1116,22 @@ _SCRIPT_WAIT_TEMPLATE_SCHEMA = vol.Schema( ) DEVICE_ACTION_BASE_SCHEMA = vol.Schema( - {vol.Required(CONF_DEVICE_ID): string, vol.Required(CONF_DOMAIN): str} + { + **SCRIPT_ACTION_BASE_SCHEMA, + vol.Required(CONF_DEVICE_ID): string, + vol.Required(CONF_DOMAIN): str, + } ) DEVICE_ACTION_SCHEMA = DEVICE_ACTION_BASE_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA) -_SCRIPT_SCENE_SCHEMA = vol.Schema({vol.Required(CONF_SCENE): entity_domain("scene")}) +_SCRIPT_SCENE_SCHEMA = vol.Schema( + {**SCRIPT_ACTION_BASE_SCHEMA, vol.Required(CONF_SCENE): entity_domain("scene")} +) _SCRIPT_REPEAT_SCHEMA = vol.Schema( { - vol.Optional(CONF_ALIAS): string, + **SCRIPT_ACTION_BASE_SCHEMA, vol.Required(CONF_REPEAT): vol.All( { vol.Exclusive(CONF_COUNT, "repeat"): vol.Any(vol.Coerce(int), template), @@ -1130,11 +1150,12 @@ _SCRIPT_REPEAT_SCHEMA = vol.Schema( _SCRIPT_CHOOSE_SCHEMA = vol.Schema( { - vol.Optional(CONF_ALIAS): string, + **SCRIPT_ACTION_BASE_SCHEMA, vol.Required(CONF_CHOOSE): vol.All( ensure_list, [ { + vol.Optional(CONF_ALIAS): string, vol.Required(CONF_CONDITIONS): vol.All( ensure_list, [CONDITION_SCHEMA] ), @@ -1148,7 +1169,7 @@ _SCRIPT_CHOOSE_SCHEMA = vol.Schema( _SCRIPT_WAIT_FOR_TRIGGER_SCHEMA = vol.Schema( { - vol.Optional(CONF_ALIAS): string, + **SCRIPT_ACTION_BASE_SCHEMA, vol.Required(CONF_WAIT_FOR_TRIGGER): TRIGGER_SCHEMA, vol.Optional(CONF_TIMEOUT): positive_time_period_template, vol.Optional(CONF_CONTINUE_ON_TIMEOUT): boolean, @@ -1157,7 +1178,7 @@ _SCRIPT_WAIT_FOR_TRIGGER_SCHEMA = vol.Schema( _SCRIPT_SET_SCHEMA = vol.Schema( { - vol.Optional(CONF_ALIAS): string, + **SCRIPT_ACTION_BASE_SCHEMA, vol.Required(CONF_VARIABLES): SCRIPT_VARIABLES_SCHEMA, } ) diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 69ba082e573..2e8348bcaf8 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -18,7 +18,7 @@ from typing import ( cast, ) -from async_timeout import timeout +import async_timeout import voluptuous as vol from homeassistant import exceptions @@ -235,6 +235,13 @@ class _ScriptRun: msg, *args, level=level, **kwargs ) + def _step_log(self, default_message, timeout=None): + self._script.last_action = self._action.get(CONF_ALIAS, default_message) + _timeout = ( + "" if timeout is None else f" (timeout: {timedelta(seconds=timeout)})" + ) + self._log("Executing step %s%s", self._script.last_action, _timeout) + async def async_run(self) -> None: """Run script.""" try: @@ -327,13 +334,12 @@ class _ScriptRun: """Handle delay.""" delay = self._get_pos_time_period_template(CONF_DELAY) - self._script.last_action = self._action.get(CONF_ALIAS, f"delay {delay}") - self._log("Executing step %s", self._script.last_action) + self._step_log(f"delay {delay}") delay = delay.total_seconds() self._changed() try: - async with timeout(delay): + async with async_timeout.timeout(delay): await self._stop.wait() except asyncio.TimeoutError: pass @@ -341,18 +347,13 @@ class _ScriptRun: async def _async_wait_template_step(self): """Handle a wait template.""" if CONF_TIMEOUT in self._action: - delay = self._get_pos_time_period_template(CONF_TIMEOUT).total_seconds() + timeout = self._get_pos_time_period_template(CONF_TIMEOUT).total_seconds() else: - delay = None + timeout = None - self._script.last_action = self._action.get(CONF_ALIAS, "wait template") - self._log( - "Executing step %s%s", - self._script.last_action, - "" if delay is None else f" (timeout: {timedelta(seconds=delay)})", - ) + self._step_log("wait template", timeout) - self._variables["wait"] = {"remaining": delay, "completed": False} + self._variables["wait"] = {"remaining": timeout, "completed": False} wait_template = self._action[CONF_WAIT_TEMPLATE] wait_template.hass = self._hass @@ -366,7 +367,7 @@ class _ScriptRun: def async_script_wait(entity_id, from_s, to_s): """Handle script after template condition is true.""" self._variables["wait"] = { - "remaining": to_context.remaining if to_context else delay, + "remaining": to_context.remaining if to_context else timeout, "completed": True, } done.set() @@ -382,7 +383,7 @@ class _ScriptRun: self._hass.async_create_task(flag.wait()) for flag in (self._stop, done) ] try: - async with timeout(delay) as to_context: + async with async_timeout.timeout(timeout) as to_context: await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) except asyncio.TimeoutError as ex: if not self._action.get(CONF_CONTINUE_ON_TIMEOUT, True): @@ -431,8 +432,7 @@ class _ScriptRun: async def _async_call_service_step(self): """Call the service specified in the action.""" - self._script.last_action = self._action.get(CONF_ALIAS, "call service") - self._log("Executing step %s", self._script.last_action) + self._step_log("call service") params = service.async_prepare_call_from_config( self._hass, self._action, self._variables @@ -467,8 +467,7 @@ class _ScriptRun: async def _async_device_step(self): """Perform the device automation specified in the action.""" - self._script.last_action = self._action.get(CONF_ALIAS, "device automation") - self._log("Executing step %s", self._script.last_action) + self._step_log("device automation") platform = await device_automation.async_get_device_automation_platform( self._hass, self._action[CONF_DOMAIN], "action" ) @@ -478,8 +477,7 @@ class _ScriptRun: async def _async_scene_step(self): """Activate the scene specified in the action.""" - self._script.last_action = self._action.get(CONF_ALIAS, "activate scene") - self._log("Executing step %s", self._script.last_action) + self._step_log("activate scene") await self._hass.services.async_call( scene.DOMAIN, SERVICE_TURN_ON, @@ -490,10 +488,7 @@ class _ScriptRun: async def _async_event_step(self): """Fire an event.""" - self._script.last_action = self._action.get( - CONF_ALIAS, self._action[CONF_EVENT] - ) - self._log("Executing step %s", self._script.last_action) + self._step_log(self._action.get(CONF_ALIAS, self._action[CONF_EVENT])) event_data = {} for conf in [CONF_EVENT_DATA, CONF_EVENT_DATA_TEMPLATE]: if conf not in self._action: @@ -627,25 +622,20 @@ class _ScriptRun: async def _async_wait_for_trigger_step(self): """Wait for a trigger event.""" if CONF_TIMEOUT in self._action: - delay = self._get_pos_time_period_template(CONF_TIMEOUT).total_seconds() + timeout = self._get_pos_time_period_template(CONF_TIMEOUT).total_seconds() else: - delay = None + timeout = None - self._script.last_action = self._action.get(CONF_ALIAS, "wait for trigger") - self._log( - "Executing step %s%s", - self._script.last_action, - "" if delay is None else f" (timeout: {timedelta(seconds=delay)})", - ) + self._step_log("wait for trigger", timeout) variables = {**self._variables} - self._variables["wait"] = {"remaining": delay, "trigger": None} + self._variables["wait"] = {"remaining": timeout, "trigger": None} done = asyncio.Event() async def async_done(variables, context=None): self._variables["wait"] = { - "remaining": to_context.remaining if to_context else delay, + "remaining": to_context.remaining if to_context else timeout, "trigger": variables["trigger"], } done.set() @@ -671,7 +661,7 @@ class _ScriptRun: self._hass.async_create_task(flag.wait()) for flag in (self._stop, done) ] try: - async with timeout(delay) as to_context: + async with async_timeout.timeout(timeout) as to_context: await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) except asyncio.TimeoutError as ex: if not self._action.get(CONF_CONTINUE_ON_TIMEOUT, True): @@ -685,8 +675,7 @@ class _ScriptRun: async def _async_variables_step(self): """Set a variable value.""" - self._script.last_action = self._action.get(CONF_ALIAS, "setting variables") - self._log("Executing step %s", self._script.last_action) + self._step_log("setting variables") self._variables = self._action[CONF_VARIABLES].async_render( self._hass, self._variables, render_as_defaults=False ) @@ -1111,10 +1100,11 @@ class Script: await self._async_get_condition(config) for config in choice.get(CONF_CONDITIONS, []) ] + choice_name = choice.get(CONF_ALIAS, f"choice {idx}") sub_script = Script( self._hass, choice[CONF_SEQUENCE], - f"{self.name}: {step_name}: choice {idx}", + f"{self.name}: {step_name}: {choice_name}", self.domain, running_description=self.running_description, script_mode=SCRIPT_MODE_PARALLEL, diff --git a/tests/helpers/test_condition.py b/tests/helpers/test_condition.py index 3e7833b24dd..63ef9ba56d8 100644 --- a/tests/helpers/test_condition.py +++ b/tests/helpers/test_condition.py @@ -34,6 +34,7 @@ async def test_and_condition(hass): test = await condition.async_from_config( hass, { + "alias": "And Condition", "condition": "and", "conditions": [ { @@ -71,6 +72,7 @@ async def test_and_condition_with_template(hass): "condition": "and", "conditions": [ { + "alias": "Template Condition", "condition": "template", "value_template": '{{ states.sensor.temperature.state == "100" }}', }, @@ -98,6 +100,7 @@ async def test_or_condition(hass): test = await condition.async_from_config( hass, { + "alias": "Or Condition", "condition": "or", "conditions": [ { @@ -159,6 +162,7 @@ async def test_not_condition(hass): test = await condition.async_from_config( hass, { + "alias": "Not Condition", "condition": "not", "conditions": [ { @@ -226,36 +230,45 @@ async def test_not_condition_with_template(hass): async def test_time_window(hass): """Test time condition windows.""" - sixam = dt.parse_time("06:00:00") - sixpm = dt.parse_time("18:00:00") + sixam = "06:00:00" + sixpm = "18:00:00" + + test1 = await condition.async_from_config( + hass, + {"alias": "Time Cond", "condition": "time", "after": sixam, "before": sixpm}, + ) + test2 = await condition.async_from_config( + hass, + {"alias": "Time Cond", "condition": "time", "after": sixpm, "before": sixam}, + ) with patch( "homeassistant.helpers.condition.dt_util.now", return_value=dt.now().replace(hour=3), ): - assert not condition.time(hass, after=sixam, before=sixpm) - assert condition.time(hass, after=sixpm, before=sixam) + assert not test1(hass) + assert test2(hass) with patch( "homeassistant.helpers.condition.dt_util.now", return_value=dt.now().replace(hour=9), ): - assert condition.time(hass, after=sixam, before=sixpm) - assert not condition.time(hass, after=sixpm, before=sixam) + assert test1(hass) + assert not test2(hass) with patch( "homeassistant.helpers.condition.dt_util.now", return_value=dt.now().replace(hour=15), ): - assert condition.time(hass, after=sixam, before=sixpm) - assert not condition.time(hass, after=sixpm, before=sixam) + assert test1(hass) + assert not test2(hass) with patch( "homeassistant.helpers.condition.dt_util.now", return_value=dt.now().replace(hour=21), ): - assert not condition.time(hass, after=sixam, before=sixpm) - assert condition.time(hass, after=sixpm, before=sixam) + assert not test1(hass) + assert test2(hass) async def test_time_using_input_datetime(hass): @@ -439,6 +452,7 @@ async def test_multiple_states(hass): "condition": "and", "conditions": [ { + "alias": "State Condition", "condition": "state", "entity_id": "sensor.temperature", "state": ["100", "200"], @@ -709,6 +723,7 @@ async def test_numeric_state_multiple_entities(hass): "condition": "and", "conditions": [ { + "alias": "Numeric State Condition", "condition": "numeric_state", "entity_id": ["sensor.temperature_1", "sensor.temperature_2"], "below": 50, @@ -911,6 +926,7 @@ async def test_zone_multiple_entities(hass): "condition": "and", "conditions": [ { + "alias": "Zone Condition", "condition": "zone", "entity_id": ["device_tracker.person_1", "device_tracker.person_2"], "zone": "zone.home", diff --git a/tests/helpers/test_config_validation.py b/tests/helpers/test_config_validation.py index 1397e499c7e..d0ae86f8f7e 100644 --- a/tests/helpers/test_config_validation.py +++ b/tests/helpers/test_config_validation.py @@ -358,6 +358,11 @@ def test_service_schema(): "service": "homeassistant.turn_on", "entity_id": ["light.kitchen", "light.ceiling"], }, + { + "service": "light.turn_on", + "entity_id": "all", + "alias": "turn on kitchen lights", + }, ) for value in options: cv.SERVICE_SCHEMA(value) diff --git a/tests/helpers/test_script.py b/tests/helpers/test_script.py index a22cf27acdc..d2946fcd494 100644 --- a/tests/helpers/test_script.py +++ b/tests/helpers/test_script.py @@ -50,7 +50,10 @@ async def test_firing_event_basic(hass, caplog): context = Context() events = async_capture_events(hass, event) - sequence = cv.SCRIPT_SCHEMA({"event": event, "event_data": {"hello": "world"}}) + alias = "event step" + sequence = cv.SCRIPT_SCHEMA( + {"alias": alias, "event": event, "event_data": {"hello": "world"}} + ) script_obj = script.Script( hass, sequence, "Test Name", "test_domain", running_description="test script" ) @@ -63,6 +66,7 @@ async def test_firing_event_basic(hass, caplog): assert events[0].data.get("hello") == "world" assert ".test_name:" in caplog.text assert "Test Name: Running test script" in caplog.text + assert f"Executing step {alias}" in caplog.text async def test_firing_event_template(hass): @@ -107,12 +111,15 @@ async def test_firing_event_template(hass): } -async def test_calling_service_basic(hass): +async def test_calling_service_basic(hass, caplog): """Test the calling of a service.""" context = Context() calls = async_mock_service(hass, "test", "script") - sequence = cv.SCRIPT_SCHEMA({"service": "test.script", "data": {"hello": "world"}}) + alias = "service step" + sequence = cv.SCRIPT_SCHEMA( + {"alias": alias, "service": "test.script", "data": {"hello": "world"}} + ) script_obj = script.Script(hass, sequence, "Test Name", "test_domain") await script_obj.async_run(context=context) @@ -121,6 +128,7 @@ async def test_calling_service_basic(hass): assert len(calls) == 1 assert calls[0].context is context assert calls[0].data.get("hello") == "world" + assert f"Executing step {alias}" in caplog.text async def test_calling_service_template(hass): @@ -250,12 +258,13 @@ async def test_multiple_runs_no_wait(hass): assert len(calls) == 4 -async def test_activating_scene(hass): +async def test_activating_scene(hass, caplog): """Test the activation of a scene.""" context = Context() calls = async_mock_service(hass, scene.DOMAIN, SERVICE_TURN_ON) - sequence = cv.SCRIPT_SCHEMA({"scene": "scene.hello"}) + alias = "scene step" + sequence = cv.SCRIPT_SCHEMA({"alias": alias, "scene": "scene.hello"}) script_obj = script.Script(hass, sequence, "Test Name", "test_domain") await script_obj.async_run(context=context) @@ -264,6 +273,7 @@ async def test_activating_scene(hass): assert len(calls) == 1 assert calls[0].context is context assert calls[0].data.get(ATTR_ENTITY_ID) == "scene.hello" + assert f"Executing step {alias}" in caplog.text @pytest.mark.parametrize("count", [1, 3]) @@ -1063,14 +1073,16 @@ async def test_condition_warning(hass, caplog): assert len(events) == 1 -async def test_condition_basic(hass): +async def test_condition_basic(hass, caplog): """Test if we can use conditions in a script.""" event = "test_event" events = async_capture_events(hass, event) + alias = "condition step" sequence = cv.SCRIPT_SCHEMA( [ {"event": event}, { + "alias": alias, "condition": "template", "value_template": "{{ states.test.entity.state == 'hello' }}", }, @@ -1083,6 +1095,8 @@ async def test_condition_basic(hass): await script_obj.async_run(context=Context()) await hass.async_block_till_done() + assert f"Test condition {alias}: True" in caplog.text + caplog.clear() assert len(events) == 2 hass.states.async_set("test.entity", "goodbye") @@ -1090,6 +1104,7 @@ async def test_condition_basic(hass): await script_obj.async_run(context=Context()) await hass.async_block_till_done() + assert f"Test condition {alias}: False" in caplog.text assert len(events) == 3 @@ -1140,14 +1155,16 @@ async def test_condition_all_cached(hass): assert len(script_obj._config_cache) == 2 -async def test_repeat_count(hass): +async def test_repeat_count(hass, caplog): """Test repeat action w/ count option.""" event = "test_event" events = async_capture_events(hass, event) count = 3 + alias = "condition step" sequence = cv.SCRIPT_SCHEMA( { + "alias": alias, "repeat": { "count": count, "sequence": { @@ -1158,7 +1175,7 @@ async def test_repeat_count(hass): "last": "{{ repeat.last }}", }, }, - } + }, } ) script_obj = script.Script(hass, sequence, "Test Name", "test_domain") @@ -1171,6 +1188,7 @@ async def test_repeat_count(hass): assert event.data.get("first") == (index == 0) assert event.data.get("index") == index + 1 assert event.data.get("last") == (index == count - 1) + assert caplog.text.count(f"Repeating {alias}") == count @pytest.mark.parametrize("condition", ["while", "until"]) @@ -1470,26 +1488,44 @@ async def test_choose_warning(hass, caplog): @pytest.mark.parametrize("var,result", [(1, "first"), (2, "second"), (3, "default")]) -async def test_choose(hass, var, result): +async def test_choose(hass, caplog, var, result): """Test choose action.""" event = "test_event" events = async_capture_events(hass, event) + alias = "choose step" + choice = {1: "choice one", 2: "choice two", 3: None} + aliases = {1: "sequence one", 2: "sequence two", 3: "default sequence"} sequence = cv.SCRIPT_SCHEMA( { + "alias": alias, "choose": [ { + "alias": choice[1], "conditions": { "condition": "template", "value_template": "{{ var == 1 }}", }, - "sequence": {"event": event, "event_data": {"choice": "first"}}, + "sequence": { + "alias": aliases[1], + "event": event, + "event_data": {"choice": "first"}, + }, }, { + "alias": choice[2], "conditions": "{{ var == 2 }}", - "sequence": {"event": event, "event_data": {"choice": "second"}}, + "sequence": { + "alias": aliases[2], + "event": event, + "event_data": {"choice": "second"}, + }, }, ], - "default": {"event": event, "event_data": {"choice": "default"}}, + "default": { + "alias": aliases[3], + "event": event, + "event_data": {"choice": "default"}, + }, } ) script_obj = script.Script(hass, sequence, "Test Name", "test_domain") @@ -1499,6 +1535,10 @@ async def test_choose(hass, var, result): assert len(events) == 1 assert events[0].data["choice"] == result + expected_choice = choice[var] + if var == 3: + expected_choice = "default" + assert f"{alias}: {expected_choice}: Executing step {aliases[var]}" in caplog.text @pytest.mark.parametrize( @@ -2115,9 +2155,10 @@ async def test_started_action(hass, caplog): async def test_set_variable(hass, caplog): """Test setting variables in scripts.""" + alias = "variables step" sequence = cv.SCRIPT_SCHEMA( [ - {"variables": {"variable": "value"}}, + {"alias": alias, "variables": {"variable": "value"}}, {"service": "test.script", "data": {"value": "{{ variable }}"}}, ] ) @@ -2129,6 +2170,7 @@ async def test_set_variable(hass, caplog): await hass.async_block_till_done() assert mock_calls[0].data["value"] == "value" + assert f"Executing step {alias}" in caplog.text async def test_set_redefines_variable(hass, caplog):