File: add_new_interaction.rst

package info (click to toggle)
python-traitsui 8.0.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 18,232 kB
  • sloc: python: 58,982; makefile: 113
file content (111 lines) | stat: -rw-r--r-- 3,743 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

.. _testing-add-new-interaction:

Add support for performing actions or inspecting states
=======================================================

Support for |UIWrapper.perform| and |UIWrapper.inspect| can be extended by
registering additional interaction type and handling logic via
|TargetRegistry.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 |UIWrapper.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
:ref:`testing-target-is-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 |TargetRegistry.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 |UIWrapper.perform| and |UIWrapper.inspect| is merely
in their returned values.

We can call |UIWrapper.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``.


.. include:: ../substitutions.rst