youtube-summarizer/test_story_3.3.py

278 lines
11 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Test script for Story 3.3: Summary History Management
Tests backend and frontend implementation
"""
import sys
import os
import json
import requests
from datetime import datetime, timedelta
from typing import Dict, List, Optional
# Add backend directory to path
backend_dir = os.path.join(os.path.dirname(__file__), 'backend')
sys.path.insert(0, backend_dir)
class Story33Tester:
def __init__(self):
self.base_url = "http://localhost:8000"
self.test_user = {
"email": "test_history@example.com",
"password": "TestPass123!",
"full_name": "Test User"
}
self.access_token = None
self.user_id = None
def print_section(self, title: str):
"""Print a section header"""
print("\n" + "=" * 60)
print(f" {title}")
print("=" * 60)
def print_result(self, test_name: str, passed: bool, details: str = ""):
"""Print test result"""
status = "✅ PASS" if passed else "❌ FAIL"
print(f"{status} - {test_name}")
if details:
print(f" {details}")
def test_backend_models(self) -> bool:
"""Test if backend models have history fields"""
self.print_section("Testing Backend Models")
try:
from backend.models.summary import Summary
from backend.core.database_registry import registry
# Check for new fields
required_fields = ['is_starred', 'notes', 'tags', 'shared_token', 'is_public', 'view_count']
model_fields = [col.name for col in Summary.__table__.columns]
all_fields_present = True
for field in required_fields:
present = field in model_fields
self.print_result(f"Field '{field}' in Summary model", present)
if not present:
all_fields_present = False
# Check for generate_share_token method
has_share_method = hasattr(Summary, 'generate_share_token')
self.print_result("generate_share_token method exists", has_share_method)
return all_fields_present and has_share_method
except ImportError as e:
self.print_result("Import backend models", False, str(e))
return False
def test_database_migration(self) -> bool:
"""Test if database migration exists"""
self.print_section("Testing Database Migration")
migration_path = os.path.join(
backend_dir,
'alembic/versions/add_history_management_fields.py'
)
exists = os.path.exists(migration_path)
self.print_result("Migration file exists", exists, migration_path)
if exists:
with open(migration_path, 'r') as f:
content = f.read()
# Check for key migration operations
checks = [
('is_starred column', "add_column(sa.Column('is_starred'"),
('notes column', "add_column(sa.Column('notes'"),
('tags column', "add_column(sa.Column('tags'"),
('shared_token column', "add_column(sa.Column('shared_token'"),
('indexes created', "create_index"),
]
for check_name, check_str in checks:
found = check_str in content
self.print_result(f"Migration includes {check_name}", found)
return exists
def test_api_endpoints(self) -> bool:
"""Test API endpoints availability"""
self.print_section("Testing API Endpoints")
# First, register and login
try:
# Register user
register_resp = requests.post(
f"{self.base_url}/api/auth/register",
json=self.test_user
)
if register_resp.status_code == 400:
# User might already exist, try login
login_resp = requests.post(
f"{self.base_url}/api/auth/login",
json={
"email": self.test_user["email"],
"password": self.test_user["password"]
}
)
if login_resp.status_code == 200:
self.access_token = login_resp.json()["access_token"]
self.user_id = login_resp.json()["user"]["id"]
elif register_resp.status_code == 201:
self.access_token = register_resp.json()["access_token"]
self.user_id = register_resp.json()["user"]["id"]
except Exception as e:
self.print_result("Authentication setup", False, str(e))
return False
if not self.access_token:
self.print_result("Authentication", False, "Could not obtain access token")
return False
headers = {"Authorization": f"Bearer {self.access_token}"}
# Test endpoints
endpoints = [
("GET /api/summaries", "get", "/api/summaries", None),
("GET /api/summaries/starred", "get", "/api/summaries/starred", None),
("GET /api/summaries/stats", "get", "/api/summaries/stats", None),
("POST /api/summaries/search", "post", "/api/summaries/search", {"query": "test"}),
]
all_passed = True
for name, method, path, data in endpoints:
try:
if method == "get":
resp = requests.get(f"{self.base_url}{path}", headers=headers)
else:
resp = requests.post(f"{self.base_url}{path}", json=data, headers=headers)
passed = resp.status_code in [200, 201, 404] # 404 ok for empty results
self.print_result(name, passed, f"Status: {resp.status_code}")
if not passed:
all_passed = False
except Exception as e:
self.print_result(name, False, str(e))
all_passed = False
return all_passed
def test_frontend_components(self) -> bool:
"""Test if frontend components exist"""
self.print_section("Testing Frontend Components")
frontend_dir = os.path.join(os.path.dirname(__file__), 'frontend/src')
components = [
('SummaryHistoryPage', 'pages/history/SummaryHistoryPage.tsx'),
('useSummaryHistory hook', 'hooks/useSummaryHistory.ts'),
('summaryAPI service', 'services/summaryAPI.ts'),
('SummaryList component', 'components/summaries/SummaryList.tsx'),
('SummaryCard component', 'components/summaries/SummaryCard.tsx'),
('SummarySearch component', 'components/summaries/SummarySearch.tsx'),
('BulkActions component', 'components/summaries/BulkActions.tsx'),
('ExportDialog component', 'components/summaries/ExportDialog.tsx'),
('UsageStats component', 'components/summaries/UsageStats.tsx'),
]
all_exist = True
for name, path in components:
full_path = os.path.join(frontend_dir, path)
exists = os.path.exists(full_path)
self.print_result(f"{name} exists", exists, path)
if not exists:
all_exist = False
return all_exist
def test_routing(self) -> bool:
"""Test if routing is configured"""
self.print_section("Testing Routing Configuration")
app_file = os.path.join(
os.path.dirname(__file__),
'frontend/src/App.tsx'
)
if os.path.exists(app_file):
with open(app_file, 'r') as f:
content = f.read()
checks = [
('SummaryHistoryPage import', 'import { SummaryHistoryPage }'),
('History route configured', 'path="/history"'),
('Protected route for history', '<ProtectedRoute'),
]
all_passed = True
for check_name, check_str in checks:
found = check_str in content
self.print_result(check_name, found)
if not found:
all_passed = False
return all_passed
else:
self.print_result("App.tsx exists", False)
return False
def run_all_tests(self) -> bool:
"""Run all tests"""
print("\n" + "🎯" * 30)
print(" STORY 3.3: SUMMARY HISTORY MANAGEMENT - TEST SUITE")
print("🎯" * 30)
results = {
"Backend Models": self.test_backend_models(),
"Database Migration": self.test_database_migration(),
"API Endpoints": self.test_api_endpoints(),
"Frontend Components": self.test_frontend_components(),
"Routing Configuration": self.test_routing(),
}
# Summary
self.print_section("TEST SUMMARY")
total = len(results)
passed = sum(1 for v in results.values() if v)
for test_name, result in results.items():
status = "" if result else ""
print(f"{status} {test_name}")
print(f"\nTotal: {passed}/{total} test groups passed")
if passed == total:
print("\n🎉 SUCCESS! Story 3.3 is fully implemented!")
print("\nNext steps:")
print("1. Run the application: cd frontend && npm run dev")
print("2. Navigate to http://localhost:3000/history")
print("3. Test the summary history functionality")
print("4. Update Epic 3 documentation to reflect completion")
else:
print("\n⚠️ Some tests failed. Please review and fix the issues above.")
return passed == total
if __name__ == "__main__":
# Check if backend server is running
try:
response = requests.get("http://localhost:8000/health")
if response.status_code != 200:
print("⚠️ Backend server is not healthy. Please start it first:")
print(" cd backend && python main.py")
sys.exit(1)
except requests.exceptions.ConnectionError:
print("❌ Backend server is not running. Please start it first:")
print(" cd backend && python main.py")
sys.exit(1)
tester = Story33Tester()
success = tester.run_all_tests()
sys.exit(0 if success else 1)