Skip to content
Merged
Show file tree
Hide file tree
Changes from 66 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)``
"""

# 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]
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
11 changes: 9 additions & 2 deletions traitsui/testing/tester/wx/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def key_click(widget, key, delay=0):
else:
wx.MilliSleep(delay)
key_event = wx.KeyEvent(wx.wxEVT_CHAR)
key_event.SetUnicodeKey(KEY)
key_event.SetKeyCode(KEY)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this results in another test to fail:

======================================================================
FAIL: test_key_click (traitsui.testing.tester.wx.tests.test_helpers.TestInteractions)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/kchoi/Work/ETS/traitsui-clone/traitsui/testing/tester/wx/tests/test_helpers.py", line 96, in test_key_click
    self.assertEqual(textbox.Value, "A")
AssertionError: 'a' != 'A'
- a
+ A

I think the test failure makes sense because to type "A", one needs to have the cap on or have used the Shift key. Apparently Qt disagrees and would happily insert a capitalized "A" in that case. So the two disagree and we should normalize it. 😂
That's orthogonal though we should open a separate issue to solve.

Copy link
Contributor

Choose a reason for hiding this comment

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

Once #1176 is merged and if we re-run the CI for this PR we should see this test failure.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should I modify the test to pass and comment on the discrepancy? I can open a separate issue about it

Copy link
Contributor

Choose a reason for hiding this comment

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

I realized that the tests with wx and key clicks are actually failing on Windows.... this is getting orthogonal. Let's revert this change to SetKeyCode and modify the tests for RangeEditor here so that it does not rely on backspaces, then open a separate issue to fix the discrepancies.

widget.EmulateKeyPress(key_event)
else:
wx.MilliSleep(delay)
Expand Down 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