diff --git a/tests/components/prusalink/test_button.py b/tests/components/prusalink/test_button.py index fc6bb2321bdbc7..3f66a6619d629b 100644 --- a/tests/components/prusalink/test_button.py +++ b/tests/components/prusalink/test_button.py @@ -1,5 +1,6 @@ """Test Prusalink buttons.""" +from collections.abc import Awaitable, Callable from unittest.mock import patch from pyprusalink.types import Conflict @@ -10,8 +11,6 @@ from homeassistant.exceptions import HomeAssistantError from homeassistant.setup import async_setup_component -from tests.typing import ClientSessionGenerator - @pytest.fixture(autouse=True) def setup_button_platform_only(): @@ -20,6 +19,45 @@ def setup_button_platform_only(): yield +@pytest.fixture +def press_button_and_verify( + hass: HomeAssistant, +) -> Callable[[str, str], Awaitable[None]]: + """Return a helper that asserts the press path for a PrusaLink button. + + The helper verifies the entity is in the `unknown` state, that pressing it + invokes the matching pyprusalink method once, and that a `Conflict` from + the API surfaces as `HomeAssistantError`. + """ + + async def _press_and_verify(entity_id: str, method: str) -> None: + state = hass.states.get(entity_id) + assert state is not None + assert state.state == "unknown" + + with patch(f"pyprusalink.PrusaLink.{method}") as mock_meth: + await hass.services.async_call( + "button", + "press", + {"entity_id": entity_id}, + blocking=True, + ) + mock_meth.assert_awaited_once() + + with ( + pytest.raises(HomeAssistantError), + patch(f"pyprusalink.PrusaLink.{method}", side_effect=Conflict), + ): + await hass.services.async_call( + "button", + "press", + {"entity_id": entity_id}, + blocking=True, + ) + + return _press_and_verify + + @pytest.mark.parametrize( ("object_id", "method"), [ @@ -31,40 +69,15 @@ async def test_button_pause_cancel( hass: HomeAssistant, mock_config_entry, mock_api, - hass_client: ClientSessionGenerator, mock_job_api_printing, mock_get_status_printing, - object_id, - method, + press_button_and_verify, + object_id: str, + method: str, ) -> None: - """Test cancel and pause button.""" - entity_id = f"button.{object_id}" + """Test cancel and pause buttons in PRINTING state.""" assert await async_setup_component(hass, "prusalink", {}) - state = hass.states.get(entity_id) - assert state is not None - assert state.state == "unknown" - - with patch(f"pyprusalink.PrusaLink.{method}") as mock_meth: - await hass.services.async_call( - "button", - "press", - {"entity_id": entity_id}, - blocking=True, - ) - - assert len(mock_meth.mock_calls) == 1 - - # Verify it calls correct method + does error handling - with ( - pytest.raises(HomeAssistantError), - patch(f"pyprusalink.PrusaLink.{method}", side_effect=Conflict), - ): - await hass.services.async_call( - "button", - "press", - {"entity_id": entity_id}, - blocking=True, - ) + await press_button_and_verify(f"button.{object_id}", method) @pytest.mark.parametrize( @@ -78,86 +91,28 @@ async def test_button_resume_cancel( hass: HomeAssistant, mock_config_entry, mock_api, - hass_client: ClientSessionGenerator, mock_job_api_paused, - object_id, - method, + press_button_and_verify, + object_id: str, + method: str, ) -> None: - """Test resume button.""" - entity_id = f"button.{object_id}" + """Test cancel and resume buttons in PAUSED state.""" assert await async_setup_component(hass, "prusalink", {}) - state = hass.states.get(entity_id) - assert state is not None - assert state.state == "unknown" - - with ( - patch(f"pyprusalink.PrusaLink.{method}") as mock_meth, - patch( - "homeassistant.components.prusalink.coordinator.PrusaLinkUpdateCoordinator._fetch_data" - ), - ): - await hass.services.async_call( - "button", - "press", - {"entity_id": entity_id}, - blocking=True, - ) - - assert len(mock_meth.mock_calls) == 1 - - # Verify it calls correct method + does error handling - with ( - pytest.raises(HomeAssistantError), - patch(f"pyprusalink.PrusaLink.{method}", side_effect=Conflict), - ): - await hass.services.async_call( - "button", - "press", - {"entity_id": entity_id}, - blocking=True, - ) + await press_button_and_verify(f"button.{object_id}", method) async def test_button_continue( hass: HomeAssistant, mock_config_entry, mock_api, - hass_client: ClientSessionGenerator, mock_job_api_attention, + press_button_and_verify, ) -> None: """Test continue button is enabled in ATTENTION state and calls continue_job.""" - entity_id = "button.workshop_mock_title_continue_job" assert await async_setup_component(hass, "prusalink", {}) - state = hass.states.get(entity_id) - assert state is not None - assert state.state == "unknown" - - with ( - patch("pyprusalink.PrusaLink.continue_job") as mock_meth, - patch( - "homeassistant.components.prusalink.coordinator.PrusaLinkUpdateCoordinator._fetch_data" - ), - ): - await hass.services.async_call( - "button", - "press", - {"entity_id": entity_id}, - blocking=True, - ) - - assert len(mock_meth.mock_calls) == 1 - - # Verify error handling — Conflict raised by API surfaces as HomeAssistantError - with ( - pytest.raises(HomeAssistantError), - patch("pyprusalink.PrusaLink.continue_job", side_effect=Conflict), - ): - await hass.services.async_call( - "button", - "press", - {"entity_id": entity_id}, - blocking=True, - ) + await press_button_and_verify( + "button.workshop_mock_title_continue_job", "continue_job" + ) async def test_button_continue_unavailable_when_printing(