mirror of
https://github.com/Sea-Haven-Industries/afterhours-shift-manager.git
synced 2026-10-02 17:53:11 +00:00
Employees and admins can pick, drop, swap, and manage coverage through GET/POST/DELETE /api/shifts. Roster PUT accepts optional email for portal identity. Slack slash commands and App Home admin modals stay in place. Co-authored-by: adam <adam@seahavenind.com>
73 lines
2.8 KiB
Python
73 lines
2.8 KiB
Python
"""Tests for portal shift mutations."""
|
|
|
|
from zoneinfo import ZoneInfo
|
|
|
|
import freezegun
|
|
import pytest
|
|
|
|
from shared.portal_ops import ActionError, drop, pick, snapshot, swap
|
|
from shared import side_effects as effects
|
|
|
|
ET = ZoneInfo("America/New_York")
|
|
|
|
|
|
@pytest.fixture
|
|
def quiet_slack(monkeypatch):
|
|
monkeypatch.setattr(effects, "slack_token", lambda: None)
|
|
monkeypatch.setattr(effects, "refresh_schedule_post", lambda *a, **k: None)
|
|
monkeypatch.setattr(effects, "post_shift_change", lambda *a, **k: None)
|
|
monkeypatch.setattr(effects, "dm_late_pickup_admins", lambda *a, **k: 1)
|
|
monkeypatch.setattr(effects, "dm_swap_request", lambda *a, **k: True)
|
|
monkeypatch.setattr(effects, "dm_text", lambda *a, **k: None)
|
|
monkeypatch.setattr(effects, "maybe_repoint_today", lambda *a, **k: False)
|
|
|
|
|
|
def _alice(schedule, seed):
|
|
seed.roster(
|
|
"114", "Alice", slack_user_id="U_ALICE", email="alice@seahavenind.com"
|
|
)
|
|
seed.roster("115", "Bob", slack_user_id="U_BOB", email="bob@seahavenind.com")
|
|
return schedule.get_employee_by_extension("114")
|
|
|
|
|
|
def test_pick_open_shift(schedule, seed, quiet_slack):
|
|
employee = _alice(schedule, seed)
|
|
seed.open_shift("2026-06-10")
|
|
with freezegun.freeze_time("2026-06-08 12:00:00-04:00"):
|
|
result = pick(schedule, employee, "2026-06-10", "night")
|
|
assert result["ok"] is True
|
|
assert schedule.get_override("2026-06-10")["extension"] == "114"
|
|
|
|
|
|
def test_drop_lock(schedule, seed, quiet_slack):
|
|
employee = _alice(schedule, seed)
|
|
seed.override("2026-06-10", "114", "Alice")
|
|
with freezegun.freeze_time("2026-06-10 12:00:00-04:00"):
|
|
with pytest.raises(ActionError) as err:
|
|
drop(schedule, employee, "2026-06-10", "night")
|
|
assert err.value.code == "DROP_LOCK"
|
|
|
|
|
|
def test_swap_creates_pending(schedule, seed, quiet_slack):
|
|
employee = _alice(schedule, seed)
|
|
seed.override("2026-06-12", "114", "Alice")
|
|
with freezegun.freeze_time("2026-06-08 12:00:00-04:00"):
|
|
result = swap(schedule, employee, "2026-06-12", "115", "night")
|
|
assert result["ok"] is True
|
|
pending = schedule.get_swap("2026-06-12", "night")
|
|
assert pending["target_ext"] == "115"
|
|
snap = snapshot(schedule, schedule.get_employee_by_extension("115"))
|
|
assert snap["pendingSwaps"][0]["requesterExt"] == "114"
|
|
assert snap["pendingSwaps"][0]["incoming"] is True
|
|
mine = snapshot(schedule, employee)
|
|
assert mine["pendingSwaps"][0]["incoming"] is False
|
|
|
|
|
|
def test_late_pickup_creates_request(schedule, seed, quiet_slack):
|
|
employee = _alice(schedule, seed)
|
|
seed.open_shift("2026-06-10")
|
|
with freezegun.freeze_time("2026-06-10 20:00:00-04:00"):
|
|
result = pick(schedule, employee, "2026-06-10", "night")
|
|
assert result["latePickup"] is True
|
|
req = schedule.get_pickup_request("2026-06-10", "night", "114")
|
|
assert req["status"] == "pending"
|