From 6b0f8982a2d02a4085f5d3c831736d59620632ec Mon Sep 17 00:00:00 2001 From: Kit Yan Choi Date: Sun, 9 Aug 2020 21:56:15 +0100 Subject: [PATCH] Make test works for both qt and wx RangeEditor --- .../Auto_editable_readonly_table_cells.py | 28 +++--- traitsui/testing/locator.py | 9 ++ traitsui/testing/qt4/default_registry.py | 31 ++++-- traitsui/testing/wx/default_registry.py | 95 +++++++++++++++++++ 4 files changed, 139 insertions(+), 24 deletions(-) diff --git a/traitsui/examples/demo/Advanced/Auto_editable_readonly_table_cells.py b/traitsui/examples/demo/Advanced/Auto_editable_readonly_table_cells.py index 9b718e1f4..2d8016f70 100644 --- a/traitsui/examples/demo/Advanced/Auto_editable_readonly_table_cells.py +++ b/traitsui/examples/demo/Advanced/Auto_editable_readonly_table_cells.py @@ -164,28 +164,24 @@ def _get_factors(self): # Create the demo: demo = Factors() +#demo.configure_traits() # Run the demo (if invoked from the command line): if __name__ == '__main__': - from traitsui.testing.api import UITester, command - tester = UITester(delay=100) + from traitsui.testing.api import UITester, command, locator + tester = UITester(delay=200) with tester.create_ui(demo) as ui: interactor = tester.find_by_name(ui, "max_n") - interactor.perform(command.KeyPress("Tab")) - interactor.perform(command.KeySequence("300")) - interactor.perform(command.KeyPress("Enter")) - interactor.perform(command.KeyPress("Shift-Tab")) + slider = interactor.locate(locator.OrderedWidget(0)) + text = interactor.locate(locator.OrderedWidget(1)) + text.perform(command.KeySequence("\b\b3")) + text.perform(command.KeyPress("Enter")) + for _ in range(5): - interactor.perform(command.KeyPress("Right")) + slider.perform(command.KeyPress("Right")) - interactor.perform(command.KeyPress("Tab")) - interactor.perform(command.KeySequence("100")) - interactor.perform(command.KeyPress("Enter")) - interactor.perform(command.KeyPress("Shift-Tab")) + text.perform(command.KeySequence("\b\b\b40")) + text.perform(command.KeyPress("Enter")) for _ in range(5): - interactor.perform(command.KeyPress("Left")) - - interactor.perform(command.KeyPress("Tab")) - interactor.perform(command.KeySequence("1")) - interactor.perform(command.KeyPress("Enter")) + slider.perform(command.KeyPress("Left")) diff --git a/traitsui/testing/locator.py b/traitsui/testing/locator.py index 06ef9ba64..99a6c5bf7 100644 --- a/traitsui/testing/locator.py +++ b/traitsui/testing/locator.py @@ -35,3 +35,12 @@ class TreeItem: def __init__(self, row, column): self.row = row self.column = column + + +class OrderedWidget: + """ Locate a widget using the order that would have been used for + keyboard navigation. + """ + + def __init__(self, index): + self.index = index diff --git a/traitsui/testing/qt4/default_registry.py b/traitsui/testing/qt4/default_registry.py index 77cb902e9..9a3025728 100644 --- a/traitsui/testing/qt4/default_registry.py +++ b/traitsui/testing/qt4/default_registry.py @@ -16,6 +16,7 @@ from traitsui.qt4.ui_panel import TabbedFoldGroupEditor from traitsui.testing import command from traitsui.testing import query +from traitsui.testing import locator from traitsui.testing.exceptions import Disabled from traitsui.testing.qt4 import helpers from traitsui.testing.interactor_registry import InteractorRegistry @@ -455,23 +456,32 @@ def list_editor_notebook_get_ui(interactor, action): ) +def validate_location_range_editor(interactor, action): + if not isinstance(action.location, locator.OrderedWidget): + raise ValueError( + "Location must be an instance of {!r}, got {!r}", + locator.OrderedWidget, + action.location, + ) + + def key_sequence_simple_range_editor(interactor, action): slider = interactor.editor.control.slider text = interactor.editor.control.text - if text.hasFocus(): - widget = text - else: - widget = slider + widget = { + 0: slider, + 1: text, + }[interactor.location.index] QTest.keyClicks(widget, action.sequence, delay=interactor.delay) def key_press_simple_range_editor(interactor, action): slider = interactor.editor.control.slider text = interactor.editor.control.text - if text.hasFocus(): - widget = text - else: - widget = slider + widget = { + 0: slider, + 1: text, + }[interactor.location.index] helpers.key_press( widget, action.key, delay=interactor.delay ) @@ -693,5 +703,10 @@ def get_default_registry(): action_class=command.KeySequence, handler=key_sequence_simple_range_editor, ) + registry.register( + editor_class=SimpleSliderEditor, + action_class=command.ValidateLocation, + handler=validate_location_range_editor, + ) return registry diff --git a/traitsui/testing/wx/default_registry.py b/traitsui/testing/wx/default_registry.py index 4815fe6a7..3ad90ed89 100644 --- a/traitsui/testing/wx/default_registry.py +++ b/traitsui/testing/wx/default_registry.py @@ -1,11 +1,15 @@ +from functools import partial, reduce + import wx from traitsui.api import ( ButtonEditor, InstanceEditor, ) +from traitsui.wx.range_editor import SimpleSliderEditor from traitsui.testing import command from traitsui.testing import query +from traitsui.testing import locator from traitsui.testing.interactor_registry import InteractorRegistry @@ -38,6 +42,80 @@ def custom_editor_get_ui(interactor, action): return interactor.editor._ui +def validate_location_range_editor_slider(interactor, action): + if not isinstance(action.location, locator.OrderedWidget): + raise ValueError( + "Location must be an instance of OrderedWidget, got {!r}".format( + action.location) + ) + + +def _key_press_range_editor_slider(slider, key, delay): + if key not in {"Up", "Down", "Right", "Left"}: + raise ValueError("Unexpected key.") + if not slider.HasFocus(): + slider.SetFocus() + value = slider.GetValue() + range_ = slider.GetMax() - slider.GetMin() + step = int(range_ / slider.GetLineSize()) + wx.MilliSleep(delay) + + if key in {"Up", "Right"}: + position = min(slider.GetMax(), value + step) + else: + position = max(0, value - step) + slider.SetValue(position) + event = wx.ScrollEvent( + wx.wxEVT_SCROLL_CHANGED, slider.GetId(), position + ) + wx.PostEvent(slider, event) + + +def _key_press_range_editor_text(text_ctrl, key, delay): + if key == "Enter": + if not text_ctrl.HasFocus(): + text_ctrl.SetFocus() + wx.MilliSleep(delay) + event = wx.CommandEvent(wx.EVT_TEXT_ENTER.typeId, text_ctrl.GetId()) + text_ctrl.ProcessEvent(event) + else: + raise ValueError("Only supported Enter key.") + + +def key_press_range_editor_simple(interactor, action): + index_to_control = { + 0: ( + partial( + _key_press_range_editor_slider, + interactor.editor.control.slider + ) + ), + 1: ( + partial( + _key_press_range_editor_text, + interactor.editor.control.text, + ) + ) + } + index_to_control[interactor.location.index]( + action.key, interactor.delay, + ) + + +def key_sequence_range_editor_simple(interactor, action): + assert interactor.location.index == 1 + text = interactor.editor.control.text + if not text.HasFocus(): + text.SetFocus() + for char in action.sequence: + wx.MilliSleep(interactor.delay) + if char == "\b": + pos = text.GetInsertionPoint() + text.Remove(max(0, pos - 1), pos) + else: + text.AppendText(char) + + def get_default_registry(): registry = InteractorRegistry() @@ -62,4 +140,21 @@ def get_default_registry(): query.NestedUI, custom_editor_get_ui, ) + + # RangeEditor + registry.register( + editor_class=SimpleSliderEditor, + action_class=command.KeyPress, + handler=key_press_range_editor_simple, + ) + registry.register( + editor_class=SimpleSliderEditor, + action_class=command.KeySequence, + handler=key_sequence_range_editor_simple, + ) + registry.register( + editor_class=SimpleSliderEditor, + action_class=command.ValidateLocation, + handler=validate_location_range_editor_slider, + ) return registry