Files
soleprint/station/tools/tester/tests/mascotas/test_pet_owners.py
2025-12-24 05:38:37 -03:00

172 lines
6.3 KiB
Python

"""
Contract Tests: Pet Owners API
Endpoint: /mascotas/api/v1/pet-owners/
App: mascotas
Related Tickets:
- VET-536: Paso 0 - Test creación del petowner invitado
- VET-535: Establecer y definir test para las apis vinculadas al procesos de solicitar turno general
Context: In the turnero general flow (guest booking), a "guest" pet owner is created
with a mock email (e.g., invitado-1759415377297@example.com). This user is fundamental
for subsequent steps as it provides the address used to filter available services.
TBD: PetOwnerViewSet needs pagination - currently loads all records on list().
See mascotas/views/api/v1/views/petowner_views.py:72
Using email filter in tests to avoid loading 14k+ records.
"""
import time
from ..base import ContractTestCase
from ..endpoints import Endpoints
from ..helpers import sample_pet_owner
class TestPetOwnerCreate(ContractTestCase):
"""POST /mascotas/api/v1/pet-owners/
VET-536: Tests for guest petowner creation (Step 0 of turnero flow)
"""
def test_create_returns_201(self):
"""
Creating a pet owner returns 201 with the created resource.
Request (from production turnero):
POST /mascotas/api/v1/pet-owners/
{
"first_name": "Juan",
"last_name": "Pérez",
"email": "invitado-1733929847293@example.com",
"phone": "1155667788",
"address": "Av. Santa Fe 1234, Buenos Aires",
"geo_latitude": -34.5955,
"geo_longitude": -58.4166
}
Response (201):
{
"id": 12345,
"first_name": "Juan",
"last_name": "Pérez",
"email": "invitado-1733929847293@example.com",
"phone": "1155667788",
"address": "Av. Santa Fe 1234, Buenos Aires",
"geo_latitude": -34.5955,
"geo_longitude": -58.4166,
"pets": [],
"created_at": "2024-12-11T15:30:47.293Z"
}
"""
data = sample_pet_owner()
response = self.post(Endpoints.PET_OWNERS, data)
self.assert_status(response, 201)
self.assert_has_fields(response.data, "id", "email", "first_name", "last_name")
self.assertEqual(response.data["email"], data["email"])
def test_requires_email(self):
"""
Pet owner creation requires email (current behavior).
Note: The turnero guest flow uses a mock email created by frontend
(e.g., invitado-1759415377297@example.com). The API always requires email.
This test ensures the contract enforcement - no petowner without email.
"""
data = {
"address": "Av. Corrientes 1234",
"first_name": "Invitado",
"last_name": str(int(time.time())),
}
response = self.post(Endpoints.PET_OWNERS, data)
self.assert_status(response, 400)
def test_duplicate_email_returns_existing(self):
"""
Creating pet owner with existing email returns the existing record.
Note: API has upsert behavior - returns 200 with existing record,
not 400 error. This allows frontend to "create or get" in one call.
Important for guest flow - if user refreshes/retries, we don't create duplicates.
"""
data = sample_pet_owner()
first_response = self.post(Endpoints.PET_OWNERS, data)
first_id = first_response.data["id"]
response = self.post(Endpoints.PET_OWNERS, data) # Same email
# Returns 200 with existing record (upsert behavior)
self.assert_status(response, 200)
self.assertEqual(response.data["id"], first_id)
def test_address_and_geolocation_persisted(self):
"""
Pet owner address and geolocation coordinates are persisted correctly.
The address is critical for the turnero flow - it's used to filter available
services by location. Geolocation (lat/lng) may be obtained from Google Maps API.
"""
data = sample_pet_owner()
response = self.post(Endpoints.PET_OWNERS, data)
self.assert_status(response, 201)
self.assert_has_fields(response.data, "address", "geo_latitude", "geo_longitude")
self.assertEqual(response.data["address"], data["address"])
# Verify geolocation fields are numeric (not null/empty)
self.assertIsNotNone(response.data.get("geo_latitude"))
self.assertIsNotNone(response.data.get("geo_longitude"))
class TestPetOwnerRetrieve(ContractTestCase):
"""GET /mascotas/api/v1/pet-owners/{id}/"""
def test_get_by_id_returns_200(self):
"""GET pet owner by ID returns owner details"""
# Create owner first
data = sample_pet_owner()
create_response = self.post(Endpoints.PET_OWNERS, data)
owner_id = create_response.data["id"]
response = self.get(Endpoints.PET_OWNER_DETAIL.format(id=owner_id))
self.assert_status(response, 200)
self.assertEqual(response.data["id"], owner_id)
self.assert_has_fields(response.data, "id", "first_name", "last_name", "address", "pets")
def test_nonexistent_returns_404(self):
"""GET non-existent owner returns 404"""
response = self.get(Endpoints.PET_OWNER_DETAIL.format(id=999999))
self.assert_status(response, 404)
class TestPetOwnerList(ContractTestCase):
"""GET /mascotas/api/v1/pet-owners/"""
def test_list_with_email_filter_returns_200(self):
"""GET pet owners filtered by email returns 200"""
# Filter by email to avoid loading 14k+ records (no pagination on this endpoint)
response = self.get(Endpoints.PET_OWNERS, params={"email": "nonexistent@test.com"})
self.assert_status(response, 200)
def test_list_filter_by_email_works(self):
"""Can filter pet owners by email"""
# Create a pet owner first
data = sample_pet_owner()
self.post(Endpoints.PET_OWNERS, data)
# Filter by that email
response = self.get(Endpoints.PET_OWNERS, params={"email": data["email"]})
self.assert_status(response, 200)
# Should find exactly one
results = response.data if isinstance(response.data, list) else response.data.get("results", [])
self.assertEqual(len(results), 1)
self.assertEqual(results[0]["email"], data["email"])