on xenial help sign in
Added methods to scroll to other scopes on autopilot tests.

Approved by PS Jenkins bot, Albert Astals Cid, Richard Huddie.

commit93a38dbe421d95bd7cc570cf960b5912b0b1c939 authorLeo Arias <leo.arias@canonical.com> dateFri 10 Jan 2014, 15:40 (13 years ago) parent11ac636216c5e3
5 files changed+236−17
debian/control+1 tests/autopilot/unity8/shell/emulators/__init__.py+11−4 tests/autopilot/unity8/shell/emulators/dash.py+102−8 tests/autopilot/unity8/shell/emulators/greeter.py+2−5 tests/autopilot/unity8/shell/tests/test_emulators.py+120
debian/control+1
@@ -104,6 +104,7 @@ Depends: gir1.2-glib-2.0,
104104 libqt5widgets5,
105105 python-evdev,
106106 python-gi,
107+ python-mock,
107108 unity8 (>= ${source:Version}),
108109 unity8-fake-env (>= ${source:Version}),
109110 ${misc:Depends},
tests/autopilot/unity8/shell/emulators/__init__.py+11−4
@@ -1,7 +1,7 @@
11# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
22#
33# Unity Autopilot Test Suite
4−# Copyright (C) 2012-2013 Canonical
4+# Copyright (C) 2012, 2013, 2014 Canonical
55#
66# This program is free software: you can redistribute it and/or modify
77# it under the terms of the GNU General Public License as published by
@@ -17,9 +17,16 @@
1717# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818#
1919
20+from autopilot import input, introspection
2021
21−from autopilot.introspection import CustomEmulatorBase
2222
23−
24−class UnityEmulatorBase(CustomEmulatorBase):
23+class UnityEmulatorBase(introspection.CustomEmulatorBase):
2524 """A base class for all unity emulators."""
25+
26+ def __init__(self, *args):
27+ super(UnityEmulatorBase, self).__init__(*args)
28+ self.pointing_device = input.Touch.create()
29+
30+
31+class UnityEmulatorException(Exception):
32+ """Exception raised when there is an error with the Unity emulators."""
tests/autopilot/unity8/shell/emulators/dash.py+102−8
@@ -1,7 +1,7 @@
11# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
22#
33# Unity Autopilot Test Suite
4−# Copyright (C) 2012-2013 Canonical
4+# Copyright (C) 2012, 2013, 2014 Canonical
55#
66# This program is free software: you can redistribute it and/or modify
77# it under the terms of the GNU General Public License as published by
@@ -17,13 +17,25 @@
1717# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818#
1919
20−from unity8.shell.emulators import UnityEmulatorBase
20+import logging
2121
22+from unity8.shell import emulators
2223
23−class Dash(UnityEmulatorBase):
24+from autopilot import logging as autopilot_logging
25+from autopilot.introspection import dbus
2426
27+
28+logger = logging.getLogger(__name__)
29+
30+
31+class Dash(emulators.UnityEmulatorBase):
2532 """An emulator that understands the Dash."""
2633
34+ def __init__(self, *args):
35+ super(Dash, self).__init__(*args)
36+ self.dash_content_list = self.wait_select_single(
37+ 'QQuickListView', objectName='dashContentList')
38+
2739 def get_home_applications_grid(self):
2840 get_grid = self.get_scope('home').wait_select_single(
2941 "GenericFilterGrid",
@@ -43,9 +55,91 @@ class Dash(UnityEmulatorBase):
4355 return resp_grid.select_single('Tile', text=text)
4456
4557 def get_scope(self, scope_name='home'):
46− dash_content = self.wait_select_single(
47− 'QQuickListView',
48− objectName='dashContentList'
49− )
5058 scope_id = "%s.scope" % scope_name
51− return dash_content.select_single('QQuickLoader', scopeId=scope_id)
59+ return self.dash_content_list.select_single(
60+ 'QQuickLoader', scopeId=scope_id)
61+
62+ @autopilot_logging.log_action(logger.info)
63+ def open_scope(self, scope_name):
64+ """Open a dash scope.
65+
66+ :parameter scope_name: The name of the scope.
67+ :return: The scope.
68+
69+ """
70+ scope_id = "%s.scope" % scope_name
71+ scope_loader = self._get_scope_loader(scope_id)
72+ if scope_loader.isCurrent:
73+ logger.info('The scope is already open.')
74+ return self._get_scope_from_loader(scope_loader)
75+ else:
76+ return self._open_scope_scrolling(scope_loader)
77+
78+ def _get_scope_loader(self, scope_id):
79+ try:
80+ return self.dash_content_list.select_single(
81+ 'QQuickLoader', scopeId=scope_id)
82+ except dbus.StateNotFoundError:
83+ raise emulators.UnityEmulatorException(
84+ 'No scope found with id {0}'.format(scope_id))
85+
86+ def _get_scope_from_loader(self, loader):
87+ if loader.scopeId == 'applications.scope':
88+ return loader.select_single(DashApps)
89+ else:
90+ return loader.select_single(GenericScopeView)
91+
92+ def _open_scope_scrolling(self, scope_loader):
93+ scroll = self._get_scroll_direction(scope_loader)
94+
95+ while not scope_loader.isCurrent:
96+ scroll()
97+
98+ scope = self._get_scope_from_loader(scope_loader)
99+ scope.moving.wait_for(False)
100+ scope.isCurrent.wait_for(True)
101+ return scope
102+
103+ def _get_scroll_direction(self, scope_loader):
104+ current_scope_loader = self.dash_content_list.select_single(
105+ 'QQuickLoader', isCurrent=True)
106+ if scope_loader.globalRect.x < current_scope_loader.globalRect.x:
107+ return self._scroll_to_left_scope
108+ elif scope_loader.globalRect.x > current_scope_loader.globalRect.x:
109+ return self._scroll_to_right_scope
110+ else:
111+ raise emulators.UnityEmulatorException('The scope is already open')
112+
113+ @autopilot_logging.log_action(logger.info)
114+ def _scroll_to_left_scope(self):
115+ original_index = self.dash_content_list.currentIndex
116+ # Scroll on the border of the page header, because some scopes have
117+ # contents that can be scrolled horizontally.
118+ page_header = self.select_single('PageHeader')
119+ border = page_header.select_single('QQuickBorderImage')
120+ start_x = border.width / 3
121+ stop_x = border.width / 3 * 2
122+ start_y = stop_y = border.globalRect.y + border.height / 2
123+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
124+ self.dash_content_list.currentIndex.wait_for(original_index - 1)
125+
126+ @autopilot_logging.log_action(logger.info)
127+ def _scroll_to_right_scope(self):
128+ original_index = self.dash_content_list.currentIndex
129+ # Scroll on the border of the page header, because some scopes have
130+ # contents that can be scrolled horizontally.
131+ page_header = self.select_single('PageHeader')
132+ border = page_header.select_single('QQuickBorderImage')
133+ start_x = border.width / 3 * 2
134+ stop_x = border.width / 3
135+ start_y = stop_y = border.globalRect.y + border.height / 2
136+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
137+ self.dash_content_list.currentIndex.wait_for(original_index + 1)
138+
139+
140+class GenericScopeView(emulators.UnityEmulatorBase):
141+ """Autopilot emulators for generic scopes."""
142+
143+
144+class DashApps(emulators.UnityEmulatorBase):
145+ """Autopilot emulators for the applications scope."""
tests/autopilot/unity8/shell/emulators/greeter.py+2−5
@@ -1,7 +1,7 @@
11# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
22#
33# Unity Autopilot Test Suite
4−# Copyright (C) 2012-2013 Canonical
4+# Copyright (C) 2012, 2013, 2014 Canonical
55#
66# This program is free software: you can redistribute it and/or modify
77# it under the terms of the GNU General Public License as published by
@@ -18,24 +18,21 @@
1818#
1919
2020from unity8.shell.emulators import UnityEmulatorBase
21−from autopilot.input import Touch
2221
2322
2423class Greeter(UnityEmulatorBase):
25−
2624 """An emulator that understands the greeter screen."""
2725
2826 def swipe(self):
2927 """Swipe the greeter screen away."""
3028 self.created.wait_for(True)
31− touch = Touch.create()
3229
3330 rect = self.globalRect
3431 start_x = rect[0] + rect[2] - 3
3532 start_y = int(rect[1] + rect[3] / 2)
3633 stop_x = int(rect[0] + rect[2] * 0.2)
3734 stop_y = start_y
38− touch.drag(start_x, start_y, stop_x, stop_y)
35+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
3936
4037 self.created.wait_for(False)
4138
tests/autopilot/unity8/shell/tests/test_emulators.pynew file+120
@@ -0,0 +1,120 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2014 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+import mock
21+
22+from unity8 import process_helpers
23+from unity8.shell import emulators, tests
24+from unity8.shell.emulators import dash as dash_emulators
25+
26+
27+class DashEmulatorTestCase(tests.UnityTestCase):
28+
29+ scenarios = tests._get_device_emulation_scenarios()
30+
31+ def setUp(self):
32+ super(DashEmulatorTestCase, self).setUp()
33+ unity_proxy = self.launch_unity()
34+ process_helpers.unlock_unity(unity_proxy)
35+ self.dash = self.main_window.get_dash()
36+
37+ def test_open_unexisting_scope(self):
38+ scope_name = 'unexisting'
39+ with mock.patch.object(self.dash, 'pointing_device') as mock_pointer:
40+ exception = self.assertRaises(
41+ emulators.UnityEmulatorException,
42+ self.dash.open_scope, scope_name)
43+
44+ self.assertEqual(
45+ 'No scope found with id unexisting.scope', str(exception))
46+ self.assertFalse(mock_pointer.called)
47+
48+ def test_open_already_opened_scope(self):
49+ scope_id = self._get_current_scope_id()
50+ with mock.patch.object(self.dash, 'pointing_device') as mock_pointer:
51+ scope = self.dash.open_scope(self._get_scope_name_from_id(
52+ scope_id))
53+
54+ self.assertFalse(mock_pointer.called)
55+ self._assert_scope_is_opened(scope, scope_id)
56+
57+ def _assert_scope_is_opened(self, scope, scope_id):
58+ self.assertTrue(scope.isCurrent)
59+ scope_loader = scope.get_parent()
60+ self.assertEqual(scope_loader.scopeId, scope_id)
61+
62+ def _get_current_scope_id(self):
63+ scope = self.dash.dash_content_list.select_single(
64+ 'QQuickLoader', isCurrent=True)
65+ return scope.scopeId
66+
67+ def test_open_scope_to_the_right(self):
68+ leftmost_scope = self._get_scope_name_from_id(
69+ self._get_leftmost_scope_id())
70+ self.dash.open_scope(leftmost_scope)
71+
72+ scope_id = self._get_rightmost_scope_id()
73+ scope = self.dash.open_scope(self._get_scope_name_from_id(scope_id))
74+ self._assert_scope_is_opened(scope, scope_id)
75+
76+ def _get_leftmost_scope_id(self):
77+ scope_loaders = self._get_scope_loaders()
78+ leftmost_scope_loader = scope_loaders[0]
79+ for loader in scope_loaders[1:]:
80+ if loader.globalRect.x < leftmost_scope_loader.globalRect.x:
81+ leftmost_scope_loader = loader
82+ return leftmost_scope_loader.scopeId
83+
84+ def _get_scope_loaders(self):
85+ item = self.dash.dash_content_list.get_children_by_type(
86+ 'QQuickItem')[0]
87+ return item.get_children_by_type('QQuickLoader')
88+
89+ def _get_scope_name_from_id(self, scope_id):
90+ if scope_id.endswith('.scope'):
91+ return scope_id[:-6]
92+
93+ def _get_rightmost_scope_id(self):
94+ scope_loaders = self._get_scope_loaders()
95+ rightmost_scope_loader = scope_loaders[0]
96+ for loader in scope_loaders[1:]:
97+ if loader.globalRect.x > rightmost_scope_loader.globalRect.x:
98+ rightmost_scope_loader = loader
99+ return rightmost_scope_loader.scopeId
100+
101+ def test_open_scope_to_the_left(self):
102+ rightmost_scope = self._get_scope_name_from_id(
103+ self._get_rightmost_scope_id())
104+ self.dash.open_scope(rightmost_scope)
105+
106+ scope_id = self._get_leftmost_scope_id()
107+ scope = self.dash.open_scope(self._get_scope_name_from_id(scope_id))
108+ self._assert_scope_is_opened(scope, scope_id)
109+
110+ def test_open_generic_scope(self):
111+ scope_id = 'home.scope'
112+ scope = self.dash.open_scope(self._get_scope_name_from_id(scope_id))
113+ self._assert_scope_is_opened(scope, scope_id)
114+ self.assertIsInstance(scope, dash_emulators.GenericScopeView)
115+
116+ def test_open_applications_scope(self):
117+ scope_id = 'applications.scope'
118+ scope = self.dash.open_scope(self._get_scope_name_from_id(scope_id))
119+ self._assert_scope_is_opened(scope, scope_id)
120+ self.assertIsInstance(scope, dash_emulators.DashApps)