diff --git a/homeassistant/data_entry_flow.py b/homeassistant/data_entry_flow.py index 5eed267fbbd..40d0a4de763 100644 --- a/homeassistant/data_entry_flow.py +++ b/homeassistant/data_entry_flow.py @@ -311,6 +311,15 @@ class FlowManager(abc.ABC): async def async_configure( self, flow_id: str, user_input: dict | None = None + ) -> FlowResult: + """Continue a data entry flow.""" + result: FlowResult | None = None + while not result or result["type"] == FlowResultType.SHOW_PROGRESS_DONE: + result = await self._async_configure(flow_id, user_input) + return result + + async def _async_configure( + self, flow_id: str, user_input: dict | None = None ) -> FlowResult: """Continue a data entry flow.""" if (flow := self._progress.get(flow_id)) is None: @@ -455,7 +464,7 @@ class FlowManager(abc.ABC): # The flow's progress task was changed, register a callback on it async def call_configure() -> None: with suppress(UnknownFlow): - await self.async_configure(flow.flow_id) + await self._async_configure(flow.flow_id) def schedule_configure(_: asyncio.Task) -> None: self.hass.async_create_task(call_configure()) diff --git a/tests/test_data_entry_flow.py b/tests/test_data_entry_flow.py index 130f4829ca2..78833ac7517 100644 --- a/tests/test_data_entry_flow.py +++ b/tests/test_data_entry_flow.py @@ -507,6 +507,54 @@ async def test_show_progress_error(hass: HomeAssistant, manager) -> None: assert result["reason"] == "error" +async def test_show_progress_hidden_from_frontend(hass: HomeAssistant, manager) -> None: + """Test show progress done is not sent to frontend.""" + manager.hass = hass + async_show_progress_done_called = False + + @manager.mock_reg_handler("test") + class TestFlow(data_entry_flow.FlowHandler): + VERSION = 5 + data = None + progress_task: asyncio.Task[None] | None = None + + async def async_step_init(self, user_input=None): + async def long_running_job() -> None: + return + + if not self.progress_task: + self.progress_task = hass.async_create_task(long_running_job()) + if self.progress_task.done(): + nonlocal async_show_progress_done_called + async_show_progress_done_called = True + return self.async_show_progress_done(next_step_id="finish") + return self.async_show_progress( + step_id="init", + progress_action="task", + # Set to None to simulate flow manager has not yet called when + # frontend loads + progress_task=None, + ) + + async def async_step_finish(self, user_input=None): + return self.async_create_entry(title=None, data=self.data) + + result = await manager.async_init("test") + assert result["type"] == data_entry_flow.FlowResultType.SHOW_PROGRESS + assert result["progress_action"] == "task" + assert len(manager.async_progress()) == 1 + assert len(manager.async_progress_by_handler("test")) == 1 + assert manager.async_get(result["flow_id"])["handler"] == "test" + + await hass.async_block_till_done() + assert not async_show_progress_done_called + + # Frontend refreshes the flow + result = await manager.async_configure(result["flow_id"]) + assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY + assert async_show_progress_done_called + + async def test_show_progress_legacy(hass: HomeAssistant, manager, caplog) -> None: """Test show progress logic. @@ -580,7 +628,10 @@ async def test_show_progress_legacy(hass: HomeAssistant, manager, caplog) -> Non result = await manager.async_configure( result["flow_id"], {"task_finished": 2, "title": "Hello"} ) - assert result["type"] == data_entry_flow.FlowResultType.SHOW_PROGRESS_DONE + # Note: The SHOW_PROGRESS_DONE is hidden from frontend; FlowManager automatically + # calls the flow again + assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY + assert result["title"] == "Hello" await hass.async_block_till_done() assert len(events) == 2 # 1 for task one and 1 for task two @@ -590,11 +641,6 @@ async def test_show_progress_legacy(hass: HomeAssistant, manager, caplog) -> Non "refresh": True, } - # Frontend refreshes the flow - result = await manager.async_configure(result["flow_id"]) - assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY - assert result["title"] == "Hello" - # Check for deprecation warning assert ( "tests.test_data_entry_flow::TestFlow calls async_show_progress without passing"