| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- #!/usr/bin/env python3
- """Comprehensive end-to-end test for Bambuddy application."""
- import time
- from playwright.sync_api import sync_playwright, expect
- BASE_URL = "http://localhost:8000"
- def test_navigation_and_sidebar(page):
- """Test sidebar navigation and all main pages."""
- print("\n=== Testing Navigation & Sidebar ===")
- # Go to home page
- page.goto(BASE_URL)
- page.wait_for_load_state('networkidle')
- # Take initial screenshot
- page.screenshot(path='/tmp/bambuddy_home.png', full_page=True)
- print("✓ Home page loaded")
- # Check sidebar is visible
- sidebar = page.locator('nav').first
- expect(sidebar).to_be_visible()
- print("✓ Sidebar is visible")
- # Test navigation to each main page
- nav_items = [
- ("Printers", "/"),
- ("Archives", "/archives"),
- ("Queue", "/queue"),
- ("Statistics", "/stats"),
- ("Profiles", "/profiles"),
- ("Maintenance", "/maintenance"),
- ("Settings", "/settings"),
- ]
- for name, path in nav_items:
- # Click on nav item by text
- nav_link = page.locator(f'nav >> text="{name}"').first
- if nav_link.is_visible():
- nav_link.click()
- page.wait_for_load_state('networkidle')
- time.sleep(0.5) # Brief wait for animations
- print(f"✓ Navigated to {name}")
- else:
- print(f"⚠ Nav item '{name}' not visible")
- return True
- def test_printers_page(page):
- """Test Printers page functionality."""
- print("\n=== Testing Printers Page ===")
- page.goto(BASE_URL)
- page.wait_for_load_state('networkidle')
- time.sleep(1)
- # Check for printer cards or "Add Printer" button
- page_content = page.content()
- # Look for printer-related elements
- if "Add Printer" in page_content or "printer" in page_content.lower():
- print("✓ Printers page content detected")
- # Check for AMS display if printers are connected
- ams_elements = page.locator('text=/AMS-[A-Z]/').all()
- if ams_elements:
- print(f"✓ Found {len(ams_elements)} AMS unit(s) displayed")
- # Take screenshot
- page.screenshot(path='/tmp/bambuddy_printers.png', full_page=True)
- print("✓ Printers page screenshot saved")
- return True
- def test_archives_page(page):
- """Test Archives page functionality."""
- print("\n=== Testing Archives Page ===")
- page.goto(f"{BASE_URL}/archives")
- page.wait_for_load_state('networkidle')
- time.sleep(1)
- # Check for search input
- search_input = page.locator('input[placeholder*="Search"]').first
- if search_input.is_visible():
- print("✓ Search input found")
- # Test search functionality
- search_input.fill("test")
- time.sleep(0.5)
- search_input.clear()
- # Check for upload button
- upload_btn = page.locator('text="Upload"').first
- if upload_btn.is_visible():
- print("✓ Upload button found")
- # Take screenshot
- page.screenshot(path='/tmp/bambuddy_archives.png', full_page=True)
- print("✓ Archives page screenshot saved")
- return True
- def test_queue_page(page):
- """Test Queue page functionality."""
- print("\n=== Testing Queue Page ===")
- page.goto(f"{BASE_URL}/queue")
- page.wait_for_load_state('networkidle')
- time.sleep(1)
- # Check for queue-related content
- page_content = page.content()
- if "Queue" in page_content or "queue" in page_content.lower():
- print("✓ Queue page content detected")
- # Take screenshot
- page.screenshot(path='/tmp/bambuddy_queue.png', full_page=True)
- print("✓ Queue page screenshot saved")
- return True
- def test_statistics_page(page):
- """Test Statistics page functionality."""
- print("\n=== Testing Statistics Page ===")
- page.goto(f"{BASE_URL}/stats")
- page.wait_for_load_state('networkidle')
- time.sleep(1)
- # Check for statistics widgets
- page_content = page.content()
- stats_keywords = ["Total", "Success", "Failed", "Prints", "Filament", "Time"]
- found_stats = [kw for kw in stats_keywords if kw in page_content]
- if found_stats:
- print(f"✓ Statistics found: {', '.join(found_stats)}")
- # Take screenshot
- page.screenshot(path='/tmp/bambuddy_statistics.png', full_page=True)
- print("✓ Statistics page screenshot saved")
- return True
- def test_settings_page(page):
- """Test Settings page functionality."""
- print("\n=== Testing Settings Page ===")
- page.goto(f"{BASE_URL}/settings")
- page.wait_for_load_state('networkidle')
- time.sleep(1)
- # Check for settings sections
- settings_sections = [
- "Spoolman",
- "Notifications",
- "Smart Plugs",
- "General",
- ]
- page_content = page.content()
- for section in settings_sections:
- if section in page_content:
- print(f"✓ Settings section found: {section}")
- # Take screenshot
- page.screenshot(path='/tmp/bambuddy_settings.png', full_page=True)
- print("✓ Settings page screenshot saved")
- return True
- def test_keyboard_shortcuts(page):
- """Test keyboard shortcuts functionality."""
- print("\n=== Testing Keyboard Shortcuts ===")
- page.goto(BASE_URL)
- page.wait_for_load_state('networkidle')
- time.sleep(0.5)
- # Press '?' to open shortcuts modal
- page.keyboard.press('?')
- time.sleep(0.5)
- # Check if modal opened
- modal = page.locator('text="Keyboard Shortcuts"').first
- if modal.is_visible():
- print("✓ Keyboard shortcuts modal opened with '?'")
- page.screenshot(path='/tmp/bambuddy_shortcuts_modal.png')
- # Close with Escape
- page.keyboard.press('Escape')
- time.sleep(0.3)
- if not modal.is_visible():
- print("✓ Modal closed with Escape")
- else:
- print("⚠ Keyboard shortcuts modal did not open")
- # Test number key navigation
- # Press '2' to go to Archives
- page.keyboard.press('2')
- page.wait_for_load_state('networkidle')
- time.sleep(0.5)
- current_url = page.url
- if "/archives" in current_url:
- print("✓ Hotkey '2' navigated to Archives")
- else:
- print(f"⚠ Hotkey '2' navigation - current URL: {current_url}")
- # Press '1' to go back to Printers
- page.keyboard.press('1')
- page.wait_for_load_state('networkidle')
- time.sleep(0.5)
- current_url = page.url
- if current_url == BASE_URL + "/" or current_url == BASE_URL:
- print("✓ Hotkey '1' navigated to Printers")
- return True
- def test_theme_toggle(page):
- """Test theme toggle functionality."""
- print("\n=== Testing Theme Toggle ===")
- page.goto(f"{BASE_URL}/settings")
- page.wait_for_load_state('networkidle')
- time.sleep(1)
- # Check if dark theme is applied (should be default)
- html = page.locator('html')
- classes = html.get_attribute('class') or ''
- if 'dark' in classes:
- print("✓ Dark theme is active (default)")
- else:
- print("ℹ Dark theme class not found on HTML element")
- # Look for theme-related UI elements
- page_content = page.content()
- if 'theme' in page_content.lower() or 'dark' in page_content.lower():
- print("✓ Theme-related content found on page")
- return True
- def test_responsive_design(page):
- """Test responsive design at different viewport sizes."""
- print("\n=== Testing Responsive Design ===")
- viewports = [
- ("Desktop", 1920, 1080),
- ("Tablet", 768, 1024),
- ("Mobile", 375, 667),
- ]
- for name, width, height in viewports:
- page.set_viewport_size({"width": width, "height": height})
- page.goto(BASE_URL)
- page.wait_for_load_state('networkidle')
- time.sleep(0.5)
- page.screenshot(path=f'/tmp/bambuddy_{name.lower()}.png', full_page=True)
- print(f"✓ {name} viewport ({width}x{height}) screenshot saved")
- # Reset to desktop
- page.set_viewport_size({"width": 1920, "height": 1080})
- return True
- def test_external_links_sidebar(page):
- """Test external links in sidebar."""
- print("\n=== Testing External Links in Sidebar ===")
- page.goto(BASE_URL)
- page.wait_for_load_state('networkidle')
- time.sleep(0.5)
- # Look for external link indicators
- external_links = page.locator('nav a[target="_blank"], nav >> text=/Spoolman|SpoolEase/i').all()
- if external_links:
- print(f"✓ Found {len(external_links)} external link(s) in sidebar")
- else:
- print("ℹ No external links configured in sidebar")
- return True
- def test_api_health(page):
- """Test basic API endpoints."""
- print("\n=== Testing API Health ===")
- # Test printers endpoint
- response = page.request.get(f"{BASE_URL}/api/v1/printers/")
- if response.ok:
- data = response.json()
- print(f"✓ GET /api/v1/printers/ - {len(data)} printer(s)")
- else:
- print(f"⚠ GET /api/v1/printers/ - Status: {response.status}")
- # Test archives endpoint
- response = page.request.get(f"{BASE_URL}/api/v1/archives/")
- if response.ok:
- data = response.json()
- print(f"✓ GET /api/v1/archives/ - {len(data)} archive(s)")
- else:
- print(f"⚠ GET /api/v1/archives/ - Status: {response.status}")
- # Test settings endpoint
- response = page.request.get(f"{BASE_URL}/api/v1/settings/")
- if response.ok:
- print("✓ GET /api/v1/settings/ - OK")
- else:
- print(f"⚠ GET /api/v1/settings/ - Status: {response.status}")
- return True
- def run_comprehensive_test():
- """Run all comprehensive tests."""
- print("=" * 60)
- print("BAMBUDDY COMPREHENSIVE E2E TEST")
- print("=" * 60)
- print(f"Target: {BASE_URL}")
- results = {}
- with sync_playwright() as p:
- browser = p.chromium.launch(headless=True)
- context = browser.new_context(viewport={"width": 1920, "height": 1080})
- page = context.new_page()
- # Enable console logging
- page.on("console", lambda msg: print(f" [Browser] {msg.text}") if msg.type == "error" else None)
- tests = [
- ("API Health", test_api_health),
- ("Navigation & Sidebar", test_navigation_and_sidebar),
- ("Printers Page", test_printers_page),
- ("Archives Page", test_archives_page),
- ("Queue Page", test_queue_page),
- ("Statistics Page", test_statistics_page),
- ("Settings Page", test_settings_page),
- ("Keyboard Shortcuts", test_keyboard_shortcuts),
- ("Theme Toggle", test_theme_toggle),
- ("External Links", test_external_links_sidebar),
- ("Responsive Design", test_responsive_design),
- ]
- for test_name, test_func in tests:
- try:
- results[test_name] = test_func(page)
- except Exception as e:
- print(f"\n❌ {test_name} FAILED: {e}")
- results[test_name] = False
- page.screenshot(path=f'/tmp/bambuddy_error_{test_name.lower().replace(" ", "_")}.png')
- browser.close()
- # Summary
- print("\n" + "=" * 60)
- print("TEST SUMMARY")
- print("=" * 60)
- passed = sum(1 for v in results.values() if v)
- total = len(results)
- for test_name, passed_test in results.items():
- status = "✓ PASS" if passed_test else "❌ FAIL"
- print(f" {status} - {test_name}")
- print(f"\nTotal: {passed}/{total} tests passed")
- print(f"Screenshots saved to /tmp/bambuddy_*.png")
- return all(results.values())
- if __name__ == "__main__":
- success = run_comprehensive_test()
- exit(0 if success else 1)
|