mirror of
https://github.com/Sea-Haven-Industries/afterhours-shift-manager.git
synced 2026-09-30 18:23:12 +00:00
* Add Slack admin modals + App Home admin section Replace the two most error-prone positional admin commands with Block Kit modals (override and holiday-add) opened from a new App Home admin section, while keeping the typed subcommands as a fallback. Validation and side effects are factored into shared helpers so the modal and command paths can't drift, and every action/view handler re-checks is_admin against get_admin_users() so a modal opened from Home can't bypass authorization. Adds Schedule.list_overrides for the upcoming-overrides overview. Refs: #136 * Update changelog date to July 02, 2026 * Add point-and-click admin actions in Slack for easier overrides and holidays * [#136] Add admin UI evaluation spike doc (#140) Co-authored-by: seahaven-openswe[bot] <296972425+seahaven-openswe[bot]@users.noreply.github.com> Co-authored-by: amoussa1229 <166072409+amoussa1229@users.noreply.github.com>
78 lines
2.9 KiB
Python
78 lines
2.9 KiB
Python
"""Tests for the App Home tab (about page + What's New)."""
|
|
|
|
from freezegun import freeze_time
|
|
|
|
from shared.blocks import build_home_view
|
|
|
|
|
|
def _headers(view):
|
|
return [b["text"]["text"] for b in view["blocks"] if b["type"] == "header"]
|
|
|
|
|
|
class TestBuildHomeView:
|
|
def test_includes_about_and_commands(self):
|
|
view = build_home_view()
|
|
assert view["type"] == "home"
|
|
assert "After-Hours Shift Manager" in _headers(view)
|
|
assert "/oncall" in str(view["blocks"])
|
|
|
|
def test_omits_whats_new_without_version(self):
|
|
view = build_home_view()
|
|
assert all("What's New" not in h for h in _headers(view))
|
|
|
|
def test_includes_whats_new_with_version(self):
|
|
view = build_home_view(
|
|
"1.10.0", "**Self-announcing** releases.", "June 11, 2026"
|
|
)
|
|
assert "What's New in v1.10.0" in _headers(view)
|
|
# Notes are converted from Markdown to Slack mrkdwn.
|
|
assert "*Self-announcing*" in str(view["blocks"])
|
|
assert any(b.get("type") == "context" for b in view["blocks"])
|
|
|
|
|
|
def test_publish_home_publishes_latest_entry(slackbot_app, client):
|
|
text = "## v1.10.0 — June 11, 2026\n\n**New stuff.**\n\n## v1.9.2 — June 1, 2026\n\nOld.\n"
|
|
slackbot_app.publish_home(client, "U_ALICE", text)
|
|
|
|
client.views_publish.assert_called_once()
|
|
kwargs = client.views_publish.call_args.kwargs
|
|
assert kwargs["user_id"] == "U_ALICE"
|
|
assert kwargs["view"]["type"] == "home"
|
|
assert "What's New in v1.10.0" in str(kwargs["view"])
|
|
assert "v1.9.2" not in str(kwargs["view"]) # only the newest entry
|
|
|
|
|
|
def test_publish_home_degrades_without_changelog(slackbot_app, client):
|
|
slackbot_app.publish_home(client, "U_BOB", "")
|
|
view = client.views_publish.call_args.kwargs["view"]
|
|
assert all("What's New" not in str(b) for b in view["blocks"])
|
|
|
|
|
|
def test_publish_home_includes_admin_section_for_admin(
|
|
slackbot_app, schedule, seed, client
|
|
):
|
|
seed.config(admin_users=["U_ADMIN"])
|
|
seed.override("2026-12-25", "114", "Alice")
|
|
seed.holiday("2026-12-25", slots=2, label="Christmas")
|
|
with freeze_time("2026-06-01"):
|
|
slackbot_app.publish_home(client, "U_ADMIN", "", schedule)
|
|
view = client.views_publish.call_args.kwargs["view"]
|
|
assert "Admin" in _headers(view)
|
|
assert "admin_open_override_modal" in str(view["blocks"])
|
|
assert "Christmas" in str(view["blocks"])
|
|
|
|
|
|
def test_publish_home_omits_admin_section_for_non_admin(
|
|
slackbot_app, schedule, seed, client
|
|
):
|
|
seed.config(admin_users=["U_ADMIN"])
|
|
slackbot_app.publish_home(client, "U_BOB", "", schedule)
|
|
view = client.views_publish.call_args.kwargs["view"]
|
|
assert "Admin" not in _headers(view)
|
|
assert "admin_open_override_modal" not in str(view["blocks"])
|
|
|
|
|
|
def test_publish_home_without_schedule_has_no_admin_section(slackbot_app, client):
|
|
slackbot_app.publish_home(client, "U_ADMIN", "")
|
|
view = client.views_publish.call_args.kwargs["view"]
|
|
assert "Admin" not in _headers(view)
|