"""Tests for booking templates API.""" import pytest from datetime import datetime, timedelta from fastapi.testclient import TestClient def test_create_template(client: TestClient, user_token: str, test_space): """Test creating a booking template.""" response = client.post( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, json={ "name": "Weekly Team Sync", "space_id": test_space.id, "duration_minutes": 60, "title": "Team Sync Meeting", "description": "Weekly team synchronization meeting", }, ) assert response.status_code == 201 data = response.json() assert data["name"] == "Weekly Team Sync" assert data["space_id"] == test_space.id assert data["space_name"] == test_space.name assert data["duration_minutes"] == 60 assert data["title"] == "Team Sync Meeting" assert data["description"] == "Weekly team synchronization meeting" assert data["usage_count"] == 0 def test_create_template_without_space(client: TestClient, user_token: str): """Test creating a template without a default space.""" response = client.post( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, json={ "name": "Generic Meeting", "duration_minutes": 30, "title": "Meeting", "description": "Generic meeting template", }, ) assert response.status_code == 201 data = response.json() assert data["name"] == "Generic Meeting" assert data["space_id"] is None assert data["space_name"] is None def test_list_templates(client: TestClient, user_token: str, test_space): """Test listing user's templates.""" # Create two templates client.post( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, json={ "name": "Template 1", "space_id": test_space.id, "duration_minutes": 30, "title": "Meeting 1", }, ) client.post( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, json={ "name": "Template 2", "space_id": test_space.id, "duration_minutes": 60, "title": "Meeting 2", }, ) # List templates response = client.get( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, ) assert response.status_code == 200 data = response.json() assert len(data) >= 2 assert any(t["name"] == "Template 1" for t in data) assert any(t["name"] == "Template 2" for t in data) def test_list_templates_isolated(client: TestClient, user_token: str, admin_token: str, test_space): """Test that users only see their own templates.""" # User creates a template client.post( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, json={ "name": "User Template", "space_id": test_space.id, "duration_minutes": 30, "title": "User Meeting", }, ) # Admin creates a template client.post( "/api/booking-templates", headers={"Authorization": f"Bearer {admin_token}"}, json={ "name": "Admin Template", "space_id": test_space.id, "duration_minutes": 60, "title": "Admin Meeting", }, ) # User lists templates user_response = client.get( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, ) user_data = user_response.json() # Admin lists templates admin_response = client.get( "/api/booking-templates", headers={"Authorization": f"Bearer {admin_token}"}, ) admin_data = admin_response.json() # User should only see their template user_template_names = [t["name"] for t in user_data] assert "User Template" in user_template_names assert "Admin Template" not in user_template_names # Admin should only see their template admin_template_names = [t["name"] for t in admin_data] assert "Admin Template" in admin_template_names assert "User Template" not in admin_template_names def test_delete_template(client: TestClient, user_token: str, test_space): """Test deleting a template.""" # Create template create_response = client.post( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, json={ "name": "To Delete", "space_id": test_space.id, "duration_minutes": 30, "title": "Meeting", }, ) template_id = create_response.json()["id"] # Delete template delete_response = client.delete( f"/api/booking-templates/{template_id}", headers={"Authorization": f"Bearer {user_token}"}, ) assert delete_response.status_code == 204 # Verify it's gone list_response = client.get( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, ) templates = list_response.json() assert not any(t["id"] == template_id for t in templates) def test_delete_template_not_found(client: TestClient, user_token: str): """Test deleting a non-existent template.""" response = client.delete( "/api/booking-templates/99999", headers={"Authorization": f"Bearer {user_token}"}, ) assert response.status_code == 404 def test_delete_template_other_user(client: TestClient, user_token: str, admin_token: str, test_space): """Test that users cannot delete other users' templates.""" # Admin creates a template create_response = client.post( "/api/booking-templates", headers={"Authorization": f"Bearer {admin_token}"}, json={ "name": "Admin Template", "space_id": test_space.id, "duration_minutes": 30, "title": "Meeting", }, ) template_id = create_response.json()["id"] # User tries to delete admin's template delete_response = client.delete( f"/api/booking-templates/{template_id}", headers={"Authorization": f"Bearer {user_token}"}, ) assert delete_response.status_code == 404 def test_create_booking_from_template(client: TestClient, user_token: str, test_space): """Test creating a booking from a template.""" # Create template template_response = client.post( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, json={ "name": "Client Meeting", "space_id": test_space.id, "duration_minutes": 90, "title": "Client Presentation", "description": "Quarterly review with client", }, ) template_id = template_response.json()["id"] # Create booking from template tomorrow = datetime.now() + timedelta(days=1) start_time = tomorrow.replace(hour=10, minute=0, second=0, microsecond=0) response = client.post( f"/api/booking-templates/from-template/{template_id}", headers={"Authorization": f"Bearer {user_token}"}, params={"start_datetime": start_time.isoformat()}, ) assert response.status_code == 201 data = response.json() assert data["space_id"] == test_space.id assert data["title"] == "Client Presentation" assert data["description"] == "Quarterly review with client" assert data["status"] == "pending" # Verify duration start_dt = datetime.fromisoformat(data["start_datetime"]) end_dt = datetime.fromisoformat(data["end_datetime"]) duration = (end_dt - start_dt).total_seconds() / 60 assert duration == 90 # Verify usage count incremented list_response = client.get( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, ) templates = list_response.json() template = next(t for t in templates if t["id"] == template_id) assert template["usage_count"] == 1 def test_create_booking_from_template_no_space(client: TestClient, user_token: str): """Test creating a booking from a template without a default space.""" # Create template without space template_response = client.post( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, json={ "name": "Generic Meeting", "duration_minutes": 60, "title": "Meeting", }, ) template_id = template_response.json()["id"] # Try to create booking tomorrow = datetime.now() + timedelta(days=1) start_time = tomorrow.replace(hour=10, minute=0, second=0, microsecond=0) response = client.post( f"/api/booking-templates/from-template/{template_id}", headers={"Authorization": f"Bearer {user_token}"}, params={"start_datetime": start_time.isoformat()}, ) assert response.status_code == 400 assert "does not have a default space" in response.json()["detail"] def test_create_booking_from_template_not_found(client: TestClient, user_token: str): """Test creating a booking from a non-existent template.""" tomorrow = datetime.now() + timedelta(days=1) start_time = tomorrow.replace(hour=10, minute=0, second=0, microsecond=0) response = client.post( "/api/booking-templates/from-template/99999", headers={"Authorization": f"Bearer {user_token}"}, params={"start_datetime": start_time.isoformat()}, ) assert response.status_code == 404 def test_create_booking_from_template_validation_error(client: TestClient, user_token: str, test_space): """Test that booking from template validates booking rules.""" # Create template template_response = client.post( "/api/booking-templates", headers={"Authorization": f"Bearer {user_token}"}, json={ "name": "Long Meeting", "space_id": test_space.id, "duration_minutes": 600, # 10 hours - exceeds max "title": "Marathon Meeting", }, ) template_id = template_response.json()["id"] # Try to create booking tomorrow = datetime.now() + timedelta(days=1) start_time = tomorrow.replace(hour=10, minute=0, second=0, microsecond=0) response = client.post( f"/api/booking-templates/from-template/{template_id}", headers={"Authorization": f"Bearer {user_token}"}, params={"start_datetime": start_time.isoformat()}, ) assert response.status_code == 400 # Should fail validation (duration exceeds max)