diff --git a/traitsui/testing/tester/wx/helpers.py b/traitsui/testing/tester/wx/helpers.py index d0ec801f4..e4a6f3af1 100644 --- a/traitsui/testing/tester/wx/helpers.py +++ b/traitsui/testing/tester/wx/helpers.py @@ -13,44 +13,6 @@ from traitsui.testing.tester.compat import check_key_compat from traitsui.testing.tester.exceptions import Disabled -from traitsui.wx.key_event_to_name import key_map as _KEY_MAP - - -def key_click(widget, key, delay=0): - """ Performs a key click of the given key on the given widget after - a delay. - - Parameters - ---------- - widget : wx.TextCtrl - The wx Object to be key cliecked to. - key : str - Standardized (pyface) name for a keyboard event. - e.g. "Enter", "Tab", "Space", "0", "1", "A", ... - Note: modifiers (e.g. Shift, Alt, etc. are not currently supported) - delay : int - Time delay (in ms) in which the key click will be performed. - """ - - mapping = {name: event for event, name in _KEY_MAP.items()} - if key not in mapping: - try: - KEY = ord(key) - except [TypeError, ValueError]: - raise ValueError( - "Unknown key {!r}. Expected one of these: {!r}, or a unicode character".format( # noqa - key, sorted(mapping) - )) - else: - wx.MilliSleep(delay) - key_event = wx.KeyEvent(wx.wxEVT_CHAR) - key_event.SetUnicodeKey(KEY) - widget.EmulateKeyPress(key_event) - else: - wx.MilliSleep(delay) - key_event = wx.KeyEvent(wx.wxEVT_CHAR) - key_event.SetKeyCode(mapping[key]) - widget.EmulateKeyPress(key_event) def mouse_click_button(control, delay): @@ -111,14 +73,19 @@ def key_click_text_ctrl(control, interaction, delay): raise Disabled("{!r} is disabled.".format(control)) if not control.HasFocus(): control.SetFocus() - # EmulateKeyPress in key_click seems to not be handling "Enter" - # correctly. + control.SetInsertionPointEnd() if interaction.key == "Enter": wx.MilliSleep(delay) event = wx.CommandEvent(wx.EVT_TEXT_ENTER.typeId, control.GetId()) control.ProcessEvent(event) + elif interaction.key == "Backspace": + wx.MilliSleep(delay) + pos = control.GetInsertionPoint() + control.Remove(max(0, pos - 1), pos) else: - key_click(control, interaction.key, delay) + check_key_compat(interaction.key) + wx.MilliSleep(delay) + control.WriteText(interaction.key) def key_sequence_text_ctrl(control, interaction, delay): diff --git a/traitsui/tests/editors/test_range_editor.py b/traitsui/tests/editors/test_range_editor.py index e03284b76..59ad76ab9 100644 --- a/traitsui/tests/editors/test_range_editor.py +++ b/traitsui/tests/editors/test_range_editor.py @@ -1,3 +1,4 @@ +import platform import unittest from traits.api import HasTraits, Int @@ -5,14 +6,17 @@ from traitsui.testing.tester import command, locator, query from traitsui.testing.tester.ui_tester import UITester from traitsui.tests._tools import ( + is_wx, requires_toolkit, ToolkitName, ) +is_windows = platform.system() == "Windows" + class RangeModel(HasTraits): - value = Int() + value = Int(1) @requires_toolkit([ToolkitName.qt, ToolkitName.wx]) @@ -50,7 +54,44 @@ def test_simple_editor_format_func(self): def test_custom_editor_format_func(self): self.check_range_enum_editor_format_func("custom") - def check_set_with_text(self, mode): + def check_set_with_text_valid(self, mode): + model = RangeModel() + view = View( + Item( + "value", + editor=RangeEditor(low=1, high=12, mode=mode) + ) + ) + tester = UITester() + with tester.create_ui(model, dict(view=view)) as ui: + # sanity check + self.assertEqual(model.value, 1) + number_field = tester.find_by_name(ui, "value") + text = number_field.locate(locator.WidgetType.textbox) + if is_windows and is_wx() and mode == 'text': + # For RangeTextEditor on wx and windows, the textbox + # automatically gets focus and the full content is selected. + # Insertion point is moved to keep the test consistent + text.target.textbox.SetInsertionPointEnd() + text.perform(command.KeyClick("0")) + text.perform(command.KeyClick("Enter")) + displayed = text.inspect(query.DisplayedText()) + self.assertEqual(model.value, 10) + self.assertEqual(displayed, str(model.value)) + + def test_simple_slider_editor_set_with_text_valid(self): + return self.check_set_with_text_valid(mode='slider') + + def test_large_range_slider_editor_set_with_text_valid(self): + return self.check_set_with_text_valid(mode='xslider') + + def test_log_range_slider_editor_set_with_text_valid(self): + return self.check_set_with_text_valid(mode='logslider') + + def test_range_text_editor_set_with_text_valid(self): + return self.check_set_with_text_valid(mode='text') + + def check_set_with_text_after_empty(self, mode): model = RangeModel() view = View( Item( @@ -62,6 +103,7 @@ def check_set_with_text(self, mode): with tester.create_ui(model, dict(view=view)) as ui: number_field = tester.find_by_name(ui, "value") text = number_field.locate(locator.WidgetType.textbox) + # Delete all contents of textbox for _ in range(5): text.perform(command.KeyClick("Backspace")) text.perform(command.KeyClick("4")) @@ -70,14 +112,17 @@ def check_set_with_text(self, mode): self.assertEqual(model.value, 4) self.assertEqual(displayed, str(model.value)) - def test_simple_slider_editor_set_with_text(self): - return self.check_set_with_text(mode='slider') + def test_simple_slider_editor_set_with_text_after_empty(self): + return self.check_set_with_text_after_empty(mode='slider') - def test_large_range_slider_editor_set_with_text(self): - return self.check_set_with_text(mode='xslider') + def test_large_range_slider_editor_set_with_text_after_empty(self): + return self.check_set_with_text_after_empty(mode='xslider') - def test_log_range_slider_editor_set_with_text(self): - return self.check_set_with_text(mode='logslider') + def test_log_range_slider_editor_set_with_text_after_empty(self): + return self.check_set_with_text_after_empty(mode='logslider') - def test_range_text_editor_set_with_text(self): - return self.check_set_with_text(mode='text') + # on wx the text style editor gives an error whenever the textbox + # is empty, even if enter has not been pressed. + @requires_toolkit([ToolkitName.qt]) + def test_range_text_editor_set_with_text_after_empty(self): + return self.check_set_with_text_after_empty(mode='text')