"""Tests for shared.blocks — Block Kit builders.""" from freezegun import freeze_time from shared.blocks import ( build_help_blocks, build_pay_summary_blocks, build_roster_blocks, build_shift_change_message, build_week_schedule, ) def _all_action_ids(blocks): ids = [] for b in blocks: if b.get("type") == "actions": ids.extend(e["action_id"] for e in b["elements"]) return ids class TestBuildWeekSchedule: @freeze_time("2026-06-01 12:00:00") # Monday def test_header_and_section_present(self, schedule): blocks = build_week_schedule(schedule) assert blocks[0]["type"] == "header" assert "After-Hours Schedule" in blocks[0]["text"]["text"] assert blocks[1]["type"] == "section" @freeze_time("2026-06-01 12:00:00") def test_all_available_produces_pickup_buttons(self, schedule): # Empty schedule → every shift is available → pickup buttons exist, # including a weekend day button with the _day suffix. blocks = build_week_schedule(schedule) action_ids = _all_action_ids(blocks) assert "pickup_2026-06-03" in action_ids # Wednesday night assert "pickup_2026-06-06_day" in action_ids # Saturday day shift assert "pickup_2026-06-06" in action_ids # Saturday night shift @freeze_time("2026-06-01 12:00:00") def test_assigned_shift_has_no_pickup_button(self, schedule, seed): seed.weekly("Wednesday", "114", "Alice") blocks = build_week_schedule(schedule) assert "pickup_2026-06-03" not in _all_action_ids(blocks) assert "Alice (Ext 114)" in blocks[1]["text"]["text"] class TestBuildShiftChangeMessage: def test_picked_up_weekday(self): blocks = build_shift_change_message( "U1", "2026-06-03", "picked_up", "114", "Alice" ) text = blocks[0]["text"]["text"] assert "<@U1>" in text and "picked up" in text and "Ext 114" in text # Weekday → no (Day/Night) label assert "(Night" not in text def test_dropped_shows_available(self): blocks = build_shift_change_message( "U1", "2026-06-03", "dropped", "114", "Alice" ) assert "Available" in blocks[0]["text"]["text"] def test_swapped_text(self): blocks = build_shift_change_message("U2", "2026-06-03", "swapped", "115", "Bob") assert "swapped" in blocks[0]["text"]["text"] def test_weekend_includes_shift_label(self): blocks = build_shift_change_message( "U1", "2026-06-06", "picked_up", "200", "Alice", shift_type="day" ) assert "Day (8am" in blocks[0]["text"]["text"] class TestBuildPaySummaryBlocks: def test_renders_breakdown_and_totals(self): breakdown = [ { "day": "Mon", "date_label": "Jun 1", "name": "Alice", "extension": "114", "rate": 50.0, } ] totals = { "Alice": {"shifts": 1, "total": 50.0, "extension": "114", "rate": 50.0} } blocks = build_pay_summary_blocks("Jun 1 to Jun 7", breakdown, totals) assert blocks[0]["type"] == "header" assert "Jun 1 to Jun 7" in blocks[0]["text"]["text"] text = blocks[1]["text"]["text"] assert "Alice" in text and "$50.00" in text and "1 shift" in text class TestBuildHelpBlocks: def test_non_admin_excludes_admin_section(self): text = build_help_blocks(is_admin=False)[0]["text"]["text"] assert "Admin Commands" not in text def test_admin_includes_admin_section(self): text = build_help_blocks(is_admin=True)[0]["text"]["text"] assert "Admin Commands" in text class TestBuildRosterBlocks: def test_empty_roster(self): text = build_roster_blocks([])[0]["text"]["text"] assert "No employees" in text def test_linked_and_unlinked(self): roster = [ {"SK": "115", "name": "Bob", "slack_user_id": ""}, {"SK": "114", "name": "Alice", "slack_user_id": "U_ALICE"}, ] text = build_roster_blocks(roster)[0]["text"]["text"] # Sorted by extension → Alice (114) appears before Bob (115) assert text.index("Alice") < text.index("Bob") assert "<@U_ALICE>" in text assert "_not linked_" in text