| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- """Unit tests for ForceRefreshButton, PromoteFromNextButton, and TestNextGuestButton.
- Uses object.__new__ to bypass HA entity setup — valid because async_press
- only calls coordinator methods, not HA lifecycle hooks.
- """
- from datetime import date, time, datetime, timezone
- from unittest.mock import AsyncMock, MagicMock, patch
- import pytest
- from custom_components.room_cal_ha.button import (
- ForceRefreshButton,
- PromoteFromNextButton,
- TestNextGuestButton,
- )
- from custom_components.room_cal_ha.const import STORE_NEXT
- from custom_components.room_cal_ha.models import OverrideData, ReservationData
- def _button(cls):
- btn = object.__new__(cls)
- btn._coordinator = MagicMock()
- btn._coordinator.async_refresh = AsyncMock()
- btn._coordinator.async_promote_next_to_current = AsyncMock()
- return btn
- async def test_force_refresh_calls_coordinator_refresh():
- btn = _button(ForceRefreshButton)
- await btn.async_press()
- btn._coordinator.async_refresh.assert_awaited_once()
- async def test_promote_from_next_calls_coordinator_promote():
- btn = _button(PromoteFromNextButton)
- await btn.async_press()
- btn._coordinator.async_promote_next_to_current.assert_awaited_once()
- async def test_force_refresh_does_not_call_promote():
- btn = _button(ForceRefreshButton)
- await btn.async_press()
- btn._coordinator.async_promote_next_to_current.assert_not_called()
- async def test_promote_does_not_call_refresh():
- btn = _button(PromoteFromNextButton)
- await btn.async_press()
- btn._coordinator.async_refresh.assert_not_called()
- # ---------------------------------------------------------------------------
- # TestNextGuestButton
- # ---------------------------------------------------------------------------
- _NEXT = ReservationData(
- guest_name="Bob",
- check_in_date=date(2026, 7, 10),
- check_in_time=time(15, 0),
- check_out_date=date(2026, 7, 14),
- check_out_time=time(11, 0),
- )
- _FROZEN_NOW = datetime(2026, 6, 22, 14, 0, 0, tzinfo=timezone.utc)
- def _test_next_button(next_data=_NEXT):
- btn = object.__new__(TestNextGuestButton)
- btn.coordinator = MagicMock()
- btn.coordinator.store = MagicMock()
- btn.coordinator.store.get.return_value = next_data
- btn.coordinator.async_start_override = AsyncMock()
- return btn
- async def test_test_next_guest_calls_start_override():
- btn = _test_next_button()
- with patch("custom_components.room_cal_ha.button.dt_util.now", return_value=_FROZEN_NOW):
- await btn.async_press()
- btn.coordinator.async_start_override.assert_awaited_once()
- async def test_test_next_guest_passes_override_data():
- btn = _test_next_button()
- with patch("custom_components.room_cal_ha.button.dt_util.now", return_value=_FROZEN_NOW):
- await btn.async_press()
- arg = btn.coordinator.async_start_override.call_args[0][0]
- assert isinstance(arg, OverrideData)
- async def test_test_next_guest_sets_check_in_to_one_hour_ago():
- btn = _test_next_button()
- with patch("custom_components.room_cal_ha.button.dt_util.now", return_value=_FROZEN_NOW):
- await btn.async_press()
- override: OverrideData = btn.coordinator.async_start_override.call_args[0][0]
- # now() naive = 2026-06-22 14:00 UTC; minus 1h = 13:00
- assert override.current.check_in_date == date(2026, 6, 22)
- assert override.current.check_in_time == time(13, 0)
- async def test_test_next_guest_preserves_other_fields():
- btn = _test_next_button()
- with patch("custom_components.room_cal_ha.button.dt_util.now", return_value=_FROZEN_NOW):
- await btn.async_press()
- override: OverrideData = btn.coordinator.async_start_override.call_args[0][0]
- assert override.current.guest_name == "Bob"
- assert override.current.check_out_date == date(2026, 7, 14)
- assert override.current.check_out_time == time(11, 0)
- async def test_test_next_guest_override_next_is_none():
- btn = _test_next_button()
- with patch("custom_components.room_cal_ha.button.dt_util.now", return_value=_FROZEN_NOW):
- await btn.async_press()
- override: OverrideData = btn.coordinator.async_start_override.call_args[0][0]
- assert override.next is None
- async def test_test_next_guest_reads_from_store():
- btn = _test_next_button()
- with patch("custom_components.room_cal_ha.button.dt_util.now", return_value=_FROZEN_NOW):
- await btn.async_press()
- btn.coordinator.store.get.assert_called_with(STORE_NEXT)
- async def test_test_next_guest_no_next_data_does_nothing():
- btn = _test_next_button(next_data=None)
- with patch("custom_components.room_cal_ha.button.dt_util.now", return_value=_FROZEN_NOW):
- await btn.async_press()
- btn.coordinator.async_start_override.assert_not_awaited()
|