tests: skip browser tests when no driver; try Firefox after Chrome

Made-with: Cursor
This commit is contained in:
2026-03-21 20:17:33 +13:00
parent 7b724e9ce1
commit 13538c39a6

View File

@@ -2,6 +2,9 @@
""" """
Browser automation tests using Selenium. Browser automation tests using Selenium.
Tests run against the device at 192.168.4.1 in an actual browser. Tests run against the device at 192.168.4.1 in an actual browser.
On Pi OS Lite (no desktop) these tests are skipped unless headless Chromium
and chromedriver are installed (e.g. chromium-browser chromium-chromedriver).
""" """
import sys import sys
@@ -13,8 +16,8 @@ from selenium import webdriver
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.options import Options as ChromeOptions
from selenium.webdriver.chrome.service import Service from selenium.webdriver.firefox.options import Options as FirefoxOptions
from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import TimeoutException, NoSuchElementException from selenium.common.exceptions import TimeoutException, NoSuchElementException
@@ -33,24 +36,41 @@ class BrowserTest:
self.created_presets: List[str] = [] self.created_presets: List[str] = []
def setup(self): def setup(self):
"""Set up the browser driver.""" """Set up the browser driver. Tries Chrome first, then Firefox."""
err_chrome, err_firefox = None, None
# Try Chrome first
try: try:
chrome_options = Options() opts = ChromeOptions()
if self.headless: if self.headless:
chrome_options.add_argument('--headless') opts.add_argument('--headless')
chrome_options.add_argument('--no-sandbox') opts.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage') opts.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--disable-gpu') opts.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size=1920,1080') opts.add_argument('--window-size=1920,1080')
self.driver = webdriver.Chrome(options=opts)
self.driver = webdriver.Chrome(options=chrome_options)
self.driver.implicitly_wait(5) self.driver.implicitly_wait(5)
print("✓ Browser started") print("✓ Browser started (Chrome)")
return True return True
except Exception as e: except Exception as e:
print(f"✗ Failed to start browser: {e}") err_chrome = e
print(" Make sure Chrome and ChromeDriver are installed") # Fallback to Firefox
return False try:
opts = FirefoxOptions()
if self.headless:
opts.add_argument('--headless')
self.driver = webdriver.Firefox(options=opts)
self.driver.implicitly_wait(5)
print("✓ Browser started (Firefox)")
return True
except Exception as e:
err_firefox = e
print("✗ Failed to start browser.")
if err_chrome:
print(f" Chrome: {err_chrome}")
if err_firefox:
print(f" Firefox: {err_firefox}")
print(" On Raspberry Pi (aarch64), install: chromium-browser and chromium-chromedriver")
return False
def teardown(self): def teardown(self):
"""Close the browser.""" """Close the browser."""
@@ -209,46 +229,6 @@ class BrowserTest:
except Exception as e: except Exception as e:
print(f" ⚠ Cleanup error: {e}") print(f" ⚠ Cleanup error: {e}")
def cleanup_test_data(self):
"""Clean up test data created during tests."""
try:
# Use requests to make API calls for cleanup
session = requests.Session()
# Delete created presets
for preset_id in self.created_presets:
try:
response = session.delete(f"{self.base_url}/presets/{preset_id}")
if response.status_code == 200:
print(f" ✓ Cleaned up preset: {preset_id}")
except Exception as e:
print(f" ⚠ Failed to cleanup preset {preset_id}: {e}")
# Delete created tabs
for tab_id in self.created_tabs:
try:
response = session.delete(f"{self.base_url}/tabs/{tab_id}")
if response.status_code == 200:
print(f" ✓ Cleaned up tab: {tab_id}")
except Exception as e:
print(f" ⚠ Failed to cleanup tab {tab_id}: {e}")
# Delete created profiles
for profile_id in self.created_profiles:
try:
response = session.delete(f"{self.base_url}/profiles/{profile_id}")
if response.status_code == 200:
print(f" ✓ Cleaned up profile: {profile_id}")
except Exception as e:
print(f" ⚠ Failed to cleanup profile {profile_id}: {e}")
# Clear the lists
self.created_tabs.clear()
self.created_profiles.clear()
self.created_presets.clear()
except Exception as e:
print(f" ⚠ Cleanup error: {e}")
def fill_input(self, by, value, text, timeout=10): def fill_input(self, by, value, text, timeout=10):
"""Fill an input field.""" """Fill an input field."""
try: try:
@@ -1005,11 +985,19 @@ def main():
print("LED Controller Browser Tests") print("LED Controller Browser Tests")
print(f"Testing against: {BASE_URL}") print(f"Testing against: {BASE_URL}")
print("=" * 60) print("=" * 60)
# On Pi OS Lite there is no browser by default; skip with exit 0 instead of failing
browser = BrowserTest(headless=True)
if not browser.setup():
print("\nSkipped (Pi OS Lite / no browser). Install chromium-browser and")
print("chromium-chromedriver to run browser tests, or run on Pi OS with desktop.")
sys.exit(0)
browser.teardown()
browser = BrowserTest(headless=False) # Set to True for headless mode browser = BrowserTest(headless=False) # Set to True for headless mode
results = [] results = []
# Run browser tests # Run browser tests
results.append(("Browser Connection", test_browser_connection(browser))) results.append(("Browser Connection", test_browser_connection(browser)))
results.append(("Tabs UI", test_tabs_ui(browser))) results.append(("Tabs UI", test_tabs_ui(browser)))