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
=== modified file 'NewEvent.qml'
--- NewEvent.qml 2013-03-29 23:12:40 +0000
+++ NewEvent.qml 2013-05-29 16:41:23 +0000
@@ -21,6 +21,7 @@
21 ListItem.Empty {21 ListItem.Empty {
22 highlightWhenPressed: false22 highlightWhenPressed: false
23 TextField {23 TextField {
24 objectName: "newEventName"
24 id: titleEdit25 id: titleEdit
25 placeholderText: i18n.tr("Add event name")26 placeholderText: i18n.tr("Add event name")
26 anchors {27 anchors {
@@ -69,6 +70,7 @@
69 anchors.left: timeContainer.left70 anchors.left: timeContainer.left
70 width: units.gu(12)71 width: units.gu(12)
71 TextField {72 TextField {
73 objectName: "startTimeInput"
72 id: startTimeEdit74 id: startTimeEdit
73 text: Qt.formatDateTime(defaultDate,"hh")75 text: Qt.formatDateTime(defaultDate,"hh")
74 anchors {76 anchors {
@@ -84,6 +86,7 @@
84 anchors.right: timeContainer.right86 anchors.right: timeContainer.right
85 width: units.gu(12)87 width: units.gu(12)
86 TextField {88 TextField {
89 objectName: "endTimeInput"
87 id: endTimeEdit90 id: endTimeEdit
88 text: Qt.formatDateTime(defaultDate,"hh")91 text: Qt.formatDateTime(defaultDate,"hh")
89 anchors {92 anchors {
@@ -100,6 +103,7 @@
100 ListItem.Empty {103 ListItem.Empty {
101 highlightWhenPressed: false104 highlightWhenPressed: false
102 TextField {105 TextField {
106 objectName: "eventLocationInput"
103 id: locationEdit107 id: locationEdit
104 placeholderText: i18n.tr("Add Location")108 placeholderText: i18n.tr("Add Location")
105 anchors {109 anchors {
@@ -113,6 +117,7 @@
113 ListItem.Empty {117 ListItem.Empty {
114 highlightWhenPressed: false118 highlightWhenPressed: false
115 TextField {119 TextField {
120 objectName: "eventPeopleInput"
116 id: personEdit121 id: personEdit
117 placeholderText: i18n.tr("Invite People")122 placeholderText: i18n.tr("Invite People")
118 anchors {123 anchors {
@@ -125,6 +130,7 @@
125 ListItem.SingleControl {130 ListItem.SingleControl {
126 highlightWhenPressed: false131 highlightWhenPressed: false
127 control: Button {132 control: Button {
133 objectName: "eventSaveButton"
128 text: i18n.tr("Save")134 text: i18n.tr("Save")
129 anchors {135 anchors {
130 fill: parent136 fill: parent
131137
=== modified file 'debian/control'
--- debian/control 2013-04-11 19:47:11 +0000
+++ debian/control 2013-05-29 16:41:23 +0000
@@ -22,3 +22,12 @@
22 It’s about the task and the context; use the calendar app as a todo list,22 It’s about the task and the context; use the calendar app as a todo list,
23 a diary, a planner, a journal, a life log; and the calendar will behave how23 a diary, a planner, a journal, a life log; and the calendar will behave how
24 you need it to.24 you need it to.
25
26Package: ubuntu-calendar-app-autopilot
27Architecture: all
28Depends: libautopilot-qt,
29 libqt5test5,
30 ubuntu-calendar-app (= ${source:Version}),
31Description: Autopilot tests for Ubuntu Calendar Application
32 This package contains autopilot tests for the Ubuntu Calendar application.
33
2534
=== added file 'debian/ubuntu-calendar-app-autopilot.install'
--- debian/ubuntu-calendar-app-autopilot.install 1970-01-01 00:00:00 +0000
+++ debian/ubuntu-calendar-app-autopilot.install 2013-05-29 16:41:23 +0000
@@ -0,0 +1,1 @@
1tests/autopilot/ubuntu_calendar_app/* usr/lib/python2.7/dist-packages/ubuntu_calendar_app/
02
=== added directory 'tests'
=== added directory 'tests/autopilot'
=== added directory 'tests/autopilot/ubuntu_calendar_app'
=== added file 'tests/autopilot/ubuntu_calendar_app/__init__.py'
--- tests/autopilot/ubuntu_calendar_app/__init__.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/ubuntu_calendar_app/__init__.py 2013-05-29 16:41:23 +0000
@@ -0,0 +1,8 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2# Copyright 2013 Canonical
3#
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8"""calendar-app tests and emulators - top level package."""
09
=== added directory 'tests/autopilot/ubuntu_calendar_app/emulators'
=== added file 'tests/autopilot/ubuntu_calendar_app/emulators/__init__.py'
--- tests/autopilot/ubuntu_calendar_app/emulators/__init__.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/ubuntu_calendar_app/emulators/__init__.py 2013-05-29 16:41:23 +0000
@@ -0,0 +1,6 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2# Copyright 2013 Canonical
3#
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
07
=== added file 'tests/autopilot/ubuntu_calendar_app/emulators/main_window.py'
--- tests/autopilot/ubuntu_calendar_app/emulators/main_window.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/ubuntu_calendar_app/emulators/main_window.py 2013-05-29 16:41:23 +0000
@@ -0,0 +1,62 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2# Copyright 2013 Canonical
3#
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8"""Calendar app autopilot emulators."""
9
10
11class MainWindow(object):
12 """An emulator class that makes it easy to interact with the
13 calendar-app.
14
15 """
16 def __init__(self, app):
17 self.app = app
18
19 def get_qml_view(self):
20 """Get the main QML view"""
21 return self.app.select_single("QQuickView")
22
23 def get_panel(self):
24 return self.app.select_single("Toolbar")
25
26 def get_toolbar_button(self, button_idx):
27 toolbar = self.app.select_single("Toolbar")
28 row = toolbar.select_single("QQuickRow")
29 buttons = row.select_many("Button")
30 return buttons[button_idx]
31
32 def get_toolbar_new_event_button(self):
33 return self.get_toolbar_button(1)
34
35 def get_toolbar_timeline_button(self):
36 return self.get_toolbar_button(2)
37
38 def get_create_event_page(self):
39 return self.app.select_single("NewEvent")
40
41 def get_new_event_name_input_box(self):
42 return self.app.select_single("TextField", objectName="newEventName")
43
44 def get_event_start_time_field(self):
45 return self.app.select_single("TextField", objectName="startTimeInput")
46
47 def get_event_end_time_field(self):
48 return self.app.select_single("TextField", objectName="endTimeInput")
49
50 def get_event_location_field(self):
51 return self.app.select_single(
52 "TextField", objectName="eventLocationInput")
53
54 def get_event_people_field(self):
55 return self.app.select_single(
56 "TextField", objectName="eventPeopleInput")
57
58 def get_event_save_button(self):
59 return self.app.select_single("Button", objectName="eventSaveButton")
60
61 def get_event_view(self):
62 return self.app.select_single("EventView")
063
=== added directory 'tests/autopilot/ubuntu_calendar_app/tests'
=== added file 'tests/autopilot/ubuntu_calendar_app/tests/__init__.py'
--- tests/autopilot/ubuntu_calendar_app/tests/__init__.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/ubuntu_calendar_app/tests/__init__.py 2013-05-29 16:41:23 +0000
@@ -0,0 +1,67 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2# Copyright 2013 Canonical
3#
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8"""Calendar app autopilot tests."""
9
10import os.path
11
12from autopilot.input import Mouse, Touch, Pointer
13from autopilot.matchers import Eventually
14from autopilot.platform import model
15from autopilot.testcase import AutopilotTestCase
16from testtools.matchers import Equals
17
18from ubuntu_calendar_app.emulators.main_window import MainWindow
19
20
21class CalendarTestCase(AutopilotTestCase):
22
23 """A common test case class that provides several useful methods for
24 calendar-app tests.
25
26 """
27 if model() == 'Desktop':
28 scenarios = [('with mouse', dict(input_device_class=Mouse))]
29 else:
30 scenarios = [('with touch', dict(input_device_class=Touch))]
31
32 local_location = "../../calendar.qml"
33
34 def setUp(self):
35 self.pointing_device = Pointer(self.input_device_class.create())
36 super(CalendarTestCase, self).setUp()
37 if os.path.exists(self.local_location):
38 self.launch_test_local()
39 else:
40 self.launch_test_installed()
41
42 def launch_test_local(self):
43 self.app = self.launch_test_application(
44 "qmlscene",
45 self.local_location,
46 app_type='qt')
47
48 def launch_test_installed(self):
49 self.app = self.launch_test_application(
50 "qmlscene",
51 "/usr/share/ubuntu-calendar-app/calendar.qml",
52 "--desktop_file_hint=/usr/share/applications/ubuntu-calendar-app.desktop",
53 app_type='qt')
54
55 def reveal_toolbar(self):
56 toolbar = self.main_window.get_panel()
57
58 x, y, w, h = toolbar.globalRect
59 tx = x + (w / 2)
60 ty = y + (h - 2)
61
62 self.pointing_device.drag(tx, ty, tx, ty - h)
63 self.assertThat(toolbar.state, Eventually(Equals("spread")))
64
65 @property
66 def main_window(self):
67 return MainWindow(self.app)
068
=== added file 'tests/autopilot/ubuntu_calendar_app/tests/test_calendar.py'
--- tests/autopilot/ubuntu_calendar_app/tests/test_calendar.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/ubuntu_calendar_app/tests/test_calendar.py 2013-05-29 16:41:23 +0000
@@ -0,0 +1,37 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2# Copyright 2013 Canonical
3#
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8"""Calendar app autopilot tests."""
9
10from __future__ import absolute_import
11
12from autopilot.matchers import Eventually
13from testtools.matchers import Equals
14
15from ubuntu_calendar_app.tests import CalendarTestCase
16
17
18class TestMainWindow(CalendarTestCase):
19
20 def setUp(self):
21 super(TestMainWindow, self).setUp()
22 self.assertThat(
23 self.main_window.get_qml_view().visible, Eventually(Equals(True)))
24
25 def tearDown(self):
26 super(TestMainWindow, self).tearDown()
27
28 def test_timeline_view_shows(self):
29 timeline_button = self.main_window.get_toolbar_timeline_button()
30 event_view = self.main_window.get_event_view()
31 self.reveal_toolbar()
32
33 self.assertThat(event_view.eventViewType, Eventually(Equals("DiaryView.qml")))
34 self.pointing_device.click_object(timeline_button)
35 self.assertThat(event_view.eventViewType, Eventually(Equals("TimeLineView.qml")))
36 self.pointing_device.click_object(timeline_button)
37 self.assertThat(event_view.eventViewType, Eventually(Equals("DiaryView.qml")))

Subscribers

People subscribed via source and target branches

to status/vote changes: