- Migrated from HIVE branding to WHOOSH across all components - Enhanced backend API with new services: AI models, BZZZ integration, templates, members - Added comprehensive testing suite with security, performance, and integration tests - Improved frontend with new components for project setup, AI models, and team management - Updated MCP server implementation with WHOOSH-specific tools and resources - Enhanced deployment configurations with production-ready Docker setups - Added comprehensive documentation and setup guides - Implemented age encryption service and UCXL integration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
290 lines
11 KiB
Python
Executable File
290 lines
11 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Visual Testing Script for WHOOSH Frontend Development
|
|
Uses Selenium WebDriver to test and capture screenshots of the frontend
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import json
|
|
from datetime import datetime
|
|
from selenium import webdriver
|
|
from selenium.webdriver.common.by import By
|
|
from selenium.webdriver.support.ui import WebDriverWait
|
|
from selenium.webdriver.support import expected_conditions as EC
|
|
from selenium.webdriver.chrome.options import Options
|
|
from selenium.common.exceptions import TimeoutException, WebDriverException
|
|
|
|
class WHOOSHVisualTester:
|
|
def __init__(self, base_url="http://localhost:3000", headless=True):
|
|
self.base_url = base_url
|
|
self.headless = headless
|
|
self.driver = None
|
|
self.screenshots_dir = "/tmp/whoosh_screenshots"
|
|
self.setup_driver()
|
|
os.makedirs(self.screenshots_dir, exist_ok=True)
|
|
|
|
def setup_driver(self):
|
|
"""Setup Chrome WebDriver with appropriate options"""
|
|
chrome_options = Options()
|
|
if self.headless:
|
|
chrome_options.add_argument("--headless")
|
|
chrome_options.add_argument("--no-sandbox")
|
|
chrome_options.add_argument("--disable-dev-shm-usage")
|
|
chrome_options.add_argument("--disable-gpu")
|
|
chrome_options.add_argument("--window-size=1920,1080")
|
|
chrome_options.add_argument("--disable-extensions")
|
|
|
|
try:
|
|
self.driver = webdriver.Chrome(options=chrome_options)
|
|
self.driver.implicitly_wait(10)
|
|
print("✅ Chrome WebDriver initialized successfully")
|
|
except Exception as e:
|
|
print(f"❌ Failed to initialize Chrome WebDriver: {e}")
|
|
sys.exit(1)
|
|
|
|
def take_screenshot(self, name, description=""):
|
|
"""Take a screenshot and save with timestamp"""
|
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
filename = f"{timestamp}_{name}.png"
|
|
filepath = os.path.join(self.screenshots_dir, filename)
|
|
|
|
try:
|
|
self.driver.save_screenshot(filepath)
|
|
print(f"📸 Screenshot saved: {filename}")
|
|
if description:
|
|
print(f" Description: {description}")
|
|
return filepath
|
|
except Exception as e:
|
|
print(f"❌ Failed to take screenshot: {e}")
|
|
return None
|
|
|
|
def wait_for_element(self, by, value, timeout=10):
|
|
"""Wait for element to be present and visible"""
|
|
try:
|
|
element = WebDriverWait(self.driver, timeout).until(
|
|
EC.presence_of_element_located((by, value))
|
|
)
|
|
return element
|
|
except TimeoutException:
|
|
print(f"⏰ Timeout waiting for element: {by}={value}")
|
|
return None
|
|
|
|
def test_homepage_load(self):
|
|
"""Test if homepage loads correctly"""
|
|
print("\n🔍 Testing Homepage Load...")
|
|
|
|
try:
|
|
self.driver.get(self.base_url)
|
|
self.take_screenshot("01_homepage_initial", "Initial homepage load")
|
|
|
|
# Wait for React to load
|
|
time.sleep(3)
|
|
|
|
# Check if we get redirected to login or see the main app
|
|
current_url = self.driver.current_url
|
|
print(f"Current URL: {current_url}")
|
|
|
|
# Look for common elements
|
|
page_title = self.driver.title
|
|
print(f"Page title: {page_title}")
|
|
|
|
# Check for main content or login form
|
|
body_text = self.driver.find_element(By.TAG_NAME, "body").text
|
|
if "login" in body_text.lower() or "sign in" in body_text.lower():
|
|
print("🔐 Detected login page")
|
|
self.take_screenshot("02_login_page", "Login page detected")
|
|
return "login"
|
|
elif "dashboard" in body_text.lower() or "agents" in body_text.lower():
|
|
print("🏠 Detected main dashboard")
|
|
self.take_screenshot("02_dashboard_page", "Dashboard page detected")
|
|
return "dashboard"
|
|
else:
|
|
print("❓ Unknown page state")
|
|
self.take_screenshot("02_unknown_state", "Unknown page state")
|
|
return "unknown"
|
|
|
|
except Exception as e:
|
|
print(f"❌ Error testing homepage: {e}")
|
|
self.take_screenshot("error_homepage", "Error on homepage")
|
|
return "error"
|
|
|
|
def test_api_connectivity(self):
|
|
"""Test API connectivity by checking network requests"""
|
|
print("\n🔍 Testing API Connectivity...")
|
|
|
|
try:
|
|
# Enable network logging
|
|
self.driver.execute_cdp_cmd('Network.enable', {})
|
|
|
|
# Navigate to a page that should make API calls
|
|
self.driver.get(f"{self.base_url}/agents")
|
|
time.sleep(5) # Wait for API calls
|
|
|
|
self.take_screenshot("03_agents_page", "Agents page with API data")
|
|
|
|
# Check for API error messages in the page
|
|
body_text = self.driver.find_element(By.TAG_NAME, "body").text
|
|
if "error" in body_text.lower() or "failed" in body_text.lower():
|
|
print("⚠️ Possible API errors detected in page content")
|
|
return False
|
|
|
|
print("✅ No obvious API errors detected")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"❌ Error testing API connectivity: {e}")
|
|
self.take_screenshot("error_api_test", "Error testing API")
|
|
return False
|
|
|
|
def test_navigation(self):
|
|
"""Test navigation between pages"""
|
|
print("\n🔍 Testing Navigation...")
|
|
|
|
nav_items = [
|
|
("/", "homepage"),
|
|
("/agents", "agents_page"),
|
|
("/tasks", "tasks_page"),
|
|
("/workflows", "workflows_page"),
|
|
("/analytics", "analytics_page"),
|
|
("/executions", "executions_page")
|
|
]
|
|
|
|
for path, name in nav_items:
|
|
try:
|
|
print(f"Navigating to: {path}")
|
|
self.driver.get(f"{self.base_url}{path}")
|
|
time.sleep(3) # Wait for page load
|
|
|
|
self.take_screenshot(f"04_nav_{name}", f"Navigation to {path}")
|
|
|
|
# Check for loading states or errors
|
|
body_text = self.driver.find_element(By.TAG_NAME, "body").text
|
|
if "loading" in body_text.lower():
|
|
print("⏳ Page still loading...")
|
|
time.sleep(3)
|
|
self.take_screenshot(f"04_nav_{name}_loaded", f"After loading: {path}")
|
|
|
|
except Exception as e:
|
|
print(f"❌ Error navigating to {path}: {e}")
|
|
self.take_screenshot(f"error_nav_{name}", f"Navigation error: {path}")
|
|
|
|
def test_live_data_display(self):
|
|
"""Test if live data is being displayed correctly"""
|
|
print("\n🔍 Testing Live Data Display...")
|
|
|
|
# Test Analytics page for data
|
|
try:
|
|
self.driver.get(f"{self.base_url}/analytics")
|
|
time.sleep(5)
|
|
|
|
page_source = self.driver.page_source
|
|
|
|
# Look for mock data indicators
|
|
mock_indicators = ["mock", "demo", "placeholder", "sample"]
|
|
found_mock = any(indicator in page_source.lower() for indicator in mock_indicators)
|
|
|
|
if found_mock:
|
|
print("⚠️ Mock data indicators found - may need to replace with live data")
|
|
else:
|
|
print("✅ No obvious mock data indicators found")
|
|
|
|
self.take_screenshot("05_analytics_data", "Analytics page data display")
|
|
|
|
# Check for charts/graphs
|
|
charts = self.driver.find_elements(By.CSS_SELECTOR, "svg, canvas, .recharts-wrapper")
|
|
print(f"Found {len(charts)} chart elements")
|
|
|
|
return not found_mock
|
|
|
|
except Exception as e:
|
|
print(f"❌ Error testing live data: {e}")
|
|
return False
|
|
|
|
def test_responsive_design(self):
|
|
"""Test responsive design at different screen sizes"""
|
|
print("\n🔍 Testing Responsive Design...")
|
|
|
|
screen_sizes = [
|
|
(1920, 1080, "desktop"),
|
|
(1024, 768, "tablet"),
|
|
(375, 667, "mobile")
|
|
]
|
|
|
|
for width, height, device in screen_sizes:
|
|
try:
|
|
self.driver.set_window_size(width, height)
|
|
time.sleep(2)
|
|
|
|
self.driver.get(f"{self.base_url}/agents")
|
|
time.sleep(3)
|
|
|
|
self.take_screenshot(f"06_responsive_{device}", f"Responsive test: {device} ({width}x{height})")
|
|
|
|
except Exception as e:
|
|
print(f"❌ Error testing {device} responsive: {e}")
|
|
|
|
def run_full_test_suite(self):
|
|
"""Run complete visual test suite"""
|
|
print("🚀 Starting WHOOSH Frontend Visual Test Suite")
|
|
print("=" * 50)
|
|
|
|
results = {}
|
|
|
|
# Test 1: Homepage load
|
|
results['homepage'] = self.test_homepage_load()
|
|
|
|
# Test 2: API connectivity
|
|
results['api'] = self.test_api_connectivity()
|
|
|
|
# Test 3: Navigation
|
|
self.test_navigation()
|
|
results['navigation'] = True
|
|
|
|
# Test 4: Live data
|
|
results['live_data'] = self.test_live_data_display()
|
|
|
|
# Test 5: Responsive design
|
|
self.test_responsive_design()
|
|
results['responsive'] = True
|
|
|
|
# Summary
|
|
print("\n" + "=" * 50)
|
|
print("📊 Test Results Summary:")
|
|
for test, result in results.items():
|
|
status = "✅ PASS" if result in [True, "dashboard", "login"] else "❌ FAIL"
|
|
print(f" {test}: {status} ({result})")
|
|
|
|
print(f"\n📁 Screenshots saved to: {self.screenshots_dir}")
|
|
|
|
return results
|
|
|
|
def cleanup(self):
|
|
"""Clean up WebDriver"""
|
|
if self.driver:
|
|
self.driver.quit()
|
|
print("🧹 WebDriver closed")
|
|
|
|
def main():
|
|
# Check if Chrome is available
|
|
try:
|
|
tester = WHOOSHVisualTester(headless=True)
|
|
results = tester.run_full_test_suite()
|
|
tester.cleanup()
|
|
|
|
# Return exit code based on results
|
|
failed_tests = [k for k, v in results.items() if v in [False, "error", "unknown"]]
|
|
if failed_tests:
|
|
print(f"\n❌ Some tests failed: {failed_tests}")
|
|
sys.exit(1)
|
|
else:
|
|
print("\n✅ All tests passed!")
|
|
sys.exit(0)
|
|
|
|
except Exception as e:
|
|
print(f"❌ Test suite failed: {e}")
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
main() |