Merge lp:~elopio/ubuntu-calendar-app/fix1332173-swipe_to_create_new_event into lp:ubuntu-calendar-app

Proposed by Leo Arias
Status: Merged
Approved by: Nicholas Skaggs
Approved revision: 347
Merged at revision: 337
Proposed branch: lp:~elopio/ubuntu-calendar-app/fix1332173-swipe_to_create_new_event
Merge into: lp:ubuntu-calendar-app
Diff against target: 872 lines (+524/-183)
9 files modified
DeleteConfirmationDialog.qml (+2/-0)
EventBubble.qml (+7/-5)
EventDetails.qml (+6/-0)
NewEvent.qml (+1/-0)
tests/autopilot/calendar_app/data.py (+57/-0)
tests/autopilot/calendar_app/emulators.py (+322/-122)
tests/autopilot/calendar_app/tests/test_custom_proxy_objects.py (+30/-0)
tests/autopilot/calendar_app/tests/test_data.py (+30/-0)
tests/autopilot/calendar_app/tests/test_new_event.py (+69/-56)
To merge this branch: bzr merge lp:~elopio/ubuntu-calendar-app/fix1332173-swipe_to_create_new_event
Reviewer Review Type Date Requested Status
Nicholas Skaggs (community) Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+224735@code.launchpad.net

Commit message

Refactored the autopilot test to add a new event. Added helpers and self tests for them.

To post a comment you must log in.
341. By Leo Arias

Removed unused code.

342. By Leo Arias

Added the name to get_events, fixed pep8.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
343. By Leo Arias

Wait for the events to appear.

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

Three greens in a row, and I've also ran it many times on my machine and on my phone. I'd say this is good to go.

344. By Leo Arias

Reverted the po changes.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
345. By Leo Arias

Added a comment to the autopilot bug that prevents us to change the date.

346. By Leo Arias

Promoted the duplicates to XXX.

347. By Leo Arias

Removed the unused page.

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

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'DeleteConfirmationDialog.qml'
2--- DeleteConfirmationDialog.qml 2014-04-13 02:03:43 +0000
3+++ DeleteConfirmationDialog.qml 2014-06-27 16:55:37 +0000
4@@ -4,6 +4,7 @@
5
6 Dialog {
7 id: dialogue
8+ objectName: "deleteConfirmationDialog"
9
10 property var event;
11
12@@ -28,6 +29,7 @@
13 }
14
15 Button {
16+ objectName: "deleteEventButton"
17 text: event.parentId ? i18n.tr("Delete this") : i18n.tr("Delete")
18 color: UbuntuColors.orange
19 onClicked: {
20
21=== modified file 'EventBubble.qml'
22--- EventBubble.qml 2014-06-21 03:37:43 +0000
23+++ EventBubble.qml 2014-06-27 16:55:37 +0000
24@@ -133,8 +133,9 @@
25
26 Label{
27 id: timeLabel
28- fontSize:"small";
29- color:"gray"
30+ objectName: "timeLabel"
31+ fontSize: "small"
32+ color: "gray"
33 width: parent.width - rect.width
34 }
35 Rectangle{
36@@ -147,15 +148,16 @@
37 }
38 Label{
39 id: titleLabel
40- fontSize:"small";
41- color:"black"
42+ objectName: "titleLabel"
43+ fontSize: "small"
44+ color: "black"
45 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
46 width: parent.width
47 }
48
49 Label{
50 id: descriptionLabel
51- fontSize:"small";
52+ fontSize: "small"
53 color:"gray"
54 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
55 width: parent.width
56
57=== modified file 'EventDetails.qml'
58--- EventDetails.qml 2014-05-27 11:28:27 +0000
59+++ EventDetails.qml 2014-06-27 16:55:37 +0000
60@@ -9,6 +9,7 @@
61
62 Page {
63 id: root
64+ objectName: "eventDetails"
65
66 property var event;
67 property string headerColor :"black"
68@@ -165,6 +166,7 @@
69 ToolbarButton {
70 action:Action {
71 text: i18n.tr("Delete");
72+ objectName: "delete"
73 iconSource: "image://theme/delete,edit-delete-symbolic"
74 onTriggered: {
75 var dialog = PopupUtils.open(Qt.resolvedUrl("DeleteConfirmationDialog.qml"),root,{"event": event});
76@@ -274,6 +276,7 @@
77 ThinDivider{}
78 Label{
79 id: titleLabel
80+ objectName: "titleLabel"
81 fontSize: "large"
82 width: parent.width
83 wrapMode: Text.WordWrap
84@@ -281,6 +284,7 @@
85 }
86 Label{
87 id: descLabel
88+ objectName: "descriptionLabel"
89 wrapMode: Text.WordWrap
90 fontSize: "small"
91 width: parent.width
92@@ -293,6 +297,7 @@
93 }
94 Label{
95 id: locationLabel
96+ objectName: "locationLabel"
97 fontSize: "medium"
98 width: parent.width
99 wrapMode: Text.WordWrap
100@@ -322,6 +327,7 @@
101 //Guest Entery Model starts
102 Column{
103 id: contactList
104+ objectName: 'contactList'
105 spacing: units.gu(1)
106 width: parent.width
107 clip: true
108
109=== modified file 'NewEvent.qml'
110--- NewEvent.qml 2014-06-19 13:21:24 +0000
111+++ NewEvent.qml 2014-06-27 16:55:37 +0000
112@@ -11,6 +11,7 @@
113
114 Page {
115 id: root
116+ objectName: 'newEventPage'
117 property var date;
118
119 property var event:null;
120
121=== added file 'tests/autopilot/calendar_app/data.py'
122--- tests/autopilot/calendar_app/data.py 1970-01-01 00:00:00 +0000
123+++ tests/autopilot/calendar_app/data.py 2014-06-27 16:55:37 +0000
124@@ -0,0 +1,57 @@
125+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
126+#
127+# Copyright (C) 2014 Canonical Ltd
128+#
129+# This program is free software: you can redistribute it and/or modify
130+# it under the terms of the GNU General Public License version 3 as
131+# published by the Free Software Foundation.
132+#
133+# This program is distributed in the hope that it will be useful,
134+# but WITHOUT ANY WARRANTY; without even the implied warranty of
135+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
136+# GNU General Public License for more details.
137+#
138+# You should have received a copy of the GNU General Public License
139+# along with this program. If not, see <http://www.gnu.org/licenses/>.
140+
141+import uuid
142+
143+
144+class DataMixin(object):
145+
146+ """Mixin with common methods for data objects."""
147+
148+ def __repr__(self):
149+ return '%s(%r)' % (self.__class__, self.__dict__)
150+
151+ def __eq__(self, other):
152+ return (isinstance(other, self.__class__) and
153+ self.__dict__ == other.__dict__)
154+
155+ def __ne__(self, other):
156+ return not self.__eq__(other)
157+
158+
159+class Event(DataMixin):
160+
161+ """Event data object for user acceptance tests."""
162+
163+ def __init__(self, name, description, location, guests):
164+ # TODO add start date and end date, is all day event, recurrence and
165+ # reminders. --elopio - 2014-06-26
166+ super(Event, self).__init__()
167+ self.name = name
168+ self.description = description
169+ self.location = location
170+ self.guests = guests
171+
172+ @classmethod
173+ def make_unique(cls, unique_id=None):
174+ """Return a unique event."""
175+ if unique_id is None:
176+ unique_id = str(uuid.uuid1())
177+ name = 'Test event {}'.format(unique_id)
178+ description = 'Test description {}.'.format(unique_id)
179+ location = 'Test location {}'.format(unique_id)
180+ guests = ['Test guest {} 1'.format(unique_id)]
181+ return cls(name, description, location, guests)
182
183=== modified file 'tests/autopilot/calendar_app/emulators.py'
184--- tests/autopilot/calendar_app/emulators.py 2014-06-26 18:10:28 +0000
185+++ tests/autopilot/calendar_app/emulators.py 2014-06-27 16:55:37 +0000
186@@ -15,20 +15,28 @@
187 # along with this program. If not, see <http://www.gnu.org/licenses/>.
188
189 """Calendar app autopilot emulators."""
190+
191+import logging
192 from time import sleep
193
194-from autopilot.introspection import dbus
195-
196-
197+import autopilot.logging
198+from dateutil import tz
199+
200+import ubuntuuitoolkit
201 from ubuntuuitoolkit import (
202 emulators as toolkit_emulators,
203 pickers
204 )
205-from dateutil import tz
206-
207-
208-class NewEventEntryField(toolkit_emulators.TextField):
209- """Autopilot helper for the NewEventEntryField component."""
210+
211+from calendar_app import data
212+
213+
214+logger = logging.getLogger(__name__)
215+
216+
217+class CalendarException(ubuntuuitoolkit.ToolkitException):
218+
219+ """Exception raised when there are problems with the Calendar."""
220
221
222 # for now we are borrowing the textfield helper for the textarea
223@@ -40,9 +48,32 @@
224
225 class MainView(toolkit_emulators.MainView):
226
227- """
228- An emulator class that makes it easy to interact with the calendar-app.
229- """
230+ """An emulator that makes it easy to interact with the calendar-app."""
231+
232+ @autopilot.logging.log_action(logger.info)
233+ def go_to_day_view(self):
234+ """Open the day view.
235+
236+ :return: The Day View page.
237+
238+ """
239+ day_tab = self.select_single('Tab', objectName='dayTab')
240+ if not day_tab.visible:
241+ self.switch_to_tab('dayTab')
242+ else:
243+ logger.debug('The Day View page is already opened.')
244+ return day_tab.select_single(DayView, objectName='DayView')
245+
246+ @autopilot.logging.log_action(logger.info)
247+ def go_to_new_event(self):
248+ """Open the page to add a new event.
249+
250+ :return: The New Event page.
251+
252+ """
253+ header = self.get_header()
254+ header.click_action_button('neweventbutton')
255+ return self.select_single(NewEvent, objectName='newEventPage')
256
257 def set_picker(self, field, mode, value):
258 # open picker
259@@ -85,52 +116,6 @@
260 else:
261 return None
262
263- def get_new_event(self):
264- try:
265- return self.wait_select_single("NewEvent")
266- except dbus.StateNotFoundError:
267- return None
268-
269- def get_new_event_name_input_box(self):
270- new_event = self.get_new_event()
271- return new_event.wait_select_single(NewEventEntryField,
272- objectName="newEventName")
273-
274- def get_event_start_time_field(self):
275- new_event = self.get_new_event()
276- return new_event.wait_select_single(NewEventEntryField,
277- objectName="startTimeInput")
278-
279- def get_event_start_date_field(self):
280- new_event = self.get_new_event()
281- return new_event.wait_select_single(NewEventEntryField,
282- objectName="startDateInput")
283-
284- def get_event_end_date_field(self):
285- new_event = self.get_new_event()
286- return new_event.wait_select_single(NewEventEntryField,
287- objectName="endDateInput")
288-
289- def get_event_end_time_field(self):
290- new_event = self.get_new_event()
291- return new_event.wait_select_single(NewEventEntryField,
292- objectName="endTimeInput")
293-
294- def get_event_location_field(self):
295- new_event = self.get_new_event()
296- return new_event.wait_select_single(NewEventEntryField,
297- objectName="eventLocationInput")
298-
299- def get_event_people_field(self):
300- new_event = self.get_new_event()
301- return new_event.wait_select_single(NewEventEntryField,
302- objectName="eventPeopleInput")
303-
304- def get_event_description_field(self):
305- new_event = self.get_new_event()
306- return new_event.wait_select_single(TextArea,
307- objectName="eventDescriptionInput")
308-
309 def safe_swipe_view(self, direction, view, date):
310 """
311 direction: direction to swip
312@@ -176,74 +161,289 @@
313 return component.wait_select_single(
314 "Label", objectName="monthLabel").text
315
316- def get_num_events(self):
317- return len(self.select_many("EventBubble"))
318-
319- def get_event(self, title):
320- """ Return an event by title
321- """
322- events = self.select_many("EventBubble")
323- for event in events:
324- try:
325- event_found = event.select_single("Label", text=title)
326- except:
327- continue
328- if event_found:
329- return event
330-
331- return 0
332-
333- def get_new_event_save_button(self):
334- new_event = self.get_new_event()
335- return new_event.wait_select_single("Button",
336- objectName="accept")
337-
338- def get_new_event_cancel_button(self):
339- new_event = self.get_new_event()
340- return new_event.wait_select_single("Button",
341- objectName="cancel")
342-
343 def to_local_date(self, date):
344 utc = date.replace(tzinfo=tz.tzutc())
345 local = utc.astimezone(tz.tzlocal())
346 return local
347
348
349-class Page(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
350- """Autopilot helper for Pages."""
351-
352- def __init__(self, *args):
353- super(Page, self).__init__(*args)
354- # XXX we need a better way to keep reference to the main view.
355- # --elopio - 2014-01-31
356- self.main_view = self.get_root_instance().select_single(MainView)
357-
358- def drag_page_up(self):
359- """Drag the given page up."""
360- self._drag_page(direction='up')
361-
362- def drag_page_down(self):
363- """Drag the given page down."""
364- self._drag_page(direction='down')
365-
366- def _drag_page(self, direction):
367- """Function to drag the page up/down."""
368- self._wait_to_stop_moving()
369-
370- x, y, w, h = self.globalRect
371- start_x = stop_x = x + (w / 2)
372- start_y = y + (h / 2)
373-
374- if direction == "down":
375- stop_y = start_y + h / 3
376- self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
377- else:
378- stop_y = start_y - h / 3
379- self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
380-
381- self._wait_to_stop_moving()
382-
383- def _wait_to_stop_moving(self):
384- self.select_single(
385- 'QQuickFlickable',
386- objectName='animationContainer').moving.wait_for(False)
387+class DayView(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
388+
389+ """Autopilot helper for the Day View page."""
390+
391+ def get_events(self, filter_duplicates=False):
392+ """Return the events for this day.
393+
394+ :return: A list with the events. Each event is a tuple with name, start
395+ time and end time.
396+
397+ """
398+ event_bubbles = self._get_selected_day_event_bubbles(filter_duplicates)
399+
400+ # sort by y, x
401+ event_bubbles = sorted(
402+ event_bubbles,
403+ key=lambda bubble: (bubble.globalRect.y, bubble.globalRect.x))
404+
405+ events = []
406+ for event in event_bubbles:
407+ events.append(event.get_information())
408+
409+ return events
410+
411+ def _get_current_day_component(self):
412+ components = self.select_many('TimeLineBaseComponent')
413+ for component in components:
414+ if (self.currentDay.datetime.date() ==
415+ component.startDay.datetime.date()):
416+ return component
417+ else:
418+ raise CalendarException(
419+ 'Could not find the current day component.')
420+
421+ def _get_selected_day_event_bubbles(self, filter_duplicates):
422+ selected_day = self._get_current_day_component()
423+ return self._get_event_bubbles(selected_day, filter_duplicates)
424+
425+ def _get_event_bubbles(self, selected_day, filter_duplicates):
426+ event_bubbles = selected_day.select_many(EventBubble)
427+ if filter_duplicates:
428+ # XXX remove this once bug http://pad.lv/1334833 is fixed.
429+ # --elopio - 2014-06-26
430+ separator_id = selected_day.select_single(
431+ 'QQuickRectangle', objectName='separator').id
432+ event_bubbles = self._remove_duplicate_events(
433+ separator_id, event_bubbles)
434+ return event_bubbles
435+
436+ def _remove_duplicate_events(self, separator_id, event_bubbles):
437+ events = []
438+ for bubble in event_bubbles:
439+ if bubble.id > separator_id:
440+ events.append(bubble)
441+
442+ return events
443+
444+ @autopilot.logging.log_action(logger.info)
445+ def open_event(self, name, filter_duplicates=False):
446+ """Open an event.
447+
448+ :param name: The name of the event to open.
449+ :return: The Event Details page.
450+
451+ """
452+ event_bubbles = self._get_selected_day_event_bubbles(filter_duplicates)
453+ for bubble in event_bubbles:
454+ if bubble.get_name() == name:
455+ return bubble.open_event()
456+ else:
457+ raise CalendarException(
458+ 'Could not find event with name {}.'.format(name))
459+
460+ @autopilot.logging.log_action(logger.info)
461+ def delete_event(self, name, filter_duplicates=False):
462+ """Delete an event.
463+
464+ :param name: The name of the event to delete.
465+ :return: The Day View page.
466+
467+ """
468+ event_details_page = self.open_event(name, filter_duplicates)
469+ return event_details_page.delete()
470+
471+
472+class EventBubble(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
473+
474+ """Autopiot helper for the Event Bubble items."""
475+
476+ def get_information(self):
477+ """Return a tuple with the name, start time and end time."""
478+ name = self.get_name()
479+ start_time, end_time = self._get_start_and_end_time()
480+ return name, start_time, end_time
481+
482+ def _get_start_and_end_time(self):
483+ """Return a tuple with the start time and end time."""
484+ time_label = self.select_single('Label', objectName='timeLabel')
485+ start_time, end_time = time_label.text.split(' - ')
486+ return start_time, end_time
487+
488+ def get_name(self):
489+ """Return the event name."""
490+ title_label = self.select_single('Label', objectName='titleLabel')
491+ return title_label.text
492+
493+ @autopilot.logging.log_action(logger.info)
494+ def open_event(self):
495+ """Open the event.
496+
497+ :return: The Event Details page.
498+
499+ """
500+ # If there are too many events, the center of the bubble
501+ # might be hidden by another event. Click the left side of the
502+ # bubble.
503+ left = self.globalRect.x + 5
504+ center_y = self.globalRect.y + self.globalRect.height // 2
505+ self.pointing_device.move(left, center_y)
506+ self.pointing_device.click()
507+ return self.get_root_instance().select_single(
508+ EventDetails, objectName='eventDetails')
509+
510+
511+class NewEvent(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
512+
513+ """Autopilot helper for the New Event page."""
514+
515+ @autopilot.logging.log_action(logger.info)
516+ def add_event(self, event_information):
517+ """Add a new event.
518+
519+ :param event_information: Values of the event to fill the form.
520+ :type event_information: data object with the attributes name,
521+ description, location and guests.
522+ :return: The Day View page.
523+
524+ """
525+ self._fill_form(event_information)
526+ self._save()
527+ return self.get_root_instance().select_single(
528+ DayView, objectName='DayView')
529+
530+ @autopilot.logging.log_action(logger.debug)
531+ def _fill_form(self, event_information):
532+ """Fill the add event form.
533+
534+ :param event_information: Values of the event to fill the form.
535+ :type event_information: data object with the attributes name,
536+ description, location and guests.
537+
538+ """
539+ # TODO fill start date and end date, is all day event, recurrence and
540+ # reminders. --elopio - 2014-06-26
541+ if event_information.name is not None:
542+ self._fill_name(event_information.name)
543+ if event_information.description is not None:
544+ self._fill_description(event_information.description)
545+ if event_information.location is not None:
546+ self._fill_location(event_information.location)
547+ if event_information.guests is not None:
548+ self._fill_guests(event_information.guests)
549+
550+ def _fill_name(self, value):
551+ self._ensure_entry_field_visible_and_write('newEventName', value)
552+
553+ def _ensure_entry_field_visible_and_write(self, object_name, value):
554+ name_text_field = self._get_new_event_entry_field(object_name)
555+ self._ensure_visible_and_write(name_text_field, value)
556+
557+ def _get_new_event_entry_field(self, object_name):
558+ return self.select_single(NewEventEntryField, objectName=object_name)
559+
560+ def _ensure_visible_and_write(self, text_field, value):
561+ text_field.swipe_into_view()
562+ text_field.write(value)
563+
564+ def _fill_description(self, value):
565+ description_text_area = self._get_description_text_area()
566+ self._ensure_visible_and_write(description_text_area, value)
567+
568+ def _get_description_text_area(self):
569+ return self.select_single(TextArea, objectName='eventDescriptionInput')
570+
571+ def _fill_location(self, value):
572+ self._ensure_entry_field_visible_and_write('eventLocationInput', value)
573+
574+ def _fill_guests(self, value):
575+ if len(value) > 1:
576+ # See bug http://pad.lv/1295941
577+ raise CalendarException(
578+ 'It is not yet possible to add more than one guest.')
579+ self._ensure_entry_field_visible_and_write(
580+ 'eventPeopleInput', value[0])
581+
582+ def _get_form_values(self):
583+ # TODO get start date and end date, is all day event, recurrence and
584+ # reminders. --elopio - 2014-06-26
585+ name = self._get_new_event_entry_field('newEventName').text
586+ description = self._get_description_text_area().text
587+ location = self._get_new_event_entry_field('eventLocationInput').text
588+ # TODO once bug http://pad.lv/1295941 is fixed, we will have to build
589+ # the list of guests. --elopio - 2014-06-26
590+ guests = [self._get_new_event_entry_field('eventPeopleInput').text]
591+ return data.Event(name, description, location, guests)
592+
593+ @autopilot.logging.log_action(logger.info)
594+ def _save(self):
595+ """Save the new event."""
596+ save_button = self.select_single('Button', objectName='accept')
597+ self.pointing_device.click_object(save_button)
598+
599+
600+class NewEventEntryField(toolkit_emulators.TextField):
601+
602+ """Autopilot helper for the NewEventEntryField component."""
603+
604+
605+class EventDetails(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
606+
607+ """Autopilot helper for the Event Details page."""
608+
609+ @autopilot.logging.log_action(logger.debug)
610+ def delete(self):
611+ """Click the delete button.
612+
613+ :return: The Day View page.
614+
615+ """
616+ root = self.get_root_instance()
617+ header = root.select_single(MainView).get_header()
618+ header.click_action_button('delete')
619+
620+ delete_confirmation_dialog = root.select_single(
621+ DeleteConfirmationDialog, objectName='deleteConfirmationDialog')
622+ delete_confirmation_dialog.confirm_deletion()
623+
624+ return root.select_single(DayView, objectName='DayView')
625+
626+ def get_event_information(self):
627+ """Return the information of the event."""
628+ name = self._get_name()
629+ description = self._get_description()
630+ location = self._get_location()
631+ guests = self._get_guests()
632+ return data.Event(name, description, location, guests)
633+
634+ def _get_name(self):
635+ return self._get_label_text('titleLabel')
636+
637+ def _get_label_text(self, object_name):
638+ return self.select_single('Label', objectName=object_name).text
639+
640+ def _get_description(self):
641+ return self._get_label_text('descriptionLabel')
642+
643+ def _get_location(self):
644+ return self._get_label_text('locationLabel')
645+
646+ def _get_guests(self):
647+ guests = []
648+ contacts_list = self.select_single(
649+ 'QQuickColumn', objectName='contactList')
650+ guest_labels = contacts_list.select_many('Label')
651+ for label in guest_labels:
652+ guests.append(label.text)
653+
654+ return guests
655+
656+
657+class DeleteConfirmationDialog(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
658+
659+ """Autopilot helper for the Delete Confirmation dialog."""
660+
661+ @autopilot.logging.log_action(logger.debug)
662+ def confirm_deletion(self):
663+ """Confirm the deletion of the event."""
664+ delete_button = self.select_single(
665+ 'Button', objectName='deleteEventButton')
666+ self.pointing_device.click_object(delete_button)
667
668=== added file 'tests/autopilot/calendar_app/tests/test_custom_proxy_objects.py'
669--- tests/autopilot/calendar_app/tests/test_custom_proxy_objects.py 1970-01-01 00:00:00 +0000
670+++ tests/autopilot/calendar_app/tests/test_custom_proxy_objects.py 2014-06-27 16:55:37 +0000
671@@ -0,0 +1,30 @@
672+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
673+#
674+# Copyright (C) 2014 Canonical Ltd
675+#
676+# This program is free software: you can redistribute it and/or modify
677+# it under the terms of the GNU General Public License version 3 as
678+# published by the Free Software Foundation.
679+#
680+# This program is distributed in the hope that it will be useful,
681+# but WITHOUT ANY WARRANTY; without even the implied warranty of
682+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
683+# GNU General Public License for more details.
684+#
685+# You should have received a copy of the GNU General Public License
686+# along with this program. If not, see <http://www.gnu.org/licenses/>.
687+
688+from calendar_app import data, tests
689+
690+
691+class NewEventFormTestCase(tests.CalendarTestCase):
692+
693+ def test_fill_form(self):
694+ """Test that the form can be filled with event information."""
695+ test_event = data.Event.make_unique(unique_id='test uuid')
696+
697+ new_event_page = new_event_page = self.main_view.go_to_new_event()
698+ new_event_page._fill_form(test_event)
699+
700+ form_values = new_event_page._get_form_values()
701+ self.assertEqual(test_event, form_values)
702
703=== added file 'tests/autopilot/calendar_app/tests/test_data.py'
704--- tests/autopilot/calendar_app/tests/test_data.py 1970-01-01 00:00:00 +0000
705+++ tests/autopilot/calendar_app/tests/test_data.py 2014-06-27 16:55:37 +0000
706@@ -0,0 +1,30 @@
707+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
708+#
709+# Copyright (C) 2014 Canonical Ltd
710+#
711+# This program is free software: you can redistribute it and/or modify
712+# it under the terms of the GNU General Public License version 3 as
713+# published by the Free Software Foundation.
714+#
715+# This program is distributed in the hope that it will be useful,
716+# but WITHOUT ANY WARRANTY; without even the implied warranty of
717+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
718+# GNU General Public License for more details.
719+#
720+# You should have received a copy of the GNU General Public License
721+# along with this program. If not, see <http://www.gnu.org/licenses/>.
722+
723+import testtools
724+
725+from calendar_app import data
726+
727+
728+class EventTestCase(testtools.TestCase):
729+
730+ def test_make_unique_event_must_return_event_with_unique_id(self):
731+ event = data.Event.make_unique(unique_id='test uuid')
732+
733+ self.assertEqual(event.name, 'Test event test uuid')
734+ self.assertEqual(event.description, 'Test description test uuid.')
735+ self.assertEqual(event.location, 'Test location test uuid')
736+ self.assertEqual(event.guests, ['Test guest test uuid 1'])
737
738=== renamed file 'tests/autopilot/calendar_app/tests/test_calendar.py' => 'tests/autopilot/calendar_app/tests/test_new_event.py'
739--- tests/autopilot/calendar_app/tests/test_calendar.py 2014-06-26 18:10:28 +0000
740+++ tests/autopilot/calendar_app/tests/test_new_event.py 2014-06-27 16:55:37 +0000
741@@ -17,62 +17,75 @@
742 """Calendar app autopilot tests."""
743
744 from __future__ import absolute_import
745+
746+import logging
747+
748 from autopilot.matchers import Eventually
749-from testtools.matchers import Not, Is, NotEquals
750+from testtools.matchers import HasLength
751+
752+from calendar_app import data
753 from calendar_app.tests import CalendarTestCase
754
755-import time
756-
757-
758-class TestMainView(CalendarTestCase):
759-
760- def test_new_event(self):
761- """test add new event """
762- # go to today
763- self.main_view.switch_to_tab("dayTab")
764- header = self.main_view.get_header()
765- header.click_action_button('todaybutton')
766- num_events = self.main_view.get_num_events()
767-
768- # click on new event button
769- header = self.main_view.get_header()
770- header.click_action_button('neweventbutton')
771- self.assertThat(self.main_view.get_new_event,
772- Eventually(Not(Is(None))))
773-
774- # due to https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1326963
775- # the first event triggered is ignored, so we trigger an event
776- # and a small sleep to clear before continuing input
777- event_name_field = self.main_view.get_new_event_name_input_box()
778- self.pointing_device.click_object(event_name_field)
779- time.sleep(1)
780-
781- # input a new event name
782- eventTitle = "Test event " + str(int(time.time()))
783- self.main_view.get_new_event_name_input_box().write(eventTitle)
784-
785- # input description
786- self.main_view.get_event_description_field(). \
787- write("My favorite test event")
788-
789- # input location
790- self.main_view.get_event_location_field().write("England")
791-
792- # input guests
793- self.main_view.get_event_people_field().write("me, myself, and I")
794-
795- # todo: iterate over all combinations
796- # and include recurrence and reminders
797-
798- # click save button
799- save_button = self.main_view.get_new_event_save_button()
800- self.pointing_device.click_object(save_button)
801-
802- # verify that the event has been created in timeline
803- self.main_view.switch_to_tab("dayTab")
804- header = self.main_view.get_header()
805- header.click_action_button('todaybutton')
806- self.assertThat(self.main_view.get_num_events,
807- Eventually(NotEquals(num_events)))
808-
809- # todo: verify entered event data
810+
811+logger = logging.getLogger(__name__)
812+
813+
814+class NewEventTestCase(CalendarTestCase):
815+
816+ # TODO add tests for events in the future and in the past, all day event,
817+ # event with recurrence and event with reminders.
818+ # We currently can't change the date of the new event because of bug
819+ # http://pad.lv/1328600 on Autopilot.
820+ # --elopio - 2014-06-26
821+
822+ def try_delete_event(self, event_name, filter_duplicates):
823+ try:
824+ day_view = self.main_view.go_to_day_view()
825+ day_view.delete_event(event_name, filter_duplicates)
826+ except Exception as exception:
827+ logger.warn(str(exception))
828+
829+ def test_add_new_event_with_default_values(self):
830+ """Test adding a new event with the default values.
831+
832+ The event must be created on the currently selected date,
833+ with an end time, without recurrence and without reminders.
834+
835+ """
836+ test_event = data.Event.make_unique()
837+
838+ day_view = self.main_view.go_to_day_view()
839+ original_events = day_view.get_events()
840+
841+ new_event_page = self.main_view.go_to_new_event()
842+ # XXX remove this once bug http://pad.lv/1334833 is fixed.
843+ # --elopio - 2014-06-26
844+ filter_duplicates = len(original_events) > 0
845+ self.addCleanup(
846+ self.try_delete_event, test_event.name, filter_duplicates)
847+ day_view = new_event_page.add_event(test_event)
848+
849+ def get_new_events():
850+ return day_view.get_events(filter_duplicates)
851+
852+ self.assertThat(
853+ get_new_events, Eventually(HasLength(len(original_events) + 1)))
854+ event_details_page = day_view.open_event(test_event.name)
855+ self.assertEqual(
856+ test_event, event_details_page.get_event_information())
857+
858+ def test_delete_event_must_remove_it_from_day_view(self):
859+ """Test deleting an event must no longer show it on the day view."""
860+ # TODO remove the skip once the bug is fixed. --elopio - 2014-06-26
861+ self.skipTest('This test fails because of bug http://pad.lv/1334883')
862+ event = data.Event.make_unique()
863+
864+ day_view = self.main_view.go_to_day_view()
865+ original_events = day_view.get_events()
866+
867+ new_event_page = self.main_view.go_to_new_event()
868+ day_view = new_event_page.add_event(event)
869+ day_view = day_view.delete_event(event.name, len(original_events) > 0)
870+
871+ events_after_delete = day_view.get_events()
872+ self.assertEqual(original_events, events_after_delete)

Subscribers

People subscribed via source and target branches

to status/vote changes: