EU-Utility/plugins/ui_test_suite/test_modules/user_flow_tests.py

549 lines
21 KiB
Python

"""
User Flow Tests
Tests for user workflows including:
- First-time user experience
- Plugin installation workflow
- Widget creation and management
- Settings changes
- Hotkey functionality
- Window positioning and persistence
"""
class UserFlowTests:
"""Test suite for user flows."""
name = "User Flows"
icon = "👤"
description = "Tests first-time experience, plugin installation, widget creation, and settings workflows"
def __init__(self):
self.tests = {
'first_time_experience': self.test_first_time_experience,
'plugin_install_workflow': self.test_plugin_install_workflow,
'widget_creation_workflow': self.test_widget_creation_workflow,
'settings_change_workflow': self.test_settings_change_workflow,
'hotkey_functionality': self.test_hotkey_functionality,
'window_positioning_persistence': self.test_window_positioning_persistence,
'overlay_toggle_flow': self.test_overlay_toggle_flow,
'tab_navigation_flow': self.test_tab_navigation_flow,
'plugin_drawer_flow': self.test_plugin_drawer_flow,
'error_recovery': self.test_error_recovery,
}
def test_first_time_experience(self) -> dict:
"""Test first-time user experience."""
try:
from core.ui.dashboard_view import DashboardView
from core.overlay_window import OverlayWindow
issues = []
recommendations = []
# Check dashboard welcome widget
if not hasattr(DashboardView, '_add_builtin_widgets'):
issues.append("Dashboard missing _add_builtin_widgets")
if not hasattr(DashboardView, '_create_widget_frame'):
issues.append("Dashboard missing _create_widget_frame")
# Check for welcome content
import inspect
if hasattr(DashboardView, '_add_builtin_widgets'):
source = inspect.getsource(DashboardView._add_builtin_widgets)
welcome_terms = ['welcome', 'install', 'plugin', 'store', 'get started']
has_welcome = any(term in source.lower() for term in welcome_terms)
if not has_welcome:
recommendations.append("Consider adding more prominent welcome guidance")
# Check for placeholder when no plugins
if not hasattr(OverlayWindow, '_create_placeholder'):
recommendations.append("Consider adding placeholder for empty plugin state")
if issues:
return {
'passed': False,
'message': "; ".join(issues),
'severity': 'warning',
'recommendation': recommendations[0] if recommendations else None
}
return {
'passed': True,
'message': "First-time experience features present",
'severity': 'info',
'recommendation': recommendations[0] if recommendations else None
}
except Exception as e:
return {
'passed': False,
'message': f"Error checking first-time experience: {e}",
'severity': 'error'
}
def test_plugin_install_workflow(self) -> dict:
"""Test plugin installation workflow."""
try:
from core.overlay_window import OverlayWindow
from core.plugin_store import PluginStoreUI
issues = []
recommendations = []
# Check settings dialog opens
if not hasattr(OverlayWindow, '_open_settings'):
issues.append("_open_settings method missing")
# Check plugin store tab exists
if not hasattr(OverlayWindow, '_create_plugin_store_tab'):
issues.append("_create_plugin_store_tab missing")
# Check store UI
if not hasattr(PluginStoreUI, 'install_plugin'):
issues.append("PluginStoreUI.install_plugin missing")
# Check for feedback after install
import inspect
if hasattr(PluginStoreUI, 'install_plugin'):
source = inspect.getsource(PluginStoreUI.install_plugin)
if 'progress' not in source.lower():
recommendations.append("Consider showing progress during installation")
if 'success' not in source.lower() and 'complete' not in source.lower():
recommendations.append("Consider showing success message after install")
if issues:
return {
'passed': False,
'message': "; ".join(issues),
'severity': 'error',
'recommendation': recommendations[0] if recommendations else None
}
return {
'passed': True,
'message': "Plugin install workflow present",
'severity': 'info',
'recommendation': recommendations[0] if recommendations else None
}
except Exception as e:
return {
'passed': False,
'message': f"Error checking install workflow: {e}",
'severity': 'error'
}
def test_widget_creation_workflow(self) -> dict:
"""Test widget creation workflow."""
try:
from core.overlay_window import OverlayWindow
from core.widget_registry import get_widget_registry
issues = []
recommendations = []
# Check widgets tab exists
if not hasattr(OverlayWindow, '_create_widgets_tab'):
issues.append("_create_widgets_tab missing")
if not hasattr(OverlayWindow, '_refresh_widgets_tab'):
issues.append("_refresh_widgets_tab missing")
if not hasattr(OverlayWindow, '_create_widget_button'):
issues.append("_create_widget_button missing")
if not hasattr(OverlayWindow, '_add_registered_widget'):
issues.append("_add_registered_widget missing")
# Check widget registry
try:
registry = get_widget_registry()
if not hasattr(registry, 'get_all_widgets'):
issues.append("WidgetRegistry.get_all_widgets missing")
except Exception as e:
issues.append(f"WidgetRegistry not accessible: {e}")
# Check for widget management
if not hasattr(OverlayWindow, '_active_widgets'):
recommendations.append("Consider tracking _active_widgets to prevent GC")
if issues:
return {
'passed': False,
'message': "; ".join(issues),
'severity': 'error',
'recommendation': recommendations[0] if recommendations else None
}
return {
'passed': True,
'message': "Widget creation workflow present",
'severity': 'info',
'recommendation': recommendations[0] if recommendations else None
}
except Exception as e:
return {
'passed': False,
'message': f"Error checking widget workflow: {e}",
'severity': 'error'
}
def test_settings_change_workflow(self) -> dict:
"""Test settings change workflow."""
try:
from core.overlay_window import OverlayWindow
issues = []
recommendations = []
# Check settings dialog
if not hasattr(OverlayWindow, '_open_settings'):
issues.append("_open_settings missing")
if not hasattr(OverlayWindow, '_save_settings'):
issues.append("_save_settings missing")
# Check for apply feedback
import inspect
if hasattr(OverlayWindow, '_save_settings'):
source = inspect.getsource(OverlayWindow._save_settings)
if 'reload' not in source.lower():
recommendations.append("Consider reloading plugins after settings save")
# Check settings persistence
if not hasattr(OverlayWindow, '_refresh_ui'):
recommendations.append("Consider adding _refresh_ui for immediate theme changes")
if issues:
return {
'passed': False,
'message': "; ".join(issues),
'severity': 'error',
'recommendation': recommendations[0] if recommendations else None
}
return {
'passed': True,
'message': "Settings change workflow present",
'severity': 'info',
'recommendation': recommendations[0] if recommendations else None
}
except Exception as e:
return {
'passed': False,
'message': f"Error checking settings workflow: {e}",
'severity': 'error'
}
def test_hotkey_functionality(self) -> dict:
"""Test hotkey functionality."""
try:
from core.overlay_window import OverlayWindow
from core.hotkey_manager import HotkeyManager
issues = []
recommendations = []
# Check shortcut setup
if not hasattr(OverlayWindow, '_setup_shortcuts'):
issues.append("_setup_shortcuts missing")
# Check toggle methods
if not hasattr(OverlayWindow, 'toggle_overlay'):
issues.append("toggle_overlay missing")
if not hasattr(OverlayWindow, 'show_overlay'):
issues.append("show_overlay missing")
if not hasattr(OverlayWindow, 'hide_overlay'):
issues.append("hide_overlay missing")
# Check hotkey manager
try:
hm = HotkeyManager()
if not hasattr(hm, 'register_hotkey'):
recommendations.append("Consider implementing global hotkeys with register_hotkey")
except Exception as e:
recommendations.append(f"HotkeyManager not fully functional: {e}")
# Check for expected shortcuts
import inspect
if hasattr(OverlayWindow, '_setup_shortcuts'):
source = inspect.getsource(OverlayWindow._setup_shortcuts)
expected = ['esc', 'ctrl+t', 'ctrl+1']
missing = [e for e in expected if e not in source.lower()]
if missing:
recommendations.append(f"Consider adding shortcuts: {missing}")
if issues:
return {
'passed': False,
'message': "; ".join(issues),
'severity': 'error',
'recommendation': recommendations[0] if recommendations else None
}
return {
'passed': True,
'message': "Hotkey functionality present",
'severity': 'info',
'recommendation': recommendations[0] if recommendations else None
}
except Exception as e:
return {
'passed': False,
'message': f"Error checking hotkey functionality: {e}",
'severity': 'error'
}
def test_window_positioning_persistence(self) -> dict:
"""Test window positioning and persistence."""
try:
from core.overlay_window import OverlayWindow
from core.activity_bar import ActivityBar
issues = []
recommendations = []
# Check center window
if not hasattr(OverlayWindow, '_center_window'):
issues.append("_center_window missing")
# Check activity bar position persistence
if not hasattr(ActivityBar, '_save_position'):
recommendations.append("Consider implementing activity bar position persistence")
# Check config persistence
if not hasattr(ActivityBar, '_save_config'):
issues.append("ActivityBar._save_config missing")
if not hasattr(ActivityBar, '_load_config'):
issues.append("ActivityBar._load_config missing")
if issues:
return {
'passed': False,
'message': "; ".join(issues),
'severity': 'warning',
'recommendation': recommendations[0] if recommendations else None
}
return {
'passed': True,
'message': "Window positioning features present",
'severity': 'info',
'recommendation': recommendations[0] if recommendations else None
}
except Exception as e:
return {
'passed': False,
'message': f"Error checking window positioning: {e}",
'severity': 'error'
}
def test_overlay_toggle_flow(self) -> dict:
"""Test overlay toggle flow."""
try:
from core.overlay_window import OverlayWindow
issues = []
# Check visibility tracking
if not hasattr(OverlayWindow, 'is_visible'):
issues.append("is_visible state not tracked")
# Check visibility signal
if not hasattr(OverlayWindow, 'visibility_changed'):
issues.append("visibility_changed signal missing")
# Check methods
required = ['show_overlay', 'hide_overlay', 'toggle_overlay']
for method in required:
if not hasattr(OverlayWindow, method):
issues.append(f"{method} missing")
# Check tray integration
if not hasattr(OverlayWindow, '_tray_activated'):
issues.append("_tray_activated missing for tray toggle")
if issues:
return {
'passed': False,
'message': "; ".join(issues),
'severity': 'error'
}
return {
'passed': True,
'message': "Overlay toggle flow complete",
'severity': 'info'
}
except Exception as e:
return {
'passed': False,
'message': f"Error checking toggle flow: {e}",
'severity': 'error'
}
def test_tab_navigation_flow(self) -> dict:
"""Test tab navigation flow."""
try:
from core.overlay_window import OverlayWindow
issues = []
# Check tab switching
if not hasattr(OverlayWindow, '_switch_tab'):
issues.append("_switch_tab missing")
if not hasattr(OverlayWindow, 'tab_buttons'):
issues.append("tab_buttons not tracked")
if not hasattr(OverlayWindow, 'tab_stack'):
issues.append("tab_stack not defined")
# Check expected tabs
expected_tabs = ['plugins', 'widgets', 'settings']
import inspect
if hasattr(OverlayWindow, '_switch_tab'):
source = inspect.getsource(OverlayWindow._switch_tab)
for tab in expected_tabs:
if f"'{tab}'" not in source and f'"{tab}"' not in source:
issues.append(f"Tab '{tab}' may not be handled in _switch_tab")
if issues:
return {
'passed': False,
'message': "; ".join(issues),
'severity': 'error'
}
return {
'passed': True,
'message': f"Tab navigation flow present ({len(expected_tabs)} tabs)",
'severity': 'info'
}
except Exception as e:
return {
'passed': False,
'message': f"Error checking tab navigation: {e}",
'severity': 'error'
}
def test_plugin_drawer_flow(self) -> dict:
"""Test plugin drawer workflow."""
try:
from core.activity_bar import ActivityBar
issues = []
recommendations = []
# Check drawer toggle
if not hasattr(ActivityBar, '_toggle_drawer'):
issues.append("_toggle_drawer missing")
if not hasattr(ActivityBar, 'drawer_open'):
issues.append("drawer_open state not tracked")
# Check drawer signals
if not hasattr(ActivityBar, 'drawer_toggled'):
issues.append("drawer_toggled signal missing")
# Check drawer content
if not hasattr(ActivityBar, '_refresh_drawer'):
issues.append("_refresh_drawer missing")
if not hasattr(ActivityBar, '_create_drawer_item'):
issues.append("_create_drawer_item missing")
# Check click handling
if not hasattr(ActivityBar, '_on_drawer_item_clicked'):
issues.append("_on_drawer_item_clicked missing")
if issues:
return {
'passed': False,
'message': "; ".join(issues),
'severity': 'error'
}
return {
'passed': True,
'message': "Plugin drawer flow complete",
'severity': 'info'
}
except Exception as e:
return {
'passed': False,
'message': f"Error checking drawer flow: {e}",
'severity': 'error'
}
def test_error_recovery(self) -> dict:
"""Test error recovery flows."""
try:
from core.overlay_window import OverlayWindow
from core.activity_bar import ActivityBar
issues = []
recommendations = []
# Check error handling in plugin loading
import inspect
if hasattr(OverlayWindow, '_load_plugins'):
source = inspect.getsource(OverlayWindow._load_plugins)
if 'try' not in source or 'except' not in source:
recommendations.append("Consider adding error handling to _load_plugins")
# Check error handling in widget creation
if hasattr(OverlayWindow, '_add_registered_widget'):
source = inspect.getsource(OverlayWindow._add_registered_widget)
if 'try' not in source or 'except' not in source:
recommendations.append("Consider adding error handling to _add_registered_widget")
# Check for fallback UI
if not hasattr(OverlayWindow, '_create_placeholder'):
recommendations.append("Consider adding placeholder UI for error states")
if issues:
return {
'passed': False,
'message': "; ".join(issues),
'severity': 'error',
'recommendation': recommendations[0] if recommendations else None
}
return {
'passed': True,
'message': "Error recovery features checked",
'severity': 'info',
'recommendation': recommendations[0] if recommendations else None
}
except Exception as e:
return {
'passed': False,
'message': f"Error checking error recovery: {e}",
'severity': 'error'
}