You've already forked MicroPythonOS
mirror of
https://github.com/m5stack/MicroPythonOS.git
synced 2026-05-20 11:51:27 -07:00
Add tests/test_graphical_hotspot_password.py
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
Executable → Regular
Reference in New Issue
Block a user