278 lines
11 KiB
Python
Executable File
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) |