Add tests/test_graphical_hotspot_password.py

This commit is contained in:
Thomas Farstrike
2026-03-25 14:23:53 +01:00
parent abcf4df5f0
commit 73b9095631
4 changed files with 352 additions and 3 deletions
+6 -2
View File
@@ -34,7 +34,9 @@ from .ui.testing import (
wait_for_render, capture_screenshot, simulate_click, get_widget_coords,
find_label_with_text, verify_text_present, print_screen_labels, find_text_on_screen,
click_button, click_label, click_keyboard_button, find_button_with_text,
get_all_widgets_with_text
get_all_widgets_with_text, find_setting_value_label, get_setting_value_text,
verify_setting_value_text, find_dropdown_widget, get_dropdown_options,
find_dropdown_option_index, select_dropdown_option_by_text
)
# UI utility functions
@@ -92,7 +94,9 @@ __all__ = [
"wait_for_render", "capture_screenshot", "simulate_click", "get_widget_coords",
"find_label_with_text", "verify_text_present", "print_screen_labels", "find_text_on_screen",
"click_button", "click_label", "click_keyboard_button", "find_button_with_text",
"get_all_widgets_with_text",
"get_all_widgets_with_text", "find_setting_value_label", "get_setting_value_text",
"verify_setting_value_text", "find_dropdown_widget", "get_dropdown_options",
"find_dropdown_option_index", "select_dropdown_option_by_text",
# Submodules
"ui", "config", "net", "content", "time", "sensor_manager",
"camera_manager", "sdcard", "audio", "hardware",
+191 -1
View File
@@ -259,7 +259,6 @@ def get_screen_text_content(obj):
pass # Error getting text
return texts
def verify_text_present(obj, expected_text):
"""
Verify that expected text is present somewhere on screen.
@@ -281,6 +280,87 @@ def verify_text_present(obj, expected_text):
return find_label_with_text(obj, expected_text) is not None
def find_setting_value_label(obj, setting_title_text):
"""
Find the value label associated with a SettingsActivity setting title.
SettingsActivity renders each setting as a container with two labels:
a title label (large) and a value label (smaller) directly below it.
This helper finds the title label, then returns the sibling value label.
Args:
obj: LVGL object to search (typically lv.screen_active())
setting_title_text: Text of the setting title (exact or substring)
Returns:
LVGL label object for the value if found, None otherwise
Example:
value_label = find_setting_value_label(lv.screen_active(), "Auth Mode")
if value_label:
assert value_label.get_text() == "(defaults to none)"
"""
title_label = find_label_with_text(obj, setting_title_text)
if not title_label:
return None
try:
parent = title_label.get_parent()
if not parent:
return None
child_count = parent.get_child_count()
for i in range(child_count):
child = parent.get_child(i)
if child is title_label:
continue
try:
if hasattr(child, "get_text"):
text = child.get_text()
if text:
return child
except:
pass
except:
pass
return None
def get_setting_value_text(obj, setting_title_text):
"""
Get the value text associated with a SettingsActivity setting title.
Args:
obj: LVGL object to search (typically lv.screen_active())
setting_title_text: Text of the setting title (exact or substring)
Returns:
str or None: The value label text if found
"""
value_label = find_setting_value_label(obj, setting_title_text)
if value_label:
try:
return value_label.get_text()
except:
return None
return None
def verify_setting_value_text(obj, setting_title_text, expected_text):
"""
Verify a SettingsActivity value label matches expected text.
Args:
obj: LVGL object to search (typically lv.screen_active())
setting_title_text: Text of the setting title (exact or substring)
expected_text: Expected text for the value label (exact match)
Returns:
bool: True if value label text matches expected, False otherwise
"""
value_text = get_setting_value_text(obj, setting_title_text)
return value_text == expected_text
def text_to_hex(text):
"""
Convert text to hex representation for debugging.
@@ -414,6 +494,116 @@ def find_button_with_text(obj, search_text):
return None
def find_dropdown_widget(obj):
"""
Find a dropdown widget in the object hierarchy.
Args:
obj: LVGL object to search (typically lv.screen_active())
Returns:
LVGL dropdown object if found, None otherwise
"""
def find_dropdown_recursive(node):
try:
if node.__class__.__name__ == "dropdown" or hasattr(node, "get_selected"):
if hasattr(node, "get_options"):
return node
except:
pass
try:
child_count = node.get_child_count()
except:
return None
for i in range(child_count):
child = node.get_child(i)
result = find_dropdown_recursive(child)
if result:
return result
return None
return find_dropdown_recursive(obj)
def get_dropdown_options(dropdown):
"""
Get dropdown options as a list of strings.
Args:
dropdown: LVGL dropdown widget
Returns:
list: List of option strings (order preserved)
"""
try:
options = dropdown.get_options()
if options:
lines = options.split("\n")
return [line for line in lines if line]
except:
pass
return []
def find_dropdown_option_index(dropdown, option_text, allow_partial=True):
"""
Find the index of an option in a dropdown by text.
Args:
dropdown: LVGL dropdown widget
option_text: Text to search for
allow_partial: If True, match substring (default: True)
Returns:
int or None: Index of matching option
"""
options = get_dropdown_options(dropdown)
if options:
for idx, text in enumerate(options):
if (allow_partial and option_text in text) or (not allow_partial and option_text == text):
return idx
return None
try:
option_count = dropdown.get_option_count()
except:
option_count = 0
for idx in range(option_count):
try:
text = dropdown.get_option_text(idx)
if (allow_partial and option_text in text) or (not allow_partial and option_text == text):
return idx
except:
pass
return None
def select_dropdown_option_by_text(dropdown, option_text, allow_partial=True):
"""
Select a dropdown option by its text.
Args:
dropdown: LVGL dropdown widget
option_text: Text to select
allow_partial: If True, match substring (default: True)
Returns:
bool: True if option was found and selected
"""
idx = find_dropdown_option_index(dropdown, option_text, allow_partial=allow_partial)
if idx is None:
return False
try:
dropdown.set_selected(idx)
return True
except:
return False
def get_keyboard_button_coords(keyboard, button_text):
"""
Get the coordinates of a specific button on an LVGL keyboard/buttonmatrix.
+155
View File
@@ -0,0 +1,155 @@
"""
Graphical test for hotspot settings password defaults.
This test verifies that the hotspot settings screen shows the
"(defaults to none)" value under the "Auth Mode" setting.
Usage:
Desktop: ./tests/unittest.sh tests/test_graphical_hotspot_password.py
Device: ./tests/unittest.sh tests/test_graphical_hotspot_password.py --ondevice
"""
import unittest
import lvgl as lv
import mpos.ui
from mpos import (
AppManager,
wait_for_render,
print_screen_labels,
click_button,
verify_text_present,
find_setting_value_label,
get_setting_value_text,
click_label,
simulate_click,
get_widget_coords,
select_dropdown_option_by_text,
find_dropdown_widget,
SharedPreferences,
)
class TestGraphicalHotspotPassword(unittest.TestCase):
"""Test suite for hotspot password defaults in settings UI."""
def _reset_hotspot_preferences(self):
"""Clear hotspot preferences to ensure default values are shown."""
prefs = SharedPreferences("com.micropythonos.settings.hotspot")
editor = prefs.edit()
editor.remove_all()
editor.commit()
def _open_hotspot_settings_screen(self):
"""Start hotspot app and open the Settings screen."""
result = AppManager.start_app("com.micropythonos.settings.hotspot")
self.assertTrue(result, "Failed to start hotspot settings app")
wait_for_render(iterations=20)
screen = lv.screen_active()
print("\nInitial screen labels:")
print_screen_labels(screen)
self.assertTrue(
click_button("Settings"),
"Could not find Settings button in hotspot app",
)
wait_for_render(iterations=40)
screen = lv.screen_active()
print("\nSettings screen labels:")
print_screen_labels(screen)
return screen
def tearDown(self):
"""Clean up after each test method."""
# Navigate back to launcher to close any opened apps
try:
mpos.ui.back_screen()
wait_for_render(5)
except:
pass
def test_auth_mode_defaults_label(self):
"""Verify Auth Mode shows defaults to none in hotspot settings."""
print("\n=== Starting Hotspot Settings Auth Mode default test ===")
self._reset_hotspot_preferences()
screen = self._open_hotspot_settings_screen()
self.assertTrue(
verify_text_present(screen, "Auth Mode"),
"Auth Mode setting title not found on settings screen",
)
value_label = find_setting_value_label(screen, "Auth Mode")
self.assertIsNotNone(
value_label,
"Could not find value label for Auth Mode setting",
)
value_text = get_setting_value_text(screen, "Auth Mode")
print(f"Auth Mode value text: {value_text}")
self.assertEqual(
value_text,
"(defaults to none)",
"Auth Mode value text did not match expected default",
)
print("\n=== Hotspot settings Auth Mode default test completed ===")
def test_auth_mode_dropdown_select_wpa2(self):
"""Change Auth Mode via dropdown and verify stored value label."""
print("\n=== Starting Hotspot Settings Auth Mode dropdown test ===")
self._reset_hotspot_preferences()
screen = self._open_hotspot_settings_screen()
self.assertTrue(
click_label("Auth Mode"),
"Could not click Auth Mode setting",
)
wait_for_render(iterations=40)
screen = lv.screen_active()
print("\nAuth Mode edit screen labels:")
print_screen_labels(screen)
dropdown = find_dropdown_widget(screen)
self.assertIsNotNone(dropdown, "Auth Mode dropdown not found")
coords = get_widget_coords(dropdown)
self.assertIsNotNone(coords, "Could not get dropdown coordinates")
print(f"Clicking dropdown at ({coords['center_x']}, {coords['center_y']})")
simulate_click(coords["center_x"], coords["center_y"], press_duration_ms=100)
wait_for_render(iterations=20)
self.assertTrue(
select_dropdown_option_by_text(dropdown, "WPA2", allow_partial=True),
"Could not select WPA2 option in dropdown",
)
wait_for_render(iterations=20)
self.assertTrue(
click_button("Save"),
"Could not click Save button in Auth Mode settings",
)
wait_for_render(iterations=40)
screen = lv.screen_active()
print("\nSettings screen labels after save:")
print_screen_labels(screen)
value_text = get_setting_value_text(screen, "Auth Mode")
print(f"Auth Mode value text after save: {value_text}")
self.assertEqual(
value_text,
"wpa2",
"Auth Mode value did not update to wpa2",
)
print("\n=== Hotspot settings Auth Mode dropdown test completed ===")
if __name__ == "__main__":
pass
View File