Merge lp:~elopio/ubuntu-ui-toolkit/datepicker-autopilot_helper into lp:ubuntu-ui-toolkit/staging
- datepicker-autopilot_helper
- Merge into staging
Status: | Merged |
---|---|
Approved by: | Cris Dywan |
Approved revision: | 1049 |
Merged at revision: | 1064 |
Proposed branch: | lp:~elopio/ubuntu-ui-toolkit/datepicker-autopilot_helper |
Merge into: | lp:ubuntu-ui-toolkit/staging |
Prerequisite: | lp:~elopio/ubuntu-ui-toolkit/swipe_into_view |
Diff against target: |
611 lines (+419/-37) 9 files modified
modules/Ubuntu/Components/Pickers/DatePicker.qml (+3/-5) modules/Ubuntu/Components/Pickers/PickerRow.qml (+1/-1) tests/autopilot/ubuntuuitoolkit/__init__.py (+2/-0) tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py (+2/-0) tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_flickable.py (+30/-20) tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py (+27/-10) tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/pickers.py (+206/-0) tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_date_picker.py (+147/-0) tests/unit_x11/tst_components/tst_datepicker.qml (+1/-1) |
To merge this branch: | bzr merge lp:~elopio/ubuntu-ui-toolkit/datepicker-autopilot_helper |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Cris Dywan | Approve | ||
Allan LeSage | Pending | ||
Review via email: mp+218909@code.launchpad.net |
This proposal supersedes a proposal from 2014-05-07.
Commit message
Added autopilot helpers to pick a date from a date picker.
Description of the change
Next branch will add support for picking a time.
Allan LeSage (allanlesage) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1041
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Leo Arias (elopio) wrote : Posted in a previous version of this proposal | # |
> Ok I think understand this change, appears thoroughly tested, nice work :) .
> I'm assuming that the comment on l.535 doesn't apply to the present merge
> proposal.
It does. I was just trying to test it the wrong way. Now I added a couple of tests for that.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1045
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : | # |
8 - Qt.formatDate(
9 + Qt.formatDate(
Why is this change needed?
It looks overall nice.
Leo Arias (elopio) wrote : | # |
that's because there's no such thing as mmmm. http://
the example doesn't work.
Cris Dywan (kalikiana) wrote : | # |
Nice catch! Thanks
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1046
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : | # |
FAIL! : tst_UCAlarms:
Loc: [tst_alarms.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1046
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1047
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1048
http://
Executed test runs:
FAILURE: http://
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 : | # |
PASSED: Continuous integration, rev:1049
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
Cris Dywan (kalikiana) wrote : | # |
FAIL! : tst_UCAlarms:
Loc: [tst_alarms.
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'modules/Ubuntu/Components/Pickers/DatePicker.qml' |
2 | --- modules/Ubuntu/Components/Pickers/DatePicker.qml 2014-04-23 08:50:20 +0000 |
3 | +++ modules/Ubuntu/Components/Pickers/DatePicker.qml 2014-05-20 07:32:50 +0000 |
4 | @@ -42,7 +42,7 @@ |
5 | Column { |
6 | Label { |
7 | text: "Selected date: W" + datePicker.week + " - " + |
8 | - Qt.formatDate(datePicker.date, "dddd, dd-mmmm-yyyy") |
9 | + Qt.formatDate(datePicker.date, "dddd, dd-MMMM-yyyy") |
10 | } |
11 | DatePicker { |
12 | id: datePicker |
13 | @@ -61,7 +61,7 @@ |
14 | |
15 | Column { |
16 | Label { |
17 | - text: "Selected month: " + Qt.formatDate(datePicker.date, "mmmm-yyyy") |
18 | + text: "Selected month: " + Qt.formatDate(datePicker.date, "MMMM-yyyy") |
19 | } |
20 | DatePicker { |
21 | id: datePicker |
22 | @@ -117,7 +117,7 @@ |
23 | |
24 | Column { |
25 | Label { |
26 | - text: "Selected date: " + Qt.formatDate(datePicker.date, "dddd, dd-mmmm-yyyy") |
27 | + text: "Selected date: " + Qt.formatDate(datePicker.date, "dddd, dd-MMMM-yyyy") |
28 | } |
29 | DatePicker { |
30 | id: datePicker |
31 | @@ -667,5 +667,3 @@ |
32 | } |
33 | } |
34 | } |
35 | - |
36 | - |
37 | |
38 | === modified file 'modules/Ubuntu/Components/Pickers/PickerRow.qml' |
39 | --- modules/Ubuntu/Components/Pickers/PickerRow.qml 2014-04-23 08:50:20 +0000 |
40 | +++ modules/Ubuntu/Components/Pickers/PickerRow.qml 2014-05-20 07:32:50 +0000 |
41 | @@ -96,7 +96,7 @@ |
42 | } |
43 | delegate: PickerDelegate { |
44 | Label { |
45 | - objectName: "PickerRow_PickerLabel" |
46 | + objectName: "PickerRow_PickerLabel" + (pickerModel ? modelData : "") |
47 | text: pickerModel ? pickerModel.text(modelData) : "" |
48 | anchors.fill: parent |
49 | verticalAlignment: Text.AlignVCenter |
50 | |
51 | === modified file 'tests/autopilot/ubuntuuitoolkit/__init__.py' |
52 | --- tests/autopilot/ubuntuuitoolkit/__init__.py 2014-04-30 00:46:11 +0000 |
53 | +++ tests/autopilot/ubuntuuitoolkit/__init__.py 2014-05-20 07:32:50 +0000 |
54 | @@ -30,6 +30,7 @@ |
55 | 'listitems', |
56 | 'MainView', |
57 | 'OptionSelector', |
58 | + 'pickers', |
59 | 'popups', |
60 | 'QQuickFlickable', |
61 | 'QQuickListView', |
62 | @@ -59,6 +60,7 @@ |
63 | listitems, |
64 | MainView, |
65 | OptionSelector, |
66 | + pickers, |
67 | popups, |
68 | QQuickFlickable, |
69 | QQuickListView, |
70 | |
71 | === modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py' |
72 | --- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py 2014-04-30 00:46:11 +0000 |
73 | +++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py 2014-05-20 07:32:50 +0000 |
74 | @@ -26,6 +26,7 @@ |
75 | 'listitems', |
76 | 'MainView', |
77 | 'OptionSelector', |
78 | + 'pickers', |
79 | 'popups', |
80 | 'QQuickFlickable', |
81 | 'QQuickListView', |
82 | @@ -52,6 +53,7 @@ |
83 | from ubuntuuitoolkit._custom_proxy_objects._optionselector import ( |
84 | OptionSelector |
85 | ) |
86 | +from ubuntuuitoolkit._custom_proxy_objects import pickers |
87 | from ubuntuuitoolkit._custom_proxy_objects import popups |
88 | from ubuntuuitoolkit._custom_proxy_objects._qquicklistview import ( |
89 | QQuickListView |
90 | |
91 | === modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_flickable.py' |
92 | --- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_flickable.py 2014-04-30 00:46:11 +0000 |
93 | +++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_flickable.py 2014-05-20 07:32:50 +0000 |
94 | @@ -38,21 +38,7 @@ |
95 | return min(containers_bottom) |
96 | |
97 | |
98 | -class QQuickFlickable(_common.UbuntuUIToolkitCustomProxyObjectBase): |
99 | - |
100 | - @autopilot_logging.log_action(logger.info) |
101 | - def swipe_child_into_view(self, child): |
102 | - """Make the child visible. |
103 | - |
104 | - Currently it works only when the object needs to be swiped vertically. |
105 | - TODO implement horizontal swiping. --elopio - 2014-03-21 |
106 | - |
107 | - """ |
108 | - containers = self._get_containers() |
109 | - if not self._is_child_visible(child, containers): |
110 | - self._swipe_non_visible_child_into_view(child, containers) |
111 | - else: |
112 | - logger.debug('The element is already visible.') |
113 | +class Scrollable(_common.UbuntuUIToolkitCustomProxyObjectBase): |
114 | |
115 | def _get_containers(self): |
116 | """Return a list with the containers to take into account when swiping. |
117 | @@ -94,6 +80,35 @@ |
118 | return (object_center >= visible_top and |
119 | object_center <= visible_bottom) |
120 | |
121 | + def _slow_drag(self, start_x, stop_x, start_y, stop_y): |
122 | + # If we drag too fast, we end up scrolling more than what we |
123 | + # should, sometimes missing the element we are looking for. |
124 | + # I found that when the flickDeceleration is 1500, the rate should be |
125 | + # 5 and that when it's 100, the rate should be 1. With those two points |
126 | + # we can get that the following equation. |
127 | + # XXX The deceleration might not be linear with respect to the rate, |
128 | + # but this works for the two types of scrollables we have for now. |
129 | + # --elopio - 2014-05-08 |
130 | + rate = (self.flickDeceleration + 250) / 350 |
131 | + self.pointing_device.drag(start_x, start_y, stop_x, stop_y, rate=rate) |
132 | + |
133 | + |
134 | +class QQuickFlickable(Scrollable): |
135 | + |
136 | + @autopilot_logging.log_action(logger.info) |
137 | + def swipe_child_into_view(self, child): |
138 | + """Make the child visible. |
139 | + |
140 | + Currently it works only when the object needs to be swiped vertically. |
141 | + TODO implement horizontal swiping. --elopio - 2014-03-21 |
142 | + |
143 | + """ |
144 | + containers = self._get_containers() |
145 | + if not self._is_child_visible(child, containers): |
146 | + self._swipe_non_visible_child_into_view(child, containers) |
147 | + else: |
148 | + logger.debug('The element is already visible.') |
149 | + |
150 | @autopilot_logging.log_action(logger.info) |
151 | def _swipe_non_visible_child_into_view(self, child, containers): |
152 | original_content_y = self.contentY |
153 | @@ -150,11 +165,6 @@ |
154 | self.dragging.wait_for(False) |
155 | self.moving.wait_for(False) |
156 | |
157 | - def _slow_drag(self, start_x, stop_x, start_y, stop_y): |
158 | - # If we drag too fast, we end up scrolling more than what we |
159 | - # should, sometimes missing the element we are looking for. |
160 | - self.pointing_device.drag(start_x, start_y, stop_x, stop_y, rate=5) |
161 | - |
162 | @autopilot_logging.log_action(logger.info) |
163 | def _scroll_to_top(self): |
164 | if not self.atYBeginning: |
165 | |
166 | === modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py' |
167 | --- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py 2014-04-30 00:46:11 +0000 |
168 | +++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py 2014-05-20 07:32:50 +0000 |
169 | @@ -19,9 +19,7 @@ |
170 | from autopilot import logging as autopilot_logging |
171 | from autopilot.introspection import dbus |
172 | |
173 | -from ubuntuuitoolkit._custom_proxy_objects import _flickable |
174 | -from ubuntuuitoolkit._custom_proxy_objects import _common |
175 | - |
176 | +from ubuntuuitoolkit._custom_proxy_objects import _common, _flickable |
177 | |
178 | logger = logging.getLogger(__name__) |
179 | |
180 | @@ -29,12 +27,16 @@ |
181 | class QQuickListView(_flickable.QQuickFlickable): |
182 | |
183 | @autopilot_logging.log_action(logger.info) |
184 | - def click_element(self, object_name): |
185 | + def click_element(self, object_name, direction=None): |
186 | """Click an element from the list. |
187 | |
188 | It swipes the element into view if it's center is not visible. |
189 | |
190 | :parameter objectName: The objectName property of the element to click. |
191 | + :parameter direction: The direction where the element is, it can be |
192 | + either 'above' or 'below'. Default value is None, which means we |
193 | + don't know where the object is and we will need to search the full |
194 | + list. |
195 | |
196 | """ |
197 | try: |
198 | @@ -42,16 +44,31 @@ |
199 | except dbus.StateNotFoundError: |
200 | # The element might be on a part of the list that hasn't been |
201 | # created yet. We have to search for it scrolling the entire list. |
202 | - element = self._find_element(object_name) |
203 | + element = self._find_element(object_name, direction) |
204 | self.swipe_child_into_view(element) |
205 | self.pointing_device.click_object(element) |
206 | |
207 | @autopilot_logging.log_action(logger.info) |
208 | - def _find_element(self, object_name): |
209 | - self._scroll_to_top() |
210 | - while not self.atYEnd: |
211 | - containers = self._get_containers() |
212 | - self._swipe_to_show_more_below(containers) |
213 | + def _find_element(self, object_name, direction=None): |
214 | + if direction is None: |
215 | + # We don't know where the object is so we start looking for it from |
216 | + # the top. |
217 | + self._scroll_to_top() |
218 | + direction = 'below' |
219 | + |
220 | + if direction == 'below': |
221 | + fail_condition = lambda: self.atYEnd |
222 | + swipe_method = self._swipe_to_show_more_below |
223 | + elif direction == 'above': |
224 | + fail_condition = lambda: self.atYBeginning |
225 | + swipe_method = self._swipe_to_show_more_above |
226 | + else: |
227 | + raise _common.ToolkitException( |
228 | + 'Invalid direction: {}'.format(direction)) |
229 | + |
230 | + containers = self._get_containers() |
231 | + while not fail_condition(): |
232 | + swipe_method(containers) |
233 | try: |
234 | return self.select_single(objectName=object_name) |
235 | except dbus.StateNotFoundError: |
236 | |
237 | === added file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/pickers.py' |
238 | --- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/pickers.py 1970-01-01 00:00:00 +0000 |
239 | +++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/pickers.py 2014-05-20 07:32:50 +0000 |
240 | @@ -0,0 +1,206 @@ |
241 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
242 | +# |
243 | +# Copyright (C) 2014 Canonical Ltd. |
244 | +# |
245 | +# This program is free software; you can redistribute it and/or modify |
246 | +# it under the terms of the GNU Lesser General Public License as published by |
247 | +# the Free Software Foundation; version 3. |
248 | +# |
249 | +# This program is distributed in the hope that it will be useful, |
250 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
251 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
252 | +# GNU Lesser General Public License for more details. |
253 | +# |
254 | +# You should have received a copy of the GNU Lesser General Public License |
255 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
256 | + |
257 | +import datetime |
258 | +import logging |
259 | + |
260 | +from autopilot import logging as autopilot_logging |
261 | +from autopilot.introspection import dbus |
262 | + |
263 | +from ubuntuuitoolkit._custom_proxy_objects import ( |
264 | + _common, |
265 | + _flickable, |
266 | + _qquicklistview |
267 | +) |
268 | + |
269 | + |
270 | +logger = logging.getLogger(__name__) |
271 | + |
272 | + |
273 | +class DatePicker(_common.UbuntuUIToolkitCustomProxyObjectBase): |
274 | + """Autopilot helper for the DatePicker component.""" |
275 | + |
276 | + @autopilot_logging.log_action(logger.info) |
277 | + def pick_date(self, date): |
278 | + """Pick a date from the date picker. |
279 | + |
280 | + :parameter date: The date to pick. |
281 | + :type date: An object with year, month and day attributes, like |
282 | + python's datetime.date. |
283 | + :raises ubuntuuitoolkit.ToolkitException if the mode of the picker |
284 | + doesn't let select a date. |
285 | + |
286 | + """ |
287 | + if not self._is_date_picker(): |
288 | + raise _common.ToolkitException( |
289 | + "Can't pick date. The picker mode is: {!r}.".format(self.mode)) |
290 | + if 'Years' in self.mode: |
291 | + self._pick_year(date.year) |
292 | + self.year.wait_for(date.year) |
293 | + if 'Month' in self.mode: |
294 | + # Python's date object starts at one. The model in the date picker |
295 | + # at 0. |
296 | + self._pick_month(date.month - 1) |
297 | + self.month.wait_for(date.month - 1) |
298 | + if 'Day' in self.mode: |
299 | + self._pick_day(date.day) |
300 | + self.day.wait_for(date.day) |
301 | + |
302 | + def _is_date_picker(self): |
303 | + mode = self.mode |
304 | + if 'Years' in mode or 'Months' in mode or 'Days' in mode: |
305 | + return True |
306 | + else: |
307 | + return False |
308 | + |
309 | + @autopilot_logging.log_action(logger.info) |
310 | + def _pick_year(self, year): |
311 | + picker = self.select_single( |
312 | + 'Picker', objectName='PickerRow_YearPicker') |
313 | + list_view = picker.select_single( |
314 | + _qquicklistview.QQuickListView, objectName='Picker_Linear') |
315 | + self._pick_date_value(self.year, year, list_view) |
316 | + |
317 | + @autopilot_logging.log_action(logger.info) |
318 | + def _pick_month(self, month): |
319 | + picker = self.select_single( |
320 | + 'Picker', objectName='PickerRow_MonthPicker') |
321 | + path_view = picker.select_single( |
322 | + QQuickPathView, objectName='Picker_WrapAround') |
323 | + self._pick_date_value(self.month, month, path_view) |
324 | + |
325 | + @autopilot_logging.log_action(logger.info) |
326 | + def _pick_day(self, day): |
327 | + picker = self.select_single( |
328 | + 'Picker', objectName='PickerRow_DayPicker') |
329 | + path_view = picker.select_single( |
330 | + QQuickPathView, objectName='Picker_WrapAround') |
331 | + # Python's date object starts at one. The model in the date picker |
332 | + # at 0. |
333 | + self._pick_date_value(self.get_date().day - 1, day - 1, path_view) |
334 | + |
335 | + def _pick_date_value(self, current_value, new_value, scrollable): |
336 | + if new_value > current_value: |
337 | + direction = 'below' |
338 | + elif new_value < current_value: |
339 | + direction = 'above' |
340 | + else: |
341 | + logger.debug('The value is already selected.') |
342 | + return |
343 | + scrollable.click_element( |
344 | + object_name='PickerRow_PickerLabel{}'.format(new_value), |
345 | + direction=direction) |
346 | + |
347 | + def get_date(self): |
348 | + """Return the currently selected date. |
349 | + |
350 | + :return: a python datetime.date object with the selected date. |
351 | + |
352 | + """ |
353 | + # Python's date object starts at one. The model in the date picker |
354 | + # at 0. |
355 | + return datetime.date( |
356 | + self.year, self.month + 1, self.day) |
357 | + |
358 | + |
359 | +class QQuickPathView(_flickable.Scrollable): |
360 | + |
361 | + # TODO make it more general and move it to its own module. |
362 | + # --elopio - 2014-05-06 |
363 | + |
364 | + @autopilot_logging.log_action(logger.info) |
365 | + def click_element(self, object_name, direction='below'): |
366 | + try: |
367 | + element = self.select_single(objectName=object_name) |
368 | + except dbus.StateNotFoundError: |
369 | + # The element might be on a part of the list that hasn't been |
370 | + # created yet. We have to search for it scrolling. |
371 | + element = self._find_element(object_name, direction) |
372 | + self.swipe_child_into_view(element) |
373 | + self.pointing_device.click_object(element) |
374 | + |
375 | + @autopilot_logging.log_action(logger.info) |
376 | + def _find_element(self, object_name, direction): |
377 | + containers = self._get_containers() |
378 | + for index in range(self.count): |
379 | + if direction == 'below': |
380 | + swipe_method = self._swipe_to_show_one_more_below |
381 | + elif direction == 'above': |
382 | + swipe_method = self._swipe_to_show_one_more_above |
383 | + else: |
384 | + raise _common.ToolkitException( |
385 | + 'Invalid direction: {}'.format(direction)) |
386 | + |
387 | + swipe_method(containers) |
388 | + |
389 | + try: |
390 | + return self.select_single(objectName=object_name) |
391 | + except dbus.StateNotFoundError: |
392 | + pass |
393 | + raise _common.ToolkitException( |
394 | + 'List element with objectName "{}" not found.'.format(object_name)) |
395 | + |
396 | + @autopilot_logging.log_action(logger.info) |
397 | + def _swipe_to_show_one_more_above(self, containers): |
398 | + self._swipe_to_show_one_more('above', containers) |
399 | + |
400 | + @autopilot_logging.log_action(logger.info) |
401 | + def _swipe_to_show_one_more_below(self, containers): |
402 | + self._swipe_to_show_one_more('below', containers) |
403 | + |
404 | + def _swipe_to_show_one_more(self, direction, containers): |
405 | + start_x = stop_x = self.globalRect.x + (self.globalRect.width // 2) |
406 | + center_y = self.globalRect.y + (self.globalRect.height // 2) |
407 | + # XXX This assumes all the children are of the same height |
408 | + child = self.get_children_by_type('PickerDelegate')[0] |
409 | + top = center_y - (child.globalRect.height // 2) |
410 | + bottom = center_y + (child.globalRect.height // 2) |
411 | + if direction == 'below': |
412 | + start_y = bottom |
413 | + stop_y = top |
414 | + elif direction == 'above': |
415 | + start_y = top |
416 | + stop_y = bottom |
417 | + else: |
418 | + raise _common.ToolkitException( |
419 | + 'Invalid direction {}.'.format(direction)) |
420 | + self._slow_drag(start_x, stop_x, start_y, stop_y) |
421 | + self.dragging.wait_for(False) |
422 | + self.moving.wait_for(False) |
423 | + |
424 | + @autopilot_logging.log_action(logger.info) |
425 | + def swipe_child_into_view(self, child): |
426 | + """Make the child visible. |
427 | + |
428 | + Currently it works only when the object needs to be swiped vertically. |
429 | + TODO implement horizontal swiping. --elopio - 2014-03-21 |
430 | + |
431 | + """ |
432 | + containers = self._get_containers() |
433 | + if not self._is_child_visible(child, containers): |
434 | + self._swipe_non_visible_child_into_view(child, containers) |
435 | + else: |
436 | + logger.debug('The element is already visible.') |
437 | + |
438 | + @autopilot_logging.log_action(logger.info) |
439 | + def _swipe_non_visible_child_into_view(self, child, containers): |
440 | + while not self._is_child_visible(child, containers): |
441 | + # Check the direction of the swipe based on the position of the |
442 | + # child relative to the immediate flickable container. |
443 | + if child.globalRect.y < self.globalRect.y: |
444 | + self._swipe_to_show_one_more_above(containers) |
445 | + else: |
446 | + self._swipe_to_show_one_more_below(containers) |
447 | |
448 | === added file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_date_picker.py' |
449 | --- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_date_picker.py 1970-01-01 00:00:00 +0000 |
450 | +++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_date_picker.py 2014-05-20 07:32:50 +0000 |
451 | @@ -0,0 +1,147 @@ |
452 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
453 | +# |
454 | +# Copyright (C) 2014 Canonical Ltd. |
455 | +# |
456 | +# This program is free software; you can redistribute it and/or modify |
457 | +# it under the terms of the GNU Lesser General Public License as published by |
458 | +# the Free Software Foundation; version 3. |
459 | +# |
460 | +# This program is distributed in the hope that it will be useful, |
461 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
462 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
463 | +# GNU Lesser General Public License for more details. |
464 | +# |
465 | +# You should have received a copy of the GNU Lesser General Public License |
466 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
467 | + |
468 | +import datetime |
469 | + |
470 | +import ubuntuuitoolkit |
471 | +from ubuntuuitoolkit import pickers, tests |
472 | + |
473 | + |
474 | +class DatePickerBaseTestCase(tests.QMLStringAppTestCase): |
475 | + |
476 | + test_qml = (""" |
477 | +import QtQuick 2.0 |
478 | +import Ubuntu.Components 1.1 |
479 | +import Ubuntu.Components.Pickers 1.0 |
480 | + |
481 | +MainView { |
482 | + width: units.gu(48) |
483 | + height: units.gu(60) |
484 | + |
485 | + Column { |
486 | + DatePicker { |
487 | + id: datePicker |
488 | + objectName: 'datePicker' |
489 | + mode: 'Years|Months|Days' |
490 | + date: { |
491 | + var d = new Date() |
492 | + // Make sure that the picker will have higher and lower values |
493 | + // to select. |
494 | + d.setFullYear(d.getFullYear() + 25) |
495 | + d.setMonth('5') |
496 | + d.setDate('15') |
497 | + return d |
498 | + } |
499 | + } |
500 | + DatePicker { |
501 | + id: timePicker |
502 | + objectName: 'timePicker' |
503 | + mode: 'Hours|Minutes|Seconds' |
504 | + } |
505 | + } |
506 | +} |
507 | +""") |
508 | + |
509 | + def setUp(self): |
510 | + super(DatePickerBaseTestCase, self).setUp() |
511 | + self.date_picker = self.main_view.select_single( |
512 | + pickers.DatePicker, objectName='datePicker') |
513 | + |
514 | + |
515 | +class DatePickerTestCase(DatePickerBaseTestCase): |
516 | + |
517 | + def test_select_date_picker_must_return_custom_proxy_object(self): |
518 | + self.assertIsInstance( |
519 | + self.date_picker, pickers.DatePicker) |
520 | + |
521 | + def test_pick_date_on_time_picker_must_raise_exception(self): |
522 | + time_picker = self.main_view.select_single( |
523 | + pickers.DatePicker, objectName='timePicker') |
524 | + error = self.assertRaises( |
525 | + ubuntuuitoolkit.ToolkitException, time_picker.pick_date, 'dummy') |
526 | + self.assertEqual( |
527 | + str(error), |
528 | + "Can't pick date. The picker mode is: {!r}.".format( |
529 | + time_picker.mode)) |
530 | + |
531 | + def test_swipe_to_show_one_more_below_must_select_next_index(self): |
532 | + """Test that we don't end up swiping more than needed. |
533 | + |
534 | + This would cause us to miss the element we are looking for, and to have |
535 | + to swipe many times in order to finally click it. |
536 | + |
537 | + """ |
538 | + picker = self.main_view.select_single( |
539 | + 'Picker', objectName='PickerRow_DayPicker') |
540 | + path_view = picker.select_single( |
541 | + pickers.QQuickPathView, objectName='Picker_WrapAround') |
542 | + current_index = path_view.currentIndex |
543 | + |
544 | + path_view._swipe_to_show_one_more_below(path_view._get_containers()) |
545 | + |
546 | + self.assertEqual(path_view.currentIndex, current_index + 1) |
547 | + |
548 | + def test_swipe_to_show_one_more_above_must_select_previous_index(self): |
549 | + """Test that we don't end up swiping more than needed. |
550 | + |
551 | + This would cause us to miss the element we are looking for, and to have |
552 | + to swipe many times in order to finally click it. |
553 | + |
554 | + """ |
555 | + picker = self.main_view.select_single( |
556 | + 'Picker', objectName='PickerRow_DayPicker') |
557 | + path_view = picker.select_single( |
558 | + pickers.QQuickPathView, objectName='Picker_WrapAround') |
559 | + current_index = path_view.currentIndex |
560 | + |
561 | + path_view._swipe_to_show_one_more_above(path_view._get_containers()) |
562 | + |
563 | + self.assertEqual(path_view.currentIndex, current_index - 1) |
564 | + |
565 | + |
566 | +class PickDateFromDatePickerTestCase(DatePickerBaseTestCase): |
567 | + |
568 | + SELECTED_YEAR = datetime.date.today().year + 25 |
569 | + SELECTED_MONTH = 6 # June |
570 | + SELECTED_DAY = 15 |
571 | + |
572 | + scenarios = [ |
573 | + ('higher year', { |
574 | + 'date_to_pick': datetime.date( |
575 | + SELECTED_YEAR + 10, SELECTED_MONTH, SELECTED_DAY)}), |
576 | + ('lower year', { |
577 | + 'date_to_pick': datetime.date( |
578 | + SELECTED_YEAR - 10, SELECTED_MONTH, SELECTED_DAY)}), |
579 | + ('higher month', { |
580 | + 'date_to_pick': datetime.date( |
581 | + SELECTED_YEAR, SELECTED_MONTH + 4, SELECTED_DAY)}), |
582 | + ('lower month', { |
583 | + 'date_to_pick': datetime.date( |
584 | + SELECTED_YEAR, SELECTED_MONTH - 4, SELECTED_DAY)}), |
585 | + ('higher day', { |
586 | + 'date_to_pick': datetime.date( |
587 | + SELECTED_YEAR, SELECTED_MONTH, SELECTED_DAY + 10)}), |
588 | + ('lower day', { |
589 | + 'date_to_pick': datetime.date( |
590 | + SELECTED_YEAR, SELECTED_MONTH, SELECTED_DAY - 10)}), |
591 | + ('change all value', { |
592 | + 'date_to_pick': datetime.date( |
593 | + SELECTED_YEAR - 10, SELECTED_MONTH + 4, SELECTED_DAY - 10)}), |
594 | + ] |
595 | + |
596 | + def test_pick_date(self): |
597 | + self.date_picker.pick_date(self.date_to_pick) |
598 | + self.assertEqual(self.date_picker.get_date(), self.date_to_pick) |
599 | |
600 | === modified file 'tests/unit_x11/tst_components/tst_datepicker.qml' |
601 | --- tests/unit_x11/tst_components/tst_datepicker.qml 2014-05-05 17:45:45 +0000 |
602 | +++ tests/unit_x11/tst_components/tst_datepicker.qml 2014-05-20 07:32:50 +0000 |
603 | @@ -59,7 +59,7 @@ |
604 | function getPickerLabel(picker, name) { |
605 | var pickerItem = findChild(picker, name); |
606 | var pickerCurrent = findChild(pickerItem, "Picker_ViewLoader"); |
607 | - return findChild(pickerCurrent.item.currentItem, "PickerRow_PickerLabel"); |
608 | + return pickerCurrent.item.currentItem.children[2]; |
609 | } |
610 | function getPickerModel(picker, name) { |
611 | var pickerItem = findInvisibleChild(picker, name); |
Ok I think understand this change, appears thoroughly tested, nice work :) . I'm assuming that the comment on l.535 doesn't apply to the present merge proposal.