Simplify tests

This commit is contained in:
Thomas Farstrike
2026-03-25 15:16:17 +01:00
parent 42c92f3fc9
commit d24a52c54c
8 changed files with 10 additions and 290 deletions
-1
View File
@@ -11,7 +11,6 @@ Usage:
class TestMyApp(GraphicalTestBase):
def test_something(self):
# self.screen is already set up
# self.screenshot_dir is configured
pass
"""
-48
View File
@@ -4,7 +4,6 @@ Base class for graphical tests in MicroPythonOS.
This class provides common setup/teardown patterns for tests that require
LVGL/UI initialization. It handles:
- Screen creation and cleanup
- Screenshot directory configuration
- Common UI testing utilities
Usage:
@@ -13,17 +12,13 @@ Usage:
class TestMyApp(GraphicalTestBase):
def test_something(self):
# self.screen is already set up (320x240)
# self.screenshot_dir is configured
label = lv.label(self.screen)
label.set_text("Hello")
self.wait_for_render()
self.capture_screenshot("my_test")
"""
import unittest
import lvgl as lv
import sys
import os
class GraphicalTestBase(unittest.TestCase):
@@ -42,33 +37,12 @@ class GraphicalTestBase(unittest.TestCase):
Instance Attributes:
screen: The LVGL screen object for the test
screenshot_dir: Path to the screenshots directory
"""
SCREEN_WIDTH = 320
SCREEN_HEIGHT = 240
DEFAULT_RENDER_ITERATIONS = 5
@classmethod
def setUpClass(cls):
"""
Set up class-level fixtures.
Configures the screenshot directory based on platform.
"""
# Determine screenshot directory based on platform
if sys.platform == "esp32":
cls.screenshot_dir = "tests/screenshots"
else:
# On desktop, tests directory is in parent
cls.screenshot_dir = "../tests/screenshots"
# Ensure screenshots directory exists
try:
os.mkdir(cls.screenshot_dir)
except OSError:
pass # Directory already exists
def setUp(self):
"""
Set up test fixtures before each test method.
@@ -103,28 +77,6 @@ class GraphicalTestBase(unittest.TestCase):
iterations = self.DEFAULT_RENDER_ITERATIONS
wait_for_render(iterations)
def capture_screenshot(self, name, width=None, height=None):
"""
Capture a screenshot with standardized naming.
Args:
name: Name for the screenshot (without extension)
width: Screenshot width (default: SCREEN_WIDTH)
height: Screenshot height (default: SCREEN_HEIGHT)
Returns:
bytes: The screenshot buffer
"""
from mpos import capture_screenshot
if width is None:
width = self.SCREEN_WIDTH
if height is None:
height = self.SCREEN_HEIGHT
path = f"{self.screenshot_dir}/{name}.raw"
return capture_screenshot(path, width=width, height=height)
def find_label_with_text(self, text, parent=None):
"""
Find a label containing the specified text.
+3 -39
View File
@@ -20,11 +20,9 @@ Usage:
import unittest
import lvgl as lv
import mpos.ui
import os
import sys
from mpos import (
wait_for_render,
capture_screenshot,
find_label_with_text,
find_button_with_text,
verify_text_present,
@@ -51,19 +49,6 @@ class TestGraphicalCameraSettings(unittest.TestCase):
except:
self.skipTest("No camera module available (webcam or internal)")
# Get absolute path to screenshots directory
import sys
if sys.platform == "esp32":
self.screenshot_dir = "tests/screenshots"
else:
self.screenshot_dir = "../tests/screenshots"
# Ensure screenshots directory exists
try:
os.mkdir(self.screenshot_dir)
except OSError:
pass # Directory already exists
def tearDown(self):
"""Clean up after each test method."""
# Navigate back to launcher (closes the camera app)
@@ -109,10 +94,9 @@ class TestGraphicalCameraSettings(unittest.TestCase):
Steps:
1. Start camera app
2. Wait for camera to initialize
3. Capture initial screenshot
4. Click settings button (found dynamically by lv.SYMBOL.SETTINGS)
5. Verify settings dialog opened
6. If we get here without crash, test passes
3. Click settings button (found dynamically by lv.SYMBOL.SETTINGS)
4. Verify settings dialog opened
5. If we get here without crash, test passes
"""
print("\n=== Testing settings button click (no crash) ===")
@@ -130,11 +114,6 @@ class TestGraphicalCameraSettings(unittest.TestCase):
print("\nInitial screen labels:")
print_screen_labels(screen)
# Capture screenshot before clicking settings
screenshot_path = f"{self.screenshot_dir}/camera_before_settings.raw"
print(f"\nCapturing initial screenshot: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
# Find and click settings button dynamically
found = self._find_and_click_settings_button(screen)
self.assertTrue(found, "Settings button with lv.SYMBOL.SETTINGS not found on screen")
@@ -171,11 +150,6 @@ class TestGraphicalCameraSettings(unittest.TestCase):
"Settings screen did not open (no Save/Cancel buttons or expected UI elements found)"
)
# Capture screenshot of settings dialog
screenshot_path = f"{self.screenshot_dir}/camera_settings_dialog.raw"
print(f"\nCapturing settings dialog screenshot: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
# If we got here without segfault, the test passes!
print("\n✓ Settings button clicked successfully without crash!")
@@ -296,11 +270,6 @@ class TestGraphicalCameraSettings(unittest.TestCase):
wait_for_render(iterations=15)
# Capture screenshot
screenshot_path = f"{self.screenshot_dir}/camera_dropdown_open.raw"
print(f"Capturing dropdown screenshot: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
screen = lv.screen_active()
print("\nScreen after dropdown interaction:")
print_screen_labels(screen)
@@ -319,11 +288,6 @@ class TestGraphicalCameraSettings(unittest.TestCase):
print("\nWaiting for reconfiguration...")
wait_for_render(iterations=30)
# Capture screenshot after reconfiguration
screenshot_path = f"{self.screenshot_dir}/camera_after_resolution_change.raw"
print(f"Capturing post-change screenshot: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
# If we got here without segfault, the test passes!
print("\n✓ Resolution changed successfully without crash!")
+3 -68
View File
@@ -2,7 +2,7 @@
Graphical tests for MposKeyboard.
Tests keyboard visual appearance, text input via simulated button presses,
and mode switching. Captures screenshots for regression testing.
and mode switching.
Usage:
Desktop: ./tests/unittest.sh tests/test_graphical_custom_keyboard.py
@@ -11,9 +11,7 @@ Usage:
import unittest
import lvgl as lv
import sys
import os
from mpos import MposKeyboard, wait_for_render, capture_screenshot, AppearanceManager
from mpos import MposKeyboard, wait_for_render, AppearanceManager
class TestGraphicalMposKeyboard(unittest.TestCase):
@@ -21,20 +19,7 @@ class TestGraphicalMposKeyboard(unittest.TestCase):
def setUp(self):
"""Set up test fixtures before each test method."""
# Determine screenshot directory
if sys.platform == "esp32":
self.screenshot_dir = "tests/screenshots"
else:
self.screenshot_dir = "../tests/screenshots"
# Ensure screenshots directory exists
try:
os.mkdir(self.screenshot_dir)
except OSError:
pass # Directory already exists
print(f"\n=== Graphical Keyboard Test Setup ===")
print(f"Platform: {sys.platform}")
def tearDown(self):
"""Clean up after each test method."""
@@ -102,7 +87,7 @@ class TestGraphicalMposKeyboard(unittest.TestCase):
"""
Test keyboard appearance in lowercase mode.
Verifies that the keyboard renders correctly and captures screenshot.
Verifies that the keyboard renders correctly.
"""
print("\n=== Testing lowercase keyboard appearance ===")
@@ -112,16 +97,6 @@ class TestGraphicalMposKeyboard(unittest.TestCase):
keyboard.set_mode(MposKeyboard.MODE_LOWERCASE)
wait_for_render(10)
# Capture screenshot
screenshot_path = f"{self.screenshot_dir}/custom_keyboard_lowercase.raw"
print(f"Capturing screenshot: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
# Verify screenshot was created
stat = os.stat(screenshot_path)
self.assertTrue(stat[6] > 0, "Screenshot file is empty")
print(f"Screenshot captured: {stat[6]} bytes")
print("=== Lowercase appearance test PASSED ===")
def test_keyboard_uppercase_appearance(self):
@@ -134,16 +109,6 @@ class TestGraphicalMposKeyboard(unittest.TestCase):
keyboard.set_mode(MposKeyboard.MODE_UPPERCASE)
wait_for_render(10)
# Capture screenshot
screenshot_path = f"{self.screenshot_dir}/custom_keyboard_uppercase.raw"
print(f"Capturing screenshot: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
# Verify screenshot was created
stat = os.stat(screenshot_path)
self.assertTrue(stat[6] > 0, "Screenshot file is empty")
print(f"Screenshot captured: {stat[6]} bytes")
print("=== Uppercase appearance test PASSED ===")
def test_keyboard_numbers_appearance(self):
@@ -156,16 +121,6 @@ class TestGraphicalMposKeyboard(unittest.TestCase):
keyboard.set_mode(MposKeyboard.MODE_NUMBERS)
wait_for_render(10)
# Capture screenshot
screenshot_path = f"{self.screenshot_dir}/custom_keyboard_numbers.raw"
print(f"Capturing screenshot: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
# Verify screenshot was created
stat = os.stat(screenshot_path)
self.assertTrue(stat[6] > 0, "Screenshot file is empty")
print(f"Screenshot captured: {stat[6]} bytes")
print("=== Numbers appearance test PASSED ===")
def test_keyboard_specials_appearance(self):
@@ -178,16 +133,6 @@ class TestGraphicalMposKeyboard(unittest.TestCase):
keyboard.set_mode(MposKeyboard.MODE_SPECIALS)
wait_for_render(10)
# Capture screenshot
screenshot_path = f"{self.screenshot_dir}/custom_keyboard_specials.raw"
print(f"Capturing screenshot: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
# Verify screenshot was created
stat = os.stat(screenshot_path)
self.assertTrue(stat[6] > 0, "Screenshot file is empty")
print(f"Screenshot captured: {stat[6]} bytes")
print("=== Specials appearance test PASSED ===")
def test_keyboard_visibility_light_mode(self):
@@ -275,11 +220,6 @@ class TestGraphicalMposKeyboard(unittest.TestCase):
lv.screen_load(screen)
wait_for_render(20)
# Capture standard keyboard
screenshot_path = f"{self.screenshot_dir}/keyboard_standard_comparison.raw"
print(f"Capturing standard keyboard: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
# Clean up
lv.screen_load(lv.obj())
wait_for_render(5)
@@ -301,11 +241,6 @@ class TestGraphicalMposKeyboard(unittest.TestCase):
lv.screen_load(screen2)
wait_for_render(20)
# Capture custom keyboard
screenshot_path = f"{self.screenshot_dir}/keyboard_custom_comparison.raw"
print(f"Capturing custom keyboard: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
print("=== Comparison test PASSED ===")
-34
View File
@@ -12,12 +12,9 @@ Usage:
import unittest
import lvgl as lv
import mpos.ui
import os
import sys
import time
from mpos import (
wait_for_render,
capture_screenshot,
find_label_with_text,
verify_text_present,
print_screen_labels,
@@ -34,20 +31,6 @@ from mpos import (
class TestIMUCalibration(unittest.TestCase):
"""Test suite for IMU calibration activities."""
def setUp(self):
"""Set up test fixtures."""
# Get screenshot directory
if sys.platform == "esp32":
self.screenshot_dir = "tests/screenshots"
else:
self.screenshot_dir = "../tests/screenshots" # it runs from internal_filesystem/
# Ensure directory exists
try:
os.mkdir(self.screenshot_dir)
except OSError:
pass
def tearDown(self):
"""Clean up after test."""
# Navigate back to launcher
@@ -82,15 +65,6 @@ class TestIMUCalibration(unittest.TestCase):
self.assertTrue(verify_text_present(screen, "Accel."), "Accel. label not found")
self.assertTrue(verify_text_present(screen, "Gyro"), "Gyro label not found")
# Capture screenshot
screenshot_path = f"{self.screenshot_dir}/check_imu_calibration.raw"
print(f"Capturing screenshot: {screenshot_path}")
capture_screenshot(screenshot_path)
# Verify screenshot saved
stat = os.stat(screenshot_path)
self.assertTrue(stat[6] > 0, "Screenshot file is empty")
print("=== CheckIMUCalibrationActivity test complete ===")
def test_calibrate_activity_flow(self):
@@ -118,10 +92,6 @@ class TestIMUCalibration(unittest.TestCase):
self.assertTrue(verify_text_present(screen, "Place device on flat"),
"Instructions not shown")
# Capture initial state
screenshot_path = f"{self.screenshot_dir}/calibrate_imu_01_initial.raw"
capture_screenshot(screenshot_path)
# Click "Calibrate Now" button to start calibration
calibrate_btn = find_button_with_text(screen, "Calibrate Now")
self.assertIsNotNone(calibrate_btn, "Could not find 'Calibrate Now' button")
@@ -144,10 +114,6 @@ class TestIMUCalibration(unittest.TestCase):
verify_text_present(screen, "offsets"),
"Calibration offsets not shown")
# Capture completion state
screenshot_path = f"{self.screenshot_dir}/calibrate_imu_02_complete.raw"
capture_screenshot(screenshot_path)
print("=== CalibrateIMUActivity flow test complete ===")
def test_navigation_from_check_to_calibrate(self):
@@ -23,7 +23,6 @@ from mpos import (
find_label_with_text,
get_widget_coords,
print_screen_labels,
capture_screenshot,
click_label,
click_button,
find_text_on_screen,
@@ -85,9 +84,6 @@ class TestIMUCalibrationUI(unittest.TestCase):
print_screen_labels(lv.screen_active())
print()
# Capture screenshot before
capture_screenshot("../tests/screenshots/check_imu_before_calib.raw")
# Look for actual values (not "--")
has_values_before = False
widgets = []
@@ -154,9 +150,6 @@ class TestIMUCalibrationUI(unittest.TestCase):
print_screen_labels(lv.screen_active())
print()
# Capture screenshot after
capture_screenshot("../tests/screenshots/check_imu_after_calib.raw")
# Look for actual values (not "--")
has_values_after = False
for widget in get_all_widgets_with_text(lv.screen_active()):
+2 -27
View File
@@ -5,9 +5,8 @@ This test verifies that keyboard buttons have proper visible contrast
in both light and dark modes. It checks for the bug where keyboard buttons
appear white-on-white in light mode on ESP32.
The test uses two approaches:
1. Programmatic: Query LVGL style properties to verify button background colors
2. Visual: Capture screenshots for manual verification and regression testing
The test uses a programmatic approach: Query LVGL style properties to verify
button background colors.
This test should INITIALLY FAIL, demonstrating the bug before the fix is applied.
@@ -21,10 +20,8 @@ import lvgl as lv
import mpos.ui
import mpos.config
import sys
import os
from mpos import (
wait_for_render,
capture_screenshot,
AppearanceManager,
)
@@ -34,18 +31,6 @@ class TestKeyboardStyling(unittest.TestCase):
def setUp(self):
"""Set up test fixtures before each test method."""
# Determine screenshot directory
if sys.platform == "esp32":
self.screenshot_dir = "tests/screenshots"
else:
self.screenshot_dir = "../tests/screenshots"
# Ensure screenshots directory exists
try:
os.mkdir(self.screenshot_dir)
except OSError:
pass # Directory already exists
# Save current theme setting
prefs = mpos.config.SharedPreferences("theme_settings")
self.original_theme = prefs.get_string("theme_light_dark", "light")
@@ -243,11 +228,6 @@ class TestKeyboardStyling(unittest.TestCase):
print(f" Screen background: {screen_bg}")
print(f" Button background: {button_bg}")
# Capture screenshot
screenshot_path = f"{self.screenshot_dir}/keyboard_light_mode.raw"
print(f"\nCapturing screenshot: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
# Verify contrast
print("\nChecking button/screen contrast...")
has_contrast = self._color_contrast_sufficient(button_bg, screen_bg, min_difference=20)
@@ -297,11 +277,6 @@ class TestKeyboardStyling(unittest.TestCase):
print(f" Screen background: {screen_bg}")
print(f" Button background: {button_bg}")
# Capture screenshot
screenshot_path = f"{self.screenshot_dir}/keyboard_dark_mode.raw"
print(f"\nCapturing screenshot: {screenshot_path}")
capture_screenshot(screenshot_path, width=320, height=240)
# Verify contrast
print("\nChecking button/screen contrast...")
has_contrast = self._color_contrast_sufficient(button_bg, screen_bg, min_difference=20)
+2 -66
View File
@@ -1,18 +1,13 @@
import unittest
import lvgl as lv
import mpos
import time
import sys
import os
# Import graphical test helper
from mpos import (
wait_for_render,
capture_screenshot,
find_label_with_text,
verify_text_present,
print_screen_labels,
DeviceInfo,
BuildInfo,
AppManager
)
@@ -107,8 +102,8 @@ class TestOSUpdateGraphicalUI(unittest.TestCase):
verify_text_present(screen, "WiFi")
self.assertTrue(checking_found, "Should show some status message")
def test_screenshot_initial_state(self):
"""Capture screenshot of initial app state."""
def test_initial_state_labels(self):
"""Print initial app labels for debugging."""
result = AppManager.start_app("com.micropythonos.osupdate")
self.assertTrue(result)
wait_for_render(20)
@@ -122,19 +117,6 @@ class TestOSUpdateGraphicalUI(unittest.TestCase):
class TestOSUpdateGraphicalStatusMessages(unittest.TestCase):
"""Graphical tests for OSUpdate status messages."""
def setUp(self):
"""Set up test fixtures."""
self.hardware_id = DeviceInfo.hardware_id
self.screenshot_dir = "tests/screenshots"
try:
os.stat(self.screenshot_dir)
except OSError:
try:
os.mkdir(self.screenshot_dir)
except OSError:
pass
def tearDown(self):
"""Clean up after test."""
mpos.ui.back_screen()
@@ -176,49 +158,3 @@ class TestOSUpdateGraphicalStatusMessages(unittest.TestCase):
self.assertTrue(version_found, "Version label should be present and readable")
class TestOSUpdateGraphicalScreenshots(unittest.TestCase):
"""Screenshot tests for visual regression testing."""
def setUp(self):
"""Set up test fixtures."""
self.hardware_id = DeviceInfo.hardware_id
self.screenshot_dir = "tests/screenshots"
try:
os.stat(self.screenshot_dir)
except OSError:
try:
os.mkdir(self.screenshot_dir)
except OSError:
pass
def tearDown(self):
"""Clean up after test."""
mpos.ui.back_screen()
wait_for_render(5)
def test_capture_main_screen(self):
"""Capture screenshot of main OSUpdate screen."""
result = AppManager.start_app("com.micropythonos.osupdate")
self.assertTrue(result)
wait_for_render(20)
def test_capture_with_labels_visible(self):
"""Capture screenshot ensuring all text is visible."""
result = AppManager.start_app("com.micropythonos.osupdate")
self.assertTrue(result)
wait_for_render(20)
screen = lv.screen_active()
# Verify key elements are visible before screenshot (case insensitive)
has_version = verify_text_present(screen, "Installed") or verify_text_present(screen, "version")
# Button text can be "Update OS", "Reinstall\nsame version", or "Install\nolder version"
has_button = verify_text_present(screen, "Update") or verify_text_present(screen, "update") or \
verify_text_present(screen, "Reinstall") or verify_text_present(screen, "Install")
self.assertTrue(has_version, "Version label should be visible")
self.assertTrue(has_button, "Update button should be visible")