Files
MicroPythonOS/tests/base/graphical_test_base.py
T
Thomas Farstrike d24a52c54c Simplify tests
2026-03-25 15:16:17 +01:00

190 lines
5.5 KiB
Python

"""
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
- Common UI testing utilities
Usage:
from base import GraphicalTestBase
class TestMyApp(GraphicalTestBase):
def test_something(self):
# self.screen is already set up (320x240)
label = lv.label(self.screen)
label.set_text("Hello")
self.wait_for_render()
"""
import unittest
import lvgl as lv
class GraphicalTestBase(unittest.TestCase):
"""
Base class for all graphical tests.
Provides:
- Automatic screen creation and cleanup
- Screenshot directory configuration
- Common UI testing utilities
Class Attributes:
SCREEN_WIDTH: Default screen width (320)
SCREEN_HEIGHT: Default screen height (240)
DEFAULT_RENDER_ITERATIONS: Default iterations for wait_for_render (5)
Instance Attributes:
screen: The LVGL screen object for the test
"""
SCREEN_WIDTH = 320
SCREEN_HEIGHT = 240
DEFAULT_RENDER_ITERATIONS = 5
def setUp(self):
"""
Set up test fixtures before each test method.
Creates a new screen and loads it.
"""
# Create and load a new screen
self.screen = lv.obj()
self.screen.set_size(self.SCREEN_WIDTH, self.SCREEN_HEIGHT)
lv.screen_load(self.screen)
self.wait_for_render()
def tearDown(self):
"""
Clean up after each test method.
Loads an empty screen to clean up.
"""
# Load an empty screen to clean up
lv.screen_load(lv.obj())
self.wait_for_render()
def wait_for_render(self, iterations=None):
"""
Wait for LVGL to render.
Args:
iterations: Number of render iterations (default: DEFAULT_RENDER_ITERATIONS)
"""
from mpos import wait_for_render
if iterations is None:
iterations = self.DEFAULT_RENDER_ITERATIONS
wait_for_render(iterations)
def find_label_with_text(self, text, parent=None):
"""
Find a label containing the specified text.
Args:
text: Text to search for
parent: Parent widget to search in (default: current screen)
Returns:
The label widget if found, None otherwise
"""
from mpos import find_label_with_text
if parent is None:
parent = lv.screen_active()
return find_label_with_text(parent, text)
def verify_text_present(self, text, parent=None):
"""
Verify that text is present on screen.
Args:
text: Text to search for
parent: Parent widget to search in (default: current screen)
Returns:
bool: True if text is found
"""
from mpos import verify_text_present
if parent is None:
parent = lv.screen_active()
return verify_text_present(parent, text)
def print_screen_labels(self, parent=None):
"""
Print all labels on screen (for debugging).
Args:
parent: Parent widget to search in (default: current screen)
"""
from mpos import print_screen_labels
if parent is None:
parent = lv.screen_active()
print_screen_labels(parent)
def click_button(self, text, use_send_event=True):
"""
Click a button by its text.
Args:
text: Button text to find and click
use_send_event: If True, use send_event (more reliable)
Returns:
bool: True if button was found and clicked
"""
from mpos import click_button
return click_button(text, use_send_event=use_send_event)
def click_label(self, text, use_send_event=True):
"""
Click a label by its text.
Args:
text: Label text to find and click
use_send_event: If True, use send_event (more reliable)
Returns:
bool: True if label was found and clicked
"""
from mpos import click_label
return click_label(text, use_send_event=use_send_event)
def simulate_click(self, x, y):
"""
Simulate a click at specific coordinates.
Note: For most UI testing, prefer click_button() or click_label()
which are more reliable. Use this only when testing touch behavior.
Args:
x: X coordinate
y: Y coordinate
"""
from mpos import simulate_click
simulate_click(x, y)
self.wait_for_render()
def assertTextPresent(self, text, msg=None):
"""
Assert that text is present on screen.
Args:
text: Text to search for
msg: Optional failure message
"""
if msg is None:
msg = f"Text '{text}' not found on screen"
self.assertTrue(self.verify_text_present(text), msg)
def assertTextNotPresent(self, text, msg=None):
"""
Assert that text is NOT present on screen.
Args:
text: Text to search for
msg: Optional failure message
"""
if msg is None:
msg = f"Text '{text}' should not be on screen"
self.assertFalse(self.verify_text_present(text), msg)