#!/usr/bin/env python3 """ Comprehensive test runner for Tritri application Runs backend API tests, frontend tests, and integration tests """ import subprocess import sys import time import os import requests from pathlib import Path def run_command(command, cwd=None, check=True): """Run a command and return the result""" print(f"๐Ÿ”„ Running: {' '.join(command)}") try: result = subprocess.run( command, cwd=cwd, check=check, capture_output=False, text=True ) print(f"โœ… Command completed successfully") return result except subprocess.CalledProcessError as e: print(f"โŒ Command failed with exit code {e.returncode}") if not check: return e sys.exit(1) def wait_for_api(timeout=30): """Wait for the API to be ready""" print("โณ Waiting for API to be ready...") start_time = time.time() while time.time() - start_time < timeout: try: response = requests.get("http://localhost:8000/health", timeout=5) if response.status_code == 200: print("โœ… API is ready") return True except requests.RequestException: pass time.sleep(1) print(f" Still waiting... ({int(time.time() - start_time)}s)") print("โŒ API failed to start within timeout") return False def check_dependencies(): """Check if required dependencies are available""" print("๐Ÿ” Checking dependencies...") # Check Python try: python_version = subprocess.run([sys.executable, "--version"], capture_output=True, text=True) print(f" Python: {python_version.stdout.strip()}") except FileNotFoundError: print("โŒ Python not found") return False # Check Node.js try: node_version = subprocess.run(["node", "--version"], capture_output=True, text=True) print(f" Node.js: {node_version.stdout.strip()}") except FileNotFoundError: print("โŒ Node.js not found") return False # Check npm try: npm_version = subprocess.run(["npm", "--version"], capture_output=True, text=True) print(f" npm: {npm_version.stdout.strip()}") except FileNotFoundError: print("โŒ npm not found") return False print("โœ… All dependencies found") return True def setup_backend(): """Setup backend environment""" print("๐Ÿ”ง Setting up backend...") backend_dir = Path("backend") if not backend_dir.exists(): print("โŒ Backend directory not found") return False # Install dependencies run_command([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"], cwd=backend_dir) print("โœ… Backend setup complete") return True def setup_frontend(): """Setup frontend environment""" print("๐Ÿ”ง Setting up frontend...") frontend_dir = Path("frontend") if not frontend_dir.exists(): print("โŒ Frontend directory not found") return False # Install dependencies run_command(["npm", "install"], cwd=frontend_dir) print("โœ… Frontend setup complete") return True def run_backend_tests(): """Run backend API tests""" print("\n๐Ÿงช Running Backend Tests...") backend_dir = Path("backend") # Run different test suites test_suites = [ ("Basic API Tests", "tests/test_api.py"), ("Expense Tests", "backend/tests/test_expenses.py"), ("Currency Tests", "backend/tests/test_currency.py"), ("Export Tests", "backend/tests/test_export.py") ] all_passed = True for suite_name, test_file in test_suites: print(f"\n ๐Ÿ“‹ Running {suite_name}...") try: if test_file.startswith("backend/"): # Run with pytest result = subprocess.run([ sys.executable, "-m", "pytest", test_file, "-v", "--tb=short" ], cwd=".", capture_output=True, text=True) else: # Run with python directly result = subprocess.run([ sys.executable, test_file ], cwd=".", capture_output=True, text=True) if result.returncode == 0: print(f" โœ… {suite_name} passed") if result.stdout: print(f" {result.stdout.strip()}") else: print(f" โŒ {suite_name} failed") if result.stderr: print(f" Error: {result.stderr.strip()}") all_passed = False except Exception as e: print(f" โŒ {suite_name} failed with exception: {e}") all_passed = False return all_passed def run_frontend_tests(): """Run frontend tests""" print("\n๐Ÿงช Running Frontend Tests...") frontend_dir = Path("frontend") # Check if frontend is built if not (frontend_dir / ".next").exists(): print(" ๐Ÿ“ฆ Building frontend...") run_command(["npm", "run", "build"], cwd=frontend_dir) # Run Playwright tests try: result = subprocess.run([ "npm", "run", "test" ], cwd=frontend_dir, capture_output=True, text=True) if result.returncode == 0: print("โœ… Frontend tests passed") return True else: print("โŒ Frontend tests failed") if result.stdout: print(f"Output: {result.stdout}") if result.stderr: print(f"Error: {result.stderr}") return False except Exception as e: print(f"โŒ Frontend tests failed with exception: {e}") return False def run_integration_tests(): """Run integration tests""" print("\n๐Ÿงช Running Integration Tests...") integration_tests = [ "test_integration.py", "test_e2e_user_flow.py", "test_trip_creator_access.py" ] all_passed = True for test_file in integration_tests: if Path(test_file).exists(): print(f" ๐Ÿ“‹ Running {test_file}...") try: result = subprocess.run([ sys.executable, test_file ], capture_output=True, text=True) if result.returncode == 0: print(f" โœ… {test_file} passed") else: print(f" โŒ {test_file} failed") if result.stderr: print(f" Error: {result.stderr.strip()}") all_passed = False except Exception as e: print(f" โŒ {test_file} failed with exception: {e}") all_passed = False else: print(f" โš ๏ธ {test_file} not found, skipping") return all_passed def generate_test_report(): """Generate a test coverage report""" print("\n๐Ÿ“Š Generating Test Report...") # This could be expanded to generate HTML reports, coverage reports, etc. report = { "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"), "features_tested": [ "Trip creation and management", "Multi-trip identity system", "Expense tracking with percentage splitting", "Currency conversion with real-time rates", "Data export (CSV/JSON)", "Analytics dashboard", "Share functionality", "Participant management", "Responsive design", "API validation and error handling" ], "test_types": [ "Unit tests (backend services)", "API endpoint tests", "Frontend component tests", "End-to-end user flow tests", "Integration tests" ] } print("โœ… Test Report Generated:") print(f" Timestamp: {report['timestamp']}") print(f" Features Tested: {len(report['features_tested'])}") print(f" Test Types: {len(report['test_types'])}") return report def main(): """Main test runner""" print("๐Ÿš€ Tritri Comprehensive Test Suite") print("=" * 50) # Check dependencies if not check_dependencies(): sys.exit(1) # Setup environments if not setup_backend(): sys.exit(1) if not setup_frontend(): sys.exit(1) # Run tests results = { "backend": False, "frontend": False, "integration": False } # Start API for tests that need it print("\n๐Ÿ”„ Starting API server for tests...") api_process = subprocess.Popen([ sys.executable, "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000" ], cwd="backend") try: # Wait for API to be ready if wait_for_api(): # Run backend tests results["backend"] = run_backend_tests() # Run integration tests results["integration"] = run_integration_tests() else: print("โŒ Skipping tests that require API") finally: # Stop API server api_process.terminate() api_process.wait() print("๐Ÿ›‘ API server stopped") # Run frontend tests (these don't need the API server running) results["frontend"] = run_frontend_tests() # Generate report report = generate_test_report() # Summary print("\n" + "=" * 50) print("๐Ÿ“‹ TEST SUMMARY") print("=" * 50) for test_type, passed in results.items(): status = "โœ… PASSED" if passed else "โŒ FAILED" print(f"{test_type.capitalize():<12}: {status}") all_passed = all(results.values()) if all_passed: print("\n๐ŸŽ‰ ALL TESTS PASSED!") print("โœ… Tritri application is ready for production") else: print("\nโŒ SOME TESTS FAILED!") print("โš ๏ธ Please review the failing tests and fix issues") sys.exit(1) if __name__ == "__main__": main()