""" Tests for weekly repeating capacity. A single capacity row is created for the nearest future Thursday, repeating every 7 days. The tests verify: - each Thursday in the series accepts bookings - days that are not Thursday are rejected - a slot that has reached capacity (capacity=1) is rejected on re-submission Fixture chain (module-scoped): repeating_timetable_id -> repeating_capacity_id repeating_timetable_id -> repeating_form_id """ import os from datetime import date, timedelta import requests import pytest BASE_URL = os.environ.get("WP_BASE_URL", "http://localhost/wordpress") API = f"{BASE_URL}/wp-json/reservations/v1" def _next_thursday() -> date: """Nearest Thursday at least 7 days from today.""" d = date.today() + timedelta(days=7) while d.weekday() != 3: # 3 = Thursday d += timedelta(days=1) return d THURSDAY = _next_thursday() FRIDAY = THURSDAY + timedelta(days=1) THURSDAY_WEEK_2 = THURSDAY + timedelta(weeks=1) THURSDAY_WEEK_3 = THURSDAY + timedelta(weeks=2) def slot(day: date, time: str = "09:00:00") -> str: return f"{day.isoformat()}T{time}+00:00" # --------------------------------------------------------------------------- # Fixtures # --------------------------------------------------------------------------- @pytest.fixture(scope="module") def repeating_timetable_id(): r = requests.post(f"{API}/timetable", json={ "name": "Weekly Thursday timetable", "block_size": 60, }) assert r.status_code == 201, r.text return r.json()["id"] @pytest.fixture(scope="module") def repeating_capacity_id(repeating_timetable_id): r = requests.post(f"{API}/timetable/{repeating_timetable_id}/capacity", json={ "capacity": 1, "min_lead_time_minutes": 0, "date": THURSDAY.isoformat(), "start_time": "08:00", "end_time": "18:00", "repeat_period_in_days": 7, "repeat_times": 52, }) print(r.json()) assert r.status_code == 201, r.text return r.json()["ids"][0] @pytest.fixture(scope="module") def repeating_form_id(repeating_timetable_id): r = requests.post(f"{API}/form-definition", json={ "name": "Weekly Thursday form", "definition": { "email_key": "email", "elements": [ { "type": "reservation", "name": "reservation", "label": "Book a slot", "calendar_id": str(repeating_timetable_id), "required": True, }, { "type": "input-text", "name": "email", "label": "Email", "required": True, "validation": "email", }, { "type": "button", "name": "submit", "label": "Submit", }, ], }, }) assert r.status_code == 201, r.text return r.json()["id"] def book(form_id, timetable_id, day: date, time: str = "09:00:00"): return requests.post(f"{API}/form/{form_id}", json={ "email": "user@example.com", "reservation": { "timetable_id": timetable_id, "timetable_reservations": [slot(day, time)], }, }) def assert_not_available(r): body = r.json() assert body["success"] is False, f"Expected failure but got: {body}" error = next((e for e in body["errors"] if e["element"] == "reservation"), None) assert error is not None assert error["code"] == "not_available" # --------------------------------------------------------------------------- # Tests # --------------------------------------------------------------------------- class TestRepeatingCapacity: def test_first_thursday_is_available( self, repeating_form_id, repeating_timetable_id, repeating_capacity_id ): r = book(repeating_form_id, repeating_timetable_id, THURSDAY) assert r.json()["success"] is True, r.text def test_first_thursday_is_full_after_booking( self, repeating_form_id, repeating_timetable_id, repeating_capacity_id ): # capacity=1; the slot booked above is now exhausted r = book(repeating_form_id, repeating_timetable_id, THURSDAY) assert_not_available(r) def test_friday_is_not_available( self, repeating_form_id, repeating_timetable_id, repeating_capacity_id ): r = book(repeating_form_id, repeating_timetable_id, FRIDAY) assert_not_available(r) def test_second_thursday_is_available( self, repeating_form_id, repeating_timetable_id, repeating_capacity_id ): r = book(repeating_form_id, repeating_timetable_id, THURSDAY_WEEK_2) assert r.json()["success"] is True, r.text def test_third_thursday_is_available( self, repeating_form_id, repeating_timetable_id, repeating_capacity_id ): r = book(repeating_form_id, repeating_timetable_id, THURSDAY_WEEK_3) assert r.json()["success"] is True, r.text def test_wednesday_before_second_thursday_is_not_available( self, repeating_form_id, repeating_timetable_id, repeating_capacity_id ): wednesday = THURSDAY_WEEK_2 - timedelta(days=1) r = book(repeating_form_id, repeating_timetable_id, wednesday) assert_not_available(r)