Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ui tester api updates4 - Implement locating textbox in RangeEditor and performing KeySequence #1171

Merged
merged 67 commits into from
Sep 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
ba2378f
first round of updates for UI Tester (default_registry toolkit setup …
aaronayres35 Aug 19, 2020
a6d28ca
attempt to handle Null toolkit
aaronayres35 Aug 19, 2020
28d5094
fixing null handling
aaronayres35 Aug 19, 2020
684be1c
setting up MouseClick for ButtonEditor
aaronayres35 Aug 20, 2020
9973d38
adding DefaultTarget locator class and logic to handle its use in ui_…
aaronayres35 Aug 20, 2020
547b52b
addressing comments
aaronayres35 Aug 20, 2020
7fecb2a
merging changes from ui-tester-api-updates1 after review comments
aaronayres35 Aug 20, 2020
a6ede42
this test update was accidentally left out of merge
aaronayres35 Aug 20, 2020
69d5cd5
adding tests (currently broken due to imports)
aaronayres35 Aug 20, 2020
b97a923
adding test for toolkit specific default registries which test mouse …
aaronayres35 Aug 20, 2020
39c034e
fixing broken tests, and convert TraitsUI test for ButtonEditor to us…
aaronayres35 Aug 20, 2020
57fcdda
addressing comments
aaronayres35 Aug 21, 2020
dcdfdf8
Merge branch 'ui-tester-api-updates1' into ui-tester-api-updates2
aaronayres35 Aug 21, 2020
6266a83
updating helper functions and adding docstrings
aaronayres35 Aug 21, 2020
578b280
Merge branch 'master' into ui-tester-api-updates2
aaronayres35 Aug 21, 2020
fe4c597
adding __init__.py files
aaronayres35 Aug 21, 2020
df81380
adding docstring for DefaultTarget locator class
aaronayres35 Aug 21, 2020
9803375
first steps for KeySequence, KeyClick and DisplayedText for TextEditor
aaronayres35 Aug 21, 2020
9077c08
add QLineEdit, change key press names to click
aaronayres35 Aug 21, 2020
400d9d3
docstring updates and simple name change
aaronayres35 Aug 24, 2020
33f750f
fixing typo
aaronayres35 Aug 24, 2020
51e5b45
adding tests for new UIWrapper DefaultTarget logic
aaronayres35 Aug 24, 2020
3149374
flake8 fixes
aaronayres35 Aug 24, 2020
c43c88a
rename wobject wx_object
aaronayres35 Aug 24, 2020
e444628
fixing wx test failures
aaronayres35 Aug 24, 2020
d4d8012
more flake8 fixes
aaronayres35 Aug 24, 2020
848d513
making suggested changes from comments
aaronayres35 Aug 24, 2020
9753816
pull new DefaultTarget logic out into its own private method, and add…
aaronayres35 Aug 24, 2020
db80b28
fixing failures from last commit
aaronayres35 Aug 24, 2020
bc0e7f1
first steps towards updating tests
aaronayres35 Aug 24, 2020
eab72a8
Merge branch 'ui-tester-api-updates2' into ui-tester-api-updates3
aaronayres35 Aug 24, 2020
8a59b57
missed in merge
aaronayres35 Aug 24, 2020
77f5903
pre-master merge
aaronayres35 Aug 25, 2020
12e9d8f
Merge branch 'master' into ui-tester-api-updates3
aaronayres35 Aug 25, 2020
8428778
more changes to align with master (recreate updates from ui-tester-ap…
aaronayres35 Aug 25, 2020
fb3a535
make refactor changes (since removal of DefaultTarget)
aaronayres35 Aug 25, 2020
8b0f2eb
updating test_helpers
aaronayres35 Aug 25, 2020
55e0bfa
fix some test and comment one out (unsure how to test key_click on wx)
aaronayres35 Aug 25, 2020
69b5618
reremoivng get_qobject_registry
aaronayres35 Aug 26, 2020
5aeef94
adding docstrings to qt helpers
aaronayres35 Aug 26, 2020
d8baa03
updating wx helpers
aaronayres35 Aug 26, 2020
0284280
simple helper test improvements
aaronayres35 Aug 26, 2020
e1fdef6
update test_text_editor
aaronayres35 Aug 26, 2020
38e6ff7
flake8 fixes
aaronayres35 Aug 26, 2020
1189ddc
adding tests using QLabel object (nothing should happen when trying t…
aaronayres35 Aug 26, 2020
7ba111e
adding range_editor implementation, and readding get___object_registr…
aaronayres35 Aug 26, 2020
f4f2be2
start of refactor for located basic object handlers
aaronayres35 Aug 27, 2020
40ad90a
improving tests, and adding mouse click on TextEditors for wx
aaronayres35 Aug 27, 2020
705a820
making suggested changes
aaronayres35 Aug 27, 2020
405a030
flake8
aaronayres35 Aug 27, 2020
e2b082a
Merge branch 'ui-tester-api-updates3' into ui-tester-api-updates4
aaronayres35 Aug 27, 2020
a96fb0d
refactor for located textbox handler logic
aaronayres35 Aug 27, 2020
7577c81
fixing broken tests
aaronayres35 Aug 28, 2020
5e75d0a
Merge branch 'master' into ui-tester-api-updates4
aaronayres35 Aug 28, 2020
1a0a7a9
starting to fix wx tests
aaronayres35 Aug 28, 2020
a287c52
fixing broken wx tests
aaronayres35 Aug 28, 2020
7c595ca
flake8
aaronayres35 Aug 28, 2020
7847933
removing commented out old code
aaronayres35 Aug 28, 2020
991be83
missed a flake8
aaronayres35 Aug 28, 2020
f08e54f
deleted an old unneeded test
aaronayres35 Aug 28, 2020
ee863e5
adding docstrings and a function rename
aaronayres35 Aug 28, 2020
73a97d4
fixing typos and adding a few docstrings
aaronayres35 Aug 31, 2020
b806e3a
making suggested changes
aaronayres35 Sep 1, 2020
78a7bf0
handling '\b' characters on wx
aaronayres35 Sep 1, 2020
c03ef46
renaming located_object_handlers as common_ui_targets
aaronayres35 Sep 1, 2020
f8b4b9c
more suggested changes
aaronayres35 Sep 1, 2020
4f723e1
revert SetKeyCode change and remove '\b' in test
aaronayres35 Sep 1, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion traitsui/qt4/range_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ def update_object_on_scroll(self, pos):
def update_object_on_enter(self):
""" Handles the user pressing the Enter key in the text field.
"""
# it is possible we get the event after the control has gone away
# It is possible the event is processed after the control is removed
# from the editor
if self.control is None:
return

Expand Down Expand Up @@ -449,6 +450,10 @@ def update_object_on_scroll(self, pos):
def update_object_on_enter(self):
""" Handles the user pressing the Enter key in the text field.
"""
# It is possible the event is processed after the control is removed
# from the editor
if self.control is None:
return
try:
self.value = eval(str(self.control.text.text()).strip())
except TraitError as excp:
Expand Down
14 changes: 14 additions & 0 deletions traitsui/testing/tester/locator.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
applied.
"""

import enum


class NestedUI:
""" A locator for locating a nested ``traitsui.ui.UI`` object assuming
Expand All @@ -35,3 +37,15 @@ class TargetByName:
"""
def __init__(self, name):
self.name = name


class WidgetType(enum.Enum):
""" A locator for locating nested widgets within a UI. Many editors will
contain many sub-widgets (e.g. a textbox, slider, tabs, buttons, etc.).

For example when working with a range editor, one could call
``tester.find_by_name(ui, "ranged_number").locate(locator.WidgetType.textbox)``
"""

aaronayres35 marked this conversation as resolved.
Show resolved Hide resolved
# A textbox within a UI
textbox = "textbox"
65 changes: 65 additions & 0 deletions traitsui/testing/tester/qt4/common_ui_targets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright (c) 2005-2020, Enthought, Inc.
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only
# under the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
#

""" This module contains targets for UIWrapper so that the logic related to
them can be reused. All handlers and solvers for these objects are
registered to the default registry via the register class methods. To use the
logic in these objects, one simply needs to register a solver with their
target_class of choice to one of these as the locator_class. For an example,
see the implementation of range_editor.
"""

from traitsui.testing.tester import command, query
from traitsui.testing.tester.qt4 import helpers


class LocatedTextbox:
""" Wrapper class for a located Textbox in Qt.

Parameters
----------
textbox : Instance of QtGui.QLineEdit
"""

def __init__(self, textbox):
self.textbox = textbox

@classmethod
def register(cls, registry):
""" Class method to register interactions on a LocatedTextbox for the
given registry.

If there are any conflicts, an error will occur.

Parameters
----------
registry : TargetRegistry
The registry being registered to.
"""
handlers = [
(command.KeySequence,
(lambda wrapper, interaction: helpers.key_sequence_qwidget(
wrapper.target.textbox, interaction, wrapper.delay))),
(command.KeyClick,
(lambda wrapper, interaction: helpers.key_click_qwidget(
wrapper.target.textbox, interaction, wrapper.delay))),
(command.MouseClick,
(lambda wrapper, _: helpers.mouse_click_qwidget(
wrapper.target.textbox, wrapper.delay))),
(query.DisplayedText,
lambda wrapper, _: wrapper.target.textbox.displayText()),
]
for interaction_class, handler in handlers:
registry.register_handler(
target_class=cls,
interaction_class=interaction_class,
handler=handler,
)
7 changes: 7 additions & 0 deletions traitsui/testing/tester/qt4/default_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#

from traitsui.testing.tester.registry import TargetRegistry
from traitsui.testing.tester.qt4 import common_ui_targets
from traitsui.testing.tester.qt4.implementation import (
button_editor,
range_editor,
text_editor,
)

Expand All @@ -27,10 +29,15 @@ def get_default_registry():
"""
registry = TargetRegistry()

common_ui_targets.LocatedTextbox.register(registry)

# ButtonEditor
button_editor.register(registry)

# TextEditor
text_editor.register(registry)

# RangeEditor
range_editor.register(registry)

return registry
96 changes: 96 additions & 0 deletions traitsui/testing/tester/qt4/implementation/range_editor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copyright (c) 2005-2020, Enthought, Inc.
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only
# under the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
#

from traitsui.qt4.range_editor import (
LargeRangeSliderEditor,
LogRangeSliderEditor,
RangeTextEditor,
SimpleSliderEditor,
Comment on lines +13 to +16
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually we will want to add SimpleSpinEditor, but this can be done in a later PR.
For later reference: The SimpleSpinEditor class in Qt has a control that is a QtGui.QSpinBox object, which subclasses QtGui.AbstractSpinBox which has a lineEdit() method which returns the QLineEdit for the spin box (likely we would just need to resolve to this and then the other handlers should work). For wx however, the SimpleSpinEditor has a control of a wx.SpinCtrl, which is supposedly combines a wx.SpinCtrl and wx.TextCtrl in one. However, it doesn't seem to subclass wx.TextCtrl and doesn't appear to support the same methods, so our handlers for KeyClick, KeySequence, etc. may not work correctly.

)

from traitsui.testing.tester import locator
from traitsui.testing.tester.qt4.common_ui_targets import LocatedTextbox


def resolve_location_slider(wrapper, location):
""" Solver from a UIWrapper wrapped Range Editor to a LocatedTextbox
containing the textbox of interest

If there are any conflicts, an error will occur.

Parameters
----------
wrapper : UIWrapper
Wrapper containing the Range Editor target.
location : locator.WidgetType
The location we are looking to resolve.
"""
if location == locator.WidgetType.textbox:
return LocatedTextbox(textbox=wrapper.target.control.text)
if location in [locator.WidgetType.slider]:
raise NotImplementedError(
f"Logic for interacting with the {location}"
" has not been implemented."
)
raise ValueError(
f"Unable to resolve {location} on {wrapper.target}."
" Currently supported: {locator.WidgetType.textbox}"
)


def resolve_location_range_text(wrapper, location):
""" Solver from a UIWrapper wrapped RangeTextEditor to a LocatedTextbox
containing the textbox of interest

If there are any conflicts, an error will occur.

Parameters
----------
wrapper : UIWrapper
Wrapper containing the RangeTextEditor target.
location : locator.WidgetType
The location we are looking to resolve.
"""

if location == locator.WidgetType.textbox:
return LocatedTextbox(textbox=wrapper.target.control)
raise ValueError(
f"Unable to resolve {location} on {wrapper.target}."
" Currently supported: {locator.WidgetType.textbox}"
)


def register(registry):
""" Register interactions for the given registry.

If there are any conflicts, an error will occur.

Parameters
----------
registry : TargetRegistry
The registry being registered to.
"""

targets = [SimpleSliderEditor,
LogRangeSliderEditor,
LargeRangeSliderEditor]
kitchoi marked this conversation as resolved.
Show resolved Hide resolved
for target_class in targets:
registry.register_solver(
target_class=target_class,
locator_class=locator.WidgetType,
solver=resolve_location_slider,
)

registry.register_solver(
target_class=RangeTextEditor,
locator_class=locator.WidgetType,
solver=resolve_location_range_text,
)
65 changes: 65 additions & 0 deletions traitsui/testing/tester/wx/common_ui_targets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright (c) 2005-2020, Enthought, Inc.
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only
# under the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
#

""" This module contains targets for UIWrapper so that the logic related to
them can be reused. All handlers and solvers for these objects are
registered to the default registry via the register class methods. To use the
logic in these objects, one simply needs to register a solver with their
target_class of choice to one of these as the locator_class. For an example,
see the implementation of range_editor.
"""

from traitsui.testing.tester import command, query
from traitsui.testing.tester.wx import helpers


class LocatedTextbox:
""" Wrapper class for a located Textbox in Wx.

Parameters
----------
textbox : Instance of wx.TextCtrl
"""

def __init__(self, textbox):
self.textbox = textbox

@classmethod
def register(cls, registry):
""" Class method to register interactions on a LocatedTextbox for the
given registry.

If there are any conflicts, an error will occur.

Parameters
----------
registry : TargetRegistry
The registry being registered to.
"""
handlers = [
(command.KeySequence,
(lambda wrapper, interaction: helpers.key_sequence_text_ctrl(
wrapper.target.textbox, interaction, wrapper.delay))),
(command.KeyClick,
(lambda wrapper, interaction: helpers.key_click_text_ctrl(
wrapper.target.textbox, interaction, wrapper.delay))),
(command.MouseClick,
(lambda wrapper, _: helpers.mouse_click_object(
wrapper.target.textbox, wrapper.delay))),
(query.DisplayedText,
lambda wrapper, _: wrapper.target.textbox.GetValue()),
]
for interaction_class, handler in handlers:
registry.register_handler(
target_class=cls,
interaction_class=interaction_class,
handler=handler,
)
7 changes: 7 additions & 0 deletions traitsui/testing/tester/wx/default_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#

from traitsui.testing.tester.registry import TargetRegistry
from traitsui.testing.tester.wx import common_ui_targets
from traitsui.testing.tester.wx.implementation import (
button_editor,
range_editor,
text_editor,
)

Expand All @@ -27,10 +29,15 @@ def get_default_registry():
"""
registry = TargetRegistry()

common_ui_targets.LocatedTextbox.register(registry)

# ButtonEditor
button_editor.register(registry)

# TextEditor
text_editor.register(registry)

# RangeEditor
range_editor.register(registry)

return registry
9 changes: 8 additions & 1 deletion traitsui/testing/tester/wx/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,14 @@ def key_click_text_ctrl(control, interaction, delay):
raise Disabled("{!r} is disabled.".format(control))
if not control.HasFocus():
control.SetFocus()
key_click(control, interaction.key, delay)
# EmulateKeyPress in key_click seems to not be handling "Enter"
# correctly.
if interaction.key == "Enter":
wx.MilliSleep(delay)
event = wx.CommandEvent(wx.EVT_TEXT_ENTER.typeId, control.GetId())
control.ProcessEvent(event)
else:
key_click(control, interaction.key, delay)


def key_sequence_text_ctrl(control, interaction, delay):
Expand Down
Loading