afterhours-shift-manager/tests/shared/test_portal_ops.py
Cursor Agent 1ab787308e
feat(portal-api): add Cognito shift API for the employee portal (DEV-287)
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>
2026-09-21 00:36:31 +00:00

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"