Merge lp:~elopio/ubuntu-ui-toolkit/textfield_emulators into lp:ubuntu-ui-toolkit
- textfield_emulators
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Cris Dywan |
Approved revision: | 818 |
Merged at revision: | 919 |
Proposed branch: | lp:~elopio/ubuntu-ui-toolkit/textfield_emulators |
Merge into: | lp:ubuntu-ui-toolkit |
Diff against target: |
226 lines (+152/-3) 4 files modified
modules/Ubuntu/Components/TextField.qml (+1/-0) modules/Ubuntu/Components/TextInputPopover.qml (+1/-0) tests/autopilot/ubuntuuitoolkit/emulators.py (+77/-3) tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py (+73/-0) |
To merge this branch: | bzr merge lp:~elopio/ubuntu-ui-toolkit/textfield_emulators |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cris Dywan | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Richard Huddie | Pending | ||
Javier Collado | Pending | ||
VĂctor R. Ruiz | Pending | ||
Florian Boucault | Pending | ||
Review via email: mp+189796@code.launchpad.net |
Commit message
Added the TextField autopilot emulator.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
I Ahmad (iahmad) wrote : | # |
Looks good!
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:793
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:793
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:793
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:795
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Leo Arias (elopio) wrote : | # |
I have the job #1000. I should get a nice gift from CI.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:797
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:798
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:800
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:801
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:802
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:803
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:805
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:805
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:806
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:809
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:810
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:812
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:813
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:815
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:815
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:816
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:817
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Leo Arias (elopio) wrote : | # |
Christian, I requested a review for this and they told me you might be affected by my changes. So, can you please take a look?
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:818
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : | # |
I don't quite like that clear() is very dynamic - if a test is expected to have a text field with a clear button using that method will hide errors involving it not being there and this extends to write. I'd rather have - clear_with_button, clear_with_keys and write without clearing out of the box. Depending on the test convenience might be a factor but I'd hesitate before seeing what it looks like in practise.
test_textinput.py needs to be updated to use the new emulator.
Leo Arias (elopio) wrote : | # |
Please notice that the autopilot tests that will be using these helpers are not the right place to check if the text field has the clear button or not. What we are trying to test with autopilot are high level user stories, so the goal of the tests would be to add your U1 account to system settings, for example. In order to do that, we will need to fill a text field, but we really don't care how autopilot does the filling.
We should already have qt tests to check that depending on the hasClearButton property, the right components are displayed. And we should have autopilot tests to check that you can write and clear text fields with and without clear button. So we don't have to check those things on the apps or on the emulators.
So, lets say that design suggest to remove the clear button from a text field on the online accounts app. That change shouldn't require a change on the autopilot test for the add u1 story. That should just require a change on the lower level qt tests.
Having said that, if you still feel we will eventually need to call clear with button or clear with keys directly, I'll make them public methods of the emulator API. So we have clear, for when we don't care how the clear is done, and the other two for when we care.
Let me know what do you think about this.
About test_textinput.py, can I do it in a separate branch? I added it to my TODO for next week, but I would like to keep the MPs small.
Thanks for reviewing!
Cris Dywan (kalikiana) wrote : | # |
I see the point of view now, it makes sense. High level app tests probably see it as an unnecessary detail which is handled in the components so UITK tests would cover that.
And yes, separate branch sounds fine.
Preview Diff
1 | === modified file 'modules/Ubuntu/Components/TextField.qml' |
2 | --- modules/Ubuntu/Components/TextField.qml 2014-01-10 15:33:02 +0000 |
3 | +++ modules/Ubuntu/Components/TextField.qml 2014-01-15 06:43:05 +0000 |
4 | @@ -948,6 +948,7 @@ |
5 | |
6 | AbstractButton { |
7 | id: clearButton |
8 | + objectName: "clear_button" |
9 | property url iconSource: control.__styleInstance.iconSource |
10 | anchors { |
11 | top: parent.top |
12 | |
13 | === modified file 'modules/Ubuntu/Components/TextInputPopover.qml' |
14 | --- modules/Ubuntu/Components/TextInputPopover.qml 2013-08-07 12:50:35 +0000 |
15 | +++ modules/Ubuntu/Components/TextInputPopover.qml 2014-01-15 06:43:05 +0000 |
16 | @@ -19,6 +19,7 @@ |
17 | import "Popups" 0.1 |
18 | |
19 | ActionSelectionPopover { |
20 | + objectName: "text_input_popover" |
21 | actions: ActionList { |
22 | Action { |
23 | text: i18n.tr("Select All") |
24 | |
25 | === modified file 'tests/autopilot/ubuntuuitoolkit/emulators.py' |
26 | --- tests/autopilot/ubuntuuitoolkit/emulators.py 2014-01-09 19:24:01 +0000 |
27 | +++ tests/autopilot/ubuntuuitoolkit/emulators.py 2014-01-15 06:43:05 +0000 |
28 | @@ -26,6 +26,7 @@ |
29 | ) |
30 | from autopilot.introspection import dbus |
31 | |
32 | + |
33 | _NO_TABS_ERROR = 'The MainView has no Tabs.' |
34 | |
35 | logger = logging.getLogger(__name__) |
36 | @@ -49,6 +50,12 @@ |
37 | return input.Pointer(device=input_device_class.create()) |
38 | |
39 | |
40 | +def get_keyboard(): |
41 | + """Return the keyboard device.""" |
42 | + # TODO return the OSK if we are on the phone. --elopio - 2014-01-13 |
43 | + return input.Keyboard.create() |
44 | + |
45 | + |
46 | def check_autopilot_version(): |
47 | """Check that the Autopilot installed version matches the one required. |
48 | |
49 | @@ -69,8 +76,6 @@ |
50 | check_autopilot_version() |
51 | super(UbuntuUIToolkitEmulatorBase, self).__init__(*args) |
52 | self.pointing_device = get_pointing_device() |
53 | - # TODO it would be nice to have access to the screen keyboard if we are |
54 | - # on the touch UI -- elopio - 2013-09-04 |
55 | |
56 | |
57 | class MainView(UbuntuUIToolkitEmulatorBase): |
58 | @@ -396,7 +401,11 @@ |
59 | 'Button with text "{0}" not found.'.format(text)) |
60 | self.pointing_device.click_object(button) |
61 | if self.autoClose: |
62 | - self.visible.wait_for(False) |
63 | + try: |
64 | + self.visible.wait_for(False) |
65 | + except dbus.StateNotFoundError: |
66 | + # The popover was removed from the tree. |
67 | + pass |
68 | |
69 | def _get_button(self, text): |
70 | buttons = self.select_many('Empty') |
71 | @@ -446,6 +455,71 @@ |
72 | self.checked.wait_for(not original_state, timeout) |
73 | |
74 | |
75 | +class TextField(UbuntuUIToolkitEmulatorBase): |
76 | + """TextField Autopilot emulator.""" |
77 | + |
78 | + def __init__(self, *args): |
79 | + super(TextField, self).__init__(*args) |
80 | + self.keyboard = get_keyboard() |
81 | + |
82 | + def write(self, text, clear=True): |
83 | + """Write into the text field. |
84 | + |
85 | + :parameter text: The text to write. |
86 | + :parameter clear: If True, the text field will be cleared before |
87 | + writing the text. If False, the text will be appended at the end |
88 | + of the text field. Default is True. |
89 | + |
90 | + """ |
91 | + with self.keyboard.focused_type(self): |
92 | + if clear: |
93 | + self.clear() |
94 | + else: |
95 | + if not self.is_empty(): |
96 | + self.keyboard.press_and_release('End') |
97 | + self.keyboard.type(text) |
98 | + |
99 | + def clear(self): |
100 | + """Clear the text field.""" |
101 | + if not self.is_empty(): |
102 | + if self.hasClearButton: |
103 | + self._click_clear_button() |
104 | + else: |
105 | + self._clear_with_keys() |
106 | + self.text.wait_for('') |
107 | + |
108 | + def is_empty(self): |
109 | + """Return True if the text field is empty. False otherwise.""" |
110 | + return self.text == '' |
111 | + |
112 | + def _click_clear_button(self): |
113 | + clear_button = self.select_single( |
114 | + 'AbstractButton', objectName='clear_button') |
115 | + if not clear_button.visible: |
116 | + self.pointing_device.click_object(self) |
117 | + self.pointing_device.click_object(clear_button) |
118 | + |
119 | + def _clear_with_keys(self): |
120 | + if platform.model() == 'Desktop': |
121 | + self._select_all() |
122 | + else: |
123 | + # Touch tap currently doesn't have a press_duration parameter, so |
124 | + # we can't show the popover. Reported as bug http://pad.lv/1268782 |
125 | + # --elopio - 2014-01-13 |
126 | + self.keyboard.press_and_release('End') |
127 | + while not self.is_empty(): |
128 | + # We delete with backspace because the on-screen keyboard has that |
129 | + # key. |
130 | + self.keyboard.press_and_release('BackSpace') |
131 | + |
132 | + def _select_all(self): |
133 | + self.pointing_device.click_object(self, press_duration=1) |
134 | + root = self.get_root_instance() |
135 | + main_view = root.select_single(MainView) |
136 | + popover = main_view.get_action_selection_popover('text_input_popover') |
137 | + popover.click_button_by_text('Select All') |
138 | + |
139 | + |
140 | class QQuickListView(UbuntuUIToolkitEmulatorBase): |
141 | |
142 | @autopilot_logging.log_action(logger.info) |
143 | |
144 | === modified file 'tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py' |
145 | --- tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py 2014-01-10 03:45:29 +0000 |
146 | +++ tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py 2014-01-15 06:43:05 +0000 |
147 | @@ -882,6 +882,79 @@ |
148 | self.assertEqual(self.header.title, 'Page 0') |
149 | |
150 | |
151 | +class TextFieldTestCase(tests.QMLStringAppTestCase): |
152 | + |
153 | + test_qml = (""" |
154 | +import QtQuick 2.0 |
155 | +import Ubuntu.Components 0.1 |
156 | + |
157 | +MainView { |
158 | + width: units.gu(48) |
159 | + height: units.gu(60) |
160 | + |
161 | + Item { |
162 | + TextField { |
163 | + id: simpleTextField |
164 | + objectName: "simple_text_field" |
165 | + } |
166 | + TextField { |
167 | + id: textFieldWithoutClearButton |
168 | + objectName: "text_field_without_clear_button" |
169 | + hasClearButton: false |
170 | + anchors.top: simpleTextField.bottom |
171 | + } |
172 | + } |
173 | +} |
174 | +""") |
175 | + |
176 | + def setUp(self): |
177 | + super(TextFieldTestCase, self).setUp() |
178 | + self.simple_text_field = self.main_view.select_single( |
179 | + emulators.TextField, objectName='simple_text_field') |
180 | + |
181 | + def test_text_field_emulator(self): |
182 | + self.assertIsInstance(self.simple_text_field, emulators.TextField) |
183 | + |
184 | + def test_write(self): |
185 | + self.simple_text_field.write('test') |
186 | + self.assertEqual(self.simple_text_field.text, 'test') |
187 | + |
188 | + def test_clear_with_clear_button(self): |
189 | + self.simple_text_field.write('test') |
190 | + self.simple_text_field.clear() |
191 | + self.assertEqual(self.simple_text_field.text, '') |
192 | + |
193 | + def test_clear_without_clear_button(self): |
194 | + text_field = self.main_view.select_single( |
195 | + emulators.TextField, objectName='text_field_without_clear_button') |
196 | + text_field.write('test') |
197 | + text_field.clear() |
198 | + self.assertEqual(text_field.text, '') |
199 | + |
200 | + def test_clear_and_write(self): |
201 | + self.simple_text_field.write('test1') |
202 | + self.simple_text_field.write('test2') |
203 | + self.assertEqual(self.simple_text_field.text, 'test2') |
204 | + |
205 | + def test_write_without_clear(self): |
206 | + self.simple_text_field.write('test1') |
207 | + self.simple_text_field.write('test2', clear=False) |
208 | + self.assertEqual(self.simple_text_field.text, 'test1test2') |
209 | + |
210 | + def test_write_without_clear_writes_at_the_end(self): |
211 | + self.simple_text_field.write( |
212 | + 'long text that will fill more than half of the text field.') |
213 | + self.simple_text_field.write('append', clear=False) |
214 | + self.assertEqual( |
215 | + self.simple_text_field.text, |
216 | + 'long text that will fill more than half of the text field.append') |
217 | + |
218 | + def test_is_empty(self): |
219 | + self.assertTrue(self.simple_text_field.is_empty()) |
220 | + self.simple_text_field.write('test') |
221 | + self.assertFalse(self.simple_text_field.is_empty()) |
222 | + |
223 | + |
224 | class ComposerSheetTestCase(tests.QMLStringAppTestCase): |
225 | |
226 | test_qml = (""" |
PASSED: Continuous integration, rev:791 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- ci/896/ jenkins. qa.ubuntu. com/job/ generic- mediumtests- saucy-vm/ 303 jenkins. qa.ubuntu. com/job/ generic- mediumtests- touch/2591 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- saucy-amd64- ci/753 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- saucy-armhf- ci/753 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- saucy-armhf- ci/753/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ autopilot- testrunner- vm-saucy/ 227 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- saucy-i386/ 4451 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- saucy-i386/ 4451/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- saucy-armhf/ 2593 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- saucy-armhf/ 2593/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ generic- mediumtests- runner- maguro/ 2140 jenkins. qa.ubuntu. com/job/ generic- mediumtests- runner- mako/2153
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: 10.97.0. 26:8080/ job/ubuntu- ui-toolkit- ci/896/ rebuild
http://