@@ -17,9 +17,19 @@
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
24+from autopilot import introspection
25+from ubuntuuitoolkit import UbuntuUIToolkitCustomProxyObjectBase
20from contextlib import contextmanager
27from contextlib import contextmanager
30+logger = logging.getLogger(__name__)
23@contextmanager
33@contextmanager
24def override_proxy_timeout(proxy, timeout_seconds):
34def override_proxy_timeout(proxy, timeout_seconds):
25 original_timeout = proxy._poll_time
35 original_timeout = proxy._poll_time
@@ -28,3 +38,486 @@ def override_proxy_timeout(proxy, timeout_seconds):
28 yield proxy
38 yield proxy
30 proxy._poll_time = original_timeout
40 proxy._poll_time = original_timeout
43+def get_wizard(current_page):
44+ return current_page.get_root_instance().select_single(Wizard)
47+class Wizard(UbuntuUIToolkitCustomProxyObjectBase):
48+ """High-level helper to navigate through the pages of the wizard"""
50+ def get_language_page(self):
51+ return self.wait_select_single(
52+ objectName='languagePage', visible='True')
54+ def get_current_page(self):
55+ return self.wait_select_single('Page', visible='True')
57+ def get_sim_page(self):
58+ return self.wait_select_single(
59+ objectName='simPage', visible='True')
61+ def get_password_page(self):
62+ return self.wait_select_single(
63+ objectName='passwdPage', visible='True')
65+ def get_password_entry_page(self):
66+ return self.wait_select_single(
67+ objectName='passwdSetPage', visible='True')
69+ def get_confirm_password_page(self):
70+ return self.wait_select_single(
71+ objectName='passwdConfirmPage', visible='True')
73+ def get_wifi_connect_page(self):
74+ return self.wait_select_single(
75+ objectName='wifiPage', visible='True')
77+ def get_reporting_page(self):
78+ return self.wait_select_single(
79+ objectName='reportingPage', visible='True')
81+ def get_finished_page(self):
82+ return self.wait_select_single(
83+ objectName='finishedPage', visible='True')
86+class WizardLanguagePage(UbuntuUIToolkitCustomProxyObjectBase):
87+ """Helper class to interact with the language welcome page"""
89+ # This class was renamed from LanguagePage to WizardLanguagePage because
90+ # there is a class with the same name in the system settings custom proxy
91+ # objects. Reported in http://pad.lv/1422904. --elopio - 2015-02-17
94+ def validate_dbus_object(cls, path, state):
95+ name = introspection.get_classname_from_path(path)
97+ if state['objectName'][1] == 'languagePage':
101+ def _get_language_button(self):
102+ return self.select_single(
103+ 'ComboButton', objectName='languageCombo')
105+ def _get_continue_button(self):
106+ return self.select_single('StackButton', text='Continue')
108+ def _swipe_to_language(self, list, language):
109+ """Swipe to the chosen language in the given list"""
111+ while not list.atYEnd:
113+ item = list.select_single(
114+ 'LabelVisual', text=language, visible='True')
115+ item.swipe_into_view()
117+ except introspection.dbus.StateNotFoundError:
118+ list.swipe_to_show_more_below()
119+ # item could not be found
120+ raise introspection.dbus.StateNotFoundError
122+ @autopilot.logging.log_action(logger.info)
123+ def select_language(self, language):
124+ """Select a different language from the list"""
125+ combo_button = self._get_language_button()
126+ self.pointing_device.click_object(combo_button)
127+ language_list = combo_button.wait_select_single(
128+ 'UbuntuListView11', visible='True')
129+ item = self._swipe_to_language(language_list, language)
130+ self.pointing_device.click_object(item)
132+ def get_selected_language(self):
133+ return self._get_language_button().get_properties()['text']
135+ @autopilot.logging.log_action(logger.info)
136+ def continue_(self):
137+ self.pointing_device.click_object(self._get_continue_button())
138+ wizard = get_wizard(self)
139+ next_page = wizard.get_current_page()
141+ if next_page.objectName == 'simPage':
142+ # no sim is inserted
143+ next_page = wizard.get_sim_page()
144+ sim_inserted = False
147+ next_page = wizard.get_password_page()
148+ return sim_inserted, next_page
151+class SimPage(UbuntuUIToolkitCustomProxyObjectBase):
152+ """Helper class to interact with the no sim notification page"""
155+ def validate_dbus_object(cls, path, state):
156+ name = introspection.get_classname_from_path(path)
158+ if state['objectName'][1] == 'simPage':
162+ def _get_back_button(self):
163+ return self.select_single('StackButton', text='Back')
165+ def _get_skip_button(self):
166+ return self.select_single('StackButton', text='Skip')
168+ @autopilot.logging.log_action(logger.info)
170+ self.pointing_device.click_object(self._get_back_button())
171+ return get_wizard(self).get_languge_page()
173+ @autopilot.logging.log_action(logger.info)
175+ self.pointing_device.click_object(self._get_skip_button())
176+ return get_wizard(self).get_password_page()
179+class PasswordPage(UbuntuUIToolkitCustomProxyObjectBase):
180+ """Helper class to interact with the password security page"""
182+ SECURITY_SWIPE = 'Swipe'
183+ SECURITY_PASSCODE = 'Passcode'
184+ SECURITY_PASSPHRASE = 'Passphrase'
187+ def validate_dbus_object(cls, path, state):
188+ name = introspection.get_classname_from_path(path)
190+ if state['objectName'][1] == 'passwdPage':
194+ def _get_option_name(self, formatted_name):
195+ # the option name is formatted as follows:
196+ # need to read the name between bold tags
197+ # '<b>Passcode</b> (4 digits only)'
198+ formatted_pattern = re.compile(r'<b>(.*?)</b>.*',
199+ re.IGNORECASE | re.DOTALL)
201+ match = formatted_pattern.search(formatted_name)
203+ name = match.group(1)
206+ def _get_all_options(self):
207+ return self.select_many('OptionSelectorDelegate')
209+ def _get_continue_button(self):
210+ return self.select_single('StackButton', text='Continue')
212+ def _get_back_button(self):
213+ return self.select_single('StackButton', text='Back')
215+ def _get_selected_option(self):
216+ return self.select_single(
217+ 'OptionSelectorDelegate', visible='True', selected='True')
219+ def get_selected_security_option(self):
220+ name_fmt = self._get_selected_option().get_properties()['subText']
221+ return self._get_option_name(name_fmt)
223+ @autopilot.logging.log_action(logger.info)
224+ def select_security_option(self, selected_option):
225+ options = self._get_all_options()
226+ for option in options:
227+ name = self._get_option_name(option.get_properties()['subText'])
228+ if name == selected_option:
229+ self.pointing_device.click_object(option)
231+ @autopilot.logging.log_action(logger.info)
232+ def back(self, sim_inserted):
233+ self.pointing_device.click_object(self._get_back_button())
234+ wizard = get_wizard(self)
236+ page = wizard.get_languge_page()
238+ page = wizard.get_sim_page()
241+ @autopilot.logging.log_action(logger.info)
242+ def continue_(self):
243+ option = self.get_selected_security_option()
244+ self.pointing_device.click_object(self._get_continue_button())
245+ wizard = get_wizard(self)
246+ if option == self.SECURITY_SWIPE:
247+ next_page = wizard.get_wifi_connect_page()
249+ next_page = wizard.get_password_entry_page()
253+class PasswordEntryPage(UbuntuUIToolkitCustomProxyObjectBase):
254+ """Helper class to interact with the pin entry page"""
257+ def validate_dbus_object(cls, path, state):
258+ name = introspection.get_classname_from_path(path)
260+ if state['objectName'][1] == 'passwdSetPage':
264+ def _get_pinpad_button(self, char):
265+ return self.select_single('PinPadButton', text=char)
267+ def _get_continue_button(self):
268+ return self.select_single('StackButton', text='Continue')
270+ def _get_back_button(self):
271+ return self.select_single('StackButton', text='Back')
273+ def _get_text_field(self):
274+ return self.select_single('QQuickTextInput')
276+ @autopilot.logging.log_action(logger.info)
277+ def enter_pin(self, pin):
279+ self.pointing_device.click_object(self._get_pinpad_button(char))
280+ return get_wizard(self).get_confirm_password_page()
282+ @autopilot.logging.log_action(logger.info)
283+ def enter_text(self, text):
284+ self.pointing_device.click_object(self._get_text_field())
285+ autopilot.input.Keyboard.create().type(text)
287+ @autopilot.logging.log_action(logger.info)
289+ self.pointing_device.click_object(self._get_back_button())
290+ return get_wizard(self).get_password_page()
292+ @autopilot.logging.log_action(logger.info)
293+ def continue_(self):
294+ autopilot.input.Keyboard.create().press_and_release('Enter')
295+ return get_wizard(self).get_confirm_password_page()
298+class ConfirmPasswordPage(UbuntuUIToolkitCustomProxyObjectBase):
299+ """Helper class to interact with the pin confirmation page"""
302+ def validate_dbus_object(cls, path, state):
303+ name = introspection.get_classname_from_path(path)
305+ if state['objectName'][1] == 'passwdConfirmPage':
309+ def _get_pinpad_button(self, char):
310+ return self.select_single('PinPadButton', text=char)
312+ def _get_continue_button(self):
313+ return self.select_single('StackButton', text='Continue')
315+ def _get_back_button(self):
316+ return self.select_single('StackButton', text='Back')
318+ def _get_text_field(self):
319+ return self.select_single('QQuickTextInput')
321+ @autopilot.logging.log_action(logger.info)
322+ def enter_pin(self, pin):
324+ self.pointing_device.click_object(self._get_pinpad_button(char))
325+ return get_wizard(self).get_wifi_connect_page()
327+ @autopilot.logging.log_action(logger.info)
328+ def enter_text(self, text):
329+ self.pointing_device.click_object(self._get_text_field())
330+ autopilot.input.Keyboard.create().type(text)
332+ @autopilot.logging.log_action(logger.info)
334+ self.pointing_device.click_object(self._get_back_button())
335+ return get_wizard(self).get_password_page()
337+ @autopilot.logging.log_action(logger.info)
338+ def continue_(self):
339+ autopilot.input.Keyboard.create().press_and_release('Enter')
340+ return get_wizard(self).get_wifi_connect_page()
343+class WifiConnectPage(UbuntuUIToolkitCustomProxyObjectBase):
344+ """Helper class to interact with the Wi-Fi network list page"""
347+ def validate_dbus_object(cls, path, state):
348+ name = introspection.get_classname_from_path(path)
350+ if state['objectName'][1] == 'wifiPage':
354+ def _get_all_networks(self):
356+ networks = self.select_many('Standard', objectName='accessPoint',
362+ def _get_network(self, ssid):
363+ return self.wait_select_single(
364+ 'Standard', objectName='accessPoint', text=ssid, visible='True')
366+ def _get_network_checkbox(self, ssid):
367+ return self._get_network(ssid).select_single(
368+ 'CheckBox', visible='True')
370+ def _get_notification(self, unity):
371+ logger.info('Waiting longer for notification object')
372+ with override_proxy_timeout(unity, 30):
373+ return unity.wait_select_single(
374+ Notification, objectName='notification1', visible='True')
376+ def _get_back_button(self):
377+ return self.wait_select_single(
378+ 'StackButton', text='Back', visible='True')
380+ def _get_skip_button(self):
381+ return self.wait_select_single(
382+ 'StackButton', text='Skip', visible='True')
384+ def _get_continue_button(self):
385+ return self.wait_select_single(
386+ 'StackButton', text='Continue', visible='True')
388+ def _get_next_button(self):
389+ # Since the phone state is unknown, this returns skip||continue
390+ # depending on which one is visible
391+ buttons = self.select_many('StackButton')
392+ for button in buttons:
393+ if button.text == "Continue" or button.text == "Skip":
395+ raise introspection.dbus.StateNotFoundError
397+ def is_any_network_checked(self):
398+ networks = self._get_all_networks()
399+ for network in networks:
400+ checkbox = network.select_single('CheckBox', visible='True')
401+ if checkbox.get_properties()['checked']:
405+ def is_any_network_found(self):
406+ num_neworks = len(self._get_all_networks())
407+ return True if num_neworks > 0 else False
409+ def is_network_checked(self, ssid):
410+ return self._get_network_checkbox(ssid).get_properties()['checked']
412+ @autopilot.logging.log_action(logger.info)
413+ def select_network(self, unity, ssid):
414+ self.pointing_device.click_object(self._get_network_checkbox(ssid))
415+ return PasswordNotification(self._get_notification(unity))
417+ @autopilot.logging.log_action(logger.info)
418+ def advance_page(self):
419+ """ Advance the wizard regardless of weather or not
420+ continue||skip button is present """
421+ self.pointing_device.click_object(self._get_next_button())
422+ return get_wizard(self).get_reporting_page()
424+ @autopilot.logging.log_action(logger.info)
426+ self.pointing_device.click_object(self._get_back_button())
427+ return get_wizard(self).get_password_page()
429+ @autopilot.logging.log_action(logger.info)
431+ self.pointing_device.click_object(self._get_skip_button())
432+ return get_wizard(self).get_reporting_page()
434+ @autopilot.logging.log_action(logger.info)
435+ def continue_(self):
436+ self.pointing_device.click_object(self._get_continue_button())
437+ return get_wizard(self).get_reporting_page()
440+class Notification(UbuntuUIToolkitCustomProxyObjectBase):
441+ """Base class for notification objects"""
445+class PasswordNotification(Notification):
446+ """Helper class to interact with the password entry notification"""
448+ def __init__(self, notification):
449+ self.notification = notification
451+ def _get_connect_button(self):
452+ return self.notification.wait_select_single(
453+ 'Button', text='Connect', objectName='notify_button0')
455+ def _get_cancel_buttoon(self):
456+ return self.notification.wait_select_single(
457+ 'Button', text='Cancel', objectName='notify_button1')
459+ def _get_text_field(self):
460+ return self.notification.wait_select_single('TextField')
462+ @autopilot.logging.log_action(logger.info)
463+ def enter_text(self, text):
464+ self._get_text_field().write(text)
466+ @autopilot.logging.log_action(logger.info)
468+ self.notification.pointing_device.click_object(
469+ self._get_connect_button())
471+ @autopilot.logging.log_action(logger.info)
473+ self.notification.pointing_device.click_object(
474+ self._get_cancel_buttoon())
477+class ReportingPage(UbuntuUIToolkitCustomProxyObjectBase):
478+ """Helper class to interact with the reporting page"""
481+ def validate_dbus_object(cls, path, state):
482+ name = introspection.get_classname_from_path(path)
484+ if state['objectName'][1] == 'reportingPage':
488+ def _get_continue_button(self):
489+ return self.select_single('StackButton', text='Continue')
491+ def _get_back_button(self):
492+ return self.select_single('StackButton', text='Back')
494+ @autopilot.logging.log_action(logger.info)
496+ self.pointing_device.click_object(self._get_back_button())
497+ return get_wizard(self).get_wifi_connect_page()
499+ @autopilot.logging.log_action(logger.info)
500+ def continue_(self):
501+ self.pointing_device.click_object(self._get_continue_button())
502+ return get_wizard(self).get_finished_page()
505+class FinishedPage(UbuntuUIToolkitCustomProxyObjectBase):
506+ """Helper class to interact with the finished page"""
509+ def validate_dbus_object(cls, path, state):
510+ name = introspection.get_classname_from_path(path)
512+ if state['objectName'][1] == 'finishedPage':
516+ def _get_finish_button(self):
517+ return self.wait_select_single(
518+ 'StackButton', text='Finish', visible='True')
520+ @autopilot.logging.log_action(logger.info)
522+ self.pointing_device.click_object(self._get_finish_button())
523+ self.wait_until_destroyed()