2025-09-09 18:15:30 -07:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
"""
|
|
|
|
E2E Test Runner for MTG Deckbuilder (M3: Cypress/Playwright Smoke Tests)
|
|
|
|
|
|
|
|
This script sets up and runs end-to-end tests for the web UI.
|
|
|
|
It can start the development server if needed and run smoke tests.
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
python run_e2e_tests.py --smoke # Run smoke tests only
|
|
|
|
python run_e2e_tests.py --full # Run all tests
|
|
|
|
python run_e2e_tests.py --mobile # Run mobile tests only
|
|
|
|
python run_e2e_tests.py --start-server # Start dev server then run tests
|
|
|
|
"""
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
import asyncio
|
|
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import time
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
class E2ETestRunner:
|
|
|
|
def __init__(self):
|
|
|
|
self.project_root = Path(__file__).parent.parent
|
|
|
|
self.server_process = None
|
2025-09-09 20:18:03 -07:00
|
|
|
self.base_url = os.getenv('TEST_BASE_URL', 'http://localhost:8080')
|
2025-09-09 18:15:30 -07:00
|
|
|
|
|
|
|
def start_dev_server(self):
|
|
|
|
"""Start the development server"""
|
|
|
|
print("Starting development server...")
|
|
|
|
|
|
|
|
# Try to start the web server
|
|
|
|
server_cmd = [
|
|
|
|
sys.executable,
|
|
|
|
"-m", "uvicorn",
|
|
|
|
"code.web.app:app",
|
|
|
|
"--host", "0.0.0.0",
|
2025-09-09 20:18:03 -07:00
|
|
|
"--port", "8080",
|
2025-09-09 18:15:30 -07:00
|
|
|
"--reload"
|
|
|
|
]
|
|
|
|
|
|
|
|
try:
|
|
|
|
self.server_process = subprocess.Popen(
|
|
|
|
server_cmd,
|
|
|
|
cwd=self.project_root,
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
stderr=subprocess.PIPE
|
|
|
|
)
|
|
|
|
|
|
|
|
# Wait for server to start
|
|
|
|
print("Waiting for server to start...")
|
|
|
|
time.sleep(5)
|
|
|
|
|
|
|
|
# Check if server is running
|
|
|
|
if self.server_process.poll() is None:
|
|
|
|
print(f"✓ Server started at {self.base_url}")
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
print("❌ Failed to start server")
|
|
|
|
return False
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
print(f"❌ Error starting server: {e}")
|
|
|
|
return False
|
|
|
|
|
|
|
|
def stop_dev_server(self):
|
|
|
|
"""Stop the development server"""
|
|
|
|
if self.server_process:
|
|
|
|
print("Stopping development server...")
|
|
|
|
self.server_process.terminate()
|
|
|
|
try:
|
|
|
|
self.server_process.wait(timeout=10)
|
|
|
|
except subprocess.TimeoutExpired:
|
|
|
|
self.server_process.kill()
|
|
|
|
print("✓ Server stopped")
|
|
|
|
|
|
|
|
def install_playwright(self):
|
|
|
|
"""Install Playwright browsers if needed"""
|
|
|
|
print("Installing Playwright browsers...")
|
|
|
|
try:
|
|
|
|
subprocess.run([
|
|
|
|
sys.executable, "-m", "playwright", "install", "chromium"
|
|
|
|
], check=True, cwd=self.project_root)
|
|
|
|
print("✓ Playwright browsers installed")
|
|
|
|
return True
|
|
|
|
except subprocess.CalledProcessError as e:
|
|
|
|
print(f"❌ Failed to install Playwright browsers: {e}")
|
|
|
|
return False
|
|
|
|
|
|
|
|
def run_tests(self, test_type="smoke"):
|
|
|
|
"""Run the specified tests"""
|
|
|
|
print(f"Running {test_type} tests...")
|
|
|
|
|
|
|
|
test_dir = self.project_root / "tests" / "e2e"
|
|
|
|
if not test_dir.exists():
|
|
|
|
print(f"❌ Test directory not found: {test_dir}")
|
|
|
|
return False
|
|
|
|
|
|
|
|
# Build pytest command
|
|
|
|
cmd = [sys.executable, "-m", "pytest", str(test_dir)]
|
|
|
|
|
|
|
|
if test_type == "smoke":
|
|
|
|
cmd.extend(["-m", "smoke", "-v"])
|
|
|
|
elif test_type == "mobile":
|
|
|
|
cmd.extend(["-m", "mobile", "-v"])
|
|
|
|
elif test_type == "full":
|
|
|
|
cmd.extend(["-v"])
|
|
|
|
else:
|
|
|
|
cmd.extend(["-v"])
|
|
|
|
|
|
|
|
# Set environment variables
|
|
|
|
env = os.environ.copy()
|
|
|
|
env["TEST_BASE_URL"] = self.base_url
|
|
|
|
|
|
|
|
try:
|
|
|
|
result = subprocess.run(cmd, cwd=self.project_root, env=env)
|
|
|
|
return result.returncode == 0
|
|
|
|
except Exception as e:
|
|
|
|
print(f"❌ Error running tests: {e}")
|
|
|
|
return False
|
|
|
|
|
|
|
|
def run_quick_smoke_test(self):
|
|
|
|
"""Run a quick smoke test without pytest"""
|
|
|
|
print("Running quick smoke test...")
|
|
|
|
|
|
|
|
try:
|
|
|
|
# Import and run the smoke test function
|
|
|
|
sys.path.insert(0, str(self.project_root))
|
|
|
|
from tests.e2e.test_web_smoke import run_smoke_tests
|
|
|
|
|
|
|
|
# Set the base URL
|
|
|
|
os.environ["TEST_BASE_URL"] = self.base_url
|
|
|
|
|
|
|
|
asyncio.run(run_smoke_tests())
|
|
|
|
return True
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
print(f"❌ Quick smoke test failed: {e}")
|
|
|
|
return False
|
|
|
|
|
|
|
|
def main():
|
|
|
|
parser = argparse.ArgumentParser(description="Run E2E tests for MTG Deckbuilder")
|
|
|
|
parser.add_argument("--smoke", action="store_true", help="Run smoke tests only")
|
|
|
|
parser.add_argument("--full", action="store_true", help="Run all tests")
|
|
|
|
parser.add_argument("--mobile", action="store_true", help="Run mobile tests only")
|
|
|
|
parser.add_argument("--start-server", action="store_true", help="Start dev server before tests")
|
|
|
|
parser.add_argument("--quick", action="store_true", help="Run quick smoke test without pytest")
|
|
|
|
parser.add_argument("--install-browsers", action="store_true", help="Install Playwright browsers")
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
runner = E2ETestRunner()
|
|
|
|
|
|
|
|
# Install browsers if requested
|
|
|
|
if args.install_browsers:
|
|
|
|
if not runner.install_playwright():
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
# Start server if requested
|
|
|
|
server_started = False
|
|
|
|
if args.start_server:
|
|
|
|
if not runner.start_dev_server():
|
|
|
|
sys.exit(1)
|
|
|
|
server_started = True
|
|
|
|
|
|
|
|
try:
|
|
|
|
# Determine test type
|
|
|
|
if args.mobile:
|
|
|
|
test_type = "mobile"
|
|
|
|
elif args.full:
|
|
|
|
test_type = "full"
|
|
|
|
else:
|
|
|
|
test_type = "smoke"
|
|
|
|
|
|
|
|
# Run tests
|
|
|
|
if args.quick:
|
|
|
|
success = runner.run_quick_smoke_test()
|
|
|
|
else:
|
|
|
|
success = runner.run_tests(test_type)
|
|
|
|
|
|
|
|
if success:
|
|
|
|
print("🎉 All tests passed!")
|
|
|
|
sys.exit(0)
|
|
|
|
else:
|
|
|
|
print("❌ Some tests failed!")
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
finally:
|
|
|
|
# Clean up
|
|
|
|
if server_started:
|
|
|
|
runner.stop_dev_server()
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|