bookmyservice-ams / tests /unit /test_appointment.py
MukeshKapoor25's picture
feat: add authentication, security middleware, and optimize JSON handling
fd2ce9d
import pytest
from unittest.mock import AsyncMock, patch
from fastapi import HTTPException
from datetime import datetime, timezone, date, time
from uuid import uuid4
from app.services.appointment import (
create_new_appointment,
reschedule_appointment,
cancel_appointment_service,
get_appointment_details,
get_appointments_by_customer_id,
)
from app.models.appointment import Appointment, AppointmentStatus, PaymentMode, PaymentStatus
from app.repositories.appointment import (
create_appointment,
update_appointment,
cancel_appointment,
get_appointment_by_id,
fetch_appointments_from_db,
)
# Mock data
MOCK_APPOINTMENT_ID = str(uuid4())
MOCK_CUSTOMER_ID = str(uuid4())
MOCK_MERCHANT_ID = str(uuid4())
MOCK_ORDER_ID = "order_123"
# Test data
TEST_APPOINTMENT = Appointment(
appointment_id=MOCK_APPOINTMENT_ID,
customer_id=MOCK_CUSTOMER_ID,
merchant_id=MOCK_MERCHANT_ID,
merchant_name="Test Merchant",
city="Test City",
merchant_address={"street": "123 Test St", "city": "Test City"},
location_id="LOC001",
appointment_date="2023-12-25",
appointment_time="10:00",
associates=[{"associate_id": "STAFF1", "name": "John Doe"}],
status=AppointmentStatus.PENDING,
services=[{"service_id": "SERV1", "name": "Test Service", "price": 100.0, "duration": "30 minutes", "quantity": 1}],
total_amount=100.0,
payment_mode=PaymentMode.ONLINE,
order_id=MOCK_ORDER_ID,
)
# Mock functions
@pytest.fixture
def mock_create_appointment():
with patch("app.repositories.appointment.create_appointment", new_callable=AsyncMock) as mock:
yield mock
@pytest.fixture
def mock_get_order_by_id():
with patch("app.repositories.payment.get_order_by_id", new_callable=AsyncMock) as mock:
mock.return_value = {"status": "pending"}
yield mock
@pytest.fixture
def mock_get_appointment_by_id():
with patch("app.repositories.appointment.get_appointment_by_id", new_callable=AsyncMock) as mock:
yield mock
@pytest.fixture
def mock_update_appointment():
with patch("app.repositories.appointment.update_appointment", new_callable=AsyncMock) as mock:
yield mock
@pytest.fixture
def mock_cancel_appointment():
with patch("app.repositories.appointment.cancel_appointment", new_callable=AsyncMock) as mock:
yield mock
@pytest.fixture
def mock_fetch_appointments_from_db():
with patch("app.repositories.appointment.fetch_appointments_from_db", new_callable=AsyncMock) as mock:
yield mock
# Tests
@pytest.mark.asyncio
async def test_create_new_appointment_success(mock_create_appointment, mock_get_order_by_id):
result = await create_new_appointment(TEST_APPOINTMENT)
assert result["appointment_id"] == MOCK_APPOINTMENT_ID
mock_create_appointment.assert_called_once()
mock_get_order_by_id.assert_called_once_with(MOCK_ORDER_ID)
@pytest.mark.asyncio
async def test_create_new_appointment_invalid_order(mock_get_order_by_id):
mock_get_order_by_id.return_value = None
with pytest.raises(HTTPException) as exc_info:
await create_new_appointment(TEST_APPOINTMENT)
assert exc_info.value.status_code == 400
assert "Invalid Razorpay Order ID" in str(exc_info.value.detail)
@pytest.mark.asyncio
async def test_reschedule_appointment_success(mock_get_appointment_by_id, mock_update_appointment):
mock_get_appointment_by_id.return_value = {
"appointment_id": MOCK_APPOINTMENT_ID,
"status": AppointmentStatus.CONFIRMED.value,
"appointment_date": "2023-12-25",
"appointment_time": "10:00:00",
}
result = await reschedule_appointment(MOCK_APPOINTMENT_ID, "2023-12-26", "11:00:00", MOCK_CUSTOMER_ID)
assert result["message"] == "Appointment rescheduled successfully"
mock_update_appointment.assert_called_once()
@pytest.mark.asyncio
async def test_reschedule_appointment_past_date(mock_get_appointment_by_id):
mock_get_appointment_by_id.return_value = {
"appointment_id": MOCK_APPOINTMENT_ID,
"status": AppointmentStatus.CONFIRMED.value,
"appointment_date": "2023-12-25",
"appointment_time": "10:00:00",
}
with pytest.raises(HTTPException) as exc_info:
await reschedule_appointment(MOCK_APPOINTMENT_ID, "2023-12-24", "11:00:00", MOCK_CUSTOMER_ID)
assert exc_info.value.status_code == 400
assert "Cannot reschedule to a past time" in str(exc_info.value.detail)
@pytest.mark.asyncio
async def test_cancel_appointment_service_success(mock_get_appointment_by_id, mock_cancel_appointment):
mock_get_appointment_by_id.return_value = {
"appointment_id": MOCK_APPOINTMENT_ID,
"status": AppointmentStatus.CONFIRMED.value,
"appointment_date": "2023-12-25",
"appointment_time": "10:00:00",
}
result = await cancel_appointment_service(MOCK_APPOINTMENT_ID, "change_of_plans", MOCK_CUSTOMER_ID)
assert result["message"] == "Appointment canceled successfully"
mock_cancel_appointment.assert_called_once()
@pytest.mark.asyncio
async def test_cancel_appointment_service_already_canceled(mock_get_appointment_by_id):
mock_get_appointment_by_id.return_value = {
"appointment_id": MOCK_APPOINTMENT_ID,
"status": AppointmentStatus.CANCELED.value,
"appointment_date": "2023-12-25",
"appointment_time": "10:00:00",
}
with pytest.raises(HTTPException) as exc_info:
await cancel_appointment_service(MOCK_APPOINTMENT_ID, "change_of_plans", MOCK_CUSTOMER_ID)
assert exc_info.value.status_code == 400
assert "Appointment is already canceled" in str(exc_info.value.detail)
@pytest.mark.asyncio
async def test_get_appointment_details_success(mock_get_appointment_by_id):
mock_get_appointment_by_id.return_value = {
"appointment_id": MOCK_APPOINTMENT_ID,
"status": AppointmentStatus.CONFIRMED.value,
"appointment_date": "2023-12-25",
"appointment_time": "10:00:00",
}
result = await get_appointment_details(MOCK_APPOINTMENT_ID)
assert result["appointment_id"] == MOCK_APPOINTMENT_ID
@pytest.mark.asyncio
async def test_get_appointments_by_customer_id_success(mock_fetch_appointments_from_db):
mock_fetch_appointments_from_db.return_value = (
[
{
"appointment_id": MOCK_APPOINTMENT_ID,
"merchant_id": MOCK_MERCHANT_ID,
"merchant_name": "Test Merchant",
"merchant_address": "123 Test St",
"location_id": str(uuid4()),
"appointment_date": date(2023, 12, 25),
"appointment_time": "10:00:00",
"status": "confirmed",
"associates": [],
"services": [],
"notes": "",
"total_amount": 100.0,
"discount": 0.0,
"payment_status": "Paid",
"payment_id": "pay_123",
"cleared_amount": 100.0,
#"created_at": datetime(2023, 12, 1, 10, 0, 0),
#"modified_at": datetime(2023, 12, 1, 10, 0, 0),
}
],
1,
)
result = await get_appointments_by_customer_id(MOCK_CUSTOMER_ID)
assert result.customer_id == MOCK_CUSTOMER_ID
assert len(result.appointments) == 1
assert result.appointments[0].appointment_id == MOCK_APPOINTMENT_ID