#!/usr/bin/env python3 import requests import sys import json from datetime import datetime class EpicTravelAPITester: def __init__(self, base_url="https://world-explorer-139.preview.emergentagent.com"): self.base_url = base_url self.api_url = f"{base_url}/api" self.token = None self.tests_run = 0 self.tests_passed = 0 self.test_results = [] def log_test(self, name, success, message="", response_data=None): """Log test results""" self.tests_run += 1 if success: self.tests_passed += 1 print(f"āœ… {name}: PASSED - {message}") else: print(f"āŒ {name}: FAILED - {message}") self.test_results.append({ "test": name, "status": "PASSED" if success else "FAILED", "message": message, "response_data": response_data }) return success def run_test(self, name, method, endpoint, expected_status, data=None, headers=None): """Run a single API test""" url = f"{self.api_url}/{endpoint}" test_headers = {'Content-Type': 'application/json'} if self.token: test_headers['Authorization'] = f'Bearer {self.token}' if headers: test_headers.update(headers) try: if method == 'GET': response = requests.get(url, headers=test_headers) elif method == 'POST': response = requests.post(url, json=data, headers=test_headers) elif method == 'PUT': response = requests.put(url, json=data, headers=test_headers) elif method == 'DELETE': response = requests.delete(url, headers=test_headers) success = response.status_code == expected_status if success: try: response_data = response.json() if response.content else {} return self.log_test(name, True, f"Status: {response.status_code}", response_data), response_data except: return self.log_test(name, True, f"Status: {response.status_code}", {}), {} else: try: error_data = response.json() if response.content else {} return self.log_test(name, False, f"Expected {expected_status}, got {response.status_code} - {error_data}"), {} except: return self.log_test(name, False, f"Expected {expected_status}, got {response.status_code}"), {} except Exception as e: return self.log_test(name, False, f"Error: {str(e)}"), {} def test_health_check(self): """Test API health check""" success, data = self.run_test("API Health Check", "GET", "", 200) return success def test_admin_login(self): """Test admin login""" login_data = { "email": "admin@epictravel.com", "password": "admin123" } success, response = self.run_test("Admin Login", "POST", "auth/login", 200, login_data) if success and 'access_token' in response: self.token = response['access_token'] self.log_test("Token Extraction", True, "JWT token successfully extracted") return True else: self.log_test("Token Extraction", False, "Failed to extract JWT token") return False def test_get_destinations(self): """Test getting all destinations""" success, data = self.run_test("Get All Destinations", "GET", "destinations", 200) if success and isinstance(data, list) and len(data) > 0: self.log_test("Destinations Data Validation", True, f"Found {len(data)} destinations") return data else: self.log_test("Destinations Data Validation", False, "No destinations returned or invalid data") return [] def test_get_specials(self): """Test getting all specials""" success, data = self.run_test("Get All Specials", "GET", "specials", 200) if success and isinstance(data, list): self.log_test("Specials Data Validation", True, f"Found {len(data)} specials") return data else: self.log_test("Specials Data Validation", False, "Failed to get specials or invalid data") return [] def test_search_destinations(self): """Test destination search functionality""" # Test search by name success, data = self.run_test("Search Destinations by Name", "GET", "destinations?search=Paris", 200) if success: found_paris = any(dest.get('name', '').lower() == 'paris' for dest in data) if found_paris: self.log_test("Search Results Validation", True, "Paris found in search results") else: self.log_test("Search Results Validation", False, "Paris not found in search results") # Test filter by category success, data = self.run_test("Filter Destinations by Category", "GET", "destinations?category=City", 200) if success: all_city = all(dest.get('category') == 'City' for dest in data) if all_city: self.log_test("Filter Results Validation", True, "All returned destinations are City type") else: self.log_test("Filter Results Validation", False, "Filter not working correctly") def test_contact_form(self): """Test contact form submission""" contact_data = { "name": "Test User", "email": "test@example.com", "message": "This is a test contact message" } success, data = self.run_test("Contact Form Submission", "POST", "contact", 200, contact_data) return success def test_newsletter_subscription(self): """Test newsletter subscription""" newsletter_data = { "email": "newsletter@test.com" } success, data = self.run_test("Newsletter Subscription", "POST", "newsletter/subscribe", 200, newsletter_data) return success def test_admin_crud_operations(self): """Test full CRUD operations for destinations (requires authentication)""" if not self.token: self.log_test("CRUD Operations", False, "No authentication token available") return False # Test creating a new destination new_destination = { "name": "Test Destination", "location": "Test Country", "description": "A test destination for API testing", "image": "https://via.placeholder.com/800x600", "category": "City", "rating": 4.5, "price": 999, "currency": "USD" } success, created_dest = self.run_test("Create New Destination", "POST", "destinations", 200, new_destination) if not success: return False dest_id = created_dest.get('id') if not dest_id: self.log_test("Destination ID Extraction", False, "Failed to get destination ID from creation response") return False # Test updating the destination update_data = { "name": "Updated Test Destination", "price": 1299 } success, updated_dest = self.run_test("Update Destination", "PUT", f"destinations/{dest_id}", 200, update_data) if success and updated_dest.get('name') == "Updated Test Destination": self.log_test("Update Validation", True, "Destination updated successfully") else: self.log_test("Update Validation", False, "Destination update failed or data not persisted") # Test getting single destination success, single_dest = self.run_test("Get Single Destination", "GET", f"destinations/{dest_id}", 200) # Test adding destination to specials special_data = { "destination_id": dest_id, "discount": 25, "end_date": "2025-12-31", "highlights": ["Test special", "Limited time", "API test"] } success, created_special = self.run_test("Add Destination to Specials", "POST", "specials", 200, special_data) special_id = created_special.get('id') if success else None if special_id: # Test updating special special_update = { "discount": 30, "end_date": "2025-11-30" } success, updated_special = self.run_test("Update Special", "PUT", f"specials/{special_id}", 200, special_update) # Test removing destination from specials success, _ = self.run_test("Remove from Specials", "DELETE", f"specials/destination/{dest_id}", 200) # Test deleting the destination (cleanup) success, _ = self.run_test("Delete Test Destination", "DELETE", f"destinations/{dest_id}", 200) return True def run_all_tests(self): """Run all tests in sequence""" print("šŸš€ Starting Epic Travel API Testing...") print("=" * 50) # Test 1: Health Check print("\nšŸ“‹ Testing Basic API Access...") if not self.test_health_check(): print("āŒ Health check failed, stopping tests") return self.generate_summary() # Test 2: Authentication print("\nšŸ” Testing Authentication...") if not self.test_admin_login(): print("āŒ Authentication failed, continuing with public endpoints only") # Test 3: Public Endpoints print("\nšŸŒ Testing Public Endpoints...") destinations = self.test_get_destinations() specials = self.test_get_specials() self.test_search_destinations() # Test 4: Forms print("\nšŸ“ Testing Form Submissions...") self.test_contact_form() self.test_newsletter_subscription() # Test 5: Admin Operations if self.token: print("\nāš™ļø Testing Admin CRUD Operations...") self.test_admin_crud_operations() else: print("\nāš ļø Skipping Admin CRUD tests - No authentication token") return self.generate_summary() def generate_summary(self): """Generate test summary""" print("\n" + "=" * 50) print("šŸ“Š TEST SUMMARY") print("=" * 50) print(f"Tests Run: {self.tests_run}") print(f"Tests Passed: {self.tests_passed}") print(f"Tests Failed: {self.tests_run - self.tests_passed}") print(f"Success Rate: {(self.tests_passed / self.tests_run * 100):.1f}%" if self.tests_run > 0 else "0%") failed_tests = [test for test in self.test_results if test['status'] == 'FAILED'] if failed_tests: print("\nāŒ FAILED TESTS:") for test in failed_tests: print(f" - {test['test']}: {test['message']}") print("\n" + "=" * 50) return { "total_tests": self.tests_run, "passed_tests": self.tests_passed, "failed_tests": self.tests_run - self.tests_passed, "success_rate": (self.tests_passed / self.tests_run * 100) if self.tests_run > 0 else 0, "detailed_results": self.test_results } def main(): tester = EpicTravelAPITester() results = tester.run_all_tests() # Return appropriate exit code return 0 if results['failed_tests'] == 0 else 1 if __name__ == "__main__": sys.exit(main())