Add support for performing actions or inspecting states¶
Support for perform()
and inspect()
can be extended by
registering additional interaction type and handling logic via
register_interaction()
on a TargetRegistry
.
Suppose we want to perform many mouse clicks on a UI component in a test, but
instead of calling perform(MouseClick())
many times in a loop like this:
my_widget = UITester().find_by_id(ui, "some_id")
for _ in range(10):
my_widget.perform(MouseClick())
We want to exercise the mouse click many times by invoking perform()
once only:
my_widget = UITester().find_by_id(ui, "some_id")
my_widget.perform(ManyMouseClick(n_times=10))
Define the interaction¶
We can define this ManyMouseClick
object simply like this:
class ManyMouseClick:
def __init__(self, n_times):
self.n_times = n_times
Identify the target¶
Next, we need to know which object implements the GUI component. This is where implementation details start to come in (see Why is Target protected?). We can inspect the object being wrapped:
>>> my_widget
<traitsui.testing.tester.ui_wrapper.UIWrapper object at 0x7f940a3f10b8>
>>> my_widget._target
<package.ui.qt.shiny_button.ShinyButton object at 0x7fc90fb3b570>
The target is an instance of a ShinyButton
class (made up
for this document). In this object, there is an instance of Qt QPushButton
widget which we want to click with the mouse:
>>> my_widget._target.control
<PyQt5.QtWidgets.QPushButton object at 0x7fbcc3ac3558>
Implement a handler¶
So now all we need to do, is to tell UITester
how to perform
ManyMouseClick
on an instance of ShinyButton
.
We define a function to perform the mouse clicks:
def many_mouse_click(wrapper, interaction):
# wrapper is an instance of UIWrapper
# interaction is an instance of ManyMouseClick
for _ in range(interaction.n_times):
wrapper._target.control.click()
Then we need to register this function with an instance of TargetRegistry
:
from traitsui.testing.api import TargetRegistry
from package.ui.qt.shiny_button import ShinyButton
custom_registry = TargetRegistry()
custom_registry.register_interaction(
target_class=ShinyButton,
interaction_class=ManyMouseClick,
handler=many_mouse_click,
)
The signature of many_mouse_click
is required by the register_interaction()
method on TargetRegistry
. By setting the target_class
and
interaction_class
, we restrict the types of wrapper._target
and
interaction
received by many_mouse_click
respectively.
Apply it¶
Finally, we can use this registry with the UITester
:
tester = UITester(registries=[custom_registry])
my_widget = tester.find_by_id(ui, "some_id")
my_widget.perform(ManyMouseClick(n_times=10))
All the builtin testing support for TraitsUI editors are still present, but now this tester can perform the additional, custom user interaction.
Inspecting states¶
The distinction between perform()
and inspect()
is merely
in their returned values.
We can call inspect()
with the ManyMouseClick
object we just
created:
value = my_widget.inspect(ManyMouseClick(n_times=10))
The returned value is the value returned by many_mouse_click
, the handler
registered for ManyMouseClick
and ShinyButton
. In this case, the
value is None
.