Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 54 additions & 99 deletions tests/components/prusalink/test_button.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Test Prusalink buttons."""

from collections.abc import Awaitable, Callable
from unittest.mock import patch

from pyprusalink.types import Conflict
Expand All @@ -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():
Expand All @@ -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:
Comment thread
heikkih marked this conversation as resolved.
await hass.services.async_call(
"button",
"press",
{"entity_id": entity_id},
blocking=True,
)
Comment thread
heikkih marked this conversation as resolved.
mock_meth.assert_awaited_once()
Comment thread
heikkih marked this conversation as resolved.
Comment thread
heikkih marked this conversation as resolved.
Comment thread
heikkih marked this conversation as resolved.

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,
)
Comment thread
heikkih marked this conversation as resolved.
Comment thread
heikkih marked this conversation as resolved.

return _press_and_verify


@pytest.mark.parametrize(
("object_id", "method"),
[
Expand All @@ -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(
Expand All @@ -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)
Comment thread
heikkih marked this conversation as resolved.


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"
)
Comment thread
heikkih marked this conversation as resolved.


async def test_button_continue_unavailable_when_printing(
Expand Down