Merge lp:~elopio/ubuntu-ui-toolkit/datepicker-autopilot_helper into lp:ubuntu-ui-toolkit/staging

Proposed by Leo Arias
Status: Merged
Approved by: Christian 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
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Christian 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.

To post a comment you must log in.
Revision history for this message
Allan LeSage (allanlesage) 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.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Christian Dywan (kalikiana) wrote :

8 - Qt.formatDate(datePicker.date, "dddd, dd-mmmm-yyyy")
9 + Qt.formatDate(datePicker.date, "dddd, dd-MMMM-yyyy")

Why is this change needed?

It looks overall nice.

review: Needs Information
Revision history for this message
Leo Arias (elopio) wrote :

that's because there's no such thing as mmmm. http://qt-project.org/doc/qt-5/qml-qtqml-date.html
the example doesn't work.

Revision history for this message
Christian Dywan (kalikiana) wrote :

Nice catch! Thanks

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Christian Dywan (kalikiana) wrote :

FAIL! : tst_UCAlarms::test_updateAlarm_Repeating() 'containsAlarm(&alarm)' returned FALSE. ()
   Loc: [tst_alarms.cpp(356)]

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:1046
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/235/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/269
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/244
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-amd64-ci/67
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/67
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/67/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-i386-ci/67
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/757
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/549
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/549/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/7254
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/220
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/308
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/308/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/235/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-autolanding/93/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/318
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/283
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-amd64-autolanding/37
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-autolanding/37
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-autolanding/37/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-i386-autolanding/37
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/798
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/629
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/629/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/7339
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/255
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/357
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/357/artifact/work/output/*zip*/output.zip

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:1047
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/247/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/322
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/287
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-amd64-ci/79
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/79
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/79/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-i386-ci/79
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/801
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/635
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/635/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/7346
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/257
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/362
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/362/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/247/rebuild

review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:1049
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/252/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/335
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/296
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-amd64-ci/84
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/84
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/84/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-i386-ci/84
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/812
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/665
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/665/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/7376
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/263
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/372
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/372/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/252/rebuild

review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Christian Dywan (kalikiana) wrote :

FAIL! : tst_UCAlarms::test_updateAlarm_Repeating() 'containsAlarm(&alarm)' returned FALSE. ()
   Loc: [tst_alarms.cpp(356)]

Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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);

Subscribers

People subscribed via source and target branches