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

Proposed by Leo Arias
Status: Superseded
Proposed branch: lp:~elopio/ubuntu-ui-toolkit/datepicker-autopilot_helper
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 985 lines (+688/-41)
12 files modified
modules/Ubuntu/Components/Pickers/DatePicker.qml (+3/-5)
modules/Ubuntu/Components/Pickers/PickerRow.qml (+1/-1)
tests/autopilot/ubuntuuitoolkit/__init__.py (+4/-2)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py (+4/-2)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_common.py (+45/-1)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_flickable.py (+50/-16)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py (+28/-11)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/pickers.py (+206/-0)
tests/autopilot/ubuntuuitoolkit/emulators.py (+2/-2)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_date_picker.py (+147/-0)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_flickable.py (+197/-0)
tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py (+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 Needs Fixing
Allan LeSage (community) Approve
Ubuntu SDK team Pending
Review via email: mp+218588@code.launchpad.net

This proposal has been superseded by a proposal from 2014-05-09.

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.
1040. By Leo Arias

The containers don't change.

1041. By Leo Arias

Missing annotation.

Revision history for this message
Allan LeSage (allanlesage) wrote :

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 :
review: Needs Fixing (continuous-integration)
1042. By Leo Arias

Added the tests for the slow drag.

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

> 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.

1043. By Leo Arias

Fixed pep8.

1044. By Leo Arias

Merged with prerequisite.

1045. By Leo Arias

Added a warning.

1046. By Leo Arias

Updated the datepicker qttests.

1047. By Leo Arias

Merged with staging.

1048. By Leo Arias

Fixed the inheritance.

1049. By Leo Arias

Fixed pep8.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'modules/Ubuntu/Components/Pickers/DatePicker.qml'
--- modules/Ubuntu/Components/Pickers/DatePicker.qml 2014-04-23 08:50:20 +0000
+++ modules/Ubuntu/Components/Pickers/DatePicker.qml 2014-05-09 04:12:47 +0000
@@ -42,7 +42,7 @@
42 Column {42 Column {
43 Label {43 Label {
44 text: "Selected date: W" + datePicker.week + " - " +44 text: "Selected date: W" + datePicker.week + " - " +
45 Qt.formatDate(datePicker.date, "dddd, dd-mmmm-yyyy")45 Qt.formatDate(datePicker.date, "dddd, dd-MMMM-yyyy")
46 }46 }
47 DatePicker {47 DatePicker {
48 id: datePicker48 id: datePicker
@@ -61,7 +61,7 @@
6161
62 Column {62 Column {
63 Label {63 Label {
64 text: "Selected month: " + Qt.formatDate(datePicker.date, "mmmm-yyyy")64 text: "Selected month: " + Qt.formatDate(datePicker.date, "MMMM-yyyy")
65 }65 }
66 DatePicker {66 DatePicker {
67 id: datePicker67 id: datePicker
@@ -117,7 +117,7 @@
117117
118 Column {118 Column {
119 Label {119 Label {
120 text: "Selected date: " + Qt.formatDate(datePicker.date, "dddd, dd-mmmm-yyyy")120 text: "Selected date: " + Qt.formatDate(datePicker.date, "dddd, dd-MMMM-yyyy")
121 }121 }
122 DatePicker {122 DatePicker {
123 id: datePicker123 id: datePicker
@@ -667,5 +667,3 @@
667 }667 }
668 }668 }
669}669}
670
671
672670
=== modified file 'modules/Ubuntu/Components/Pickers/PickerRow.qml'
--- modules/Ubuntu/Components/Pickers/PickerRow.qml 2014-04-23 08:50:20 +0000
+++ modules/Ubuntu/Components/Pickers/PickerRow.qml 2014-05-09 04:12:47 +0000
@@ -96,7 +96,7 @@
96 }96 }
97 delegate: PickerDelegate {97 delegate: PickerDelegate {
98 Label {98 Label {
99 objectName: "PickerRow_PickerLabel"99 objectName: "PickerRow_PickerLabel" + (pickerModel ? modelData : "")
100 text: pickerModel ? pickerModel.text(modelData) : ""100 text: pickerModel ? pickerModel.text(modelData) : ""
101 anchors.fill: parent101 anchors.fill: parent
102 verticalAlignment: Text.AlignVCenter102 verticalAlignment: Text.AlignVCenter
103103
=== modified file 'tests/autopilot/ubuntuuitoolkit/__init__.py'
--- tests/autopilot/ubuntuuitoolkit/__init__.py 2014-04-25 18:39:51 +0000
+++ tests/autopilot/ubuntuuitoolkit/__init__.py 2014-05-09 04:12:47 +0000
@@ -24,14 +24,15 @@
24 'environment',24 'environment',
25 'emulators',25 'emulators',
26 'fixture_setup',26 'fixture_setup',
27 'Flickable',
28 'get_keyboard',27 'get_keyboard',
29 'get_pointing_device',28 'get_pointing_device',
30 'Header',29 'Header',
31 'listitems',30 'listitems',
32 'MainView',31 'MainView',
33 'OptionSelector',32 'OptionSelector',
33 'pickers',
34 'popups',34 'popups',
35 'QQuickFlickable',
35 'QQuickListView',36 'QQuickListView',
36 'TabBar',37 'TabBar',
37 'Tabs',38 'Tabs',
@@ -53,14 +54,15 @@
53from ubuntuuitoolkit._custom_proxy_objects import (54from ubuntuuitoolkit._custom_proxy_objects import (
54 check_autopilot_version,55 check_autopilot_version,
55 CheckBox,56 CheckBox,
56 Flickable,
57 get_keyboard,57 get_keyboard,
58 get_pointing_device,58 get_pointing_device,
59 Header,59 Header,
60 listitems,60 listitems,
61 MainView,61 MainView,
62 OptionSelector,62 OptionSelector,
63 pickers,
63 popups,64 popups,
65 QQuickFlickable,
64 QQuickListView,66 QQuickListView,
65 TabBar,67 TabBar,
66 Tabs,68 Tabs,
6769
=== modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py'
--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py 2014-04-28 15:39:24 +0000
+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/__init__.py 2014-05-09 04:12:47 +0000
@@ -20,14 +20,15 @@
20__all__ = [20__all__ = [
21 'check_autopilot_version',21 'check_autopilot_version',
22 'CheckBox',22 'CheckBox',
23 'Flickable',
24 'get_keyboard',23 'get_keyboard',
25 'get_pointing_device',24 'get_pointing_device',
26 'Header',25 'Header',
27 'listitems',26 'listitems',
28 'MainView',27 'MainView',
29 'OptionSelector',28 'OptionSelector',
29 'pickers',
30 'popups',30 'popups',
31 'QQuickFlickable',
31 'QQuickListView',32 'QQuickListView',
32 'TabBar',33 'TabBar',
33 'Tabs',34 'Tabs',
@@ -45,13 +46,14 @@
45 ToolkitException,46 ToolkitException,
46 UbuntuUIToolkitCustomProxyObjectBase,47 UbuntuUIToolkitCustomProxyObjectBase,
47)48)
48from ubuntuuitoolkit._custom_proxy_objects._flickable import Flickable49from ubuntuuitoolkit._custom_proxy_objects._flickable import QQuickFlickable
49from ubuntuuitoolkit._custom_proxy_objects._header import Header50from ubuntuuitoolkit._custom_proxy_objects._header import Header
50from ubuntuuitoolkit._custom_proxy_objects import listitems51from ubuntuuitoolkit._custom_proxy_objects import listitems
51from ubuntuuitoolkit._custom_proxy_objects._mainview import MainView52from ubuntuuitoolkit._custom_proxy_objects._mainview import MainView
52from ubuntuuitoolkit._custom_proxy_objects._optionselector import (53from ubuntuuitoolkit._custom_proxy_objects._optionselector import (
53 OptionSelector54 OptionSelector
54)55)
56from ubuntuuitoolkit._custom_proxy_objects import pickers
55from ubuntuuitoolkit._custom_proxy_objects import popups57from ubuntuuitoolkit._custom_proxy_objects import popups
56from ubuntuuitoolkit._custom_proxy_objects._qquicklistview import (58from ubuntuuitoolkit._custom_proxy_objects._qquicklistview import (
57 QQuickListView59 QQuickListView
5860
=== modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_common.py'
--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_common.py 2014-04-16 21:13:39 +0000
+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_common.py 2014-05-09 04:12:47 +0000
@@ -16,13 +16,21 @@
1616
17"""Common helpers for Ubuntu UI Toolkit Autopilot custom proxy objects."""17"""Common helpers for Ubuntu UI Toolkit Autopilot custom proxy objects."""
1818
19import logging
19from distutils import version20from distutils import version
2021
21import autopilot22import autopilot
22from autopilot import platform, input23from autopilot import (
24 input,
25 logging as autopilot_logging,
26 platform
27)
23from autopilot.introspection import dbus28from autopilot.introspection import dbus
2429
2530
31logger = logging.getLogger(__name__)
32
33
26class ToolkitException(Exception):34class ToolkitException(Exception):
27 """Exception raised when there is an error with the emulator."""35 """Exception raised when there is an error with the emulator."""
2836
@@ -67,3 +75,39 @@
67 check_autopilot_version()75 check_autopilot_version()
68 super(UbuntuUIToolkitCustomProxyObjectBase, self).__init__(*args)76 super(UbuntuUIToolkitCustomProxyObjectBase, self).__init__(*args)
69 self.pointing_device = get_pointing_device()77 self.pointing_device = get_pointing_device()
78
79 def is_flickable(self):
80 """Check if the object is flickable.
81
82 If the object has a flicking attribute, we consider it as a flickable.
83
84 :return: True if the object is flickable. False otherwise.
85
86 """
87 try:
88 self.flicking
89 return True
90 except AttributeError:
91 return False
92
93 @autopilot_logging.log_action(logger.info)
94 def swipe_into_view(self):
95 """Make the object visible.
96
97 Currently it works only when the object needs to be swiped vertically.
98 TODO implement horizontal swiping. --elopio - 2014-03-21
99
100 """
101 flickable_parent = self._get_flickable_parent()
102 flickable_parent.swipe_child_into_view(self)
103
104 def _get_flickable_parent(self):
105 parent = self.get_parent()
106 root = self.get_root_instance()
107 while parent.id != root.id:
108 if parent.is_flickable():
109 return parent
110 parent = parent.get_parent()
111 raise ToolkitException(
112 "The element is not contained in a Flickable so it can't be "
113 "swiped into view.")
70114
=== modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_flickable.py'
--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_flickable.py 2014-04-16 21:13:39 +0000
+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_flickable.py 2014-05-09 04:12:47 +0000
@@ -38,7 +38,7 @@
38 return min(containers_bottom)38 return min(containers_bottom)
3939
4040
41class Flickable(_common.UbuntuUIToolkitCustomProxyObjectBase):41class Scrollable(_common.UbuntuUIToolkitCustomProxyObjectBase):
4242
43 @autopilot_logging.log_action(logger.info)43 @autopilot_logging.log_action(logger.info)
44 def swipe_child_into_view(self, child):44 def swipe_child_into_view(self, child):
@@ -68,15 +68,19 @@
68 def _get_top_container(self):68 def _get_top_container(self):
69 """Return the top-most container with a globalRect."""69 """Return the top-most container with a globalRect."""
70 root = self.get_root_instance()70 root = self.get_root_instance()
71 containers = [root]71 parent = self.get_parent()
72 while len(containers) == 1:72 top_container = None
73 try:73 while parent.id != root.id:
74 containers[0].globalRect74 if hasattr(parent, 'globalRect'):
75 return containers[0]75 top_container = parent
76 except AttributeError:76
77 containers = containers[0].get_children()77 parent = parent.get_parent()
7878
79 raise _common.ToolkitException("Couldn't find the top-most container.")79 if top_container is None:
80 raise _common.ToolkitException(
81 "Couldn't find the top-most container.")
82 else:
83 return top_container
8084
81 def _is_child_visible(self, child, containers):85 def _is_child_visible(self, child, containers):
82 """Check if the center of the child is visible.86 """Check if the center of the child is visible.
@@ -90,8 +94,35 @@
90 return (object_center >= visible_top and94 return (object_center >= visible_top and
91 object_center <= visible_bottom)95 object_center <= visible_bottom)
9296
97 def _slow_drag(self, start_x, stop_x, start_y, stop_y):
98 # If we drag too fast, we end up scrolling more than what we
99 # should, sometimes missing the element we are looking for.
100 # I found that when the flickDeceleration is 1500, the rate should be
101 # 5 and that when it's 100, the rate should be 1. With those two points
102 # we can get that the following equation.
103 rate = (self.flickDeceleration + 250) / 350
104 self.pointing_device.drag(start_x, start_y, stop_x, stop_y, rate=rate)
105
106
107class QQuickFlickable(Scrollable):
108
109 @autopilot_logging.log_action(logger.info)
110 def swipe_child_into_view(self, child):
111 """Make the child visible.
112
113 Currently it works only when the object needs to be swiped vertically.
114 TODO implement horizontal swiping. --elopio - 2014-03-21
115
116 """
117 containers = self._get_containers()
118 if not self._is_child_visible(child, containers):
119 self._swipe_non_visible_child_into_view(child, containers)
120 else:
121 logger.debug('The element is already visible.')
122
93 @autopilot_logging.log_action(logger.info)123 @autopilot_logging.log_action(logger.info)
94 def _swipe_non_visible_child_into_view(self, child, containers):124 def _swipe_non_visible_child_into_view(self, child, containers):
125 original_content_y = self.contentY
95 while not self._is_child_visible(child, containers):126 while not self._is_child_visible(child, containers):
96 # Check the direction of the swipe based on the position of the127 # Check the direction of the swipe based on the position of the
97 # child relative to the immediate flickable container.128 # child relative to the immediate flickable container.
@@ -100,6 +131,10 @@
100 else:131 else:
101 self._swipe_to_show_more_below(containers)132 self._swipe_to_show_more_below(containers)
102133
134 if self.contentY == original_content_y:
135 raise _common.ToolkitException(
136 "Couldn't swipe in the flickable.")
137
103 @autopilot_logging.log_action(logger.info)138 @autopilot_logging.log_action(logger.info)
104 def _swipe_to_show_more_above(self, containers):139 def _swipe_to_show_more_above(self, containers):
105 if self.atYBeginning:140 if self.atYBeginning:
@@ -124,8 +159,12 @@
124 # bottom.159 # bottom.
125 top = _get_visible_container_top(containers) + 5160 top = _get_visible_container_top(containers) + 5
126 bottom = _get_visible_container_bottom(containers) - 5161 bottom = _get_visible_container_bottom(containers) - 5
162
127 if direction == 'below':163 if direction == 'below':
128 start_y = bottom164 # Take into account that swiping from below can open the toolbar or
165 # trigger the bottom edge gesture.
166 # XXX Do this only if we are close to the bottom edge.
167 start_y = bottom - 20
129 stop_y = top168 stop_y = top
130 elif direction == 'above':169 elif direction == 'above':
131 start_y = top170 start_y = top
@@ -137,11 +176,6 @@
137 self.dragging.wait_for(False)176 self.dragging.wait_for(False)
138 self.moving.wait_for(False)177 self.moving.wait_for(False)
139178
140 def _slow_drag(self, start_x, stop_x, start_y, stop_y):
141 # If we drag too fast, we end up scrolling more than what we
142 # should, sometimes missing the element we are looking for.
143 self.pointing_device.drag(start_x, start_y, stop_x, stop_y, rate=5)
144
145 @autopilot_logging.log_action(logger.info)179 @autopilot_logging.log_action(logger.info)
146 def _scroll_to_top(self):180 def _scroll_to_top(self):
147 if not self.atYBeginning:181 if not self.atYBeginning:
148182
=== modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py'
--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py 2014-04-16 21:13:39 +0000
+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py 2014-05-09 04:12:47 +0000
@@ -19,22 +19,24 @@
19from autopilot import logging as autopilot_logging19from autopilot import logging as autopilot_logging
20from autopilot.introspection import dbus20from autopilot.introspection import dbus
2121
22from ubuntuuitoolkit._custom_proxy_objects import _flickable22from ubuntuuitoolkit._custom_proxy_objects import _common, _flickable
23from ubuntuuitoolkit._custom_proxy_objects import _common
24
2523
26logger = logging.getLogger(__name__)24logger = logging.getLogger(__name__)
2725
2826
29class QQuickListView(_flickable.Flickable):27class QQuickListView(_flickable.QQuickFlickable):
3028
31 @autopilot_logging.log_action(logger.info)29 @autopilot_logging.log_action(logger.info)
32 def click_element(self, object_name):30 def click_element(self, object_name, direction=None):
33 """Click an element from the list.31 """Click an element from the list.
3432
35 It swipes the element into view if it's center is not visible.33 It swipes the element into view if it's center is not visible.
3634
37 :parameter objectName: The objectName property of the element to click.35 :parameter objectName: The objectName property of the element to click.
36 :parameter direction: The direction where the element is, it can be
37 either 'above' or 'below'. Default value is None, which means we
38 don't know where the object is and we will need to search the full
39 list.
3840
39 """41 """
40 try:42 try:
@@ -42,16 +44,31 @@
42 except dbus.StateNotFoundError:44 except dbus.StateNotFoundError:
43 # The element might be on a part of the list that hasn't been45 # The element might be on a part of the list that hasn't been
44 # created yet. We have to search for it scrolling the entire list.46 # created yet. We have to search for it scrolling the entire list.
45 element = self._find_element(object_name)47 element = self._find_element(object_name, direction)
46 self.swipe_child_into_view(element)48 self.swipe_child_into_view(element)
47 self.pointing_device.click_object(element)49 self.pointing_device.click_object(element)
4850
49 @autopilot_logging.log_action(logger.info)51 @autopilot_logging.log_action(logger.info)
50 def _find_element(self, object_name):52 def _find_element(self, object_name, direction=None):
51 self._scroll_to_top()53 if direction is None:
52 while not self.atYEnd:54 # We don't know where the object is so we start looking for it from
53 containers = self._get_containers()55 # the top.
54 self._swipe_to_show_more_below(containers)56 self._scroll_to_top()
57 direction = 'below'
58
59 if direction == 'below':
60 fail_condition = lambda: self.atYEnd
61 swipe_method = self._swipe_to_show_more_below
62 elif direction == 'above':
63 fail_condition = lambda: self.atYBeginning
64 swipe_method = self._swipe_to_show_more_above
65 else:
66 raise _common.ToolkitException(
67 'Invalid direction: {}'.format(direction))
68
69 containers = self._get_containers()
70 while not fail_condition():
71 swipe_method(containers)
55 try:72 try:
56 return self.select_single(objectName=object_name)73 return self.select_single(objectName=object_name)
57 except dbus.StateNotFoundError:74 except dbus.StateNotFoundError:
5875
=== added file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/pickers.py'
--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/pickers.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/pickers.py 2014-05-09 04:12:47 +0000
@@ -0,0 +1,206 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Copyright (C) 2014 Canonical Ltd.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as published by
7# the Free Software Foundation; version 3.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import datetime
18import logging
19
20from autopilot import logging as autopilot_logging
21from autopilot.introspection import dbus
22
23from ubuntuuitoolkit._custom_proxy_objects import (
24 _common,
25 _flickable,
26 _qquicklistview
27)
28
29
30logger = logging.getLogger(__name__)
31
32
33class DatePicker(_common.UbuntuUIToolkitCustomProxyObjectBase):
34 """Autopilot helper for the DatePicker component."""
35
36 @autopilot_logging.log_action(logger.info)
37 def pick_date(self, date):
38 """Pick a date from the date picker.
39
40 :parameter date: The date to pick.
41 :type date: An object with year, month and day attributes, like
42 python's datetime.date.
43 :raises ubuntuuitoolkit.ToolkitException if the mode of the picker
44 doesn't let select a date.
45
46 """
47 if not self._is_date_picker():
48 raise _common.ToolkitException(
49 "Can't pick date. The picker mode is: {!r}.".format(self.mode))
50 if 'Years' in self.mode:
51 self._pick_year(date.year)
52 self.year.wait_for(date.year)
53 if 'Month' in self.mode:
54 # Python's date object starts at one. The model in the date picker
55 # at 0.
56 self._pick_month(date.month - 1)
57 self.month.wait_for(date.month - 1)
58 if 'Day' in self.mode:
59 self._pick_day(date.day)
60 self.day.wait_for(date.day)
61
62 def _is_date_picker(self):
63 mode = self.mode
64 if 'Years' in mode or 'Months' in mode or 'Days' in mode:
65 return True
66 else:
67 return False
68
69 @autopilot_logging.log_action(logger.info)
70 def _pick_year(self, year):
71 picker = self.select_single(
72 'Picker', objectName='PickerRow_YearPicker')
73 list_view = picker.select_single(
74 _qquicklistview.QQuickListView, objectName='Picker_Linear')
75 self._pick_date_value(self.year, year, list_view)
76
77 @autopilot_logging.log_action(logger.info)
78 def _pick_month(self, month):
79 picker = self.select_single(
80 'Picker', objectName='PickerRow_MonthPicker')
81 path_view = picker.select_single(
82 QQuickPathView, objectName='Picker_WrapAround')
83 self._pick_date_value(self.month, month, path_view)
84
85 @autopilot_logging.log_action(logger.info)
86 def _pick_day(self, day):
87 picker = self.select_single(
88 'Picker', objectName='PickerRow_DayPicker')
89 path_view = picker.select_single(
90 QQuickPathView, objectName='Picker_WrapAround')
91 # Python's date object starts at one. The model in the date picker
92 # at 0.
93 self._pick_date_value(self.get_date().day - 1, day - 1, path_view)
94
95 def _pick_date_value(self, current_value, new_value, scrollable):
96 if new_value > current_value:
97 direction = 'below'
98 elif new_value < current_value:
99 direction = 'above'
100 else:
101 logger.debug('The value is already selected.')
102 return
103 scrollable.click_element(
104 object_name='PickerRow_PickerLabel{}'.format(new_value),
105 direction=direction)
106
107 def get_date(self):
108 """Return the currently selected date.
109
110 :return: a python datetime.date object with the selected date.
111
112 """
113 # Python's date object starts at one. The model in the date picker
114 # at 0.
115 return datetime.date(
116 self.year, self.month + 1, self.day)
117
118
119class QQuickPathView(_flickable.Scrollable):
120
121 # TODO make it more general and move it to its own module.
122 # --elopio - 2014-05-06
123
124 @autopilot_logging.log_action(logger.info)
125 def click_element(self, object_name, direction='below'):
126 try:
127 element = self.select_single(objectName=object_name)
128 except dbus.StateNotFoundError:
129 # The element might be on a part of the list that hasn't been
130 # created yet. We have to search for it scrolling.
131 element = self._find_element(object_name, direction)
132 self.swipe_child_into_view(element)
133 self.pointing_device.click_object(element)
134
135 @autopilot_logging.log_action(logger.info)
136 def _find_element(self, object_name, direction):
137 containers = self._get_containers()
138 for index in range(self.count):
139 if direction == 'below':
140 swipe_method = self._swipe_to_show_one_more_below
141 elif direction == 'above':
142 swipe_method = self._swipe_to_show_one_more_above
143 else:
144 raise _common.ToolkitException(
145 'Invalid direction: {}'.format(direction))
146
147 swipe_method(containers)
148
149 try:
150 return self.select_single(objectName=object_name)
151 except dbus.StateNotFoundError:
152 pass
153 raise _common.ToolkitException(
154 'List element with objectName "{}" not found.'.format(object_name))
155
156 @autopilot_logging.log_action(logger.info)
157 def _swipe_to_show_one_more_above(self, containers):
158 self._swipe_to_show_one_more('above', containers)
159
160 @autopilot_logging.log_action(logger.info)
161 def _swipe_to_show_one_more_below(self, containers):
162 self._swipe_to_show_one_more('below', containers)
163
164 def _swipe_to_show_one_more(self, direction, containers):
165 start_x = stop_x = self.globalRect.x + (self.globalRect.width // 2)
166 center_y = self.globalRect.y + (self.globalRect.height // 2)
167 # XXX This assumes all the children are of the same height
168 child = self.get_children_by_type('PickerDelegate')[0]
169 top = center_y - (child.globalRect.height // 2)
170 bottom = center_y + (child.globalRect.height // 2)
171 if direction == 'below':
172 start_y = bottom
173 stop_y = top
174 elif direction == 'above':
175 start_y = top
176 stop_y = bottom
177 else:
178 raise _common.ToolkitException(
179 'Invalid direction {}.'.format(direction))
180 self._slow_drag(start_x, stop_x, start_y, stop_y)
181 self.dragging.wait_for(False)
182 self.moving.wait_for(False)
183
184 @autopilot_logging.log_action(logger.info)
185 def swipe_child_into_view(self, child):
186 """Make the child visible.
187
188 Currently it works only when the object needs to be swiped vertically.
189 TODO implement horizontal swiping. --elopio - 2014-03-21
190
191 """
192 containers = self._get_containers()
193 if not self._is_child_visible(child, containers):
194 self._swipe_non_visible_child_into_view(child, containers)
195 else:
196 logger.debug('The element is already visible.')
197
198 @autopilot_logging.log_action(logger.info)
199 def _swipe_non_visible_child_into_view(self, child, containers):
200 while not self._is_child_visible(child, containers):
201 # Check the direction of the swipe based on the position of the
202 # child relative to the immediate flickable container.
203 if child.globalRect.y < self.globalRect.y:
204 self._swipe_to_show_one_more_above(containers)
205 else:
206 self._swipe_to_show_one_more_below(containers)
0207
=== modified file 'tests/autopilot/ubuntuuitoolkit/emulators.py'
--- tests/autopilot/ubuntuuitoolkit/emulators.py 2014-04-25 18:39:51 +0000
+++ tests/autopilot/ubuntuuitoolkit/emulators.py 2014-05-09 04:12:47 +0000
@@ -36,12 +36,12 @@
36 'CheckBox',36 'CheckBox',
37 'ComposerSheet',37 'ComposerSheet',
38 'Empty',38 'Empty',
39 'Flickable',
40 'Header',39 'Header',
41 'ItemSelector',40 'ItemSelector',
42 'MainView',41 'MainView',
43 'MultiValue',42 'MultiValue',
44 'OptionSelector',43 'OptionSelector',
44 'QQuickFlickable',
45 'QQuickListView',45 'QQuickListView',
46 'SingleControl',46 'SingleControl',
47 'SingleValue',47 'SingleValue',
@@ -61,10 +61,10 @@
61 get_keyboard,61 get_keyboard,
62 get_pointing_device,62 get_pointing_device,
63 CheckBox,63 CheckBox,
64 Flickable,
65 Header,64 Header,
66 MainView,65 MainView,
67 OptionSelector,66 OptionSelector,
67 QQuickFlickable,
68 QQuickListView,68 QQuickListView,
69 TabBar,69 TabBar,
70 Tabs,70 Tabs,
7171
=== added file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_date_picker.py'
--- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_date_picker.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_date_picker.py 2014-05-09 04:12:47 +0000
@@ -0,0 +1,147 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Copyright (C) 2014 Canonical Ltd.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as published by
7# the Free Software Foundation; version 3.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import datetime
18
19import ubuntuuitoolkit
20from ubuntuuitoolkit import pickers, tests
21
22
23class DatePickerBaseTestCase(tests.QMLStringAppTestCase):
24
25 test_qml = ("""
26import QtQuick 2.0
27import Ubuntu.Components 1.1
28import Ubuntu.Components.Pickers 1.0
29
30MainView {
31 width: units.gu(48)
32 height: units.gu(60)
33
34 Column {
35 DatePicker {
36 id: datePicker
37 objectName: 'datePicker'
38 mode: 'Years|Months|Days'
39 date: {
40 var d = new Date()
41 // Make sure that the picker will have higher and lower values
42 // to select.
43 d.setFullYear(d.getFullYear() + 25)
44 d.setMonth('5')
45 d.setDate('15')
46 return d
47 }
48 }
49 DatePicker {
50 id: timePicker
51 objectName: 'timePicker'
52 mode: 'Hours|Minutes|Seconds'
53 }
54 }
55}
56""")
57
58 def setUp(self):
59 super(DatePickerBaseTestCase, self).setUp()
60 self.date_picker = self.main_view.select_single(
61 pickers.DatePicker, objectName='datePicker')
62
63
64class DatePickerTestCase(DatePickerBaseTestCase):
65
66 def test_select_date_picker_must_return_custom_proxy_object(self):
67 self.assertIsInstance(
68 self.date_picker, pickers.DatePicker)
69
70 def test_pick_date_on_time_picker_must_raise_exception(self):
71 time_picker = self.main_view.select_single(
72 pickers.DatePicker, objectName='timePicker')
73 error = self.assertRaises(
74 ubuntuuitoolkit.ToolkitException, time_picker.pick_date, 'dummy')
75 self.assertEqual(
76 str(error),
77 "Can't pick date. The picker mode is: {!r}.".format(
78 time_picker.mode))
79
80 def test_swipe_to_show_one_more_below_must_select_next_index(self):
81 """Test that we don't end up swiping more than needed.
82
83 This would cause us to miss the element we are looking for, and to have
84 to swipe many times in order to finally click it.
85
86 """
87 picker = self.main_view.select_single(
88 'Picker', objectName='PickerRow_DayPicker')
89 path_view = picker.select_single(
90 pickers.QQuickPathView, objectName='Picker_WrapAround')
91 current_index = path_view.currentIndex
92
93 path_view._swipe_to_show_one_more_below(path_view._get_containers())
94
95 self.assertEqual(path_view.currentIndex, current_index + 1)
96
97 def test_swipe_to_show_one_more_above_must_select_previous_index(self):
98 """Test that we don't end up swiping more than needed.
99
100 This would cause us to miss the element we are looking for, and to have
101 to swipe many times in order to finally click it.
102
103 """
104 picker = self.main_view.select_single(
105 'Picker', objectName='PickerRow_DayPicker')
106 path_view = picker.select_single(
107 pickers.QQuickPathView, objectName='Picker_WrapAround')
108 current_index = path_view.currentIndex
109
110 path_view._swipe_to_show_one_more_above(path_view._get_containers())
111
112 self.assertEqual(path_view.currentIndex, current_index - 1)
113
114
115class PickDateFromDatePickerTestCase(DatePickerBaseTestCase):
116
117 SELECTED_YEAR = datetime.date.today().year + 25
118 SELECTED_MONTH = 6 # June
119 SELECTED_DAY = 15
120
121 scenarios = [
122 ('higher year', {
123 'date_to_pick': datetime.date(
124 SELECTED_YEAR + 10, SELECTED_MONTH, SELECTED_DAY)}),
125 ('lower year', {
126 'date_to_pick': datetime.date(
127 SELECTED_YEAR - 10, SELECTED_MONTH, SELECTED_DAY)}),
128 ('higher month', {
129 'date_to_pick': datetime.date(
130 SELECTED_YEAR, SELECTED_MONTH + 4, SELECTED_DAY)}),
131 ('lower month', {
132 'date_to_pick': datetime.date(
133 SELECTED_YEAR, SELECTED_MONTH - 4, SELECTED_DAY)}),
134 ('higher day', {
135 'date_to_pick': datetime.date(
136 SELECTED_YEAR, SELECTED_MONTH, SELECTED_DAY + 10)}),
137 ('lower day', {
138 'date_to_pick': datetime.date(
139 SELECTED_YEAR, SELECTED_MONTH, SELECTED_DAY - 10)}),
140 ('change all value', {
141 'date_to_pick': datetime.date(
142 SELECTED_YEAR - 10, SELECTED_MONTH + 4, SELECTED_DAY - 10)}),
143 ]
144
145 def test_pick_date(self):
146 self.date_picker.pick_date(self.date_to_pick)
147 self.assertEqual(self.date_picker.get_date(), self.date_to_pick)
0148
=== added file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_flickable.py'
--- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_flickable.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_flickable.py 2014-05-09 04:12:47 +0000
@@ -0,0 +1,197 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Copyright (C) 2014 Canonical Ltd.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as published by
7# the Free Software Foundation; version 3.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
18import testtools
19
20import ubuntuuitoolkit
21from ubuntuuitoolkit import tests
22from ubuntuuitoolkit._custom_proxy_objects import _common
23
24
25class FlickableTestCase(testtools.TestCase):
26
27 def test_get_unity_top_container(self):
28 """Test that we can get the top cointainer in Unity."""
29 # This tests bug http://pad.lv/1314390
30 # On Unity, the top container is not the first child as it is in all
31 # the apps that have a MainView. This makes the first implementation of
32 # _get_top_container fail. Instead of going from the top looking for
33 # a container, we should start from the flickable until we find the
34 # top-most container.
35 RootClass = type('obj', (object,), {'id': 'root'})
36 mock_root_instance = RootClass()
37 # We consider a container is an object with a globalRect.
38 MockNonContainerClass = type('obj', (object,), {})
39 mock_non_container = MockNonContainerClass()
40 MockContainerClass = type(
41 'obj', (object,), {'id': 'container', 'globalRect': 'dummy'})
42 mock_container = MockContainerClass()
43 mock_container.get_parent = lambda: mock_root_instance
44
45 # The root instance has two children. This exposes the bug.
46 mock_root_instance.get_children = lambda: [
47 mock_non_container, mock_container]
48
49 dummy_state = {'id': '10'}
50 flickable = ubuntuuitoolkit.QQuickFlickable(
51 dummy_state, 'dummy', 'dummy')
52
53 flickable.get_root_instance = lambda: mock_root_instance
54 # The top container of the flickable is its immediate parent.
55 flickable.get_parent = lambda: mock_container
56
57 top_container = flickable._get_top_container()
58 self.assertEqual(top_container, mock_container)
59
60 def test_is_flickable_with_flicking_property_must_return_true(self):
61 """is_flickable returns True if flickable property exists."""
62 dummy_id = (0, 0)
63 dummy_flicking = (0, 'dummy')
64 state_with_flicking = {'id': dummy_id, 'flicking': dummy_flicking}
65 element = _common.UbuntuUIToolkitCustomProxyObjectBase(
66 state_with_flicking, 'dummy', 'dummy')
67 with element.no_automatic_refreshing():
68 self.assertTrue(element.is_flickable())
69
70 def test_is_flickable_without_flicking_property_must_return_false(self):
71 """is_flickable returns False if flickable property doesn't exist."""
72 dummy_id = (0, 0)
73 state_without_flicking = {'id': dummy_id}
74 element = _common.UbuntuUIToolkitCustomProxyObjectBase(
75 state_without_flicking, 'dummy', 'dummy')
76 with element.no_automatic_refreshing():
77 self.assertFalse(element.is_flickable())
78
79
80class IsFlickableTestCase(tests.QMLStringAppTestCase):
81 """Functional test to check that is_flickable returns the right value.
82
83 We already have tests for is_flickable with mocks, so here we just check
84 with some real elements.
85
86 """
87
88 test_qml = ("""
89import QtQuick 2.0
90import Ubuntu.Components 0.1
91import Ubuntu.Components.ListItems 0.1 as ListItem
92
93MainView {
94 objectName: 'mainView'
95 width: units.gu(48)
96 height: units.gu(60)
97
98 Flickable {
99 objectName: 'flickable'
100 }
101 ListView {
102 objectName: 'listView'
103 }
104 Label {
105 objectName: 'label'
106 }
107}
108""")
109
110 scenarios = [
111 ('main view', dict(object_name='mainView', is_flickable=False)),
112 ('flickable', dict(object_name='flickable', is_flickable=True)),
113 ('list view', dict(object_name='listView', is_flickable=True)),
114 ('label', dict(object_name='label', is_flickable=False))
115 ]
116
117 def test_is_flickable(self):
118 """Test that is_flickable identifies the elements correctly."""
119 element = self.app.select_single(objectName=self.object_name)
120 self.assertEqual(element.is_flickable(), self.is_flickable)
121
122
123class SwipeIntoViewTestCase(tests.QMLStringAppTestCase):
124
125 test_qml = ("""
126import QtQuick 2.0
127import Ubuntu.Components 0.1
128
129MainView {
130 width: units.gu(48)
131 height: units.gu(60)
132
133 Label {
134 id: clickedLabel
135 objectName: "clickedLabel"
136 text: "No element clicked."
137 }
138
139 Flickable {
140 anchors {
141 fill: parent
142 topMargin: clickedLabel.height
143 // It can't be at the bottom, or the toolbar will be opened
144 // when we try to click it.
145 bottomMargin: units.gu(10)
146 }
147 objectName: 'flickable'
148 height: units.gu(60)
149 contentHeight: bottomButton.y + bottomButton.height
150
151 Button {
152 id: topButton
153 objectName: 'topButton'
154 text: 'Top button'
155 onClicked: clickedLabel.text = objectName
156 }
157 Rectangle {
158 id: emptyRectangle
159 height: units.gu(80)
160 anchors.top: topButton.bottom
161 }
162 Button {
163 id: bottomButton
164 objectName: 'bottomButton'
165 text: 'Bottom button'
166 onClicked: clickedLabel.text = objectName
167 anchors.top: emptyRectangle.bottom
168 }
169 }
170}
171""")
172
173 def setUp(self):
174 super(SwipeIntoViewTestCase, self).setUp()
175 self.label = self.main_view.select_single(
176 'Label', objectName='clickedLabel')
177 self.assertEqual(self.label.text, 'No element clicked.')
178
179 def test_swipe_to_bottom(self):
180 self.main_view.close_toolbar()
181
182 button = self.main_view.select_single(objectName='bottomButton')
183 button.swipe_into_view()
184
185 self.pointing_device.click_object(button)
186 self.assertEqual(self.label.text, 'bottomButton')
187
188 def test_swipe_to_top(self):
189 self.main_view.close_toolbar()
190 bottomButton = self.main_view.select_single(objectName='bottomButton')
191 bottomButton.swipe_into_view()
192
193 topButton = self.main_view.select_single(objectName='topButton')
194 topButton.swipe_into_view()
195
196 self.pointing_device.click_object(topButton)
197 self.assertEqual(self.label.text, 'topButton')
0198
=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py'
--- tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py 2014-04-28 15:39:24 +0000
+++ tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py 2014-05-09 04:12:47 +0000
@@ -32,7 +32,7 @@
3232
33 symbols_retaining_name = [33 symbols_retaining_name = [
34 'check_autopilot_version', 'get_keyboard', 'get_pointing_device',34 'check_autopilot_version', 'get_keyboard', 'get_pointing_device',
35 'CheckBox', 'Flickable', 'Header', 'MainView', 'OptionSelector',35 'CheckBox', 'Header', 'MainView', 'OptionSelector', 'QQuickFlickable',
36 'QQuickListView', 'TabBar', 'Tabs', 'TextField', 'Toolbar',36 'QQuickListView', 'TabBar', 'Tabs', 'TextField', 'Toolbar',
37 ]37 ]
3838

Subscribers

People subscribed via source and target branches