def send(self, string): self.switch_to_keyboard() for val in string: if ord(val) > 127: # this would get the right key to long press and switch to the right keyboard middle_key_val = self._find_key_for_longpress( val.encode('UTF-8')) self._switch_to_correct_layout(middle_key_val) # find the key to long press and press it to get the extended characters list middle_key = self.marionette.find_element( *self._key_locator(middle_key_val)) action = Actions(self.marionette) action.press(middle_key).wait(1).perform() # find the targeted extended key to send key = Wait(self.marionette).until( expected.element_present(*self._key_locator(val))) Wait(self.marionette).until(expected.element_displayed(key)) action.move(key).release().perform() else: # after switching to correct keyboard, tap/click if the key is there self._switch_to_correct_layout(val) self._tap(val) # when we tap on '@' the layout switches to the default keyboard - Bug 996332 if val == '@': Wait(self.marionette).until( lambda m: self._layout_page == 0) self.apps.switch_to_displayed_app()
def edge_scroll(self, frame, direction, dist, release=True): """edge scroll - performs task switching action. direction = 'LtoR' or 'RtoL' (finger movement direction) dist = percentage of horizontal distance travel, max is 1.0 release = if set to False, the Action object will be returned so the user can complete the release action""" start_x = 0 dist_travelled = 0 time_increment = 0.01 if dist > 1: dist = 1 if direction == 'LtoR': start_x = 0 elif direction == 'RtoL': start_x = frame.size['width'] dist *= -1 # travel opposite direction limit = dist * frame.size['width'] dist_unit = limit * time_increment action = Actions(self.marionette) action.press(frame, start_x, frame.size['height'] / 2) # press either the left or right edge while abs(dist_travelled) < abs(limit): action.move_by_offset(dist_unit, 0) action.wait(time_increment) dist_travelled += dist_unit if release: action.release() action.perform() return action
def wait(marionette, wait_for_condition, expected): testAction = marionette.absolute_url("testAction.html") marionette.navigate(testAction) action = Actions(marionette) button = marionette.find_element(By.ID, "button1") action.press(button).wait().release().perform() wait_for_condition_else_raise(marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
def send(self, string): self.switch_to_keyboard() for val in string: if ord(val) > 127: # this would get the right key to long press and switch to the right keyboard middle_key_val = self._find_key_for_longpress(val.encode("UTF-8")) self._switch_to_correct_layout(middle_key_val) # find the key to long press and press it to get the extended characters list middle_key = self.marionette.find_element(*self._key_locator(middle_key_val)) action = Actions(self.marionette) action.press(middle_key).wait(1).perform() # find the targeted extended key to send key = Wait(self.marionette).until(expected.element_present(*self._key_locator(val))) Wait(self.marionette).until(expected.element_displayed(key)) action.move(key).release().perform() else: # after switching to correct keyboard, tap/click if the key is there self._switch_to_correct_layout(val) self._tap(val) # when we tap on '@' the layout switches to the default keyboard - Bug 996332 if val == "@": Wait(self.marionette).until(lambda m: self._layout_page == 0) self.apps.switch_to_displayed_app()
def move_seek_slider(self, offset): scale = self.marionette.find_element(*self._video_seek_head_locator) finger = Actions(self.marionette) finger.press(scale) finger.move_by_offset(offset, 0) finger.release() finger.perform()
def move_slider(self, slider, dir_x): scale = self.marionette.find_element(*slider) finger = Actions(self.marionette) finger.press(scale) finger.move_by_offset(dir_x, 0) finger.release() finger.perform() time.sleep(2)
def context_menu(marionette, wait_for_condition, expected1, expected2): testAction = marionette.absolute_url("testAction.html") marionette.navigate(testAction) button = marionette.find_element("id", "button1") action = Actions(marionette) action.press(button).wait(5).perform() wait_for_condition_else_raise(marionette, wait_for_condition, expected1, "return document.getElementById('button1').innerHTML;") action.release().perform() wait_for_condition_else_raise(marionette, wait_for_condition, expected2, "return document.getElementById('button1').innerHTML;")
def move_element_offset(marionette, wait_for_condition, expected1, expected2): testAction = marionette.absolute_url("testAction.html") marionette.navigate(testAction) ele = marionette.find_element(By.ID, "button1") action = Actions(marionette) action.press(ele).move_by_offset(0,150).move_by_offset(0, 150).release() action.perform() wait_for_condition_else_raise(marionette, wait_for_condition, expected1, "return document.getElementById('button1').innerHTML;") wait_for_condition_else_raise(marionette, wait_for_condition, expected2, "return document.getElementById('button2').innerHTML;")
def wait(marionette, wait_for_condition, expected): testAction = marionette.absolute_url("testAction.html") marionette.navigate(testAction) action = Actions(marionette) button = marionette.find_element(By.ID, "button1") action.press(button).wait().release().perform() wait_for_condition_else_raise( marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
def chain(marionette, wait_for_condition, expected1, expected2): testAction = marionette.absolute_url("testAction.html") marionette.navigate(testAction) marionette.timeout.implicit = 15 action = Actions(marionette) button1 = marionette.find_element(By.ID, "button1") action.press(button1).perform() button2 = marionette.find_element(By.ID, "delayed") wait_for_condition_else_raise(marionette, wait_for_condition, expected1, "return document.getElementById('button1').innerHTML;") action.move(button2).release().perform() wait_for_condition_else_raise(marionette, wait_for_condition, expected2, "return document.getElementById('delayed').innerHTML;")
def _flick_menu_down(self, locator): self.parent.parent.wait_for_element_displayed(*self._current_element(*locator), timeout=2) current_element = self.marionette.find_element(*self._current_element(*locator)) next_element = self.marionette.find_element(*self._next_element(*locator)) # TODO: update this with more accurate Actions action = Actions(self.marionette) action.press(current_element) action.move(next_element) action.release() action.perform()
def press_release(marionette, times, wait_for_condition, expected): testAction = marionette.absolute_url("testAction.html") marionette.navigate(testAction) action = Actions(marionette) button = marionette.find_element(By.ID, "button1") action.press(button).release() # Insert wait between each press and release chain. for _ in range(times-1): action.wait(0.1) action.press(button).release() action.perform() wait_for_condition_else_raise(marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
def switch_keyboard_language(self, lang_code): # TODO At the moment this doesn't work because the UI has changed # An attempted repair ran into https://bugzilla.mozilla.org/show_bug.cgi?id=779284 (Modal dialog) keyboard_language_locator = (By.CSS_SELECTOR, ".keyboard-row button[data-keyboard='%s']" % lang_code) self.switch_to_keyboard() language_key = self.marionette.find_element(*self._language_key_locator) action = Actions(self.marionette) action.press(language_key).wait(1).perform() target_kb_layout = self.marionette.find_element(*keyboard_language_locator) action.move(target_kb_layout).release().perform() self.apps.switch_to_displayed_app()
def move_element_offset(marionette, wait_for_condition, expected1, expected2): testAction = marionette.absolute_url("testAction.html") marionette.navigate(testAction) ele = marionette.find_element(By.ID, "button1") action = Actions(marionette) action.press(ele).move_by_offset(0, 150).move_by_offset(0, 150).release() action.perform() wait_for_condition_else_raise( marionette, wait_for_condition, expected1, "return document.getElementById('button1').innerHTML;") wait_for_condition_else_raise( marionette, wait_for_condition, expected2, "return document.getElementById('button2').innerHTML;")
def context_menu(marionette, wait_for_condition, expected1, expected2): testAction = marionette.absolute_url("testAction.html") marionette.navigate(testAction) button = marionette.find_element("id", "button1") action = Actions(marionette) action.press(button).wait(5).perform() wait_for_condition_else_raise( marionette, wait_for_condition, expected1, "return document.getElementById('button1').innerHTML;") action.release().perform() wait_for_condition_else_raise( marionette, wait_for_condition, expected2, "return document.getElementById('button1').innerHTML;")
def press_release(marionette, times, wait_for_condition, expected): testAction = marionette.absolute_url("testAction.html") marionette.navigate(testAction) action = Actions(marionette) button = marionette.find_element(By.ID, "button1") action.press(button).release() # Insert wait between each press and release chain. for _ in range(times - 1): action.wait(0.1) action.press(button).release() action.perform() wait_for_condition_else_raise( marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
def test_move_offset_element(self): testAction = self.marionette.absolute_url("testAction.html") self.marionette.navigate(testAction) start = self.marionette.find_element("id", "button1") ele = self.marionette.find_element("id", "button3") multi_action = MultiActions(self.marionette) action1 = Actions(self.marionette) action2 = Actions(self.marionette) action1.press(start).move_by_offset(0,300).wait().release() action2.press(ele).wait(5).release() multi_action.add(action1).add(action2).perform() expected = "button1-touchstart" self.wait_for_condition(lambda m: m.execute_script("return document.getElementById('button1').innerHTML;") == expected) self.assertEqual("button2-touchmove-touchend", self.marionette.execute_script("return document.getElementById('button2').innerHTML;")) self.assertTrue("button3-touchstart-touchend" in self.marionette.execute_script("return document.getElementById('button3').innerHTML;"))
def chain(marionette, wait_for_condition, expected1, expected2): testAction = marionette.absolute_url("testAction.html") marionette.navigate(testAction) marionette.timeout.implicit = 15 action = Actions(marionette) button1 = marionette.find_element(By.ID, "button1") action.press(button1).perform() button2 = marionette.find_element(By.ID, "delayed") wait_for_condition_else_raise( marionette, wait_for_condition, expected1, "return document.getElementById('button1').innerHTML;") action.move(button2).release().perform() wait_for_condition_else_raise( marionette, wait_for_condition, expected2, "return document.getElementById('delayed').innerHTML;")
def choose_extended_character(self, long_press_key, selection, movement=True): self.switch_to_keyboard() action = Actions(self.marionette) # after switching to correct keyboard, set long press if the key is there self._switch_to_correct_layout(long_press_key) key = Wait(self.marionette).until(expected.element_present(*self._key_locator(long_press_key))) Wait(self.marionette).until(expected.element_displayed(key)) action.press(key).wait(1).perform() # find the extended key and perform the action chain extend_keys = self.marionette.find_elements(*self._highlight_key_locator) if movement is True: action.move(extend_keys[selection - 1]).perform() action.release().perform() self.apps.switch_to_displayed_app()
def switch_keyboard_language(self, lang_code): # TODO At the moment this doesn't work because the UI has changed # An attempted repair ran into https://bugzilla.mozilla.org/show_bug.cgi?id=779284 (Modal dialog) keyboard_language_locator = ( By.CSS_SELECTOR, ".keyboard-row button[data-keyboard='%s']" % lang_code) self.switch_to_keyboard() language_key = self.marionette.find_element( *self._language_key_locator) action = Actions(self.marionette) action.press(language_key).wait(1).perform() target_kb_layout = self.marionette.find_element( *keyboard_language_locator) action.move(target_kb_layout).release().perform() self.apps.switch_to_displayed_app()
def test_three_fingers(self): testAction = self.marionette.absolute_url("testAction.html") self.marionette.navigate(testAction) start_one = self.marionette.find_element(By.ID, "button1") start_two = self.marionette.find_element(By.ID, "button2") element1 = self.marionette.find_element(By.ID, "button3") element2 = self.marionette.find_element(By.ID, "button4") multi_action = MultiActions(self.marionette) action1 = Actions(self.marionette) action2 = Actions(self.marionette) action3 = Actions(self.marionette) action1.press(start_one).move_by_offset(0, 300).release() action2.press(element1).wait().wait(5).release() action3.press(element2).wait().wait().release() multi_action.add(action1).add(action2).add(action3).perform() expected = "button1-touchstart" self.wait_for_condition(lambda m: m.execute_script( "return document.getElementById('button1').innerHTML;") == expected ) self.assertEqual( "button2-touchmove-touchend", self.marionette.execute_script( "return document.getElementById('button2').innerHTML;")) button3_text = self.marionette.execute_script( "return document.getElementById('button3').innerHTML;") button4_text = self.marionette.execute_script( "return document.getElementById('button4').innerHTML;") self.assertTrue("button3-touchstart-touchend" in button3_text) self.assertTrue("button4-touchstart-touchend" in button4_text) self.assertTrue(int(button3_text.rsplit("-")[-1]) >= 5000) self.assertTrue(int(button4_text.rsplit("-")[-1]) >= 5000)
def choose_extended_character(self, long_press_key, selection, movement=True): self.switch_to_keyboard() action = Actions(self.marionette) # after switching to correct keyboard, set long press if the key is there self._switch_to_correct_layout(long_press_key) key = Wait(self.marionette).until( expected.element_present(*self._key_locator(long_press_key))) Wait(self.marionette).until(expected.element_displayed(key)) action.press(key).wait(1).perform() # find the extended key and perform the action chain extend_keys = self.marionette.find_elements( *self._highlight_key_locator) if movement is True: action.move(extend_keys[selection - 1]).perform() action.release().perform() self.apps.switch_to_displayed_app()
def test_move_offset_element(self): testAction = self.marionette.absolute_url("testAction.html") self.marionette.navigate(testAction) start = self.marionette.find_element(By.ID, "button1") ele = self.marionette.find_element(By.ID, "button3") multi_action = MultiActions(self.marionette) action1 = Actions(self.marionette) action2 = Actions(self.marionette) action1.press(start).move_by_offset(0, 300).wait().release() action2.press(ele).wait(5).release() multi_action.add(action1).add(action2).perform() expected = "button1-touchstart" self.wait_for_condition(lambda m: m.execute_script( "return document.getElementById('button1').innerHTML;") == expected ) self.assertEqual( "button2-touchmove-touchend", self.marionette.execute_script( "return document.getElementById('button2').innerHTML;")) self.assertTrue( "button3-touchstart-touchend" in self.marionette.execute_script( "return document.getElementById('button3').innerHTML;"))
def test_three_fingers(self): testAction = self.marionette.absolute_url("testAction.html") self.marionette.navigate(testAction) start_one = self.marionette.find_element("id", "button1") start_two = self.marionette.find_element("id", "button2") element1 = self.marionette.find_element("id", "button3") element2 = self.marionette.find_element("id", "button4") multi_action = MultiActions(self.marionette) action1 = Actions(self.marionette) action2 = Actions(self.marionette) action3 = Actions(self.marionette) action1.press(start_one).move_by_offset(0,300).release() action2.press(element1).wait().wait(5).release() action3.press(element2).wait().wait().release() multi_action.add(action1).add(action2).add(action3).perform() expected = "button1-touchstart" self.wait_for_condition(lambda m: m.execute_script("return document.getElementById('button1').innerHTML;") == expected) self.assertEqual("button2-touchmove-touchend", self.marionette.execute_script("return document.getElementById('button2').innerHTML;")) button3_text = self.marionette.execute_script("return document.getElementById('button3').innerHTML;") button4_text = self.marionette.execute_script("return document.getElementById('button4').innerHTML;") self.assertTrue("button3-touchstart-touchend" in button3_text) self.assertTrue("button4-touchstart-touchend" in button4_text) self.assertTrue(int(button3_text.rsplit("-")[-1]) >= 5000) self.assertTrue(int(button4_text.rsplit("-")[-1]) >= 5000)
class EverythingMe(object): def __init__(self, p_parent): self.apps = p_parent.apps self.data_layer = p_parent.data_layer self.parent = p_parent self.marionette = p_parent.marionette self.UTILS = p_parent.UTILS self.actions = Actions(self.marionette) def launch(self): self.apps.kill_all() # If EME has already been launched, then the DOM has changed. self.UTILS.reporting.logResult("info", "Launching Everything ME.") boolOK = False try: self.parent.wait_for_element_displayed(*DOM.EME.start_eme_icon, timeout=1) x = self.marionette.find_element(*DOM.EME.start_eme_icon) x.tap() boolOK = True except: self.UTILS.reporting.logResult( "info", "Everything ME is already 'running', so just waking it up ...") self._relaunch() try: self.parent.wait_for_element_displayed(*DOM.EME.groups, timeout=3) except: self._relaunch() boolOK = True self.UTILS.test.test(boolOK, "EME Starting up ...") def _relaunch(self): """ Private function to re-launch. This gets complicated: 1. el.tap() and el.click() only work *sometimes*, so use the keyboard to relaunch. 2. Sometimes the messges app randomly launches instead of evme! """ x = self.marionette.find_element(*DOM.EME.search_field) x.send_keys("waking up evme") x = self.marionette.find_element(*DOM.EME.search_clear) x.tap() def add_app_to_homescreen(self, name): """ Pick an app from the apps listed in this group. """ x = self.UTILS.element.getElementByXpath( DOM.EME.app_to_install.format(name)) app_name = x.text self.UTILS.reporting.logResult( "debug", "icon displayed: {}".format(x.is_displayed())) time.sleep(2) self.UTILS.test.test(app_name == name, "" + app_name + "'is the correct app", True) self.actions.long_press(x, 2).perform() x = self.UTILS.element.getElement(DOM.EME.add_to_homescreen_btn, "Add app to homescreen button") x.tap() time.sleep(2) return True def add_group(self, group): """ Adds a group to EME (assumes you're already in the EME group screen). """ self.UTILS.reporting.logResult("info", "(Adding group '" + group + "'.)") # Click the 'More' icon. x = self.UTILS.element.getElement(DOM.EME.add_group_button, "'More' icon") x.tap() # Wait for the 'loading' spinner to go away (can take a while!). self.UTILS.element.waitForNotElements(DOM.EME.loading_groups_message, "'Loading' message", True, 120) # Chose an item from the groups list... self.UTILS.general.selectFromSystemDialog(group) # Verify the new group is in the groups list. x = self.UTILS.element.getElements(DOM.EME.groups, "Groups") boolOK = False for i in x: if i.get_attribute("data-query") == group: boolOK = True break self.UTILS.test.test( boolOK, "New group '" + group + "' is now present in the EME groups.") return boolOK def add_multiple_groups(self, group_array=False): """ Adds multiple groups based on an array of numbers (defaults to all available groups). <br><br> For example: add_multiple_groups([0,1,2,3,8,11]) ... or just: add_multiple_groups() """ x = self.UTILS.element.getElement(DOM.EME.add_group_button, "'More' icon") x.tap() self.UTILS.element.waitForNotElements(DOM.EME.loading_groups_message, "'Loading' message", True, 120) # Switch to group selector (in top level iframe). self.marionette.switch_to_frame() # for checking later list_names = [] elements = self.UTILS.element.getElements( DOM.GLOBAL.modal_valueSel_list, "Groups list", False) for i in range(len(elements)): if i > 0: # Keep shuffling the groups into view so they can be tapped. self.actions.press(elements[i]).move( elements[i - 1]).wait(0.5).release().perform() elements = self.marionette.find_elements( *DOM.GLOBAL.modal_valueSel_list) # Only select it if it's the list, or there is no list. select_elements = False if group_array: if len(group_array) == len(list_names): # # We've done all of them - stop looping! break if i in group_array: select_elements = True else: select_elements = True if select_elements: tmp_name = elements[i].find_element("tag name", "span").text self.UTILS.reporting.logResult( "info", "Selecting '{}' ...".format(tmp_name)) list_names.append(tmp_name) elements[i].tap() # Sometimes the first tap does nothing for some reason. if not elements[i].get_attribute("aria-checked"): elements[i].tap() # Click the OK button. x = self.UTILS.element.getElement(DOM.GLOBAL.modal_valueSel_ok, "OK button") try: # Sometimes it's one, sometimes the other ... x.tap() x.click() except: pass time.sleep(1) # Checkk all the items we expect are now loaded in evme. self.UTILS.iframe.switchToFrame(*DOM.Home.frame_locator) time.sleep(5) for name in list_names: ok = False # Reload the groups (silently or we'll have loads of these messages!). try: x = self.marionette.find_elements(*DOM.EME.groups) except: break for i in x: group_name = i.get_attribute("data-query") if group_name == name: ok = True break self.UTILS.test.test(ok, "'{}' is now among the groups.".format(name)) def install_app(self, category, name, expect_btn=True): """Try to install an application. Try to install the application with the given name in the given category. expect_btn determines if we expect the "Add to Home Screen" button in the bookmark page. Returns True if the application was successfully installed. """ self.pick_group(category) self.UTILS.iframe.switchToFrame(*DOM.EME.frame_locator) app_name = self.UTILS.element.getElementByXpath( DOM.EME.app_to_install.format(name)).text # Add the app to the homescreen. self.add_app_to_homescreen(app_name) self.UTILS.iframe.switchToFrame(*DOM.EME.bookmark_frame_locator) time.sleep(4) result = False # We expect the application to be installed, so find the Add to Home Screen button and tap it if expect_btn: add_btn = self.UTILS.element.getElement( DOM.EME.add_to_homescreen_done_btn, "Add bookmark to Home Screen Button") add_btn.tap() result = True else: # We expect the application is already installed, so find the proper header title = self.UTILS.element.getElement(DOM.EME.edit_bookmark_header, "Edit link header") self.UTILS.test.test(title, "Title '{}' found".format(title.text)) return result def launch_from_group(self, app_name): """ Function to launch an app directly from an EME group. """ x = self.UTILS.element.getElement( ("xpath", "//li[@data-name='{}']".format(app_name)), "Icon for app '{}'".format(app_name), False) try: x.tap() except: # App is not visible, so I need to move it into view first. _id = x.get_attribute("_id") self.marionette.execute_script( "document.getElementById('{}').scrollIntoView();".format(_id)) x.tap() time.sleep(1) self.UTILS.element.waitForNotElements(DOM.EME.launched_activity_bar, "Activity notifier", True, 30) x = self.UTILS.debug.screenShotOnErr() self.UTILS.reporting.logResult("info", "Screenshot of app running:", x) def pick_group(self, name): """ Pick a group from the main icons. """ screenshot = self.UTILS.debug.screenShotOnErr() self.UTILS.reporting.logResult( "info", "<b>Choosing group '{}' from here ...</b>".format(name), screenshot) ok = False self.UTILS.reporting.info("searching for element: {}".format( DOM.Home.app_icon_css_selector.format(name))) icon = self.marionette.find_element( 'css selector', DOM.Home.app_icon_css_selector.format(name)) self.UTILS.reporting.logResult( "debug", "icon displayed: {}".format(icon.is_displayed())) icon.tap() try: self.UTILS.iframe.switchToFrame(*DOM.EME.frame_locator) self.parent.wait_for_element_displayed(*DOM.EME.apps_not_installed, timeout=20) self.UTILS.reporting.logResult( "info", "(Apps for group {} were displayed.)".format(name)) ok = True except Exception as e: self.UTILS.reporting.debug( "*** Error getting apps not installed: {}".format(e)) screenshot = self.UTILS.debug.screenShotOnErr() self.UTILS.reporting.logResult("info", "(<b>NOTE:</b>Apps for group {} were not displayed.)|{}|{}".\ format(name, screenshot[0], screenshot[1])) return ok def remove_groups(self, group_array): """ Removes groups from the EME group page. group_array is an array of group names (default = all groups) For example: remove_groups(["Games","Local"]) """ """ Put the groups into edit mode. Sometimes this takes a while to happen, so increase the length of time you press the icon until it works! """ ok = False x = self.marionette.find_element( 'xpath', DOM.Home.app_icon_css_selector.format(group_array[0])) self.actions.press(x).wait(3).release() try: actions.perform() except: pass try: x = self.UTILS.element.getElement( ("xpath", DOM.Home.app_delete_icon_xpath.format( group_array[0])), "Delete button", False, 5, True) if x.is_displayed(): ok = True except: pass time.sleep(2) self.UTILS.test.test(ok, "Enabled EDIT mode.") x = self.UTILS.debug.screenShotOnErr() self.UTILS.reporting.logResult("info", "Screenshot of app in EDIT mode:", x) # Remove all groups in the array. removed = 0 group_cnt = len(group_array) self.UTILS.reporting.logResult("info", "Removing {} groups".format(group_cnt)) self.UTILS.reporting.logResult( "info", "Removing groups: {}".format(group_array)) for group_specified in group_array: # Remove it. self.marionette.find_element( 'xpath', DOM.Home.app_icon_css_selector.format(group_specified)) y = self.UTILS.element.getElement( ("xpath", DOM.Home.app_delete_icon_xpath.format(group_specified)), "Delete button", False, 5, True) y.tap() delete = self.UTILS.element.getElement( DOM.Home.app_confirm_delete, "Confirm app delete button") delete.tap() removed = removed + 1 self.UTILS.reporting.logResult( "info", "Removed group '{}' ...".format(group_specified)) self.UTILS.reporting.logResult("info", "Removed {} groups".format(removed)) if removed == group_cnt: break # Turn off edit mode. self.UTILS.reporting.logResult("info", "Disabling edit mode ...") self.UTILS.home.touchHomeButton() def search_for_app(self, name): """ Uses the search field to find the app (waits for the result to appear etc...).<br> Returns the element for the icon (or False if it's not found). """ x = self.UTILS.element.getElement(DOM.EME.search_field, "Search field") x.clear() x.send_keys(name) x.click() time.sleep(5) # Can take a few seconds to appear, so try a few times (about 1 min). for retry in range(10): x = self.UTILS.debug.screenShotOnErr() self.UTILS.reporting.logResult( "debug", "Looking for '{}' - attempt {} ...".format(name, retry), x) x = self.UTILS.element.getElements(DOM.EME.search_suggestions, "Search suggestions") ok = False for i in x: i_name = i.get_attribute("data-suggestion") if i_name: i_name = i_name.lower() i_name = i_name.replace("[", "") i_name = i_name.replace("]", "") is_in = False for i2 in name.lower().split(): self.UTILS.reporting.logResult( "debug", "Is '{}' in '{}'?".format(i2, i_name)) if i2 not in i_name: is_in = False break else: is_in = True if is_in: i.tap() ok = True break if ok: break time.sleep(6) self.UTILS.test.test(ok, "Found '%s' in suggestions." % name) ok = True try: elem = ("xpath", DOM.EME.search_result_icon_xpath.format(name)) self.parent.wait_for_element_displayed(*elem, timeout=60) x = self.marionette.find_element(*elem) return x except: ok = False return ok
class EverythingMe(object): def __init__(self, p_parent): self.apps = p_parent.apps self.data_layer = p_parent.data_layer self.parent = p_parent self.marionette = p_parent.marionette self.UTILS = p_parent.UTILS self.actions = Actions(self.marionette) def launch(self): self.apps.kill_all() # If EME has already been launched, then the DOM has changed. self.UTILS.reporting.logResult("info", "Launching Everything ME.") boolOK = False try: self.parent.wait_for_element_displayed(*DOM.EME.start_eme_icon, timeout=1) x = self.marionette.find_element(*DOM.EME.start_eme_icon) x.tap() boolOK = True except: self.UTILS.reporting.logResult("info", "Everything ME is already 'running', so just waking it up ...") self._relaunch() try: self.parent.wait_for_element_displayed(*DOM.EME.groups, timeout=3) except: self._relaunch() boolOK = True self.UTILS.test.test(boolOK, "EME Starting up ...") def _relaunch(self): """ Private function to re-launch. This gets complicated: 1. el.tap() and el.click() only work *sometimes*, so use the keyboard to relaunch. 2. Sometimes the messges app randomly launches instead of evme! """ x = self.marionette.find_element(*DOM.EME.search_field) x.send_keys("waking up evme") x = self.marionette.find_element(*DOM.EME.search_clear) x.tap() def add_app_to_homescreen(self, name): """ Pick an app from the apps listed in this group. """ x = self.UTILS.element.getElementByXpath(DOM.EME.app_to_install.format(name)) app_name = x.text self.UTILS.reporting.logResult("debug", "icon displayed: {}".format(x.is_displayed())) time.sleep(2) self.UTILS.test.test(app_name == name, "" + app_name + "'is the correct app", True) self.actions.long_press(x, 2).perform() x = self.UTILS.element.getElement(DOM.EME.add_to_homescreen_btn, "Add app to homescreen button") x.tap() time.sleep(2) return True def add_group(self, group): """ Adds a group to EME (assumes you're already in the EME group screen). """ self.UTILS.reporting.logResult("info", "(Adding group '" + group + "'.)") # Click the 'More' icon. x = self.UTILS.element.getElement(DOM.EME.add_group_button, "'More' icon") x.tap() # Wait for the 'loading' spinner to go away (can take a while!). self.UTILS.element.waitForNotElements(DOM.EME.loading_groups_message, "'Loading' message", True, 120) # Chose an item from the groups list... self.UTILS.general.selectFromSystemDialog(group) # Verify the new group is in the groups list. x = self.UTILS.element.getElements(DOM.EME.groups, "Groups") boolOK = False for i in x: if i.get_attribute("data-query") == group: boolOK = True break self.UTILS.test.test(boolOK, "New group '" + group + "' is now present in the EME groups.") return boolOK def add_multiple_groups(self, group_array=False): """ Adds multiple groups based on an array of numbers (defaults to all available groups). <br><br> For example: add_multiple_groups([0,1,2,3,8,11]) ... or just: add_multiple_groups() """ x = self.UTILS.element.getElement(DOM.EME.add_group_button, "'More' icon") x.tap() self.UTILS.element.waitForNotElements(DOM.EME.loading_groups_message, "'Loading' message", True, 120) # Switch to group selector (in top level iframe). self.marionette.switch_to_frame() # for checking later list_names = [] elements = self.UTILS.element.getElements(DOM.GLOBAL.modal_valueSel_list, "Groups list", False) for i in range(len(elements)): if i > 0: # Keep shuffling the groups into view so they can be tapped. self.actions.press(elements[i]).move(elements[i - 1]).wait(0.5).release().perform() elements = self.marionette.find_elements(*DOM.GLOBAL.modal_valueSel_list) # Only select it if it's the list, or there is no list. select_elements = False if group_array: if len(group_array) == len(list_names): # # We've done all of them - stop looping! break if i in group_array: select_elements = True else: select_elements = True if select_elements: tmp_name = elements[i].find_element("tag name", "span").text self.UTILS.reporting.logResult("info", "Selecting '{}' ...".format(tmp_name)) list_names.append(tmp_name) elements[i].tap() # Sometimes the first tap does nothing for some reason. if not elements[i].get_attribute("aria-checked"): elements[i].tap() # Click the OK button. x = self.UTILS.element.getElement(DOM.GLOBAL.modal_valueSel_ok, "OK button") try: # Sometimes it's one, sometimes the other ... x.tap() x.click() except: pass time.sleep(1) # Checkk all the items we expect are now loaded in evme. self.UTILS.iframe.switchToFrame(*DOM.Home.frame_locator) time.sleep(5) for name in list_names: ok = False # Reload the groups (silently or we'll have loads of these messages!). try: x = self.marionette.find_elements(*DOM.EME.groups) except: break for i in x: group_name = i.get_attribute("data-query") if group_name == name: ok = True break self.UTILS.test.test(ok, "'{}' is now among the groups.".format(name)) def install_app(self, category, name, expect_btn=True): """Try to install an application. Try to install the application with the given name in the given category. expect_btn determines if we expect the "Add to Home Screen" button in the bookmark page. Returns True if the application was successfully installed. """ self.pick_group(category) self.UTILS.iframe.switchToFrame(*DOM.EME.frame_locator) app_name = self.UTILS.element.getElementByXpath(DOM.EME.app_to_install.format(name)).text # Add the app to the homescreen. self.add_app_to_homescreen(app_name) self.UTILS.iframe.switchToFrame(*DOM.EME.bookmark_frame_locator) time.sleep(4) result = False # We expect the application to be installed, so find the Add to Home Screen button and tap it if expect_btn: add_btn = self.UTILS.element.getElement(DOM.EME.add_to_homescreen_done_btn, "Add bookmark to Home Screen Button") add_btn.tap() result = True else: # We expect the application is already installed, so find the proper header title = self.UTILS.element.getElement(DOM.EME.edit_bookmark_header, "Edit link header") self.UTILS.test.test(title, "Title '{}' found".format(title.text)) return result def launch_from_group(self, app_name): """ Function to launch an app directly from an EME group. """ x = self.UTILS.element.getElement(("xpath", "//li[@data-name='{}']".format(app_name)), "Icon for app '{}'".format(app_name), False) try: x.tap() except: # App is not visible, so I need to move it into view first. _id = x.get_attribute("_id") self.marionette.execute_script("document.getElementById('{}').scrollIntoView();".format(_id)) x.tap() time.sleep(1) self.UTILS.element.waitForNotElements(DOM.EME.launched_activity_bar, "Activity notifier", True, 30) x = self.UTILS.debug.screenShotOnErr() self.UTILS.reporting.logResult("info", "Screenshot of app running:", x) def pick_group(self, name): """ Pick a group from the main icons. """ screenshot = self.UTILS.debug.screenShotOnErr() self.UTILS.reporting.logResult("info", "<b>Choosing group '{}' from here ...</b>".format(name), screenshot) ok = False self.UTILS.reporting.info("searching for element: {}".format(DOM.Home.app_icon_css_selector.format(name))) icon = self.marionette.find_element('css selector', DOM.Home.app_icon_css_selector.format(name)) self.UTILS.reporting.logResult("debug", "icon displayed: {}".format(icon.is_displayed())) icon.tap() try: self.UTILS.iframe.switchToFrame(*DOM.EME.frame_locator) self.parent.wait_for_element_displayed(*DOM.EME.apps_not_installed, timeout=20) self.UTILS.reporting.logResult("info", "(Apps for group {} were displayed.)".format(name)) ok = True except Exception as e: self.UTILS.reporting.debug("*** Error getting apps not installed: {}".format(e)) screenshot = self.UTILS.debug.screenShotOnErr() self.UTILS.reporting.logResult("info", "(<b>NOTE:</b>Apps for group {} were not displayed.)|{}|{}".\ format(name, screenshot[0], screenshot[1])) return ok def remove_groups(self, group_array): """ Removes groups from the EME group page. group_array is an array of group names (default = all groups) For example: remove_groups(["Games","Local"]) """ """ Put the groups into edit mode. Sometimes this takes a while to happen, so increase the length of time you press the icon until it works! """ ok = False x = self.marionette.find_element('xpath', DOM.Home.app_icon_css_selector.format(group_array[0])) self.actions.press(x).wait(3).release() try: actions.perform() except: pass try: x = self.UTILS.element.getElement(("xpath", DOM.Home.app_delete_icon_xpath.format(group_array[0])), "Delete button", False, 5, True) if x.is_displayed(): ok = True except: pass time.sleep(2) self.UTILS.test.test(ok, "Enabled EDIT mode.") x = self.UTILS.debug.screenShotOnErr() self.UTILS.reporting.logResult("info", "Screenshot of app in EDIT mode:", x) # Remove all groups in the array. removed = 0 group_cnt = len(group_array) self.UTILS.reporting.logResult("info", "Removing {} groups".format(group_cnt)) self.UTILS.reporting.logResult("info", "Removing groups: {}".format(group_array)) for group_specified in group_array: # Remove it. self.marionette.find_element('xpath', DOM.Home.app_icon_css_selector.format(group_specified)) y = self.UTILS.element.getElement(("xpath", DOM.Home.app_delete_icon_xpath.format(group_specified)), "Delete button", False, 5, True) y.tap() delete = self.UTILS.element.getElement(DOM.Home.app_confirm_delete, "Confirm app delete button") delete.tap() removed = removed + 1 self.UTILS.reporting.logResult("info", "Removed group '{}' ...".format(group_specified)) self.UTILS.reporting.logResult("info", "Removed {} groups".format(removed)) if removed == group_cnt: break # Turn off edit mode. self.UTILS.reporting.logResult("info", "Disabling edit mode ...") self.UTILS.home.touchHomeButton() def search_for_app(self, name): """ Uses the search field to find the app (waits for the result to appear etc...).<br> Returns the element for the icon (or False if it's not found). """ x = self.UTILS.element.getElement(DOM.EME.search_field, "Search field") x.clear() x.send_keys(name) x.click() time.sleep(5) # Can take a few seconds to appear, so try a few times (about 1 min). for retry in range(10): x = self.UTILS.debug.screenShotOnErr() self.UTILS.reporting.logResult("debug", "Looking for '{}' - attempt {} ...".format(name, retry), x) x = self.UTILS.element.getElements(DOM.EME.search_suggestions, "Search suggestions") ok = False for i in x: i_name = i.get_attribute("data-suggestion") if i_name: i_name = i_name.lower() i_name = i_name.replace("[", "") i_name = i_name.replace("]", "") is_in = False for i2 in name.lower().split(): self.UTILS.reporting.logResult("debug", "Is '{}' in '{}'?".format(i2, i_name)) if i2 not in i_name: is_in = False break else: is_in = True if is_in: i.tap() ok = True break if ok: break time.sleep(6) self.UTILS.test.test(ok, "Found '%s' in suggestions." % name) ok = True try: elem = ("xpath", DOM.EME.search_result_icon_xpath.format(name)) self.parent.wait_for_element_displayed(*elem, timeout=60) x = self.marionette.find_element(*elem) return x except: ok = False return ok
class Camera(object): def __init__(self, parent): self.apps = parent.apps self.data_layer = parent.data_layer self.parent = parent self.marionette = parent.marionette self.UTILS = parent.UTILS self.actions = Actions(self.marionette) def launch(self): self.app = self.apps.launch(self.__class__.__name__) self.UTILS.element.waitForNotElements( DOM.GLOBAL.loading_overlay, self.__class__.__name__ + " app - loading overlay") self._wait_for_camera_ready() return self.app def _wait_for_camera_ready(self): self.parent.wait_for_condition(lambda m: m.find_element( *DOM.Camera.controls_pane).get_attribute('data-enabled') == 'true', timeout=10, message="Camera ready") def is_video_being_recorded(self): try: self.parent.wait_for_condition(lambda m: m.find_element( *DOM.Camera.controls_pane).get_attribute('data-recording') == 'true', timeout=10, message="Video recording") return True except: return False def go_to_gallery(self): """ Clicks the Gallery button to switch to the Gallery application (warning: this will land you in the gallery iframe). """ options = self.UTILS.element.getElement(DOM.Camera.preview_options, "preview options") time.sleep(1) options.tap() gallery_option = self.UTILS.element.getElement(DOM.Camera.action_menu_gallery, "Gallery option") time.sleep(1) gallery_option.tap() self.UTILS.iframe.switchToFrame(*DOM.Gallery.frame_locator) def click_on_thumbnail_at_pos(self, num): """ Click on a certain thumbnail. """ thumb_list = self.UTILS.element.getElements(DOM.Camera.thumbnail, "Camera thumbnails") the_thumb = thumb_list[num] the_thumb.tap() def convert_str_to_seconds(self, the_string): """ Converts a str of the form "aa:bb" into seconds """ processed = time.strptime(the_string, '%M:%S') return (int(datetime.timedelta(minutes=processed.tm_min, seconds=processed.tm_sec).total_seconds())) def check_video_length(self, expected_duration, margin=2): """ This method asserts that the video has the desired duration @expected_duration: specify the video duration in seconds """ # Play the video and get total duration self.play_current_video() video_length = self.UTILS.element.getElement(DOM.Camera.preview_video_slider_duration, "Video length") real_duration = self.convert_str_to_seconds(video_length.text) # Note: we give 1 second margin in case the things went a little bit slower when recording the video interval = range(expected_duration - margin, expected_duration + margin + 1, 1) self.UTILS.test.test(real_duration in interval, "Duration matches") def _tap_on_capture_button(self): capture_button = self.UTILS.element.getElement(DOM.Camera.capture_button, "Capture button") time.sleep(1) capture_button.tap() def take_video(self, video_length): """ Record a video. video_length is the number of seconds to record for. """ # Switch to video. self.switch_source() # Record a video and click the thumbnail to play it. self._tap_on_capture_button() self.UTILS.test.test(self.is_video_being_recorded(), "Video recording") # Record for video_length seconds. Looks like it always takes one second more # Wait for duration timer_text = '00:{:02d}'.format(video_length) self.parent.wait_for_condition(lambda m: m.find_element( *DOM.Camera.recording_timer).text >= timer_text, timeout=video_length + 10) # Stop recording self._tap_on_capture_button() self.UTILS.element.waitForNotElements(DOM.Camera.recording_timer, "Video timer", True, 10, False) self.UTILS.element.waitForElements(DOM.Camera.open_thumbs, "Thumbnail appears after recording video", True, 10, False) def switch_source(self): """ Switch between still shot and video. """ switch_btn = self.UTILS.element.getElement(DOM.Camera.switch_source, "Source switcher") self.actions.press(switch_btn).move_by_offset(0, 0).release().perform() self._wait_for_camera_ready() def take_picture(self): """ Take a picture. """ self.parent.wait_for_condition(lambda m: m.find_element( *DOM.Camera.controls_pane).get_attribute('data-enabled') == 'true', 20) capture_button = self.UTILS.element.getElement(DOM.Camera.capture_button, "Capture button") time.sleep(1) capture_button.tap() self.UTILS.element.waitForElements(DOM.Camera.open_thumbs, "Camera thumbnails") def open_preview(self): """ Open the preview screen by clicking thumbnail's shortcut """ open_thumbs = self.UTILS.element.getElement(DOM.Camera.open_thumbs, "Thumbnail bubble") time.sleep(1) open_thumbs.tap() self.UTILS.element.waitForElements(DOM.Camera.preview_header, "Preview header") # Check the last picture is shown count_text = self.UTILS.element.getElement(DOM.Camera.preview_count_text, "Preview count") self.UTILS.reporting.logResult('info', "The text is: {}".format(count_text.text)) self.UTILS.test.test(count_text.text.split( "/")[0] == "1", "Once we open the preview screen, the last picture is shown") def delete_from_preview(self, confirm=True): options = self.UTILS.element.getElement(DOM.Camera.preview_options, "preview options") time.sleep(1) options.tap() delete_option = self.UTILS.element.getElement(DOM.Camera.action_menu_delete, "Delete option") time.sleep(1) delete_option.tap() if confirm: confirm = self.UTILS.element.getElement(DOM.Camera.dialog_menu_yes, "Delete option") time.sleep(1) confirm.tap() else: cancel = self.UTILS.element.getElement(DOM.Camera.dialog_menu_no, "Delete option") time.sleep(1) cancel.tap() def play_current_video(self): """ Plays the video that has previously been loaded (by pressing its thumbnail first), then press a play button. """ play_btn = self.UTILS.element.getElement(DOM.Camera.preview_video_play, "Video play button") time.sleep(1) self.UTILS.element.simulateClick(play_btn) play_btn.tap() self.UTILS.element.waitForElements(DOM.Camera.preview_video_pause, "Pause button", True, 20, False) def take_and_select_picture(self): """ This method takes a picture and hits on select. It is """ self.parent.wait_for_condition(lambda m: m.find_element( *DOM.Camera.controls_pane).get_attribute('data-enabled') == 'true', 20) capture_button = self.UTILS.element.getElement(DOM.Camera.capture_button, "Capture button") time.sleep(1) capture_button.tap() # Confirm the picture. select_button = self.UTILS.element.getElement(DOM.Camera.select_button, "Select Camera photo", timeout=10) time.sleep(1) select_button.tap()