""" Phase 6 Regression Tests - Automated API Tests Tests all broken features without manual UI interaction """ import requests import json import sys from datetime import datetime BASE_URL = "http://localhost:8916" FRONTEND_URL = "http://localhost:8917" # Test results tracker results = { "passed": [], "failed": [], "errors": [], "timestamp": datetime.now().isoformat() } def log_result(test_name, passed, details=""): """Log test result""" result = { "name": test_name, "details": details, "timestamp": datetime.now().isoformat() } if passed: results["passed"].append(result) print(f"✅ PASS: {test_name}") if details: print(f" {details}") else: results["failed"].append(result) print(f"❌ FAIL: {test_name}") if details: print(f" {details}") return passed def log_error(test_name, error): """Log exception""" results["errors"].append({ "name": test_name, "error": str(error), "timestamp": datetime.now().isoformat() }) print(f"⚠️ ERROR: {test_name}") print(f" {str(error)}") return False # ============================================================================ # TEST 1: CREATE ITEM (Foundation - blocks all other tests) # ============================================================================ def test_create_item(): """Test creating a new item via API""" print("\n--- TEST 1: CREATE ITEM ---") try: payload = { "barcode": "TEST-001", "name": "Test Item", "category": "Electronics", "quantity": 5, "min_quantity": 1 } response = requests.post( f"{BASE_URL}/items/", json=payload, headers={"Content-Type": "application/json"} ) if response.status_code == 200: data = response.json() item_id = data.get("id") log_result("Create Item", True, f"Created item ID {item_id}") return item_id else: log_result("Create Item", False, f"Status {response.status_code}: {response.text}") return None except Exception as e: log_error("Create Item", e) return None # ============================================================================ # TEST 2: READ ITEMS (Verify DB) # ============================================================================ def test_read_items(): """Test fetching items from API""" print("\n--- TEST 2: READ ITEMS ---") try: response = requests.get(f"{BASE_URL}/items/") if response.status_code == 200: items = response.json() log_result("Read Items", True, f"Found {len(items)} items") return items else: log_result("Read Items", False, f"Status {response.status_code}") return [] except Exception as e: log_error("Read Items", e) return [] # ============================================================================ # TEST 3: DELETE ITEM (Test cascade) # ============================================================================ def test_delete_item(item_id): """Test deleting an item""" print("\n--- TEST 3: DELETE ITEM ---") if not item_id: log_result("Delete Item", False, "No item ID provided (create test failed)") return False try: response = requests.delete(f"{BASE_URL}/items/{item_id}") if response.status_code == 200: log_result("Delete Item", True, f"Deleted item ID {item_id}") return True else: log_result("Delete Item", False, f"Status {response.status_code}: {response.text}") return False except Exception as e: log_error("Delete Item", e) return False # ============================================================================ # TEST 4: SEARCH API (Test backend search) # ============================================================================ def test_search_items(): """Test searching items via API""" print("\n--- TEST 4: SEARCH ITEMS ---") try: response = requests.get( f"{BASE_URL}/items/search", params={"q": "test"} ) if response.status_code == 200: results_list = response.json() log_result("Search Items", True, f"Search returned {len(results_list)} results") return True elif response.status_code == 404: log_result("Search Items", False, "Endpoint /api/items/search not found") return False else: log_result("Search Items", False, f"Status {response.status_code}") return False except Exception as e: log_error("Search Items", e) return False # ============================================================================ # TEST 5: ADMIN API (Test admin data) # ============================================================================ def test_admin_stats(): """Test admin stats endpoint""" print("\n--- TEST 5: ADMIN STATS ---") try: response = requests.get(f"{BASE_URL}/admin/db/stats") if response.status_code == 200: stats = response.json() log_result("Admin Stats", True, f"Stats: {stats}") return True elif response.status_code == 404: log_result("Admin Stats", False, "Endpoint /api/admin/stats not found") return False else: log_result("Admin Stats", False, f"Status {response.status_code}: {response.text}") return False except Exception as e: log_error("Admin Stats", e) return False # ============================================================================ # TEST 6: EXPORT ENDPOINT (Test Excel export) # ============================================================================ def test_export_snapshot(): """Test export snapshot endpoint""" print("\n--- TEST 6: EXPORT SNAPSHOT ---") try: response = requests.get(f"{BASE_URL}/admin/db/export") if response.status_code == 200: # Check if response is binary (Excel file) if response.headers.get("content-type", "").startswith("application/vnd"): log_result("Export Snapshot", True, f"Exported {len(response.content)} bytes") return True else: log_result("Export Snapshot", False, "Response not Excel file") return False elif response.status_code == 404: log_result("Export Snapshot", False, "Endpoint not found") return False else: log_result("Export Snapshot", False, f"Status {response.status_code}") return False except Exception as e: log_error("Export Snapshot", e) return False # ============================================================================ # TEST 7: BACKEND HEALTH # ============================================================================ def test_backend_health(): """Test backend health endpoint""" print("\n--- TEST 7: BACKEND HEALTH ---") try: response = requests.get(f"{BASE_URL}/health") if response.status_code == 200: log_result("Backend Health", True, "Backend responding") return True else: log_result("Backend Health", False, f"Status {response.status_code}") return False except Exception as e: log_error("Backend Health", e) return False # ============================================================================ # TEST 8: FRONTEND LOADS # ============================================================================ def test_frontend_loads(): """Test frontend HTML loads""" print("\n--- TEST 8: FRONTEND LOADS ---") try: response = requests.get(FRONTEND_URL) if response.status_code == 200 and "Inventory" in response.text: log_result("Frontend Loads", True, "Frontend HTML responding") return True else: log_result("Frontend Loads", False, f"Status {response.status_code}") return False except Exception as e: log_error("Frontend Loads", e) return False # ============================================================================ # MAIN TEST EXECUTION # ============================================================================ if __name__ == "__main__": print("=" * 70) print(" PHASE 6 REGRESSION TEST SUITE - Automated API Tests") print("=" * 70) print(f"Backend: {BASE_URL}") print(f"Frontend: {FRONTEND_URL}") print(f"Time: {datetime.now().isoformat()}") print("=" * 70) # Run tests in order print("\n[PHASE A: Infrastructure Tests]") test_backend_health() test_frontend_loads() print("\n[PHASE B: Core CRUD Operations]") item_id = test_create_item() items = test_read_items() if item_id: test_delete_item(item_id) print("\n[PHASE C: Feature Tests]") test_search_items() test_admin_stats() test_export_snapshot() # Summary print("\n" + "=" * 70) print(" TEST SUMMARY") print("=" * 70) print(f"✅ Passed: {len(results['passed'])}") print(f"❌ Failed: {len(results['failed'])}") print(f"⚠️ Errors: {len(results['errors'])}") print("=" * 70) # Write results to file with open("tests/PHASE6_TEST_RESULTS.json", "w") as f: json.dump(results, f, indent=2) print(f"\nResults saved to: tests/PHASE6_TEST_RESULTS.json") # Exit with appropriate code sys.exit(0 if len(results["failed"]) == 0 and len(results["errors"]) == 0 else 1)