~ubuntu-clock-dev/ubuntu-clock-app/reboot-packaging

« back to all changes in this revision

Viewing changes to tests/autopilot/ubuntu_clock_app/emulators.py

Setup autopilot infrastructure and added alarm test

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2014 Canonical Ltd
 
2
#
 
3
# This file is part of Ubuntu Clock App
 
4
#
 
5
# Ubuntu Clock App is free software: you can redistribute it and/or modify
 
6
# it under the terms of the GNU General Public License version 3 as
 
7
# published by the Free Software Foundation.
 
8
#
 
9
# Ubuntu Clock App 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 General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 
 
17
import logging
 
18
 
 
19
from autopilot import logging as autopilot_logging
 
20
 
 
21
from ubuntuuitoolkit import pickers
 
22
import ubuntuuitoolkit
 
23
 
 
24
logger = logging.getLogger(__name__)
 
25
 
 
26
 
 
27
class ClockEmulatorException(ubuntuuitoolkit.ToolkitException):
 
28
 
 
29
    """Exception raised when there is an error with the emulator."""
 
30
 
 
31
 
 
32
class MainView(ubuntuuitoolkit.MainView):
 
33
 
 
34
    @autopilot_logging.log_action(logger.info)
 
35
    def open_clock(self):
 
36
        """Open the Clock Page.
 
37
 
 
38
        :return the Clock Page
 
39
 
 
40
        """
 
41
        return self.wait_select_single(ClockPage)
 
42
 
 
43
    @autopilot_logging.log_action(logger.info)
 
44
    def open_alarm(self):
 
45
        """Open the Alarm Page.
 
46
 
 
47
        :return: the Alarm Page.
 
48
 
 
49
        """
 
50
        clockPage = self.wait_select_single(ClockPage)
 
51
        clockPage.drag_bottomEdge_up()
 
52
        self.get_header().visible.wait_for(True)
 
53
        return self.wait_select_single(Page11)
 
54
 
 
55
    def get_AlarmList(self):
 
56
        """ Get the AlarmList object. """
 
57
        return AlarmList.select(self)
 
58
 
 
59
 
 
60
class Page(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
 
61
 
 
62
    """Autopilot helper for Pages."""
 
63
 
 
64
    def __init__(self, *args):
 
65
        super(Page, self).__init__(*args)
 
66
        # XXX we need a better way to keep reference to the main view.
 
67
        # --elopio - 2014-01-31
 
68
        self.main_view = self.get_root_instance().select_single(MainView)
 
69
 
 
70
 
 
71
class ClockPage(Page):
 
72
 
 
73
    """Autopilot helper for the Clock page."""
 
74
 
 
75
    @autopilot_logging.log_action(logger.info)
 
76
    def drag_bottomEdge_up(self):
 
77
        """Function to drag the bottom edge up."""
 
78
        self._click_bottomEdge()
 
79
 
 
80
        x, y, w, h = self.globalRect
 
81
        start_x = stop_x = x + (w / 2)
 
82
        start_y = y + (h - 1)
 
83
 
 
84
        stop_y = start_y - h
 
85
        self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
 
86
 
 
87
        self._wait_for_ClockPage_to_close()
 
88
 
 
89
    def _click_bottomEdge(self):
 
90
        """Function to click on the bottom edge."""
 
91
        bottomEdge = self.wait_select_single(
 
92
            'QQuickItem', objectName='bottomEdgeTip')
 
93
        self.pointing_device.click_object(bottomEdge)
 
94
 
 
95
    def _wait_for_ClockPage_to_close(self):
 
96
        self.isCollapsed.wait_for(False)
 
97
 
 
98
 
 
99
class Page11(Page):
 
100
 
 
101
    """Autopilot helper for the Alarm page."""
 
102
 
 
103
    @autopilot_logging.log_action(logger.info)
 
104
    def add_single_alarm(self, name, day, time_to_set, test_sound_name):
 
105
        """Add a single type alarm
 
106
 
 
107
        :param name: name of alarm
 
108
        :param day: day on which the alarm should be triggered
 
109
        :param time_to_set: time to set alarm to
 
110
        :param test_sound_name: sound to set in alarm
 
111
 
 
112
        """
 
113
        alarmListPage = AlarmList.select(self.main_view)
 
114
        old_alarm_count = alarmListPage.get_num_of_alarms()
 
115
 
 
116
        edit_alarm_page = self._click_add_alarm_button()
 
117
        edit_alarm_page.set_alarm_time(time_to_set)
 
118
 
 
119
        alarm_repeat_page = edit_alarm_page.open_alarmRepeat_page()
 
120
        alarm_repeat_page.set_single_alarm_day(day)
 
121
        self._click_header_backButton()
 
122
 
 
123
        alarm_label_page = edit_alarm_page.open_alarmLabel_page()
 
124
        alarm_label_page.set_alarm_label(name)
 
125
        self._click_header_customBackButton()
 
126
 
 
127
        alarm_sound_page = edit_alarm_page.open_alarmSound_page()
 
128
        alarm_sound_page.set_alarm_sound(test_sound_name)
 
129
        self._click_header_customBackButton()
 
130
        edit_alarm_page._check_sound_changed(test_sound_name)
 
131
 
 
132
        self._click_save()
 
133
        self._confirm_alarm_creation(old_alarm_count)
 
134
 
 
135
    def _click_add_alarm_button(self):
 
136
        """Click the add alarm header button."""
 
137
        header = self.main_view.get_header()
 
138
        header.click_action_button('addAlarmAction')
 
139
        return self.main_view.wait_select_single(EditAlarmPage)
 
140
 
 
141
    def _click_header_customBackButton(self):
 
142
        """Click the  header button:  'customBackButton' """
 
143
        header = self.main_view.get_header()
 
144
        header.click_custom_back_button()
 
145
 
 
146
    def _click_header_backButton(self):
 
147
        """Click the  header button:  'backButton' """
 
148
        header = self.main_view.get_header()
 
149
        header.click_back_button()
 
150
 
 
151
    def _click_save(self):
 
152
        """Click the save timer header button"""
 
153
        header = self.main_view.get_header()
 
154
        header.click_action_button('saveAlarmAction')
 
155
 
 
156
    def _confirm_alarm_creation(self, count):
 
157
        """Confirm creation of alarm
 
158
 
 
159
        :param count: alarm count before alarm creation
 
160
 
 
161
        """
 
162
        try:
 
163
            AlarmList.select(self.main_view)._get_saved_alarms_list().\
 
164
                count.wait_for(count + 1)
 
165
        except AssertionError:
 
166
            raise ClockEmulatorException('Error creating alarm.')
 
167
 
 
168
 
 
169
class EditAlarmPage(Page):
 
170
 
 
171
    """Autopilot helper for the Add Alarm page."""
 
172
 
 
173
    @autopilot_logging.log_action(logger.info)
 
174
    def set_alarm_time(self, time_to_set):
 
175
        """Set alarm time on datepicker.
 
176
 
 
177
        :param time_to_set: time to set on datepicker
 
178
 
 
179
        """
 
180
        PickerRow_HoursPicker = self.wait_select_single(
 
181
            "Picker", objectName="PickerRow_HoursPicker")
 
182
        self._set_picker(PickerRow_HoursPicker, 'time', time_to_set)
 
183
 
 
184
    def _set_picker(self, field, mode, value):
 
185
        # open picker
 
186
        self.pointing_device.click_object(field)
 
187
        # valid options are date or time; assume date if invalid/no option
 
188
        mode_value = 'Hours|Minutes'
 
189
        picker = self.wait_select_single(
 
190
            pickers.DatePicker, mode=mode_value, visible=True)
 
191
        picker.pick_time(value)
 
192
        # close picker
 
193
        self.pointing_device.click_object(field)
 
194
 
 
195
    @autopilot_logging.log_action(logger.info)
 
196
    def open_alarmRepeat_page(self):
 
197
        """ Open the alarmRepeat page """
 
198
 
 
199
        alarmRepeatItem = self.wait_select_single(
 
200
            "SubtitledListItem", objectName="alarmRepeat")
 
201
        self.pointing_device.click_object(alarmRepeatItem)
 
202
        return self.main_view.wait_select_single(AlarmRepeat)
 
203
 
 
204
    @autopilot_logging.log_action(logger.info)
 
205
    def open_alarmLabel_page(self):
 
206
        """ Open the alarmLabel page """
 
207
 
 
208
        alarmLabelItem = self.wait_select_single(
 
209
            "SubtitledListItem", objectName="alarmLabel")
 
210
        self.pointing_device.click_object(alarmLabelItem)
 
211
        return AlarmLable.select(self.main_view)
 
212
 
 
213
    @autopilot_logging.log_action(logger.info)
 
214
    def open_alarmSound_page(self):
 
215
        """ Open the alarmSound page """
 
216
 
 
217
        alarmSoundItem = self.wait_select_single(
 
218
            "SubtitledListItem", objectName="alarmSound")
 
219
        self.pointing_device.click_object(alarmSoundItem)
 
220
        return self.main_view.wait_select_single(AlarmSound)
 
221
 
 
222
    def _check_sound_changed(self, test_sound_name):
 
223
        """ function to check that sound has changed.
 
224
 
 
225
        :param test_sound_name = new sound name
 
226
 
 
227
        """
 
228
        self.wait_select_single("SubtitledListItem", objectName="alarmSound")\
 
229
            .subText == test_sound_name
 
230
 
 
231
 
 
232
class AlarmRepeat(Page):
 
233
 
 
234
    """Autopilot helper for the  AlarmRepeat page."""
 
235
 
 
236
    @autopilot_logging.log_action(logger.info)
 
237
    def set_single_alarm_day(self, day):
 
238
        """Set the alarm day of a single type alarm.
 
239
 
 
240
        :param day: single day on which alarm is triggered
 
241
 
 
242
        """
 
243
        self.unselect_selected_days()
 
244
        index = 0
 
245
        for index in range(self._get_num_of_days()):
 
246
            if self.wait_select_single(
 
247
                    'Label', objectName='alarmDay{}'.format(index))\
 
248
                    .text == day:
 
249
                self._select_single_alarm_day(index)
 
250
                break
 
251
 
 
252
    def _get_num_of_days(self):
 
253
        return int(self.wait_select_single(
 
254
            'QQuickRepeater', objectName='alarmDays').count)
 
255
 
 
256
    def _select_single_alarm_day(self, index):
 
257
        """ function for selecting the day passed to the function.
 
258
 
 
259
        :param index: the day to be selected
 
260
 
 
261
        """
 
262
        dayCheckbox = self.wait_select_single(
 
263
            'CheckBox', objectName='daySwitch{}'.format(index))
 
264
        dayCheckbox.check()
 
265
 
 
266
    @autopilot_logging.log_action(logger.info)
 
267
    def unselect_selected_days(self):
 
268
        """ function for unselecting already selected days.   """
 
269
        for index in range(self._get_num_of_days()):
 
270
            dayCheckbox = self.wait_select_single(
 
271
                'CheckBox', objectName='daySwitch{}'.format(index))
 
272
            dayCheckbox.uncheck()
 
273
 
 
274
 
 
275
class AlarmSound(Page):
 
276
 
 
277
    """Autopilot helper for the  AlarmSound page."""
 
278
 
 
279
    @autopilot_logging.log_action(logger.info)
 
280
    def set_alarm_sound(self, test_sound_name):
 
281
        """Set alarm sound.
 
282
 
 
283
        :param test_sound_name: sound to set for alarm
 
284
 
 
285
        """
 
286
        for index in range(self._get_num_of_sounds()):
 
287
            if self.wait_select_single(
 
288
                    'Label', objectName='soundName{}'.format(index)).\
 
289
                    text == test_sound_name:
 
290
                self._select_alarm_sound(index)
 
291
                break
 
292
 
 
293
    def _get_num_of_sounds(self):
 
294
        return int(self.wait_select_single(
 
295
            'QQuickRepeater', objectName='alarmSounds').count)
 
296
 
 
297
    def _select_alarm_sound(self, index):
 
298
        """ function for selecting the sound passed to the function.
 
299
 
 
300
        :param index: the sound to be selected
 
301
 
 
302
        """
 
303
        soundCheckbox = self.wait_select_single(
 
304
            'CheckBox', objectName='soundStatus{}'.format(index))
 
305
        soundCheckbox.check()
 
306
 
 
307
 
 
308
class AlarmLable(object):
 
309
 
 
310
    """Autopilot helper for the  AlarmLabel page."""
 
311
 
 
312
    def __init__(self, proxy_object):
 
313
        super(AlarmLable, self).__init__()
 
314
        self.proxy_object = proxy_object
 
315
 
 
316
    @classmethod
 
317
    def select(cls, main_view):
 
318
        proxy_object = main_view.wait_select_single(
 
319
            objectName='alarmLabelPage')
 
320
        proxy_object.visible.wait_for(True)
 
321
        return cls(proxy_object)
 
322
 
 
323
    @autopilot_logging.log_action(logger.info)
 
324
    def set_alarm_label(self, name):
 
325
        """Set alarm label.
 
326
 
 
327
        :param name: label for alarm to set
 
328
 
 
329
        """
 
330
        alarmTextfield = self.proxy_object.wait_select_single(
 
331
            "TextField", objectName='labelEntry')
 
332
        # TODO: This wait to ensure that the textfield is visible before
 
333
        # entering text should be part of the SDK emulator. Until then, it has
 
334
        # been added here. http://pad.lv/1289616  --nik90 2014-03-06
 
335
        alarmTextfield.visible.wait_for(True)
 
336
        alarmTextfield.write(name)
 
337
 
 
338
 
 
339
class AlarmList(object):
 
340
 
 
341
    """Autopilot helper for the  AlarmList."""
 
342
 
 
343
    def __init__(self, proxy_object):
 
344
        super(AlarmList, self).__init__()
 
345
        self.proxy_object = proxy_object
 
346
 
 
347
    @classmethod
 
348
    def select(cls, main_view):
 
349
        proxy_object = main_view.wait_select_single(
 
350
            objectName='alarmListFlickable')
 
351
        proxy_object.visible.wait_for(True)
 
352
        return cls(proxy_object)
 
353
 
 
354
    def get_num_of_alarms(self):
 
355
        """Return the number of saved alarms."""
 
356
        return int(self._get_saved_alarms_list().count)
 
357
 
 
358
    def _get_saved_alarms_list(self):
 
359
        """Return the saved alarm list"""
 
360
        return self.proxy_object.wait_select_single(
 
361
            'QQuickRepeater', objectName='alarmListRepeater')
 
362
 
 
363
    def get_saved_alarms(self):
 
364
        """Return a list with the information of the saved alarms.
 
365
 
 
366
        Each item of the returned list is a tuple of
 
367
        (name, recurrence, time, enabled).
 
368
 
 
369
        """
 
370
        alarms = []
 
371
        for index in range(self.get_num_of_alarms()):
 
372
            name = self.proxy_object.wait_select_single(
 
373
                'Label', objectName='listAlarmLabel{}'.format(index)).text
 
374
            recurrence = self.proxy_object.wait_select_single(
 
375
                'Label', objectName='listAlarmSubtitle{}'.format(index)).text
 
376
            time = self.proxy_object.wait_select_single(
 
377
                'Label', objectName='listAlarmTime{}'.format(index)).text
 
378
            enabled = self.proxy_object.wait_select_single(
 
379
                ubuntuuitoolkit.CheckBox,
 
380
                objectName='listAlarmStatus{}'.format(index)).checked
 
381
            alarms.append((name, recurrence, enabled, time))
 
382
        return alarms
 
383
 
 
384
    @autopilot_logging.log_action(logger.info)
 
385
    def delete_alarm(self, index):
 
386
        """Delete an alarm at the specified index."""
 
387
        old_alarm_count = self.get_num_of_alarms()
 
388
        alarm = self.proxy_object.wait_select_single(
 
389
            'Base', objectName='alarm{}'.format(index))
 
390
        alarm.swipe_to_delete()
 
391
        alarm.confirm_removal()
 
392
        try:
 
393
            self._get_saved_alarms_list().count.wait_for(old_alarm_count - 1)
 
394
        except AssertionError:
 
395
            raise ClockEmulatorException('Error deleting alarm.')