""" Backend API Test Suite for Todo List App Phase II This test suite verifies all backend functionality including: - Authentication endpoints (register, login, logout) - Task management endpoints (CRUD operations) - User management endpoints - JWT authentication and authorization - Database connectivity """ import requests import json from datetime import datetime # Base URL for the backend API BASE_URL = "http://localhost:8000" def test_health_check(): """Test the health check endpoint""" print("Testing health check endpoint...") try: response = requests.get(f"{BASE_URL}/") print(f"Health check: {response.status_code} - {response.json()}") return response.status_code == 200 except Exception as e: print(f"Health check failed: {e}") return False def test_register_user(): """Test user registration""" print("Testing user registration...") try: # Generate unique email for testing timestamp = str(int(datetime.now().timestamp())) user_data = { "email": f"testuser_{timestamp}@example.com", "password": "securepassword123", "name": f"Test User {timestamp}" } response = requests.post(f"{BASE_URL}/api/auth/register", json=user_data, headers={"Content-Type": "application/json"}) print(f"Registration: {response.status_code}") if response.status_code == 201: result = response.json() print(f"User registered successfully: {result['user']['email']}") return result['token'], result['user']['id'] else: print(f"Registration failed: {response.status_code} - {response.text}") return None, None except Exception as e: print(f"Registration test failed: {e}") return None, None def test_login_user(): """Test user login""" print("Testing user login...") try: # First register a user to login with timestamp = str(int(datetime.now().timestamp())) register_data = { "email": f"login_test_{timestamp}@example.com", "password": "securepassword123", "name": f"Login Test {timestamp}" } register_response = requests.post(f"{BASE_URL}/api/auth/register", json=register_data, headers={"Content-Type": "application/json"}) if register_response.status_code != 201: print(f"Failed to create test user for login: {register_response.status_code}") return None # Now try to login with the same credentials login_data = { "email": register_data["email"], "password": register_data["password"] } response = requests.post(f"{BASE_URL}/api/auth/login", json=login_data, headers={"Content-Type": "application/json"}) print(f"Login: {response.status_code}") if response.status_code == 200: result = response.json() print(f"User logged in successfully: {result['user']['email']}") return result['token'] else: print(f"Login failed: {response.status_code} - {response.text}") return None except Exception as e: print(f"Login test failed: {e}") return None def test_task_crud_operations(token, user_id): """Test all task CRUD operations with authentication""" print("Testing task CRUD operations...") if not token: print("No valid token provided for task operations") return False headers = { "Content-Type": "application/json", "Authorization": f"Bearer {token}" } # Test 1: Create a task print(" Creating task...") task_data = { "title": "Test Task", "description": "This is a test task", "completed": False } try: response = requests.post(f"{BASE_URL}/api/{user_id}/tasks", json=task_data, headers=headers) print(f" Create task: {response.status_code}") if response.status_code != 201: print(f" Create task failed: {response.text}") return False created_task = response.json() task_id = created_task['id'] print(f" Task created with ID: {task_id}") # Test 2: Get all tasks for user print(" Getting all tasks...") response = requests.get(f"{BASE_URL}/api/{user_id}/tasks", headers=headers) print(f" Get tasks: {response.status_code}") if response.status_code != 200: print(f" Get tasks failed: {response.text}") return False tasks = response.json() print(f" Retrieved {len(tasks)} tasks") # Test 3: Get specific task print(" Getting specific task...") response = requests.get(f"{BASE_URL}/api/{user_id}/tasks/{task_id}", headers=headers) print(f" Get specific task: {response.status_code}") if response.status_code != 200: print(f" Get specific task failed: {response.text}") return False retrieved_task = response.json() print(f" Retrieved task: {retrieved_task['title']}") # Test 4: Update task print(" Updating task...") update_data = { "title": "Updated Test Task", "description": "This is an updated test task", "completed": True } response = requests.put(f"{BASE_URL}/api/{user_id}/tasks/{task_id}", json=update_data, headers=headers) print(f" Update task: {response.status_code}") if response.status_code != 200: print(f" Update task failed: {response.text}") return False updated_task = response.json() print(f" Task updated: {updated_task['title']}") # Test 5: Update task completion status print(" Updating task completion status...") completion_data = {"completed": False} response = requests.patch(f"{BASE_URL}/api/{user_id}/tasks/{task_id}/complete", json=completion_data, headers=headers) print(f" Update completion: {response.status_code}") if response.status_code != 200: print(f" Update completion failed: {response.text}") return False completed_task = response.json() print(f" Completion updated: {completed_task['completed']}") # Test 6: Delete task print(" Deleting task...") response = requests.delete(f"{BASE_URL}/api/{user_id}/tasks/{task_id}", headers=headers) print(f" Delete task: {response.status_code}") if response.status_code != 204: print(f" Delete task failed: {response.text}") return False print(" Task deleted successfully") return True except Exception as e: print(f"Task CRUD operations test failed: {e}") return False def test_logout_user(token): """Test user logout""" print("Testing user logout...") if not token: print("No valid token provided for logout") return False try: headers = { "Authorization": f"Bearer {token}" } response = requests.post(f"{BASE_URL}/api/auth/logout", headers=headers) print(f"Logout: {response.status_code}") if response.status_code == 200: print("User logged out successfully") return True else: print(f"Logout failed: {response.text}") return False except Exception as e: print(f"Logout test failed: {e}") return False def test_invalid_token(): """Test API with invalid token""" print("Testing API with invalid token...") try: headers = { "Authorization": "Bearer invalid_token_here" } # Try to access a protected endpoint response = requests.get(f"{BASE_URL}/api/1/tasks", headers=headers) print(f"Invalid token test: {response.status_code}") # Should return 401 for invalid token return response.status_code == 401 except Exception as e: print(f"Invalid token test failed: {e}") return False def run_all_tests(): """Run all backend tests""" print("=" * 60) print("Starting Backend API Tests") print("=" * 60) results = {} # Test 1: Health check results['health_check'] = test_health_check() # Test 2: User registration token, user_id = test_register_user() results['registration'] = token is not None # Test 3: User login login_token = test_login_user() results['login'] = login_token is not None # Test 4: Task CRUD operations (if we have a valid token from registration) if token and user_id: results['task_crud'] = test_task_crud_operations(token, user_id) else: results['task_crud'] = False print("Skipping task CRUD tests - no valid token from registration") # Test 5: Logout (if we have a valid login token) if login_token: results['logout'] = test_logout_user(login_token) else: results['logout'] = False print("Skipping logout test - no valid login token") # Test 6: Invalid token handling results['invalid_token'] = test_invalid_token() print("=" * 60) print("Test Results Summary:") print("=" * 60) all_passed = True for test_name, result in results.items(): status = "PASS" if result else "FAIL" print(f"{test_name:20}: {status}") if not result: all_passed = False print("=" * 60) print(f"Overall Result: {'ALL TESTS PASSED' if all_passed else 'SOME TESTS FAILED'}") print("=" * 60) return all_passed if __name__ == "__main__": run_all_tests()