Merge lp:~om26er/ubuntu-calendar-app/autopilot_tests_bootstrap into lp:ubuntu-calendar-app

Proposed by Omer Akram
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 43
Merged at revision: 36
Proposed branch: lp:~om26er/ubuntu-calendar-app/autopilot_tests_bootstrap
Merge into: lp:ubuntu-calendar-app
Diff against target: 284 lines (+196/-0)
8 files modified
NewEvent.qml (+6/-0)
debian/control (+9/-0)
debian/ubuntu-calendar-app-autopilot.install (+1/-0)
tests/autopilot/ubuntu_calendar_app/__init__.py (+8/-0)
tests/autopilot/ubuntu_calendar_app/emulators/__init__.py (+6/-0)
tests/autopilot/ubuntu_calendar_app/emulators/main_window.py (+62/-0)
tests/autopilot/ubuntu_calendar_app/tests/__init__.py (+67/-0)
tests/autopilot/ubuntu_calendar_app/tests/test_calendar.py (+37/-0)
To merge this branch: bzr merge lp:~om26er/ubuntu-calendar-app/autopilot_tests_bootstrap
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Olivier Tilloy (community) Approve
Ubuntu Calendar Developers Pending
Review via email: mp+165901@code.launchpad.net

Commit message

Initial autopilot structure

Description of the change

Initial autopilot structure

To post a comment you must log in.
Revision history for this message
Olivier Tilloy (osomon) wrote :

32 +# Copyright 2012 Canonical

All the copyright notices say 2012, they should be updated to 2013.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

163 +class CalendarTestCase(CalendarTestCase):

It looks unwise to give a class the exact same name as its parent.

As a suggestion, in the webbrowser-app, the names of all the actual test cases begin with "Test", e.g.:

    class TestWindowTitle(BrowserTestCaseBase):

Feel free to choose a different naming scheme, but in any case do not use the same name as the base class.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

173 + def test_this(self):
174 + print "Now start writing your tests"

How about writing a very simple test case that actually tests something, to give a starting point to other developers? It could be something as simple as asserting that when the app starts, the default view is visible (the calendar app has several types of views).

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

Warnings raised by pyflakes:

  tests/autopilot/ubuntu_calendar_app/tests/__init__.py:13: 'Eventually' imported but unused
  tests/autopilot/ubuntu_calendar_app/tests/__init__.py:16: 'Equals' imported but unused
  tests/autopilot/ubuntu_calendar_app/tests/test_calendar.py:13: 'model' imported but unused

Warnings raised by pep8:

  tests/autopilot/ubuntu_calendar_app/tests/__init__.py:52:80: E501 line too long (86 > 79 characters)

review: Needs Fixing
37. By Omer Akram

year is 2013 now

38. By Omer Akram

rename test class

39. By Omer Akram

fix pyflakes warnings

40. By Omer Akram

add autopilot test for NewEvent dialog

41. By Omer Akram

fix more

Revision history for this message
Omer Akram (om26er) wrote :

> Warnings raised by pyflakes:
>
> tests/autopilot/ubuntu_calendar_app/tests/__init__.py:13: 'Eventually'
> imported but unused
> tests/autopilot/ubuntu_calendar_app/tests/__init__.py:16: 'Equals' imported
> but unused
> tests/autopilot/ubuntu_calendar_app/tests/test_calendar.py:13: 'model'
> imported but unused
>
>
>
> Warnings raised by pep8:
>
> tests/autopilot/ubuntu_calendar_app/tests/__init__.py:52:80: E501 line too
> long (86 > 79 characters)

Thanks for the review, I have now made the changes as you suggested.

Revision history for this message
Olivier Tilloy (osomon) wrote :

133 + def get_new_event_button(self):
134 + return self.app.select_many("Button", visible=True)[1]
135 +
136 + def get_timeline_button(self):
137 + return self.app.select_many("Button", visible=True)[2]

That’s not robust, instead you should give an objectName to those buttons and get a reference to them using self.app.select_single("Button", objectName="…").

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

224 + x, y, h, w = toolbar.globalRect
225 + tx = x + (h / 2)
226 + ty = y + (w - 2)

If I’m not mistaken the globalRect tuple contains, in this order: x, y, width, height. Using 'h' for width and 'w' for height is very confusing.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

ensure_toolbar_visible() works if the toolbar is initially hidden, but will it work if it’s already shown? If not, either the method should be renamed ('ensure' implies that the toolbar will be shown after executing it, regardless of the initial state), or it should account for all possible initial states.

Revision history for this message
Omer Akram (om26er) wrote :

> 133 + def get_new_event_button(self):
> 134 + return self.app.select_many("Button", visible=True)[1]
> 135 +
> 136 + def get_timeline_button(self):
> 137 + return self.app.select_many("Button", visible=True)[2]
>
> That’s not robust, instead you should give an objectName to those buttons and
> get a reference to them using self.app.select_single("Button",
> objectName="…").

That's the problem, I have not been able to assign objectNames to those buttons, it seems that doesn't work there.

Revision history for this message
Olivier Tilloy (osomon) wrote :

> > 133 + def get_new_event_button(self):
> > 134 + return self.app.select_many("Button", visible=True)[1]
> > 135 +
> > 136 + def get_timeline_button(self):
> > 137 + return self.app.select_many("Button", visible=True)[2]
> >
> > That’s not robust, instead you should give an objectName to those buttons
> and
> > get a reference to them using self.app.select_single("Button",
> > objectName="…").
>
> That's the problem, I have not been able to assign objectNames to those
> buttons, it seems that doesn't work there.

What’s the error you’re getting? If it’s an issue in autopilot itself, we should make sure it’s reported and fixed, not just worked around silently.

Revision history for this message
Olivier Tilloy (osomon) wrote :

266 + def test_new_event_page(self):

In its current state, it’s not a very useful test, it doesn’t verify that the event gets actually created, could you please update it to do that?

Revision history for this message
Omer Akram (om26er) wrote :

> > > 133 + def get_new_event_button(self):
> > > 134 + return self.app.select_many("Button", visible=True)[1]
> > > 135 +
> > > 136 + def get_timeline_button(self):
> > > 137 + return self.app.select_many("Button", visible=True)[2]
> > >
> > > That’s not robust, instead you should give an objectName to those buttons
> > and
> > > get a reference to them using self.app.select_single("Button",
> > > objectName="…").
> >
> > That's the problem, I have not been able to assign objectNames to those
> > buttons, it seems that doesn't work there.
>
> What’s the error you’re getting? If it’s an issue in autopilot itself, we
> should make sure it’s reported and fixed, not just worked around silently.

I don't think the issue is with autopilot, I am trying this patch http://paste.ubuntu.com/5713531/ to set objectName but it seems I cannot find any thing in autopilot vis with that objectName.

42. By Omer Akram

write a simple autopilot test instead of a complex one

Revision history for this message
Omer Akram (om26er) wrote :

Now I am using a more "reliable" approach to select object, I have written a much simpler test as you suggested on IRC and also renamed ensure_toolbar_visible()

Revision history for this message
Olivier Tilloy (osomon) wrote :

133 + def get_toolbar_button(self, button_idx):
134 + toolbar = self.app.select_single("Toolbar")
135 + item = toolbar.get_children_by_type("QQuickItem")[0]
136 + row = item.get_children_by_type("QQuickRow")[0]
137 + button_loaders = row.get_children_by_type("QQuickLoader")
138 + button_loader = button_loaders[button_idx]
139 + return button_loader

This can be greatly simplified:

    def get_toolbar_button(self, button_idx):
        toolbar = self.app.select_single("Toolbar")
        row = toolbar.select_single("QQuickRow")
        buttons = row.select_many("Button")
        return buttons[button_idx]

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

277 + def test_timline_view_shows(self):

typo: timline

review: Needs Fixing
43. By Omer Akram

fix per suggestions

Revision history for this message
Omer Akram (om26er) wrote :

> 133 + def get_toolbar_button(self, button_idx):
> 134 + toolbar = self.app.select_single("Toolbar")
> 135 + item = toolbar.get_children_by_type("QQuickItem")[0]
> 136 + row = item.get_children_by_type("QQuickRow")[0]
> 137 + button_loaders = row.get_children_by_type("QQuickLoader")
> 138 + button_loader = button_loaders[button_idx]
> 139 + return button_loader
>
> This can be greatly simplified:
>
> def get_toolbar_button(self, button_idx):
> toolbar = self.app.select_single("Toolbar")
> row = toolbar.select_single("QQuickRow")
> buttons = row.select_many("Button")
> return buttons[button_idx]

Done. Tested the change as well.

Revision history for this message
Olivier Tilloy (osomon) wrote :

Looks good now.

review: Approve
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NewEvent.qml'
2--- NewEvent.qml 2013-03-29 23:12:40 +0000
3+++ NewEvent.qml 2013-05-29 16:41:23 +0000
4@@ -21,6 +21,7 @@
5 ListItem.Empty {
6 highlightWhenPressed: false
7 TextField {
8+ objectName: "newEventName"
9 id: titleEdit
10 placeholderText: i18n.tr("Add event name")
11 anchors {
12@@ -69,6 +70,7 @@
13 anchors.left: timeContainer.left
14 width: units.gu(12)
15 TextField {
16+ objectName: "startTimeInput"
17 id: startTimeEdit
18 text: Qt.formatDateTime(defaultDate,"hh")
19 anchors {
20@@ -84,6 +86,7 @@
21 anchors.right: timeContainer.right
22 width: units.gu(12)
23 TextField {
24+ objectName: "endTimeInput"
25 id: endTimeEdit
26 text: Qt.formatDateTime(defaultDate,"hh")
27 anchors {
28@@ -100,6 +103,7 @@
29 ListItem.Empty {
30 highlightWhenPressed: false
31 TextField {
32+ objectName: "eventLocationInput"
33 id: locationEdit
34 placeholderText: i18n.tr("Add Location")
35 anchors {
36@@ -113,6 +117,7 @@
37 ListItem.Empty {
38 highlightWhenPressed: false
39 TextField {
40+ objectName: "eventPeopleInput"
41 id: personEdit
42 placeholderText: i18n.tr("Invite People")
43 anchors {
44@@ -125,6 +130,7 @@
45 ListItem.SingleControl {
46 highlightWhenPressed: false
47 control: Button {
48+ objectName: "eventSaveButton"
49 text: i18n.tr("Save")
50 anchors {
51 fill: parent
52
53=== modified file 'debian/control'
54--- debian/control 2013-04-11 19:47:11 +0000
55+++ debian/control 2013-05-29 16:41:23 +0000
56@@ -22,3 +22,12 @@
57 It’s about the task and the context; use the calendar app as a todo list,
58 a diary, a planner, a journal, a life log; and the calendar will behave how
59 you need it to.
60+
61+Package: ubuntu-calendar-app-autopilot
62+Architecture: all
63+Depends: libautopilot-qt,
64+ libqt5test5,
65+ ubuntu-calendar-app (= ${source:Version}),
66+Description: Autopilot tests for Ubuntu Calendar Application
67+ This package contains autopilot tests for the Ubuntu Calendar application.
68+
69
70=== added file 'debian/ubuntu-calendar-app-autopilot.install'
71--- debian/ubuntu-calendar-app-autopilot.install 1970-01-01 00:00:00 +0000
72+++ debian/ubuntu-calendar-app-autopilot.install 2013-05-29 16:41:23 +0000
73@@ -0,0 +1,1 @@
74+tests/autopilot/ubuntu_calendar_app/* usr/lib/python2.7/dist-packages/ubuntu_calendar_app/
75
76=== added directory 'tests'
77=== added directory 'tests/autopilot'
78=== added directory 'tests/autopilot/ubuntu_calendar_app'
79=== added file 'tests/autopilot/ubuntu_calendar_app/__init__.py'
80--- tests/autopilot/ubuntu_calendar_app/__init__.py 1970-01-01 00:00:00 +0000
81+++ tests/autopilot/ubuntu_calendar_app/__init__.py 2013-05-29 16:41:23 +0000
82@@ -0,0 +1,8 @@
83+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
84+# Copyright 2013 Canonical
85+#
86+# This program is free software: you can redistribute it and/or modify it
87+# under the terms of the GNU General Public License version 3, as published
88+# by the Free Software Foundation.
89+
90+"""calendar-app tests and emulators - top level package."""
91
92=== added directory 'tests/autopilot/ubuntu_calendar_app/emulators'
93=== added file 'tests/autopilot/ubuntu_calendar_app/emulators/__init__.py'
94--- tests/autopilot/ubuntu_calendar_app/emulators/__init__.py 1970-01-01 00:00:00 +0000
95+++ tests/autopilot/ubuntu_calendar_app/emulators/__init__.py 2013-05-29 16:41:23 +0000
96@@ -0,0 +1,6 @@
97+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
98+# Copyright 2013 Canonical
99+#
100+# This program is free software: you can redistribute it and/or modify it
101+# under the terms of the GNU General Public License version 3, as published
102+# by the Free Software Foundation.
103
104=== added file 'tests/autopilot/ubuntu_calendar_app/emulators/main_window.py'
105--- tests/autopilot/ubuntu_calendar_app/emulators/main_window.py 1970-01-01 00:00:00 +0000
106+++ tests/autopilot/ubuntu_calendar_app/emulators/main_window.py 2013-05-29 16:41:23 +0000
107@@ -0,0 +1,62 @@
108+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
109+# Copyright 2013 Canonical
110+#
111+# This program is free software: you can redistribute it and/or modify it
112+# under the terms of the GNU General Public License version 3, as published
113+# by the Free Software Foundation.
114+
115+"""Calendar app autopilot emulators."""
116+
117+
118+class MainWindow(object):
119+ """An emulator class that makes it easy to interact with the
120+ calendar-app.
121+
122+ """
123+ def __init__(self, app):
124+ self.app = app
125+
126+ def get_qml_view(self):
127+ """Get the main QML view"""
128+ return self.app.select_single("QQuickView")
129+
130+ def get_panel(self):
131+ return self.app.select_single("Toolbar")
132+
133+ def get_toolbar_button(self, button_idx):
134+ toolbar = self.app.select_single("Toolbar")
135+ row = toolbar.select_single("QQuickRow")
136+ buttons = row.select_many("Button")
137+ return buttons[button_idx]
138+
139+ def get_toolbar_new_event_button(self):
140+ return self.get_toolbar_button(1)
141+
142+ def get_toolbar_timeline_button(self):
143+ return self.get_toolbar_button(2)
144+
145+ def get_create_event_page(self):
146+ return self.app.select_single("NewEvent")
147+
148+ def get_new_event_name_input_box(self):
149+ return self.app.select_single("TextField", objectName="newEventName")
150+
151+ def get_event_start_time_field(self):
152+ return self.app.select_single("TextField", objectName="startTimeInput")
153+
154+ def get_event_end_time_field(self):
155+ return self.app.select_single("TextField", objectName="endTimeInput")
156+
157+ def get_event_location_field(self):
158+ return self.app.select_single(
159+ "TextField", objectName="eventLocationInput")
160+
161+ def get_event_people_field(self):
162+ return self.app.select_single(
163+ "TextField", objectName="eventPeopleInput")
164+
165+ def get_event_save_button(self):
166+ return self.app.select_single("Button", objectName="eventSaveButton")
167+
168+ def get_event_view(self):
169+ return self.app.select_single("EventView")
170
171=== added directory 'tests/autopilot/ubuntu_calendar_app/tests'
172=== added file 'tests/autopilot/ubuntu_calendar_app/tests/__init__.py'
173--- tests/autopilot/ubuntu_calendar_app/tests/__init__.py 1970-01-01 00:00:00 +0000
174+++ tests/autopilot/ubuntu_calendar_app/tests/__init__.py 2013-05-29 16:41:23 +0000
175@@ -0,0 +1,67 @@
176+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
177+# Copyright 2013 Canonical
178+#
179+# This program is free software: you can redistribute it and/or modify it
180+# under the terms of the GNU General Public License version 3, as published
181+# by the Free Software Foundation.
182+
183+"""Calendar app autopilot tests."""
184+
185+import os.path
186+
187+from autopilot.input import Mouse, Touch, Pointer
188+from autopilot.matchers import Eventually
189+from autopilot.platform import model
190+from autopilot.testcase import AutopilotTestCase
191+from testtools.matchers import Equals
192+
193+from ubuntu_calendar_app.emulators.main_window import MainWindow
194+
195+
196+class CalendarTestCase(AutopilotTestCase):
197+
198+ """A common test case class that provides several useful methods for
199+ calendar-app tests.
200+
201+ """
202+ if model() == 'Desktop':
203+ scenarios = [('with mouse', dict(input_device_class=Mouse))]
204+ else:
205+ scenarios = [('with touch', dict(input_device_class=Touch))]
206+
207+ local_location = "../../calendar.qml"
208+
209+ def setUp(self):
210+ self.pointing_device = Pointer(self.input_device_class.create())
211+ super(CalendarTestCase, self).setUp()
212+ if os.path.exists(self.local_location):
213+ self.launch_test_local()
214+ else:
215+ self.launch_test_installed()
216+
217+ def launch_test_local(self):
218+ self.app = self.launch_test_application(
219+ "qmlscene",
220+ self.local_location,
221+ app_type='qt')
222+
223+ def launch_test_installed(self):
224+ self.app = self.launch_test_application(
225+ "qmlscene",
226+ "/usr/share/ubuntu-calendar-app/calendar.qml",
227+ "--desktop_file_hint=/usr/share/applications/ubuntu-calendar-app.desktop",
228+ app_type='qt')
229+
230+ def reveal_toolbar(self):
231+ toolbar = self.main_window.get_panel()
232+
233+ x, y, w, h = toolbar.globalRect
234+ tx = x + (w / 2)
235+ ty = y + (h - 2)
236+
237+ self.pointing_device.drag(tx, ty, tx, ty - h)
238+ self.assertThat(toolbar.state, Eventually(Equals("spread")))
239+
240+ @property
241+ def main_window(self):
242+ return MainWindow(self.app)
243
244=== added file 'tests/autopilot/ubuntu_calendar_app/tests/test_calendar.py'
245--- tests/autopilot/ubuntu_calendar_app/tests/test_calendar.py 1970-01-01 00:00:00 +0000
246+++ tests/autopilot/ubuntu_calendar_app/tests/test_calendar.py 2013-05-29 16:41:23 +0000
247@@ -0,0 +1,37 @@
248+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
249+# Copyright 2013 Canonical
250+#
251+# This program is free software: you can redistribute it and/or modify it
252+# under the terms of the GNU General Public License version 3, as published
253+# by the Free Software Foundation.
254+
255+"""Calendar app autopilot tests."""
256+
257+from __future__ import absolute_import
258+
259+from autopilot.matchers import Eventually
260+from testtools.matchers import Equals
261+
262+from ubuntu_calendar_app.tests import CalendarTestCase
263+
264+
265+class TestMainWindow(CalendarTestCase):
266+
267+ def setUp(self):
268+ super(TestMainWindow, self).setUp()
269+ self.assertThat(
270+ self.main_window.get_qml_view().visible, Eventually(Equals(True)))
271+
272+ def tearDown(self):
273+ super(TestMainWindow, self).tearDown()
274+
275+ def test_timeline_view_shows(self):
276+ timeline_button = self.main_window.get_toolbar_timeline_button()
277+ event_view = self.main_window.get_event_view()
278+ self.reveal_toolbar()
279+
280+ self.assertThat(event_view.eventViewType, Eventually(Equals("DiaryView.qml")))
281+ self.pointing_device.click_object(timeline_button)
282+ self.assertThat(event_view.eventViewType, Eventually(Equals("TimeLineView.qml")))
283+ self.pointing_device.click_object(timeline_button)
284+ self.assertThat(event_view.eventViewType, Eventually(Equals("DiaryView.qml")))

Subscribers

People subscribed via source and target branches

to status/vote changes: