def long_press_action(marionette, wait_for_condition, expected):
    testAction = marionette.absolute_url("testAction.html")
    marionette.navigate(testAction)
    button = marionette.find_element(By.ID, "button1")
    action = Actions(marionette)
    action.long_press(button, 5).perform()
    wait_for_condition_else_raise(marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
Example #2
0
File: app.py Project: nullaus/gaia
    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 wait(marionette, wait_for_condition, expected):
    testAction = marionette.absolute_url("testAction.html")
    marionette.navigate(testAction)
    action = Actions(marionette)
    button = marionette.find_element("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_flick(marionette, wait_for_condition, expected1, expected2):
    testAction = marionette.absolute_url("testAction.html")
    marionette.navigate(testAction)
    button = marionette.find_element(By.ID, "button1")
    action = Actions(marionette)
    action.flick(button, 0, 0, 0, 200).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('buttonFlick').innerHTML;")
def context_menu(marionette, wait_for_condition, expected1, expected2):
    testAction = marionette.absolute_url("testAction.html")
    marionette.navigate(testAction)
    button = marionette.find_element(By.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;")
Example #7
0
 def _flick_to_image(self, direction):
     image = self.marionette.find_element(*self._current_image_locator)
     action = Actions(self.marionette)
     x_start = (image.size['width'] / 100) * (direction == 'next' and 90 or 10)
     x_end = (image.size['width'] / 100) * (direction == 'next' and 10 or 90)
     y_start = image.size['height'] / 4
     y_end = image.size['height'] / 4
     action.flick(image, x_start, y_start, x_end, y_end, 200).perform()
     Wait(self.marionette).until(
         lambda m: abs(image.location['x']) >= image.size['width'])
Example #8
0
 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 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;")
Example #10
0
 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 long_press_on_xy_action(marionette, wait_for_condition, expected):
    testAction = marionette.absolute_url("testAction.html")
    marionette.navigate(testAction)
    html = marionette.find_element(By.TAG_NAME, "html")
    button = marionette.find_element(By.ID, "button1")
    action = Actions(marionette)

    # Press the center of the button with respect to html.
    x = button.rect['x'] + button.rect['width'] / 2.0
    y = button.rect['y'] + button.rect['height'] / 2.0
    action.long_press(html, 5, x, y).perform()
    wait_for_condition_else_raise(marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
Example #12
0
File: app.py Project: nullaus/gaia
    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()
Example #13
0
 def _flick_to_image(self, direction):
     image = self.marionette.find_element(*self._current_image_locator)
     action = Actions(self.marionette)
     x_start = (image.size['width'] / 100) * (direction == 'next' and 90 or 10)
     x_end = (image.size['width'] / 100) * (direction == 'next' and 10 or 90)
     y_start = image.size['height'] / 4
     y_end = image.size['height'] / 4
     action.flick(image, x_start, y_start, x_end, y_end, 200).perform()
     Wait(self.marionette).until(
         lambda m: abs(image.location['x']) >= image.size['width'])
     # Workaround for bug 1161441, the transitionend event is not firing in this
     # case with a Marionette flick action, as opposed to a manual flick action
     self.marionette.execute_script("""
           arguments[0].dispatchEvent(new CustomEvent("transitionend"));
         """, [self.current_image_frame])
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;")
Example #15
0
    def test_run(self):

        # Launch messages app.
        self.messages.launch()

        # Create and send a new test message.
        self.messages.create_and_send_sms([self.phone_number], self.test_msg)
        send_time = self.messages.last_sent_message_timestamp()
        msg = self.messages.wait_for_message(send_time=send_time)
        self.messages.check_last_message_contents(self.test_msg)

        # Tap on edit mode.
        edit_btn = self.UTILS.element.getElement(DOM.Messages.edit_messages_icon, "Edit button")
        edit_btn.tap()

        select_btn = self.UTILS.element.getElement(DOM.Messages.edit_msgs_select_btn, "Select button")
        select_btn.tap()

        # Long press the email link.
        _link = msg.find_element("tag name", "a")
        self.actions = Actions(self.marionette)
        self.actions.long_press(_link, 2).perform()

        # Check the email address is not a link in edit mode.
        self.UTILS.element.waitForNotElements(DOM.Messages.header_create_new_contact_btn, "Create new contact button")
Example #16
0
 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 setUp(self):
     # Code to execute before every test is running.
     super(AccessibleCaretSelectionModeTestCase, self).setUp()
     self.carets_tested_pref = "layout.accessiblecaret.enabled"
     self.prefs = {"layout.word_select.eat_space_to_next_word": False, self.carets_tested_pref: True}
     self.marionette.set_prefs(self.prefs)
     self.actions = Actions(self.marionette)
Example #18
0
 def setUp(self):
     MarionetteTestCase.setUp(self)
     if self.marionette.session_capabilities["platformName"] == "darwin":
         self.mod_key = Keys.META
     else:
         self.mod_key = Keys.CONTROL
     self.action = Actions(self.marionette)
Example #19
0
 def setUp(self):
     MarionetteTestCase.setUp(self)
     if self.marionette.session_capabilities['platformName'] == 'DARWIN':
         self.mod_key = Keys.META
     else:
         self.mod_key = Keys.CONTROL
     self.action = Actions(self.marionette)
Example #20
0
class test_main(GaiaTestCase):

    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)

        self.actions = Actions(self.marionette)

        # Establish which phone number to use.
        self.phone_number = self.UTILS.general.get_config_variable("phone_number", "custom")
        self.incoming_sms_num = self.UTILS.general.get_config_variable("sms_platform_numbers", "common").split(',')
        self.UTILS.reporting.logComment("Sending sms to telephone number " + self.phone_number)
        self.data_layer.delete_all_sms()

    def tearDown(self):
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):
        self.UTILS.statusbar.clearAllStatusBarNotifs()

        timestamp = " {}".format(time.time())
        sms_message = "0123456789" * 5 + timestamp
        self.UTILS.reporting.logComment("Message length sent: {}".format((len(sms_message))))

        self.UTILS.messages.create_incoming_sms(self.phone_number, sms_message)
        self.UTILS.statusbar.wait_for_notification_toaster_detail(timestamp, timeout=120)
        title = self.UTILS.statusbar.wait_for_notification_toaster_with_titles(self.incoming_sms_num, timeout=5)
        self.UTILS.statusbar.click_on_notification_title(title, DOM.Messages.frame_locator)

        # Open sms option with longtap on it
        self.UTILS.reporting.logResult("info", "Open sms option with longtap on it")
        sms = self.messages.last_message_in_this_thread()
        body = self.marionette.find_element(*DOM.Messages.last_message_body, id=sms.id)
        self.actions.long_press(body, 2).perform()

        # Press cancel button
        self.UTILS.reporting.logResult("info", "Clicking cancel button")
        time.sleep(2)
        cancel_btn = self.UTILS.element.getElement(DOM.Messages.cancel_btn_msg_opt, "Cancel button is displayed")
        self.UTILS.reporting.debug("*** Cancel button: {}   text: {}".format(cancel_btn, cancel_btn.text))
        self.UTILS.element.simulateClick(cancel_btn)
Example #21
0
class test_main(GaiaTestCase):

    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)
        self.UTILS = UTILS(self)
        self.messages = Messages(self)

        self.contacts = Contacts(self)

        self.phone_number = self.UTILS.general.get_config_variable("phone_number", "custom")
        self.emailAddy = self.UTILS.general.get_config_variable("gmail_1_email", "common")
        self.test_msg = "Hello {} old bean at {}.".format(self.emailAddy, time.time())

    def tearDown(self):
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):

        # Launch messages app.
        self.messages.launch()

        # Create and send a new test message.
        self.messages.create_and_send_sms([self.phone_number], self.test_msg)
        send_time = self.messages.last_sent_message_timestamp()
        msg = self.messages.wait_for_message(send_time=send_time)
        self.messages.check_last_message_contents(self.test_msg)

        # Tap on edit mode.
        edit_btn = self.UTILS.element.getElement(DOM.Messages.edit_messages_icon, "Edit button")
        edit_btn.tap()

        select_btn = self.UTILS.element.getElement(DOM.Messages.edit_msgs_select_btn, "Select button")
        select_btn.tap()

        # Long press the email link.
        _link = msg.find_element("tag name", "a")
        self.actions = Actions(self.marionette)
        self.actions.long_press(_link, 2).perform()

        # Check the email address is not a link in edit mode.
        self.UTILS.element.waitForNotElements(DOM.Messages.header_create_new_contact_btn, "Create new contact button")
Example #22
0
class test_main(GaiaTestCase):

    def __init__(self, *args, **kwargs):
        kwargs['restart'] = True
        super(test_main, self).__init__(*args, **kwargs)

    def setUp(self):

        # Set up child objects...
        GaiaTestCase.setUp(self)

        self.UTILS = UTILS(self)
        self.settings = Settings(self)
        self.EME = EverythingMe(self)
        self.actions = Actions(self.marionette)

        try:
            self.apps.set_permission('Homescreen', 'geolocation', 'deny')
            self.apps.set_permission('Smart Collections', 'geolocation', 'deny')
        except:
            self.UTILS.reporting.logComment("Unable to automatically set geolocation permission.")

    def tearDown(self):
        # Restart device to restore collections
        self.device.restart_b2g()
        GaiaTestCase.setUp(self)
        self.UTILS.reporting.reportResults()
        GaiaTestCase.tearDown(self)

    def test_run(self):
        self.UTILS.iframe.switchToFrame(*DOM.Home.frame_locator)
        categories = self.UTILS.element.getElements(DOM.EME.all_collections, "All collections")
        for cat in categories:
            name = self.marionette.find_element('css selector', 'span.title', cat.id).text
            self.UTILS.reporting.debug("** Removing collection: {}".format(name))
            self.actions.long_press(cat, 2).perform()
            delete_btn = ("xpath", DOM.Home.app_delete_icon_xpath.format(name))
            delete_button = self.UTILS.element.getElement(delete_btn, "Delete button", False, 30, True)
            delete_button.tap()

            delete = self.UTILS.element.getElement(DOM.Home.app_confirm_delete, "Confirm app delete button")
            delete.tap()

        self.UTILS.element.waitForNotElements(DOM.EME.all_collections, "All collections", timeout=10)
Example #23
0
    def _flick_to_month(self, direction):
        """Flick current monthly calendar to next or previous month.

        @param direction: flick to next month if direction='next', else flick to previous month
        """
        action = Actions(self.marionette)

        month = self.marionette.find_element(
            *self._current_monthly_calendar_locator)
        month_year = self.current_month_year

        x_start = (month.size['width'] / 100) * (direction == 'next' and 90 or 10)
        x_end = (month.size['width'] / 100) * (direction == 'next' and 10 or 90)
        y_start = month.size['height'] / 4
        y_end = month.size['height'] / 4

        action.flick(month, x_start, y_start, x_end, y_end, 200).perform()

        Wait(self.marionette).until(lambda m: self.current_month_year != month_year)
    def setUp(self):
        # Code to execute before a tests are run.
        MarionetteTestCase.setUp(self)
        self.actions = Actions(self.marionette)

        # The carets to be tested.
        self.carets_tested_pref = None

        # The carets to be disabled in this test suite.
        self.carets_disabled_pref = None
Example #25
0
    def setUp(self):
        # Code to execute before a test is being run.
        super(CommonCaretTestCase, self).setUp()
        self.actions = Actions(self.marionette)

        # The caret to be tested.
        self.caret_tested_pref = None

        # The caret to be disabled in this test suite.
        self.caret_disabled_pref = None
        self.caret_timeout_ms_pref = None
Example #26
0
 def setUp(self):
     MarionetteTestCase.setUp(self)
     if self.marionette.session_capabilities['platformName'] == 'DARWIN':
         self.mod_key = Keys.META
     else:
         self.mod_key = Keys.CONTROL
     test_html = self.marionette.absolute_url("javascriptPage.html")
     self.marionette.navigate(test_html)
     self.reporter_element = self.marionette.find_element("id", "keyReporter")
     self.reporter_element.click()
     self.key_action = Actions(self.marionette)
 def setUp(self):
     # Code to execute before every test is running.
     super(AccessibleCaretCursorModeTestCase, self).setUp()
     self.caret_tested_pref = 'layout.accessiblecaret.enabled'
     self.hide_carets_for_mouse = 'layout.accessiblecaret.hide_carets_for_mouse_input'
     self.prefs = {
         self.caret_tested_pref: True,
         self.hide_carets_for_mouse: False,
     }
     self.marionette.set_prefs(self.prefs)
     self.actions = Actions(self.marionette)
 def setUp(self):
     # Code to execute before a tests are run.
     super(AccessibleCaretSelectionModeTestCase, self).setUp()
     self.carets_tested_pref = 'layout.accessiblecaret.enabled'
     self.prefs = {
         'layout.word_select.eat_space_to_next_word': False,
         'layout.accessiblecaret.use_long_tap_injector': False,
         self.carets_tested_pref: True,
     }
     self.marionette.set_prefs(self.prefs)
     self.actions = Actions(self.marionette)
 def setUp(self):
     # Code to execute before every test is running.
     super(AccessibleCaretCursorModeTestCase, self).setUp()
     self.caret_tested_pref = 'layout.accessiblecaret.enabled'
     self.caret_timeout_ms_pref = 'layout.accessiblecaret.timeout_ms'
     self.prefs = {
         self.caret_tested_pref: True,
         self.caret_timeout_ms_pref: 0,
     }
     self.marionette.set_prefs(self.prefs)
     self.actions = Actions(self.marionette)
Example #30
0
 def setUp(self):
     super(TestKeyActions, self).setUp()
     if self.marionette.session_capabilities["platformName"] == "darwin":
         self.mod_key = Keys.META
     else:
         self.mod_key = Keys.CONTROL
     test_html = self.marionette.absolute_url("javascriptPage.html")
     self.marionette.navigate(test_html)
     self.reporter_element = self.marionette.find_element(By.ID, "keyReporter")
     self.reporter_element.click()
     self.key_action = Actions(self.marionette)
Example #31
0
class element(object):

    def __init__(self, parent):
        self.parent = parent
        self.marionette = parent.marionette
        self.actions = Actions(self.marionette)

    def getElement(self, elem, msg, is_displayed=True, timeout=5, stop_on_error=True):
        """
        Returns an element, or False it it's not found
        """
        x = self.getElements(elem, msg, is_displayed, timeout, stop_on_error)
        if x:
            # We're expecting ONE element back (it has different methods if it's one).
            return x[0]
        else:
            return False

    def getElements(self, elem, msg, is_displayed=True, timeout=5, stop_on_error=True):
        """
        Returns a list of matching elements, or False if none are found
        """
        boolEl = self.waitForElements(elem, msg, is_displayed, timeout, stop_on_error)

        if boolEl:
            el = self.marionette.find_elements(*elem)
            return el
        else:
            return False

    def headerCheck(self, value):
        """
        Returns the header that matches a string.
        NOTE: ALL headers in this iframe return true for ".is_displayed()"!
        """
        is_ok = False
        try:
            self.parent.parent.wait_for_element_present(*DOM.GLOBAL.app_head, timeout=1)
            headerNames = self.marionette.find_elements(*DOM.GLOBAL.app_head)
            for i in headerNames:
                if i.text == value:
                    if i.is_displayed():
                        is_ok = True
                        break
        except:
            is_ok = False

        self.parent.test.test(is_ok, "Header is \"" + value + "\".")
        return is_ok

    def move_scroller(self, scroller, forward=True):
        """Move the scroller one item forward or backwards.
        """
        x_pos = scroller.size['width'] / 2
        y_start = scroller.size['height'] / 2

        y_end = -scroller.size['height'] if forward else scroller.size['height']
        self.actions.flick(scroller, x_pos, y_start, x_pos, y_end, 100)
        self.actions.perform()

    def set_scroller_val(self, scroller_elem, number):
        """
        Set the numeric value of a scroller (only works with numbers right now).
        """
        current_value = int(scroller_elem.find_element(*DOM.GLOBAL.scroller_curr_val).text)

        # Now flick the scroller as many times as required
        n = int(number)
        while n != current_value:
            # Do we need to go forwards or backwards?
            if n > int(current_value):
                self.move_scroller(scroller_elem, True)
            if n < int(current_value):
                self.move_scroller(scroller_elem, False)

            # Get the new 'current_value'.
            current_value = int(scroller_elem.find_element(*DOM.GLOBAL.scroller_curr_val).text)

    # From gaiatest Clock -> regions -> alarm.py
    def _flick_menu_up(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(next_element)
        action.move(current_element)
        action.release()
        action.perform()

    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 _current_element(self, method, target):
        self.parent.reporting.debug("*** Finding current element for target {}".format(target))
        return (method, '{}.picker-unit.selected'.format(target))

    def _next_element(self, method, target):
        self.parent.reporting.debug("*** Finding next element for target {}".format(target))
        return (method, '{}.picker-unit.selected + div'.format(target))

    def simulateClick(self, element):
        self.marionette.execute_script("""
            /**
            * Helper method to simulate clicks on iFrames which is not currently
            *  working in the Marionette JS Runner.
            * @param {Marionette.Element} element The element to simulate the click on.
            **/

            var event = new MouseEvent('click', {
             'view': window,
             'bubbles': true,
             'cancelable': true
             });
            arguments[0].dispatchEvent(event);
        """, script_args=[element])

    def simulateClickAtPos(self, element, posX, posY):
        self.parent.reporting.logResult('info', 'Simulating click....')
        self.marionette.execute_script("""
            /**
            * Helper method to simulate clicks on iFrames which is not currently
            *  working in the Marionette JS Runner.
            * @param {Marionette.Element} element The element to simulate the click on.
            **/

            var event = document.createEvent('MouseEvents');
            event.initMouseEvent(
            'click', true, true, window, 0,
            0, 0, arguments[1], arguments[2], false, false,
            false, false, 0, null
            );
            arguments[0].dispatchEvent(event);
        """, script_args=[element, posX, posY])

    def waitForElements(self, elem, msg, is_displayed=True, timeout=5, stop_on_error=True):
        """
        Waits for an element to be displayed and captures the error if not
        """
        is_ok = True
        msg = u"" + msg
        try:
            if is_displayed:
                msg = u"{} displayed within {} seconds.|{}".format(msg, timeout, elem)
                self.parent.parent.wait_for_element_displayed(*elem, timeout=timeout)
            else:
                msg = u"{} present within {} seconds.|{}".format(msg, timeout, elem)
                self.parent.parent.wait_for_element_present(*elem, timeout=timeout)
        except Exception:
            is_ok = False

        self.parent.test.test(is_ok, msg, stop_on_error)

        return is_ok

    def waitForNotElements(self, elem, msg, is_displayed=True, timeout=5, stop_on_error=True):
        """
        Waits for an element to be displayed and captures the error if not
        """
        is_ok = True
        try:
            if is_displayed:
                msg = "{} no longer displayed within {} seconds.|{}".format(msg, timeout, elem)
                self.parent.parent.wait_for_element_not_displayed(*elem, timeout=timeout)
            else:
                msg = "{} no longer present within {} seconds.|{}".format(msg, timeout, elem)
                self.parent.parent.wait_for_element_not_present(*elem, timeout=timeout)
        except:
            is_ok = False

        self.parent.test.test(is_ok, msg, stop_on_error)
        return is_ok

    def getElementByXpath(self, path):
        """
        Use this function when normal getElement did not work
        """
        return self.marionette.execute_script("""
            return document.evaluate(arguments[0], document, null, 9, null).singleNodeValue;
        """, script_args=[path])

    def getParent(self, element):
        """
        Gets the element's parent. Can be called recursively
        """
        return self.marionette.execute_script("""
            return arguments[0].parentNode;
        """, script_args=[element])

    def getChildren(self, element):
        """
        Gets the element's children
        """
        return self.marionette.execute_script("""
            return arguments[0].children;
        """, script_args=[element])

    def find_nested(self, context, css_selector):
        return self.marionette.execute_script("""
            return arguments[0].querySelector(arguments[1])
        """, script_args=[context, css_selector])

    def get_css_value(self, element, css_property):
        """
        Gets the value of a certain css property.
        """
        return self.marionette.execute_script("""
            function getStyle (el, styleProp) {
                if (el.currentStyle)
                    var y = x.currentStyle[styleProp];
                else if (window.getComputedStyle)
                    var y = document.defaultView.getComputedStyle(el,null)
                                                .getPropertyValue(styleProp);
                return y;
            }
            return getStyle(arguments[0], arguments[1])
        """, script_args=[element, css_property])

    def is_ellipsis_active(self, element):
        """
        Checks whether a certain element is really ellipsed when its content
        overflows its width
        """
        return self.marionette.execute_script("""
            function isEllipsisActive(element) {
                return (element.offsetWidth < element.scrollWidth);
            }
            return isEllipsisActive(arguments[0])
        """, script_args=[element])

    def scroll_into_view(self, element):
        self.marionette.execute_script("""
            arguments[0].scrollIntoView();
        """, script_args=[element])

    def perform_action_over_element(self, locator, action, position=None):
        script = """
            var _locatorMap = {
                "id": document.getElementById,
                "class name": document.getElementsByClassName,
                "css selector": document.querySelector,
                "xpath": function () {
                            return document.evaluate(arguments[0], document, null, 9, null).singleNodeValue
                        },
                "tag name": document.getElementsByTagName
            };

            // TODO - Add more events here
            var _actionMap = {
                "click":    new MouseEvent('click', {
                                'view': window,
                                'bubbles': true,
                                'cancelable': true
                            }), //HTMLElement.prototype.click
            }

            var location_method = arguments[0][0];
            var locator         = arguments[0][1];
            var action          = arguments[1];
            var position        = arguments[2];

            if (position) {
                var element = _locatorMap[location_method].call(document, locator)[position];
            } else {
                if ((locator === "class name") || (locator === "tag name")) {
                    var e = 'JavaScriptException: InvalidParametersException: '
                    var msg = 'If using "class name" or "tag name", it is mandatory to specify a position'
                    throw  e + msg
                }
                var element = _locatorMap[location_method].call(document, locator);
            }

            if (element) {
                if (_actionMap.hasOwnProperty(action)) {
                    element.dispatchEvent(_actionMap[action])
                } else {
                    var e = 'JavaScriptException: InvalidParametersException: '
                    var msg = 'Specified action <' + action + '> not supported';
                    throw  e + msg
                }
            }
        """
        self.marionette.execute_script(script, script_args=[list(locator), action, position])
 def setUp(self):
     # Code to execute before a tests are run.
     MarionetteTestCase.setUp(self)
     self.actions = Actions(self.marionette)
Example #33
0
 def long_tap_to_install(self):
     Actions(self.marionette).long_press(self.root_element, 2).perform()
Example #34
0
 def _tap_page_switching_key(self, val):
     locator = (self._page_switching_key_locator[0],
                self._page_switching_key_locator[1] % val)
     key = Wait(self.marionette).until(expected.element_present(*locator))
     Wait(self.marionette).until(expected.element_displayed(key))
     Actions(self.marionette).press(key).release().perform()
Example #35
0
class Dialer(object):

    """Object representing the Dialer application.
    """

    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)
        self.app_name = "Phone"

    def launch(self):
        """
        Launch the app 
        It's called a different name (Phone) to the everyone knows it as, so hardcode it!
        """
        self.app = self.apps.launch(self.app_name)
        self.UTILS.element.waitForNotElements(DOM.GLOBAL.loading_overlay,
                                              self.__class__.__name__ + " app - loading overlay")
        return self.app

    def _cancel_addNumberToContact(self):
        self.UTILS.iframe.switchToFrame(*DOM.Contacts.frame_locator)
        self.UTILS.element.waitForElements(
            ("xpath", "//h1[text()='{}']".format(_("Contacts"))), "'Select contact' header")
        self.UTILS.element.getElement(DOM.Dialer.contact_list_header, "Header").tap(25, 25)

    def _complete_addNumberToContact(self, p_num, p_name):
        """
        Finishes the process of adding a number to an existing contact
        (used bu addThisNumberToContact() etc...).<br>
        Handles switching frames etc... and finishes with you back in the dialer.
        """
        self.UTILS.iframe.switchToFrame(*DOM.Contacts.frame_locator)
        self.UTILS.element.waitForElements(
            ("xpath", "//h1[text()='{}']".format(_("Contacts"))), "'Select contact' header")

        y = self.UTILS.element.getElements(DOM.Contacts.view_all_contact_list, "All contacts list")
        boolOK = False
        for i in y:
            if p_name in i.text:
                self.UTILS.reporting.logResult("info", "Contact '{}' found in all contacts.".format(p_num))
                i.tap()
                boolOK = True
                break

        self.UTILS.test.test(boolOK, "Succesfully selected contact from list.")
        self.UTILS.element.waitForElements(DOM.Contacts.edit_contact_header, "'Edit contact' header")

        # Test for an input field for number_<x> contaiing our number.
        self.UTILS.element.waitForElements(("xpath", DOM.Contacts.phone_field_xpath.format(p_num)),
                                           "Phone field containing {}".format(p_num))

        # Hit 'update' to save the changes to this contact.
        done_button = self.UTILS.element.getElement(DOM.Contacts.edit_update_button, "'Update' button")
        done_button.tap()

        # Verify that the contacts app is closed and we are returned to the call log.
        self.marionette.switch_to_frame()
        self.UTILS.element.waitForNotElements(("xpath", "//iframe[contains(@{}, '{}')]".
                                               format(DOM.Contacts.frame_locator[0], DOM.Contacts.frame_locator[1])),
                                              "COntacts frame")
        self.UTILS.iframe.switchToFrame(*DOM.Dialer.frame_locator)

    def addThisNumberToContact(self, p_name):

        # Adds the current number to existing contact.
        x = self.UTILS.element.getElement(DOM.Dialer.phone_number, "Phone number field", False)
        dialer_num = x.get_attribute("value")

        x = self.UTILS.element.getElement(DOM.Dialer.add_to_contacts_button, "Add to contacts button")
        x.tap()

        x = self.UTILS.element.getElement(DOM.Dialer.add_to_existing_contact_btn, "Add to existing contact button")
        x.tap()

        self._complete_addNumberToContact(dialer_num, p_name)

    def callLog_createContact(self, entry, p_open_call_log=True):
        """
        Creates a new contact from the call log (only
        as far as the contacts app opening).
        If p_open_call_log is set to False it will assume you are
        already in the call log.
        """
        if p_open_call_log:
            self.open_call_log()

        self.callLog_long_tap(entry)
        self.callLog_long_tap_select_action(
            DOM.Dialer.call_log_numtap_create_new, "Create new contact button", call_info=True)

        self.UTILS.iframe.switchToFrame(*DOM.Contacts.frame_locator)
        self.UTILS.element.waitForElements(DOM.Contacts.add_contact_header, "'Add contact' header")

    def callLog_addToContact(self, phone_number, contact_name, p_open_call_log=True, cancel_process=False):
        """
        Adds this number in the call log to an existing contact
        (and returns you to the call log).
        If p_open_call_log is set to False it will assume you are
        already in the call log.
        """

        if p_open_call_log:
            self.open_call_log()

        self.callLog_long_tap(phone_number)
        time.sleep(1)
        self.callLog_long_tap_select_action(
            DOM.Dialer.call_log_numtap_add_to_existing, "Add to existing contact button", call_info=True)

        if cancel_process:
            self._cancel_addNumberToContact()
        else:
            self._complete_addNumberToContact(phone_number, contact_name)

    def callLog_long_tap(self, phone_number):
        entry = self.UTILS.element.getElement(("xpath", DOM.Dialer.call_log_number_xpath.format(phone_number)),
                                              "The call log for number {}".format(phone_number))
        self.actions.long_press(entry, 3).perform()

    def callLog_long_tap_select_action(self, locator, msg="Option chosen", call_info=True):
        if call_info:
            call_info = self.UTILS.element.getElement(DOM.Dialer.call_log_numtap_call_info, "Call information button")
            call_info.tap()

        option = self.UTILS.element.getElement(locator, msg, True, 10)
        option.tap()

    def callLog_call(self, p_num):

        own_num = self.UTILS.general.get_config_variable("phone_number", "custom")
        # Calls a number from the call log.
        try:
            self.parent.wait_for_element_displayed(*DOM.Dialer.call_log_filter, timeout=1)
        except:
            self.open_call_log()

        entry = self.UTILS.element.getElement(("xpath", DOM.Dialer.call_log_number_xpath.format(p_num)),
                                              "The call log for number {}".format(p_num))
        entry.tap()

        if own_num == p_num:
            time.sleep(2)
            # self.marionette.switch_to_frame()
            x = self.UTILS.element.getElement(DOM.Dialer.call_busy_button_ok, "OK button (callLog_call)")
            x.tap()
        else:
            time.sleep(1)
            self.UTILS.iframe.switchToFrame(*DOM.Dialer.frame_locator_calling)
            self.UTILS.element.waitForElements(("xpath", DOM.Dialer.outgoing_call_numberXP.format(p_num)),
                                               "Outgoing call found with number matching {}".format(p_num))

    def callLog_clearAll(self):
        """
        Wipes all entries from the call log.
        """
        try:
            self.parent.wait_for_element_displayed(*DOM.Dialer.call_log_filter, timeout=1)
        except:
            self.open_call_log()

        try:
            self.parent.wait_for_element_displayed(*DOM.Dialer.call_log_no_calls_msg, timeout=1)
        except:
            self.UTILS.reporting.logResult("info", "Some numbers are in the call log here - removing them ...")
            edit_btn = self.UTILS.element.getElement(DOM.Dialer.call_log_edit_btn, "Edit button")
            edit_btn.tap()

            """Here something weird is happening, since the form where this button should appear, remains
            hidden. Thus, when we try to get the button, it won't appear. Then, we have have to use
            raw JavaScript in order to obtain the button and click on it."""

            self.parent.wait_for_element_present(*DOM.Dialer.call_log_edit_selAll, timeout=10)
            self.marionette.execute_script("document.getElementById('{}').click();".
                                           format(DOM.Dialer.call_log_edit_selAll[1]))

            self.parent.wait_for_element_present(*DOM.Dialer.call_log_edit_delete, timeout=2)
            self.marionette.execute_script("document.getElementById('{}').click();".
                                           format(DOM.Dialer.call_log_edit_delete[1]))

            confirm_delete = self.UTILS.element.getElement(DOM.Dialer.call_log_confirm_delete, "Confirm button")
            confirm_delete.tap()

            self.UTILS.element.waitForElements(DOM.Dialer.call_log_no_calls_msg, "'No calls ...' message")

    def callLog_clearSome(self, p_entryNumbers):
        """
        Wipes entries from the call log, using p_entryNumbers as an array of
        numbers. For example: callLog_clearSome([1,2,3]) will remove the first 3.
        <br><b>NOTE:</b> the first item is 1, <i>not</i> 0.
        """
        try:
            self.parent.wait_for_element_displayed(*DOM.Dialer.call_log_filter, timeout=1)
        except:
            self.open_call_log()

        boolLIST = True
        try:
            self.parent.wait_for_element_displayed(*DOM.Dialer.call_log_no_calls_msg, timeout=1)
            boolLIST = False
        except:
            pass

        if boolLIST:
            """
            At the moment, the 'edit' div looks like it's not displayed, so Marionette can't tap it.
            For this reason I'm using JS to click() instead.
            """
            self.UTILS.reporting.logResult("info", "Some numbers are in the call log here - removing them ...")
            x = self.UTILS.element.getElement(DOM.Dialer.call_log_edit_btn, "Edit button")
            x.tap()
            """
            The edit mode doens't seem to be 'displayed', so we have to work around
            that at the moment.
            """
            time.sleep(2)
            self.parent.wait_for_element_present(*DOM.Dialer.call_log_edit_header, timeout=2)
            _els = ("xpath", "//ol[@class='log-group']//li")
            x = self.UTILS.element.getElements(_els, "Call log items", False)

            _precount = len(x)
            self.UTILS.reporting.logResult("info", "{} items found.".format(_precount))
            for i in p_entryNumbers:
                if i != 0:
                    _precount = _precount - 1
                    x[i - 1].tap()

            self.parent.wait_for_element_present(*DOM.Dialer.call_log_edit_delete, timeout=2)
            self.marionette.execute_script("document.getElementById('{}').click();".
                                           format(DOM.Dialer.call_log_edit_delete[1]))

            # Click on Delete button
            delete_btn = self.UTILS.element.getElement(DOM.GLOBAL.confirm_form_delete_btn, "Confirm delete")
            delete_btn.tap()

            try:
                _postcount = self.UTILS.element.getElements(_els, "Call log items", False)
                _postcount = len(_postcount)
            except:
                _postcount = 0

            self.UTILS.test.test(_postcount == _precount,
                                 "{} numbers are left after deletion (there are {}).".format(_precount, _postcount))

    def tap_on_call_button(self):
        call_number_button = self.UTILS.element.getElement(DOM.Dialer.call_number_button, "Call number button")
        self.UTILS.element.simulateClick(call_number_button)

    def call_this_number(self):
        """ 
        Calls the current number.
        """
        self.tap_on_call_button()
        self.UTILS.iframe.switchToFrame(*DOM.Dialer.frame_locator_calling)
        self.UTILS.element.waitForElements(DOM.Dialer.outgoing_call_locator, "Outgoing call locator", True, 5)

    def call_this_number_and_hangup(self, delay):
        self.call_this_number()
        time.sleep(delay)
        self.hangUp()

    def get_and_accept_fdn_warning(self, phone_number):
        # Check warning message
        self.UTILS.element.waitForElements(DOM.Settings.fdn_warning_header, "Waiting for FDN warning header", True, 10)
        self.UTILS.element.waitForElements(DOM.Settings.fdn_warning_body, "Waiting for FDN warning body")
        body = self.marionette.find_element(*DOM.Settings.fdn_warning_body)
        self.UTILS.reporting.log_to_file("body.text: {}   msg: {}".format(body.text, DOM.Dialer.fdn_warning_msg.
                                                                          format(phone_number)))
        self.UTILS.test.test(body.text == DOM.Dialer.fdn_warning_msg.format(phone_number),
                             "Correct FDN warning message")

        ok_btn = self.UTILS.element.getElement(DOM.Settings.fdn_warning_ok, "OK button")
        ok_btn.tap()

    def createContactFromThisNum(self):
        """
        Creates a new contact from the number currently in the dialer
        (doesn't fill in the contact details).
        """
        self.UTILS.iframe.switchToFrame(*DOM.Dialer.frame_locator)

        add_btn = self.UTILS.element.getElement(DOM.Dialer.add_to_contacts_button, "Add to contacts button")
        add_btn.tap()

        create_btn = self.UTILS.element.getElement(DOM.Dialer.create_new_contact_btn, "Create new contact button")
        create_btn.tap()

        # Switch to the contacts frame.
        self.UTILS.iframe.switchToFrame(*DOM.Contacts.frame_locator)

    def createMultipleCallLogEntries(self, phone_number, entries_number):
        """
        Put a number in the call log multiple times
        (done by manipulating the device time).
        Leaves you in the call log.
        """

        today = datetime.datetime.today()
        for i in range(entries_number):
            delta = datetime.timedelta(days=i)
            new_date = today - delta

            self.UTILS.date_and_time.setTimeToSpecific(p_day=new_date.day, p_month=new_date.month)

            self.enterNumber(phone_number)
            self.call_this_number_and_hangup(delay=7)
            # This needs to be done bcs sometimes (50%) the Dialer app crushes after hanging up
            self.apps.kill_all()
            time.sleep(2)
            self.launch()

    def enterNumber(self, number, validate=True):
        """
        Enters a number into the dialer using the keypad.
        """
        try:
            self.parent.wait_for_element_displayed(*DOM.Dialer.phone_number, timeout=1)
        except:
            keypad_selector = self.UTILS.element.getElement(DOM.Dialer.option_bar_keypad, "Keypad option selector")
            keypad_selector.tap()
            self.UTILS.element.waitForElements(DOM.Dialer.phone_number, "Phone number area")

        for i in str(number):

            if i == "+":
                plus_symbol = self.UTILS.element.getElement(("xpath", DOM.Dialer.dialer_button_xpath.format(0)),
                                                            "keypad symbol '+'")
                self.actions.long_press(plus_symbol, 2).perform()
            else:
                number_symbol = self.UTILS.element.getElement(("xpath", DOM.Dialer.dialer_button_xpath.format(i)),
                                                              "keypad number {}".format(i))
                number_symbol.tap()

        # Verify that the number field contains the expected number.
        if validate:
            dialed_num = self.marionette.execute_script("return window.wrappedJSObject.KeypadManager._phoneNumber")
            self.UTILS.reporting.debug(u"** Dialer_num entered: [{}]".format(dialed_num))
            self.UTILS.test.test(
                str(number) in dialed_num, u"Dialed number matches the original number".format(number, dialed_num))

    def clear_dialer(self):
        """
        Deletes a single number from the dialer
        """
        try:
            self.parent.wait_for_element_displayed(*DOM.Dialer.keypad_delete)
            delete = self.marionette.find_element(*DOM.Dialer.keypad_delete)
            delete.tap()
        except:
            return

    def clear_dialer_all(self):
        """
        Clears all dialer input area
        """
        try:
            self.parent.wait_for_element_displayed(*DOM.Dialer.keypad_delete)
            delete = self.marionette.find_element(*DOM.Dialer.keypad_delete)
            self.actions.long_press(delete, 3).perform()
        except:
            return

    def answer(self):
        self.marionette.switch_to_frame()
        elDef = ("xpath", "//iframe[contains(@{}, '{}')]".
                 format(DOM.Dialer.frame_locator_calling[0],
                        DOM.Dialer.frame_locator_calling[1]))

        self.parent.wait_for_element_displayed(*elDef, timeout=60)
        frame_calling = self.marionette.find_element(*elDef)

        if frame_calling:
            self.UTILS.iframe.switchToFrame(*DOM.Dialer.frame_locator_calling)
            self.parent.wait_for_element_displayed(*DOM.Dialer.answer_callButton, timeout=1)
            answer = self.marionette.find_element(*DOM.Dialer.answer_callButton)
            if answer:
                answer.tap()

    def answer_and_hangup(self, delay=5):
        self.answer()
        time.sleep(delay)

        self.parent.wait_for_element_displayed(*DOM.Dialer.hangup_bar_locator, timeout=1)
        hangup = self.marionette.find_element(*DOM.Dialer.hangup_bar_locator)
        if hangup:
            hangup.tap()
        else:
            try:
                self.parent.data_layer.kill_active_call()
            except:
                self.UTILS.reporting.logResult("info", "Exception when killing active call via data_layer")
                pass

    def hangUp(self):
        """
        Hangs up (assuming we're in the 'calling' frame).
        """

        self.marionette.switch_to_frame()
        try:
            self.parent.wait_for_element_displayed(*DOM.Dialer.frame_locator_calling)
            self.UTILS.iframe.switchToFrame(*DOM.Dialer.frame_locator_calling)
            self.marionette.find_element(*DOM.Dialer.hangup_bar_locator).tap()
            self.apps.switch_to_displayed_app()
        except:
            self.apps.switch_to_displayed_app()
            self.parent.wait_for_element_displayed(*DOM.Dialer.call_busy_button_ok, timeout=5)
            ok_btn = self.marionette.find_element(*DOM.Dialer.call_busy_button_ok)
            ok_btn.tap()

    def open_call_log(self):
        """
        Opens the call log.
        """
        x = self.UTILS.element.getElement(DOM.Dialer.option_bar_call_log, "Call log button")
        x.tap()

        time.sleep(2)

    def wait_for_incoming_call(self, phone_number, timeout=30):
        self.marionette.switch_to_frame()
        try:
            self.parent.wait_for_element_displayed(*DOM.Dialer.call_screen_locator, timeout=60)
            frame = self.marionette.find_element(*DOM.Dialer.call_screen_frame_locator)
            self.marionette.switch_to_frame(frame)
            elem = ("xpath", DOM.Dialer.outgoing_call_numberXP.format(phone_number))
            self.UTILS.element.waitForElements(
                elem, "Phone number [{}] is displayed in call_screen frame".format(phone_number))
        except:
            self.UTILS.test.test(False, "No incoming call received", True)

    def resume_hidden_call(self):
        self.marionette.switch_to_frame()
        self.UTILS.statusbar.displayStatusBar()
        attention = self.marionette.find_element('id', 'attention-window-notifications-container')
        attention.tap()
        self.UTILS.iframe.switchToFrame(*DOM.Dialer.frame_locator_calling)
Example #36
0
 def send_message(self, to_user, message, wait_load=0.5):
     # Make firefox go to the users page.
     self.client.navigate("https://www.messenger.com/t/{}".format(to_user))
     # Give a little bit of time to load.
     time.sleep(wait_load)
     for letter in message:
         # Make the typing look realistic.
         keep_down = random.uniform(0.005, 0.010)
         wait_time = keep_down + random.uniform(0.02, 0.05)
         # Send off the action
         action = Actions(self.client)
         if letter != '\n':
             action.key_down(letter).wait(keep_down).key_up(letter)
         else:
             # Handle multi line messages.
             action.key_down(Keys.SHIFT).key_down(Keys.ENTER)\
                 .wait(keep_down).key_up(Keys.SHIFT).key_up(Keys.ENTER)
         action.perform()
         # wait for it to complete.
         time.sleep(wait_time)
     # Send message.
     action.key_down('\n').wait(keep_down).key_up('\n')
     action.perform()
Example #37
0
    def edge_scroll(marionette, 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.rect['width']
            dist *= -1  # travel opposite direction

        limit = dist * frame.rect['width']
        dist_unit = limit * time_increment

        assert isinstance(marionette, object)
        action = Actions(marionette)
        action.press(frame, start_x, frame.rect['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()
        time.sleep(
            2
        )  # compensate for the time taken for edge scroll to bring another app to active

        return action
Example #38
0
class AccessibleCaretSelectionModeTestCase(MarionetteTestCase):
    '''Test cases for AccessibleCaret under selection mode.'''
    # Element IDs.
    _input_id = 'input'
    _input_padding_id = 'input-padding'
    _textarea_id = 'textarea'
    _textarea2_id = 'textarea2'
    _textarea_one_line_id = 'textarea-one-line'
    _textarea_rtl_id = 'textarea-rtl'
    _contenteditable_id = 'contenteditable'
    _contenteditable2_id = 'contenteditable2'
    _content_id = 'content'
    _content2_id = 'content2'
    _non_selectable_id = 'non-selectable'

    # Test html files.
    _selection_html = 'test_carets_selection.html'
    _multipleline_html = 'test_carets_multipleline.html'
    _multiplerange_html = 'test_carets_multiplerange.html'
    _longtext_html = 'test_carets_longtext.html'
    _iframe_html = 'test_carets_iframe.html'
    _display_none_html = 'test_carets_display_none.html'

    def setUp(self):
        # Code to execute before every test is running.
        super(AccessibleCaretSelectionModeTestCase, self).setUp()
        self.carets_tested_pref = 'layout.accessiblecaret.enabled'
        self.prefs = {
            'layout.word_select.eat_space_to_next_word': False,
            'layout.accessiblecaret.use_long_tap_injector': False,
            self.carets_tested_pref: True,
        }
        self.marionette.set_prefs(self.prefs)
        self.actions = Actions(self.marionette)

    def open_test_html(self, test_html):
        self.marionette.navigate(self.marionette.absolute_url(test_html))

    def word_offset(self, text, ordinal):
        'Get the character offset of the ordinal-th word in text.'
        tokens = re.split(r'(\S+)', text)         # both words and spaces
        spaces = tokens[0::2]                     # collect spaces at odd indices
        words = tokens[1::2]                      # collect word at even indices

        if ordinal >= len(words):
            raise IndexError('Only %d words in text, but got ordinal %d' %
                             (len(words), ordinal))

        # Cursor position of the targeting word is behind the the first
        # character in the word. For example, offset to 'def' in 'abc def' is
        # between 'd' and 'e'.
        offset = len(spaces[0]) + 1
        offset += sum(len(words[i]) + len(spaces[i + 1]) for i in range(ordinal))
        return offset

    def test_word_offset(self):
        text = ' ' * 3 + 'abc' + ' ' * 3 + 'def'

        self.assertTrue(self.word_offset(text, 0), 4)
        self.assertTrue(self.word_offset(text, 1), 10)
        with self.assertRaises(IndexError):
            self.word_offset(text, 2)

    def word_location(self, el, ordinal):
        '''Get the location (x, y) of the ordinal-th word in el.

        The ordinal starts from 0.

        Note: this function has a side effect which changes focus to the
        target element el.

        '''
        sel = SelectionManager(el)
        offset = self.word_offset(sel.content, ordinal)

        # Move the blinking cursor to the word.
        el.tap()
        sel.move_cursor_to_front()
        sel.move_cursor_by_offset(offset)
        x, y = sel.cursor_location()

        return x, y

    def rect_relative_to_window(self, el):
        '''Get element's bounding rectangle.

        This function is similar to el.rect, but the coordinate is relative to
        the top left corner of the window instead of the document.

        '''
        return self.marionette.execute_script('''
            let rect = arguments[0].getBoundingClientRect();
            return {x: rect.x, y:rect.y, width: rect.width, height: rect.height};
            ''', script_args=[el])

    def long_press_on_location(self, el, x=None, y=None):
        '''Long press the location (x, y) to select a word.

        If no (x, y) are given, it will be targeted at the center of the
        element. On Windows, those spaces after the word will also be selected.
        This function sends synthesized eMouseLongTap to gecko.

        '''
        rect = self.rect_relative_to_window(el)
        target_x = rect['x'] + (x if x is not None else rect['width'] // 2)
        target_y = rect['y'] + (y if y is not None else rect['height'] // 2)

        self.marionette.execute_script('''
            let Ci = Components.interfaces;
            let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIDOMWindowUtils);
            utils.sendTouchEventToWindow('touchstart', [0],
                                         [arguments[0]], [arguments[1]],
                                         [1], [1], [0], [1], 1, 0);
            utils.sendMouseEventToWindow('mouselongtap', arguments[0], arguments[1],
                                          0, 1, 0);
            utils.sendTouchEventToWindow('touchend', [0],
                                         [arguments[0]], [arguments[1]],
                                         [1], [1], [0], [1], 1, 0);
            ''', script_args=[target_x, target_y], sandbox='system')

    def long_press_on_word(self, el, wordOrdinal):
        x, y = self.word_location(el, wordOrdinal)
        self.long_press_on_location(el, x, y)

    def to_unix_line_ending(self, s):
        """Changes all Windows/Mac line endings in s to UNIX line endings."""

        return s.replace('\r\n', '\n').replace('\r', '\n')

    @parameterized(_input_id, el_id=_input_id)
    @parameterized(_textarea_id, el_id=_textarea_id)
    @parameterized(_textarea_rtl_id, el_id=_textarea_rtl_id)
    @parameterized(_contenteditable_id, el_id=_contenteditable_id)
    @parameterized(_content_id, el_id=_content_id)
    def test_long_press_to_select_a_word(self, el_id):
        self.open_test_html(self._selection_html)
        el = self.marionette.find_element(By.ID, el_id)
        self._test_long_press_to_select_a_word(el)

    def _test_long_press_to_select_a_word(self, el):
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(len(words) >= 2, 'Expect at least two words in the content.')
        target_content = words[0]

        # Goal: Select the first word.
        self.long_press_on_word(el, 0)

        # Ignore extra spaces selected after the word.
        self.assertEqual(target_content, sel.selected_content)

    @parameterized(_input_id, el_id=_input_id)
    @parameterized(_textarea_id, el_id=_textarea_id)
    @parameterized(_textarea_rtl_id, el_id=_textarea_rtl_id)
    @parameterized(_contenteditable_id, el_id=_contenteditable_id)
    @parameterized(_content_id, el_id=_content_id)
    def test_drag_carets(self, el_id):
        self.open_test_html(self._selection_html)
        el = self.marionette.find_element(By.ID, el_id)
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(len(words) >= 1, 'Expect at least one word in the content.')

        # Goal: Select all text after the first word.
        target_content = original_content[len(words[0]):]

        # Get the location of the carets at the end of the content for later
        # use.
        el.tap()
        sel.select_all()
        end_caret_x, end_caret_y = sel.second_caret_location()

        self.long_press_on_word(el, 0)

        # Drag the second caret to the end of the content.
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.carets_location()
        self.actions.flick(el, caret2_x, caret2_y, end_caret_x, end_caret_y).perform()

        # Drag the first caret to the previous position of the second caret.
        self.actions.flick(el, caret1_x, caret1_y, caret2_x, caret2_y).perform()

        self.assertEqual(target_content, sel.selected_content)

    @parameterized(_input_id, el_id=_input_id)
    @parameterized(_textarea_id, el_id=_textarea_id)
    @parameterized(_textarea_rtl_id, el_id=_textarea_rtl_id)
    @parameterized(_contenteditable_id, el_id=_contenteditable_id)
    @parameterized(_content_id, el_id=_content_id)
    def test_minimum_select_one_character(self, el_id):
        self.open_test_html(self._selection_html)
        el = self.marionette.find_element(By.ID, el_id)
        self._test_minimum_select_one_character(el)

    @parameterized(_textarea2_id, el_id=_textarea2_id)
    @parameterized(_contenteditable2_id, el_id=_contenteditable2_id)
    @parameterized(_content2_id, el_id=_content2_id)
    def test_minimum_select_one_character2(self, el_id):
        self.open_test_html(self._multipleline_html)
        el = self.marionette.find_element(By.ID, el_id)
        self._test_minimum_select_one_character(el)

    def _test_minimum_select_one_character(self, el, x=None, y=None):
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(len(words) >= 1, 'Expect at least one word in the content.')

        # Get the location of the carets at the end of the content for later
        # use.
        sel.select_all()
        end_caret_x, end_caret_y = sel.second_caret_location()
        el.tap()

        # Goal: Select the first character.
        target_content = original_content[0]

        if x and y:
            # If we got x and y from the arguments, use it as a hint of the
            # location of the first word
            pass
        else:
            x, y = self.word_location(el, 0)
        self.long_press_on_location(el, x, y)

        # Drag the second caret to the end of the content.
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.carets_location()
        self.actions.flick(el, caret2_x, caret2_y, end_caret_x, end_caret_y).perform()

        # Drag the second caret to the position of the first caret.
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.carets_location()
        self.actions.flick(el, caret2_x, caret2_y, caret1_x, caret1_y).perform()

        self.assertEqual(target_content, sel.selected_content)

    @parameterized(_input_id + '_to_' + _textarea_id,
                   el1_id=_input_id, el2_id=_textarea_id)
    @parameterized(_input_id + '_to_' + _contenteditable_id,
                   el1_id=_input_id, el2_id=_contenteditable_id)
    @parameterized(_input_id + '_to_' + _content_id,
                   el1_id=_input_id, el2_id=_content_id)
    @parameterized(_textarea_id + '_to_' + _input_id,
                   el1_id=_textarea_id, el2_id=_input_id)
    @parameterized(_textarea_id + '_to_' + _contenteditable_id,
                   el1_id=_textarea_id, el2_id=_contenteditable_id)
    @parameterized(_textarea_id + '_to_' + _content_id,
                   el1_id=_textarea_id, el2_id=_content_id)
    @parameterized(_contenteditable_id + '_to_' + _input_id,
                   el1_id=_contenteditable_id, el2_id=_input_id)
    @parameterized(_contenteditable_id + '_to_' + _textarea_id,
                   el1_id=_contenteditable_id, el2_id=_textarea_id)
    @parameterized(_contenteditable_id + '_to_' + _content_id,
                   el1_id=_contenteditable_id, el2_id=_content_id)
    @parameterized(_content_id + '_to_' + _input_id,
                   el1_id=_content_id, el2_id=_input_id)
    @parameterized(_content_id + '_to_' + _textarea_id,
                   el1_id=_content_id, el2_id=_textarea_id)
    @parameterized(_content_id + '_to_' + _contenteditable_id,
                   el1_id=_content_id, el2_id=_contenteditable_id)
    def test_long_press_changes_focus_from(self, el1_id, el2_id):
        '''Test the focus could be changed from el1 to el2 by long press.

        If the focus is changed to e2 successfully, the carets should appear and
        could be dragged.

        '''
        # Goal: Tap to focus el1, and then select the first character on
        # el2.

        # We want to collect the location of the first word in el2 here
        # since self.word_location() has the side effect which would
        # change the focus.
        self.open_test_html(self._selection_html)
        el1 = self.marionette.find_element(By.ID, el1_id)
        el2 = self.marionette.find_element(By.ID, el2_id)
        x, y = self.word_location(el2, 0)
        el1.tap()
        self._test_minimum_select_one_character(el2, x=x, y=y)

    @parameterized(_input_id, el_id=_input_id)
    @parameterized(_textarea_id, el_id=_textarea_id)
    @parameterized(_textarea_rtl_id, el_id=_textarea_rtl_id)
    @parameterized(_contenteditable_id, el_id=_contenteditable_id)
    def test_focus_not_changed_by_long_press_on_non_selectable(self, el_id):
        self.open_test_html(self._selection_html)
        el = self.marionette.find_element(By.ID, el_id)
        non_selectable = self.marionette.find_element(By.ID, self._non_selectable_id)

        # Goal: Focus remains on the editable element el after long pressing on
        # the non-selectable element.
        sel = SelectionManager(el)
        self.long_press_on_word(el, 0)
        self.long_press_on_location(non_selectable)
        active_sel = SelectionManager(self.marionette.get_active_element())
        self.assertEqual(sel.content, active_sel.content)

    @parameterized(_input_id, el_id=_input_id)
    @parameterized(_textarea_id, el_id=_textarea_id)
    @parameterized(_textarea_rtl_id, el_id=_textarea_rtl_id)
    @parameterized(_contenteditable_id, el_id=_contenteditable_id)
    @parameterized(_content_id, el_id=_content_id)
    def test_handle_tilt_when_carets_overlap_each_other(self, el_id):
        '''Test tilt handling when carets overlap to each other.

        Let the two carets overlap each other. If they are set to tilted
        successfully, tapping the tilted carets should not cause the selection
        to be collapsed and the carets should be draggable.

        '''
        self.open_test_html(self._selection_html)
        el = self.marionette.find_element(By.ID, el_id)
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(len(words) >= 1, 'Expect at least one word in the content.')

        # Goal: Select the first word.
        self.long_press_on_word(el, 0)
        target_content = sel.selected_content

        # Drag the first caret to the position of the second caret to trigger
        # carets overlapping.
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.carets_location()
        self.actions.flick(el, caret1_x, caret1_y, caret2_x, caret2_y).perform()

        # We make two hit tests targeting the left edge of the left tilted caret
        # and the right edge of the right tilted caret. If either of the hits is
        # missed, selection would be collapsed and both carets should not be
        # draggable.
        (caret3_x, caret3_y), (caret4_x, caret4_y) = sel.carets_location()

        # The following values are from ua.css and all.js
        caret_width = float(self.marionette.get_pref('layout.accessiblecaret.width'))
        caret_margin_left = float(self.marionette.get_pref('layout.accessiblecaret.margin-left'))
        tilt_right_margin_left = 0.41 * caret_width
        tilt_left_margin_left = -0.39 * caret_width

        left_caret_left_edge_x = caret3_x + caret_margin_left + tilt_left_margin_left
        el.tap(left_caret_left_edge_x + 2, caret3_y)

        right_caret_right_edge_x = (caret4_x + caret_margin_left +
                                    tilt_right_margin_left + caret_width)
        el.tap(right_caret_right_edge_x - 2, caret4_y)

        # Drag the first caret back to the initial selection, the first word.
        self.actions.flick(el, caret3_x, caret3_y, caret1_x, caret1_y).perform()

        self.assertEqual(target_content, sel.selected_content)

    def test_drag_caret_over_non_selectable_field(self):
        '''Test dragging the caret over a non-selectable field.

        The selected content should exclude non-selectable elements and the
        second caret should appear in last range's position.

        '''
        self.open_test_html(self._multiplerange_html)
        body = self.marionette.find_element(By.ID, 'bd')
        sel3 = self.marionette.find_element(By.ID, 'sel3')
        sel4 = self.marionette.find_element(By.ID, 'sel4')
        sel6 = self.marionette.find_element(By.ID, 'sel6')

        # Select target element and get target caret location
        self.long_press_on_word(sel4, 3)
        sel = SelectionManager(body)
        end_caret_x, end_caret_y = sel.second_caret_location()

        self.long_press_on_word(sel6, 0)
        end_caret2_x, end_caret2_y = sel.second_caret_location()

        # Select start element
        self.long_press_on_word(sel3, 3)

        # Drag end caret to target location
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.carets_location()
        self.actions.flick(body, caret2_x, caret2_y, end_caret_x, end_caret_y, 1).perform()
        self.assertEqual(self.to_unix_line_ending(sel.selected_content.strip()),
                         'this 3\nuser can select this')

        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.carets_location()
        self.actions.flick(body, caret2_x, caret2_y, end_caret2_x, end_caret2_y, 1).perform()
        self.assertEqual(self.to_unix_line_ending(sel.selected_content.strip()),
                         'this 3\nuser can select this 4\nuser can select this 5\nuser')

        # Drag first caret to target location
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.carets_location()
        self.actions.flick(body, caret1_x, caret1_y, end_caret_x, end_caret_y, 1).perform()
        self.assertEqual(self.to_unix_line_ending(sel.selected_content.strip()),
                         '4\nuser can select this 5\nuser')

    def test_drag_caret_to_beginning_of_a_line(self):
        '''Bug 1094056
        Test caret visibility when caret is dragged to beginning of a line
        '''
        self.open_test_html(self._multiplerange_html)
        body = self.marionette.find_element(By.ID, 'bd')
        sel1 = self.marionette.find_element(By.ID, 'sel1')
        sel2 = self.marionette.find_element(By.ID, 'sel2')

        # Select the first word in the second line
        self.long_press_on_word(sel2, 0)
        sel = SelectionManager(body)
        (start_caret_x, start_caret_y), (end_caret_x, end_caret_y) = sel.carets_location()

        # Select target word in the first line
        self.long_press_on_word(sel1, 2)

        # Drag end caret to the beginning of the second line
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.carets_location()
        self.actions.flick(body, caret2_x, caret2_y, start_caret_x, start_caret_y).perform()

        # Drag end caret back to the target word
        self.actions.flick(body, start_caret_x, start_caret_y, caret2_x, caret2_y).perform()

        self.assertEqual(self.to_unix_line_ending(sel.selected_content), 'select')

    @skip_if_not_rotatable
    def test_caret_position_after_changing_orientation_of_device(self):
        '''Bug 1094072
        If positions of carets are updated correctly, they should be draggable.
        '''
        self.open_test_html(self._longtext_html)
        body = self.marionette.find_element(By.ID, 'bd')
        longtext = self.marionette.find_element(By.ID, 'longtext')

        # Select word in portrait mode, then change to landscape mode
        self.marionette.set_orientation('portrait')
        self.long_press_on_word(longtext, 12)
        sel = SelectionManager(body)
        (p_start_caret_x, p_start_caret_y), (p_end_caret_x, p_end_caret_y) = sel.carets_location()
        self.marionette.set_orientation('landscape')
        (l_start_caret_x, l_start_caret_y), (l_end_caret_x, l_end_caret_y) = sel.carets_location()

        # Drag end caret to the start caret to change the selected content
        self.actions.flick(body, l_end_caret_x, l_end_caret_y,
                           l_start_caret_x, l_start_caret_y).perform()

        # Change orientation back to portrait mode to prevent affecting
        # other tests
        self.marionette.set_orientation('portrait')

        self.assertEqual(self.to_unix_line_ending(sel.selected_content), 'o')

    def test_select_word_inside_an_iframe(self):
        '''Bug 1088552
        The scroll offset in iframe should be taken into consideration properly.
        In this test, we scroll content in the iframe to the bottom to cause a
        huge offset. If we use the right coordinate system, selection should
        work. Otherwise, it would be hard to trigger select word.
        '''
        self.open_test_html(self._iframe_html)
        iframe = self.marionette.find_element(By.ID, 'frame')

        # switch to inner iframe and scroll to the bottom
        self.marionette.switch_to_frame(iframe)
        self.marionette.execute_script(
            'document.getElementById("bd").scrollTop += 999')

        # long press to select bottom text
        body = self.marionette.find_element(By.ID, 'bd')
        sel = SelectionManager(body)
        self._bottomtext = self.marionette.find_element(By.ID, 'bottomtext')
        self.long_press_on_location(self._bottomtext)

        self.assertNotEqual(self.to_unix_line_ending(sel.selected_content), '')

    def test_carets_initialized_in_display_none(self):
        '''Test AccessibleCaretEventHub is properly initialized on a <html> with
        display: none.

        '''
        self.open_test_html(self._display_none_html)
        html = self.marionette.find_element(By.ID, 'html')
        content = self.marionette.find_element(By.ID, 'content')

        # Remove 'display: none' from <html>
        self.marionette.execute_script(
            'arguments[0].style.display = "unset";',
            script_args=[html]
        )

        # If AccessibleCaretEventHub is initialized successfully, select a word
        # should work.
        self._test_long_press_to_select_a_word(content)

    def test_long_press_to_select_when_partial_visible_word_is_selected(self):
        self.open_test_html(self._selection_html)
        el = self.marionette.find_element(By.ID, self._input_id)
        sel = SelectionManager(el)

        # To successfully select the second word while the first word is being
        # selected, use sufficient spaces between 'a' and 'b' to avoid the
        # second caret covers on the second word.
        original_content = 'aaaaaaaa          bbbbbbbb'
        el.clear()
        el.send_keys(original_content)
        words = original_content.split()

        # We cannot use self.long_press_on_word() directly since it has will
        # change the cursor position which affects this test. We have to store
        # the position of word 0 and word 1 before long-pressing to select the
        # word.
        word0_x, word0_y = self.word_location(el, 0)
        word1_x, word1_y = self.word_location(el, 1)

        self.long_press_on_location(el, word0_x, word0_y)
        self.assertEqual(words[0], sel.selected_content)

        self.long_press_on_location(el, word1_x, word1_y)
        self.assertEqual(words[1], sel.selected_content)

        self.long_press_on_location(el, word0_x, word0_y)
        self.assertEqual(words[0], sel.selected_content)

        # If the second carets is visible, it can be dragged to the position of
        # the first caret. After that, selection will contain only the first
        # character.
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.carets_location()
        self.actions.flick(el, caret2_x, caret2_y, caret1_x, caret1_y).perform()
        self.assertEqual(words[0][0], sel.selected_content)

    @parameterized(_input_id, el_id=_input_id)
    @parameterized(_input_padding_id, el_id=_input_padding_id)
    @parameterized(_textarea_one_line_id, el_id=_textarea_one_line_id)
    @parameterized(_contenteditable_id, el_id=_contenteditable_id)
    def test_carets_not_jump_when_dragging_to_editable_content_boundary(self, el_id):
        self.open_test_html(self._selection_html)
        el = self.marionette.find_element(By.ID, el_id)
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(len(words) >= 3, 'Expect at least three words in the content.')

        # Goal: the selection is not changed after dragging the caret on the
        # Y-axis.
        target_content = words[1]

        self.long_press_on_word(el, 1)
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.carets_location()

        # Drag the first caret up by 50px.
        self.actions.flick(el, caret1_x, caret1_y, caret1_x, caret1_y - 50).perform()
        self.assertEqual(target_content, sel.selected_content)

        # Drag the second caret down by 50px.
        self.actions.flick(el, caret2_x, caret2_y, caret2_x, caret2_y + 50).perform()
        self.assertEqual(target_content, sel.selected_content)
Example #39
0
class TestMouseAction(MarionetteTestCase):
    def setUp(self):
        MarionetteTestCase.setUp(self)
        if self.marionette.session_capabilities["platformName"] == "darwin":
            self.mod_key = Keys.META
        else:
            self.mod_key = Keys.CONTROL
        self.action = Actions(self.marionette)

    def test_click_action(self):
        test_html = self.marionette.absolute_url("test.html")
        self.marionette.navigate(test_html)
        link = self.marionette.find_element(By.ID, "mozLink")
        self.action.click(link).perform()
        self.assertEqual(
            "Clicked",
            self.marionette.execute_script(
                "return document.getElementById('mozLink').innerHTML"))

    def test_clicking_element_out_of_view_succeeds(self):
        # The action based click doesn"t check for visibility.
        test_html = self.marionette.absolute_url("hidden.html")
        self.marionette.navigate(test_html)
        el = self.marionette.find_element(By.ID, "child")
        self.action.click(el).perform()

    def test_double_click_action(self):
        test_html = self.marionette.absolute_url("double_click.html")
        self.marionette.navigate(test_html)
        el = self.marionette.find_element(By.ID, "one-word-div")
        self.action.double_click(el).perform()
        el.send_keys(self.mod_key + "c")
        rel = self.marionette.find_element(By.ID, "input-field")
        rel.send_keys(self.mod_key + "v")
        self.assertEqual("zyxw", rel.get_property("value"))

    def test_context_click_action(self):
        test_html = self.marionette.absolute_url("javascriptPage.html")
        self.marionette.navigate(test_html)
        click_el = self.marionette.find_element(By.ID, "resultContainer")

        def context_menu_state():
            with self.marionette.using_context("chrome"):
                cm_el = self.marionette.find_element(By.ID,
                                                     "contentAreaContextMenu")
                return cm_el.get_property("state")

        self.assertEqual("closed", context_menu_state())
        self.action.context_click(click_el).perform()
        self.wait_for_condition(lambda _: context_menu_state() == "open")

        with self.marionette.using_context("chrome"):
            self.marionette.find_element(By.ID,
                                         "main-window").send_keys(Keys.ESCAPE)
        self.wait_for_condition(lambda _: context_menu_state() == "closed")

    def test_middle_click_action(self):
        test_html = self.marionette.absolute_url("clicks.html")
        self.marionette.navigate(test_html)

        self.marionette.find_element(By.ID, "addbuttonlistener").click()

        el = self.marionette.find_element(By.ID, "showbutton")
        self.action.middle_click(el).perform()

        self.wait_for_condition(lambda _: el.get_property("innerHTML") == "1")

    def test_chrome_click(self):
        self.marionette.navigate("about:blank")
        data_uri = "data:text/html,<html></html>"
        with self.marionette.using_context("chrome"):
            urlbar = self.marionette.find_element(By.ID, "urlbar")
            urlbar.send_keys(data_uri)
            go_button = self.marionette.find_element(By.ID, "urlbar-go-button")
            self.action.click(go_button).perform()
        self.wait_for_condition(lambda mn: mn.get_url() == data_uri)

    def test_chrome_double_click(self):
        self.marionette.navigate("about:blank")
        test_word = "quux"

        with self.marionette.using_context("chrome"):
            urlbar = self.marionette.find_element(By.ID, "urlbar")
            self.assertEqual("", urlbar.get_property("value"))

            urlbar.send_keys(test_word)
            self.assertEqual(urlbar.get_property("value"), test_word)
            (self.action.double_click(urlbar).perform().key_down(
                self.mod_key).key_down("x").perform())
            self.assertEqual(urlbar.get_property("value"), "")

    def test_chrome_context_click_action(self):
        self.marionette.set_context("chrome")

        def context_menu_state():
            cm_el = self.marionette.find_element(By.ID, "tabContextMenu")
            return cm_el.get_property("state")

        currtab = self.marionette.execute_script("return gBrowser.selectedTab")
        self.assertEqual("closed", context_menu_state())
        self.action.context_click(currtab).perform()
        self.wait_for_condition(lambda _: context_menu_state() == "open")

        (self.marionette.find_element(By.ID,
                                      "main-window").send_keys(Keys.ESCAPE))

        self.wait_for_condition(lambda _: context_menu_state() == "closed")
Example #40
0
class TestKeyActions(WindowManagerMixin, MarionetteTestCase):
    def setUp(self):
        super(TestKeyActions, self).setUp()
        if self.marionette.session_capabilities["platformName"] == "darwin":
            self.mod_key = Keys.META
        else:
            self.mod_key = Keys.CONTROL
        test_html = self.marionette.absolute_url("javascriptPage.html")
        self.marionette.navigate(test_html)
        self.reporter_element = self.marionette.find_element(
            By.ID, "keyReporter")
        self.reporter_element.click()
        self.key_action = Actions(self.marionette)

    @property
    def key_reporter_value(self):
        return self.reporter_element.get_property("value")

    def test_key_action_basic_input(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")

    def test_upcase_input(self):
        (self.key_action.key_down(Keys.SHIFT).key_down("a").key_up(
            Keys.SHIFT).key_down("b").key_down("c").perform())
        self.assertEqual(self.key_reporter_value, "Abc")

    def test_replace_input(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")
        (self.key_action.key_down(self.mod_key).key_down("a").key_up(
            self.mod_key).key_down("x").perform())
        self.assertEqual(self.key_reporter_value, "x")

    def test_clear_input(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")
        (self.key_action.key_down(
            self.mod_key).key_down("a").key_down("x").perform())
        self.assertEqual(self.key_reporter_value, "")
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")

    def test_input_with_wait(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        (self.key_action.key_down(
            self.mod_key).key_down("a").wait(.5).key_down("x").perform())
        self.assertEqual(self.key_reporter_value, "")

    @skip_if_mobile("Interacting with chrome windows not available for Fennec")
    def test_open_in_new_window_shortcut(self):
        def open_window_with_action():
            el = self.marionette.find_element(By.ID, "updatediv")
            # Ensure that the element is in the current view port because press() doesn't
            # handle that inside the action chain (bug 1295538).
            self.marionette.execute_script('arguments[0].scrollIntoView()',
                                           script_args=[el])
            (self.key_action.key_down(Keys.SHIFT).press(el).release().key_up(
                Keys.SHIFT).perform())

        new_window = self.open_window(trigger=open_window_with_action)
        self.marionette.switch_to_window(new_window)
        self.marionette.close_chrome_window()
        self.marionette.switch_to_window(self.start_window)
        self.assertEqual(self.key_reporter_value, "")
Example #41
0
class TestKeyActions(MarionetteTestCase):
    def setUp(self):
        MarionetteTestCase.setUp(self)
        if self.marionette.session_capabilities["platformName"] == "darwin":
            self.mod_key = Keys.META
        else:
            self.mod_key = Keys.CONTROL
        test_html = self.marionette.absolute_url("javascriptPage.html")
        self.marionette.navigate(test_html)
        self.reporter_element = self.marionette.find_element(
            By.ID, "keyReporter")
        self.reporter_element.click()
        self.key_action = Actions(self.marionette)

    @property
    def key_reporter_value(self):
        return self.reporter_element.get_property("value")

    def test_key_action_basic_input(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")

    def test_upcase_input(self):
        (self.key_action.key_down(Keys.SHIFT).key_down("a").key_up(
            Keys.SHIFT).key_down("b").key_down("c").perform())
        self.assertEqual(self.key_reporter_value, "Abc")

    def test_replace_input(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")
        (self.key_action.key_down(self.mod_key).key_down("a").key_up(
            self.mod_key).key_down("x").perform())
        self.assertEqual(self.key_reporter_value, "x")

    def test_clear_input(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")
        (self.key_action.key_down(
            self.mod_key).key_down("a").key_down("x").perform())
        self.assertEqual(self.key_reporter_value, "")
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")

    def test_input_with_wait(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        (self.key_action.key_down(
            self.mod_key).key_down("a").wait(.5).key_down("x").perform())
        self.assertEqual(self.key_reporter_value, "")

    def test_open_in_new_window_shortcut(self):
        el = self.marionette.find_element(By.ID, "updatediv")
        start_win = self.marionette.current_chrome_window_handle
        (self.key_action.key_down(Keys.SHIFT).press(el).release().key_up(
            Keys.SHIFT).perform())
        self.wait_for_condition(
            lambda mn: len(self.marionette.window_handles) == 2)
        chrome_window_handles = self.marionette.chrome_window_handles
        chrome_window_handles.remove(start_win)
        [new_win] = chrome_window_handles
        self.marionette.switch_to_window(new_win)
        self.marionette.close()
        self.marionette.switch_to_window(start_win)
        self.assertEqual(self.key_reporter_value, "")
Example #42
0
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
Example #43
0
 def wait(self, seconds: int):
     actions = Actions(self.marionette)
     actions.wait(seconds).perform()
Example #44
0
class SelectionCaretsTest(MarionetteTestCase):
    _long_press_time = 1  # 1 second
    _input_selector = (By.ID, 'input')
    _textarea_selector = (By.ID, 'textarea')
    _textarea_rtl_selector = (By.ID, 'textarea_rtl')
    _contenteditable_selector = (By.ID, 'contenteditable')
    _content_selector = (By.ID, 'content')
    _textarea2_selector = (By.ID, 'textarea2')
    _contenteditable2_selector = (By.ID, 'contenteditable2')
    _content2_selector = (By.ID, 'content2')

    def setUp(self):
        # Code to execute before a tests are run.
        MarionetteTestCase.setUp(self)
        self.actions = Actions(self.marionette)

    def openTestHtml(self, enabled=True):
        '''Open html for testing and locate elements, and enable/disable touch
        caret.'''
        self.marionette.execute_async_script(
            'SpecialPowers.pushPrefEnv({"set": [["selectioncaret.enabled", %s]]}, marionetteScriptFinished);'
            % ('true' if enabled else 'false'))
        test_html = self.marionette.absolute_url('test_selectioncarets.html')
        self.marionette.navigate(test_html)

        self._input = self.marionette.find_element(*self._input_selector)
        self._textarea = self.marionette.find_element(*self._textarea_selector)
        self._textarea_rtl = self.marionette.find_element(
            *self._textarea_rtl_selector)
        self._contenteditable = self.marionette.find_element(
            *self._contenteditable_selector)
        self._content = self.marionette.find_element(*self._content_selector)

    def openTestHtml2(self, enabled=True):
        '''Open html for testing and locate elements, and enable/disable touch
        caret.'''
        self.marionette.execute_script(
            'SpecialPowers.setBoolPref("selectioncaret.enabled", %s);' %
            ('true' if enabled else 'false'))

        test_html2 = self.marionette.absolute_url(
            'test_selectioncarets_multipleline.html')
        self.marionette.navigate(test_html2)

        self._textarea2 = self.marionette.find_element(
            *self._textarea2_selector)
        self._contenteditable2 = self.marionette.find_element(
            *self._contenteditable2_selector)
        self._content2 = self.marionette.find_element(*self._content2_selector)

    def _first_word_location(self, el):
        '''Get the location (x, y) of the first word in el.

        Note: this function has a side effect which changes focus to the
        target element el.

        '''
        sel = SelectionManager(el)

        # Move caret behind the first character to get the location of the first
        # word.
        el.tap()
        sel.move_caret_to_front()
        sel.move_caret_by_offset(1)

        return sel.caret_location()

    def _long_press_to_select(self, el, x, y):
        '''Long press the location (x, y) to select a word.

        SelectionCarets should appear. On Windows, those spaces after the
        word will also be selected.

        '''
        long_press_without_contextmenu(self.marionette, el,
                                       self._long_press_time, x, y)

    def _test_long_press_to_select_a_word(self, el, assertFunc):
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(
            len(words) >= 2, 'Expect at least two words in the content.')
        target_content = words[0]

        # Goal: Select the first word.
        x, y = self._first_word_location(el)
        self._long_press_to_select(el, x, y)

        # Ignore extra spaces selected after the word.
        assertFunc(target_content, sel.selected_content.rstrip())

    def _test_move_selection_carets(self, el, assertFunc):
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(
            len(words) >= 1, 'Expect at least one word in the content.')

        # Goal: Select all text after the first word.
        target_content = original_content[len(words[0]):]

        # Get the location of the selection carets at the end of the content for
        # later use.
        el.tap()
        sel.select_all()
        (_, _), (end_caret_x, end_caret_y) = sel.selection_carets_location()

        x, y = self._first_word_location(el)
        self._long_press_to_select(el, x, y)

        # Move the right caret to the end of the content.
        (caret1_x, caret1_y), (caret2_x,
                               caret2_y) = sel.selection_carets_location()
        self.actions.flick(el, caret2_x, caret2_y, end_caret_x,
                           end_caret_y).perform()

        # Move the left caret to the previous position of the right caret.
        self.actions.flick(el, caret1_x, caret1_y, caret2_x,
                           caret2_y).perform()

        # Ignore extra spaces at the beginning of the content in comparison.
        assertFunc(target_content.lstrip(), sel.selected_content.lstrip())

    def _test_minimum_select_one_character(self,
                                           el,
                                           assertFunc,
                                           x=None,
                                           y=None):
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(
            len(words) >= 1, 'Expect at least one word in the content.')

        # Get the location of the selection carets at the end of the content for
        # later use.
        sel.select_all()
        (_, _), (end_caret_x, end_caret_y) = sel.selection_carets_location()
        el.tap()

        # Goal: Select the first character.
        target_content = original_content[0]

        if x and y:
            # If we got x and y from the arguments, use it as a hint of the
            # location of the first word
            pass
        else:
            x, y = self._first_word_location(el)
        self._long_press_to_select(el, x, y)

        # Move the right caret to the end of the content.
        (caret1_x, caret1_y), (caret2_x,
                               caret2_y) = sel.selection_carets_location()
        self.actions.flick(el, caret2_x, caret2_y, end_caret_x,
                           end_caret_y).perform()

        # Move the right caret to the position of the left caret.
        (caret1_x, caret1_y), (caret2_x,
                               caret2_y) = sel.selection_carets_location()
        self.actions.flick(el, caret2_x, caret2_y, caret1_x,
                           caret1_y).perform()

        assertFunc(target_content, sel.selected_content)

    def _test_focus_obtained_by_long_press(self, el1, el2):
        '''Test the focus could be changed from el1 to el2 by long press.

        If the focus is changed to e2 successfully, SelectionCarets should
        appear and could be dragged.

        '''
        # Goal: Tap to focus el1, and then select the first character on
        # el2.

        # We want to collect the location of the first word in el2 here
        # since self._first_word_location() has the side effect which would
        # change the focus.
        x, y = self._first_word_location(el2)
        el1.tap()
        self._test_minimum_select_one_character(el2,
                                                self.assertEqual,
                                                x=x,
                                                y=y)

    def _test_handle_tilt_when_carets_overlap_to_each_other(
            self, el, assertFunc):
        '''Test tilt handling when carets overlap to each other.

        Let SelectionCarets overlap to each other. If SelectionCarets are set
        to tilted successfully, tapping the tilted carets should not cause the
        selection to be collapsed and the carets should be draggable.
        '''

        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(
            len(words) >= 1, 'Expect at least one word in the content.')

        # Goal: Select the first word.
        x, y = self._first_word_location(el)
        self._long_press_to_select(el, x, y)
        target_content = sel.selected_content

        # Move the left caret to the position of the right caret to trigger
        # carets overlapping.
        (caret1_x, caret1_y), (caret2_x,
                               caret2_y) = sel.selection_carets_location()
        self.actions.flick(el, caret1_x, caret1_y, caret2_x,
                           caret2_y).perform()

        # We make two hit tests targeting the left edge of the left tilted caret
        # and the right edge of the right tilted caret. If either of the hits is
        # missed, selection would be collapsed and both carets should not be
        # draggable.
        (caret3_x, caret3_y), (caret4_x,
                               caret4_y) = sel.selection_carets_location()

        # The following values are from ua.css.
        caret_width = 44
        caret_margin_left = -23
        tilt_right_margin_left = 18
        tilt_left_margin_left = -17

        left_caret_left_edge_x = caret3_x + caret_margin_left + tilt_left_margin_left
        el.tap(ceil(left_caret_left_edge_x), caret3_y)

        right_caret_right_edge_x = (caret4_x + caret_margin_left +
                                    tilt_right_margin_left + caret_width)
        el.tap(floor(right_caret_right_edge_x), caret4_y)

        # Drag the left caret back to the initial selection, the first word.
        self.actions.flick(el, caret3_x, caret3_y, caret1_x,
                           caret1_y).perform()

        assertFunc(target_content, sel.selected_content)

    ########################################################################
    # <input> test cases with selection carets enabled
    ########################################################################
    def test_input_long_press_to_select_a_word(self):
        self.openTestHtml(enabled=True)
        self._test_long_press_to_select_a_word(self._input, self.assertEqual)

    def test_input_move_selection_carets(self):
        self.openTestHtml(enabled=True)
        self._test_move_selection_carets(self._input, self.assertEqual)

    def test_input_minimum_select_one_character(self):
        self.openTestHtml(enabled=True)
        self._test_minimum_select_one_character(self._input, self.assertEqual)

    def test_input_focus_obtained_by_long_press_from_textarea(self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._textarea, self._input)

    def test_input_focus_obtained_by_long_press_from_contenteditable(self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._contenteditable,
                                                self._input)

    def test_input_focus_obtained_by_long_press_from_content_non_editable(
            self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._content, self._input)

    def test_input_handle_tilt_when_carets_overlap_to_each_other(self):
        self.openTestHtml(enabled=True)
        self._test_handle_tilt_when_carets_overlap_to_each_other(
            self._input, self.assertEqual)

    ########################################################################
    # <input> test cases with selection carets disabled
    ########################################################################
    def test_input_long_press_to_select_a_word_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_long_press_to_select_a_word(self._input,
                                               self.assertNotEqual)

    def test_input_move_selection_carets_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_move_selection_carets(self._input, self.assertNotEqual)

    ########################################################################
    # <textarea> test cases with selection carets enabled
    ########################################################################
    def test_textarea_long_press_to_select_a_word(self):
        self.openTestHtml(enabled=True)
        self._test_long_press_to_select_a_word(self._textarea,
                                               self.assertEqual)

    def test_textarea_move_selection_carets(self):
        self.openTestHtml(enabled=True)
        self._test_move_selection_carets(self._textarea, self.assertEqual)

    def test_textarea_minimum_select_one_character(self):
        self.openTestHtml(enabled=True)
        self._test_minimum_select_one_character(self._textarea,
                                                self.assertEqual)

    def test_textarea_focus_obtained_by_long_press_from_input(self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._input, self._textarea)

    def test_textarea_focus_obtained_by_long_press_from_contenteditable(self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._contenteditable,
                                                self._textarea)

    def test_textarea_focus_obtained_by_long_press_from_content_non_editable(
            self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._content, self._textarea)

    def test_textarea_handle_tilt_when_carets_overlap_to_each_other(self):
        self.openTestHtml(enabled=True)
        self._test_handle_tilt_when_carets_overlap_to_each_other(
            self._textarea, self.assertEqual)

    ########################################################################
    # <textarea> test cases with selection carets disabled
    ########################################################################
    def test_textarea_long_press_to_select_a_word_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_long_press_to_select_a_word(self._textarea,
                                               self.assertNotEqual)

    def test_textarea_move_selection_carets_disable(self):
        self.openTestHtml(enabled=False)
        self._test_move_selection_carets(self._textarea, self.assertNotEqual)

    ########################################################################
    # <textarea> right-to-left test cases with selection carets enabled
    ########################################################################
    def test_textarea_rtl_long_press_to_select_a_word(self):
        self.openTestHtml(enabled=True)
        self._test_long_press_to_select_a_word(self._textarea_rtl,
                                               self.assertEqual)

    def test_textarea_rtl_move_selection_carets(self):
        self.openTestHtml(enabled=True)
        self._test_move_selection_carets(self._textarea_rtl, self.assertEqual)

    def test_textarea_rtl_minimum_select_one_character(self):
        self.openTestHtml(enabled=True)
        self._test_minimum_select_one_character(self._textarea_rtl,
                                                self.assertEqual)

    ########################################################################
    # <textarea> right-to-left test cases with selection carets disabled
    ########################################################################
    def test_textarea_rtl_long_press_to_select_a_word_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_long_press_to_select_a_word(self._textarea_rtl,
                                               self.assertNotEqual)

    def test_textarea_rtl_move_selection_carets_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_move_selection_carets(self._textarea_rtl,
                                         self.assertNotEqual)

    ########################################################################
    # <div> contenteditable test cases with selection carets enabled
    ########################################################################
    def test_contenteditable_long_press_to_select_a_word(self):
        self.openTestHtml(enabled=True)
        self._test_long_press_to_select_a_word(self._contenteditable,
                                               self.assertEqual)

    def test_contenteditable_move_selection_carets(self):
        self.openTestHtml(enabled=True)
        self._test_move_selection_carets(self._contenteditable,
                                         self.assertEqual)

    def test_contenteditable_minimum_select_one_character(self):
        self.openTestHtml(enabled=True)
        self._test_minimum_select_one_character(self._contenteditable,
                                                self.assertEqual)

    def test_contenteditable_focus_obtained_by_long_press_from_input(self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._input,
                                                self._contenteditable)

    def test_contenteditable_focus_obtained_by_long_press_from_textarea(self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._textarea,
                                                self._contenteditable)

    def test_contenteditable_focus_obtained_by_long_press_from_content_non_editable(
            self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._content,
                                                self._contenteditable)

    def test_contenteditable_handle_tilt_when_carets_overlap_to_each_other(
            self):
        self.openTestHtml(enabled=True)
        self._test_handle_tilt_when_carets_overlap_to_each_other(
            self._contenteditable, self.assertEqual)

    ########################################################################
    # <div> contenteditable test cases with selection carets disabled
    ########################################################################
    def test_contenteditable_long_press_to_select_a_word_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_long_press_to_select_a_word(self._contenteditable,
                                               self.assertNotEqual)

    def test_contenteditable_move_selection_carets_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_move_selection_carets(self._contenteditable,
                                         self.assertNotEqual)

    ########################################################################
    # <div> non-editable test cases with selection carets enabled
    ########################################################################
    def test_content_non_editable_long_press_to_select_a_word(self):
        self.openTestHtml(enabled=True)
        self._test_long_press_to_select_a_word(self._content, self.assertEqual)

    def test_content_non_editable_move_selection_carets(self):
        self.openTestHtml(enabled=True)
        self._test_move_selection_carets(self._content, self.assertEqual)

    def test_content_non_editable_minimum_select_one_character_by_selection(
            self):
        self.openTestHtml(enabled=True)
        self._test_minimum_select_one_character(self._content,
                                                self.assertEqual)

    def test_content_non_editable_focus_obtained_by_long_press_from_input(
            self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._input, self._content)

    def test_content_non_editable_focus_obtained_by_long_press_from_textarea(
            self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._textarea, self._content)

    def test_content_non_editable_focus_obtained_by_long_press_from_contenteditable(
            self):
        self.openTestHtml(enabled=True)
        self._test_focus_obtained_by_long_press(self._contenteditable,
                                                self._content)

    def test_content_non_editable_handle_tilt_when_carets_overlap_to_each_other(
            self):
        self.openTestHtml(enabled=True)
        self._test_handle_tilt_when_carets_overlap_to_each_other(
            self._content, self.assertEqual)

    ########################################################################
    # <textarea> (multi-lines) test cases with selection carets enabled
    ########################################################################
    def test_textarea2_minimum_select_one_character(self):
        self.openTestHtml2(enabled=True)
        self._test_minimum_select_one_character(self._textarea2,
                                                self.assertEqual)

    ########################################################################
    # <div> contenteditable2 (multi-lines) test cases with selection carets enabled
    ########################################################################
    def test_contenteditable2_minimum_select_one_character(self):
        self.openTestHtml2(enabled=True)
        self._test_minimum_select_one_character(self._contenteditable2,
                                                self.assertEqual)

    ########################################################################
    # <div> non-editable2 (multi-lines) test cases with selection carets enabled
    ########################################################################
    def test_content_non_editable2_minimum_select_one_character(self):
        self.openTestHtml2(enabled=True)
        self._test_minimum_select_one_character(self._content2,
                                                self.assertEqual)
 def test_no_press(self):
     testAction = self.marionette.absolute_url("testAction.html")
     self.marionette.navigate(testAction)
     action = Actions(self.marionette)
     action.release()
     self.assertRaises(MarionetteException, action.perform)
class AccessibleCaretCursorModeTestCase(MarionetteTestCase):
    '''Test cases for AccessibleCaret under cursor mode.

    We call the blinking cursor (nsCaret) as cursor, and call AccessibleCaret as
    caret for short.

    '''
    # Element IDs.
    _input_id = 'input'
    _input_padding_id = 'input-padding'
    _textarea_id = 'textarea'
    _textarea_one_line_id = 'textarea-one-line'
    _contenteditable_id = 'contenteditable'

    # Test html files.
    _cursor_html = 'layout/test_carets_cursor.html'

    def setUp(self):
        # Code to execute before every test is running.
        super(AccessibleCaretCursorModeTestCase, self).setUp()
        self.caret_tested_pref = 'layout.accessiblecaret.enabled'
        self.hide_carets_for_mouse = 'layout.accessiblecaret.hide_carets_for_mouse_input'
        self.prefs = {
            self.caret_tested_pref: True,
            self.hide_carets_for_mouse: False,
        }
        self.marionette.set_prefs(self.prefs)
        self.actions = Actions(self.marionette)

    def open_test_html(self, test_html):
        self.marionette.navigate(self.marionette.absolute_url(test_html))

    @parameterized(_input_id, el_id=_input_id)
    @parameterized(_textarea_id, el_id=_textarea_id)
    @parameterized(_contenteditable_id, el_id=_contenteditable_id)
    def test_move_cursor_to_the_right_by_one_character(self, el_id):
        self.open_test_html(self._cursor_html)
        el = self.marionette.find_element(By.ID, el_id)
        sel = SelectionManager(el)
        content_to_add = '!'
        target_content = sel.content
        target_content = target_content[:1] + content_to_add + target_content[1:]

        # Get first caret (x, y) at position 1 and 2.
        el.tap()
        sel.move_cursor_to_front()
        cursor0_x, cursor0_y = sel.cursor_location()
        first_caret0_x, first_caret0_y = sel.first_caret_location()
        sel.move_cursor_by_offset(1)
        first_caret1_x, first_caret1_y = sel.first_caret_location()

        # Tap the front of the input to make first caret appear.
        el.tap(cursor0_x, cursor0_y)

        # Move first caret.
        self.actions.flick(el, first_caret0_x, first_caret0_y,
                           first_caret1_x, first_caret1_y).perform()

        self.actions.key_down(content_to_add).key_up(content_to_add).perform()
        self.assertEqual(target_content, sel.content)

    @parameterized(_input_id, el_id=_input_id)
    @parameterized(_textarea_id, el_id=_textarea_id)
    @parameterized(_contenteditable_id, el_id=_contenteditable_id)
    def test_move_cursor_to_end_by_dragging_caret_to_bottom_right_corner(self, el_id):
        self.open_test_html(self._cursor_html)
        el = self.marionette.find_element(By.ID, el_id)
        sel = SelectionManager(el)
        content_to_add = '!'
        target_content = sel.content + content_to_add

        # Tap the front of the input to make first caret appear.
        el.tap()
        sel.move_cursor_to_front()
        el.tap(*sel.cursor_location())

        # Move first caret to the bottom-right corner of the element.
        src_x, src_y = sel.first_caret_location()
        dest_x, dest_y = el.rect['width'], el.rect['height']
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        self.actions.key_down(content_to_add).key_up(content_to_add).perform()
        self.assertEqual(target_content, sel.content)

    @parameterized(_input_id, el_id=_input_id)
    @parameterized(_textarea_id, el_id=_textarea_id)
    @parameterized(_contenteditable_id, el_id=_contenteditable_id)
    def test_move_cursor_to_front_by_dragging_caret_to_front(self, el_id):
        self.open_test_html(self._cursor_html)
        el = self.marionette.find_element(By.ID, el_id)
        sel = SelectionManager(el)
        content_to_add = '!'
        target_content = content_to_add + sel.content

        # Get first caret location at the front.
        el.tap()
        sel.move_cursor_to_front()
        dest_x, dest_y = sel.first_caret_location()

        # Tap to make first caret appear. Note: it's strange that when the caret
        # is at the end, the rect of the caret in <textarea> cannot be obtained.
        # A bug perhaps.
        el.tap()
        sel.move_cursor_to_end()
        sel.move_cursor_by_offset(1, backward=True)
        el.tap(*sel.cursor_location())
        src_x, src_y = sel.first_caret_location()

        # Move first caret to the front of the input box.
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        self.actions.key_down(content_to_add).key_up(content_to_add).perform()
        self.assertEqual(target_content, sel.content)

    def test_caret_not_appear_when_typing_in_scrollable_content(self):
        self.open_test_html(self._cursor_html)
        el = self.marionette.find_element(By.ID, self._input_id)
        sel = SelectionManager(el)
        content_to_add = '!'
        non_target_content = content_to_add + sel.content + string.ascii_letters

        el.tap()
        sel.move_cursor_to_end()

        # Insert a long string to the end of the <input>, which triggers
        # ScrollPositionChanged event.
        el.send_keys(string.ascii_letters)

        # The caret should not be visible. If it does appear wrongly due to the
        # ScrollPositionChanged event, we can drag it to the front of the
        # <input> to change the cursor position.
        src_x, src_y = sel.first_caret_location()
        dest_x, dest_y = 0, 0
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        # The content should not be inserted at the front of the <input>.
        el.send_keys(content_to_add)

        self.assertNotEqual(non_target_content, sel.content)

    @parameterized(_input_id, el_id=_input_id)
    @parameterized(_input_padding_id, el_id=_input_padding_id)
    @parameterized(_textarea_one_line_id, el_id=_textarea_one_line_id)
    @parameterized(_contenteditable_id, el_id=_contenteditable_id)
    def test_caret_not_jump_when_dragging_to_editable_content_boundary(self, el_id):
        self.open_test_html(self._cursor_html)
        el = self.marionette.find_element(By.ID, el_id)
        sel = SelectionManager(el)
        content_to_add = '!'
        non_target_content = sel.content + content_to_add

        # Goal: the cursor position is not changed after dragging the caret down
        # on the Y-axis.
        el.tap()
        sel.move_cursor_to_front()
        el.tap(*sel.cursor_location())
        x, y = sel.first_caret_location()

        # Drag the caret down by 50px, and insert '!'.
        self.actions.flick(el, x, y, x, y + 50).perform()
        self.actions.key_down(content_to_add).key_up(content_to_add).perform()
        self.assertNotEqual(non_target_content, sel.content)

    @parameterized(_input_id, el_id=_input_id)
    @parameterized(_input_padding_id, el_id=_input_padding_id)
    @parameterized(_textarea_one_line_id, el_id=_textarea_one_line_id)
    @parameterized(_contenteditable_id, el_id=_contenteditable_id)
    def test_caret_not_jump_to_front_when_dragging_up_to_editable_content_boundary(self, el_id):
        self.open_test_html(self._cursor_html)
        el = self.marionette.find_element(By.ID, el_id)
        sel = SelectionManager(el)
        content_to_add = '!'
        non_target_content = content_to_add + sel.content

        # Goal: the cursor position is not changed after dragging the caret down
        # on the Y-axis.
        el.tap()
        sel.move_cursor_to_end()
        sel.move_cursor_by_offset(1, backward=True)
        el.tap(*sel.cursor_location())
        x, y = sel.first_caret_location()

        # Drag the caret up by 50px, and insert '!'.
        self.actions.flick(el, x, y, x, y - 50).perform()
        self.actions.key_down(content_to_add).key_up(content_to_add).perform()
        self.assertNotEqual(non_target_content, sel.content)

    def test_drag_caret_from_front_to_end_across_columns(self):
        self.open_test_html('layout/test_carets_columns.html')
        el = self.marionette.find_element(By.ID, 'columns-inner')
        sel = SelectionManager(el)
        content_to_add = '!'
        target_content = sel.content + content_to_add

        # Goal: the cursor position can be changed by dragging the caret from
        # the front to the end of the content.

        # Tap to make the cursor appear.
        before_image_1 = self.marionette.find_element(By.ID, 'before-image-1')
        before_image_1.tap()

        # Tap the front of the content to make first caret appear.
        sel.move_cursor_to_front()
        el.tap(*sel.cursor_location())
        src_x, src_y = sel.first_caret_location()
        dest_x, dest_y = el.rect['width'], el.rect['height']

        # Drag the first caret to the bottom-right corner of the element.
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        self.actions.key_down(content_to_add).key_up(content_to_add).perform()
        self.assertEqual(target_content, sel.content)

    def test_move_cursor_to_front_by_dragging_caret_to_front_br_element(self):
        self.open_test_html(self._cursor_html)
        el = self.marionette.find_element(By.ID, self._contenteditable_id)
        sel = SelectionManager(el)
        content_to_add_1 = '!'
        content_to_add_2 = '\n\n'
        target_content = content_to_add_1 + content_to_add_2 + sel.content

        # Goal: the cursor position can be changed by dragging the caret from
        # the end of the content to the front br element. Because we cannot get
        # caret location if it's on a br element, we need to get the first caret
        # location then adding the new lines.

        # Get first caret location at the front.
        el.tap()
        sel.move_cursor_to_front()
        dest_x, dest_y = sel.first_caret_location()

        # Append new line to the front of the content.
        el.send_keys(content_to_add_2);

        # Tap to make first caret appear.
        el.tap()
        sel.move_cursor_to_end()
        sel.move_cursor_by_offset(1, backward=True)
        el.tap(*sel.cursor_location())
        src_x, src_y = sel.first_caret_location()

        # Move first caret to the front of the input box.
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        self.actions.key_down(content_to_add_1).key_up(content_to_add_1).perform()
        self.assertEqual(target_content, sel.content)
Example #47
0
 def double_tap_image(self):
     image = self.marionette.find_element(*self._current_image_locator)
     action = Actions(self.marionette)
     action.double_tap(image)
     action.perform()
class CommonCaretsTestCase(object):
    '''Common test cases for a selection with a two carets.

    To run these test cases, a subclass must inherit from both this class and
    MarionetteTestCase.

    '''
    def setUp(self):
        # Code to execute before a tests are run.
        super(CommonCaretsTestCase, self).setUp()
        self.actions = Actions(self.marionette)

    def open_test_html(self):
        'Open html for testing and locate elements.'
        test_html = self.marionette.absolute_url('test_selectioncarets.html')
        self.marionette.navigate(test_html)

        self._input = self.marionette.find_element(By.ID, 'input')
        self._textarea = self.marionette.find_element(By.ID, 'textarea')
        self._textarea_rtl = self.marionette.find_element(By.ID, 'textarea_rtl')
        self._contenteditable = self.marionette.find_element(By.ID, 'contenteditable')
        self._content = self.marionette.find_element(By.ID, 'content')
        self._non_selectable = self.marionette.find_element(By.ID, 'non_selectable')

    def open_test_html2(self):
        'Open html for testing and locate elements.'
        test_html2 = self.marionette.absolute_url('test_selectioncarets_multipleline.html')
        self.marionette.navigate(test_html2)

        self._textarea2 = self.marionette.find_element(By.ID, 'textarea2')
        self._contenteditable2 = self.marionette.find_element(By.ID, 'contenteditable2')
        self._content2 = self.marionette.find_element(By.ID, 'content2')

    def open_test_html_multirange(self):
        'Open html for testing non-editable support.'
        test_html = self.marionette.absolute_url('test_selectioncarets_multiplerange.html')
        self.marionette.navigate(test_html)

        self._body = self.marionette.find_element(By.ID, 'bd')
        self._sel1 = self.marionette.find_element(By.ID, 'sel1')
        self._sel2 = self.marionette.find_element(By.ID, 'sel2')
        self._sel3 = self.marionette.find_element(By.ID, 'sel3')
        self._sel4 = self.marionette.find_element(By.ID, 'sel4')
        self._sel6 = self.marionette.find_element(By.ID, 'sel6')
        self._nonsel1 = self.marionette.find_element(By.ID, 'nonsel1')

    def open_test_html_long_text(self):
        'Open html for testing long text.'
        test_html = self.marionette.absolute_url('test_selectioncarets_longtext.html')
        self.marionette.navigate(test_html)

        self._body = self.marionette.find_element(By.ID, 'bd')
        self._longtext = self.marionette.find_element(By.ID, 'longtext')

    def open_test_html_iframe(self):
        'Open html for testing iframe.'
        test_html = self.marionette.absolute_url('test_selectioncarets_iframe.html')
        self.marionette.navigate(test_html)

        self._iframe = self.marionette.find_element(By.ID, 'frame')

    def word_offset(self, text, ordinal):
        'Get the character offset of the ordinal-th word in text.'
        tokens = re.split(r'(\S+)', text)         # both words and spaces
        spaces = tokens[0::2]                     # collect spaces at odd indices
        words = tokens[1::2]                      # collect word at even indices

        if ordinal >= len(words):
            raise IndexError('Only %d words in text, but got ordinal %d' %
                             (len(words), ordinal))

        # Cursor position of the targeting word is behind the the first
        # character in the word. For example, offset to 'def' in 'abc def' is
        # between 'd' and 'e'.
        offset = len(spaces[0]) + 1
        offset += sum(len(words[i]) + len(spaces[i + 1]) for i in range(ordinal))
        return offset

    def test_word_offset(self):
        text = ' ' * 3 + 'abc' + ' ' * 3 + 'def'

        self.assertTrue(self.word_offset(text, 0), 4)
        self.assertTrue(self.word_offset(text, 1), 10)
        with self.assertRaises(IndexError):
            self.word_offset(text, 2)

    def word_location(self, el, ordinal):
        '''Get the location (x, y) of the ordinal-th word in el.

        The ordinal starts from 0.

        Note: this function has a side effect which changes focus to the
        target element el.

        '''
        sel = SelectionManager(el)
        offset = self.word_offset(sel.content, ordinal)

        # Move caret to the word.
        el.tap()
        sel.move_caret_to_front()
        sel.move_caret_by_offset(offset)
        x, y = sel.caret_location()

        return x, y

    def rect_relative_to_window(self, el):
        '''Get element's bounding rectangle.

        This function is similar to el.rect, but the coordinate is relative to
        the top left corner of the window instead of the document.

        '''
        return self.marionette.execute_script('''
            let rect = arguments[0].getBoundingClientRect();
            return {x: rect.x, y:rect.y, width: rect.width, height: rect.height};
            ''', script_args=[el])

    def long_press_on_location(self, el, x=None, y=None):
        '''Long press the location (x, y) to select a word.

        If no (x, y) are given, it will be targeted at the center of the
        element. On Windows, those spaces after the word will also be selected.
        This function sends synthesized eMouseLongTap to gecko.

        '''
        rect = self.rect_relative_to_window(el)
        target_x = rect['x'] + (x if x is not None else rect['width'] // 2)
        target_y = rect['y'] + (y if y is not None else rect['height'] // 2)

        self.marionette.execute_script('''
            let Ci = Components.interfaces;
            let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIDOMWindowUtils);
            utils.sendTouchEventToWindow('touchstart', [0],
                                         [arguments[0]], [arguments[1]],
                                         [1], [1], [0], [1], 1, 0);
            utils.sendMouseEventToWindow('mouselongtap', arguments[0], arguments[1],
                                          0, 1, 0);
            utils.sendTouchEventToWindow('touchend', [0],
                                         [arguments[0]], [arguments[1]],
                                         [1], [1], [0], [1], 1, 0);
            ''', script_args=[target_x, target_y], sandbox='system')

    def long_press_on_word(self, el, wordOrdinal):
        x, y = self.word_location(el, wordOrdinal)
        self.long_press_on_location(el, x, y)

    def to_unix_line_ending(self, s):
        """Changes all Windows/Mac line endings in s to UNIX line endings."""

        return s.replace('\r\n', '\n').replace('\r', '\n')

    def _test_long_press_to_select_a_word(self, el, assertFunc):
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(len(words) >= 2, 'Expect at least two words in the content.')
        target_content = words[0]

        # Goal: Select the first word.
        self.long_press_on_word(el, 0)

        # Ignore extra spaces selected after the word.
        assertFunc(target_content, sel.selected_content)

    def _test_move_selection_carets(self, el, assertFunc):
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(len(words) >= 1, 'Expect at least one word in the content.')

        # Goal: Select all text after the first word.
        target_content = original_content[len(words[0]):]

        # Get the location of the selection carets at the end of the content for
        # later use.
        el.tap()
        sel.select_all()
        (_, _), (end_caret_x, end_caret_y) = sel.selection_carets_location()

        self.long_press_on_word(el, 0)

        # Move the right caret to the end of the content.
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
        self.actions.flick(el, caret2_x, caret2_y, end_caret_x, end_caret_y).perform()

        # Move the left caret to the previous position of the right caret.
        self.actions.flick(el, caret1_x, caret1_y, caret2_x, caret2_y).perform()

        assertFunc(target_content, sel.selected_content)

    def _test_minimum_select_one_character(self, el, assertFunc,
                                           x=None, y=None):
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(len(words) >= 1, 'Expect at least one word in the content.')

        # Get the location of the selection carets at the end of the content for
        # later use.
        sel.select_all()
        (_, _), (end_caret_x, end_caret_y) = sel.selection_carets_location()
        el.tap()

        # Goal: Select the first character.
        target_content = original_content[0]

        if x and y:
            # If we got x and y from the arguments, use it as a hint of the
            # location of the first word
            pass
        else:
            x, y = self.word_location(el, 0)
        self.long_press_on_location(el, x, y)

        # Move the right caret to the end of the content.
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
        self.actions.flick(el, caret2_x, caret2_y, end_caret_x, end_caret_y).perform()

        # Move the right caret to the position of the left caret.
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
        self.actions.flick(el, caret2_x, caret2_y, caret1_x, caret1_y).perform()

        assertFunc(target_content, sel.selected_content)

    def _test_focus_obtained_by_long_press(self, el1, el2):
        '''Test the focus could be changed from el1 to el2 by long press.

        If the focus is changed to e2 successfully, SelectionCarets should
        appear and could be dragged.

        '''
        # Goal: Tap to focus el1, and then select the first character on
        # el2.

        # We want to collect the location of the first word in el2 here
        # since self.word_location() has the side effect which would
        # change the focus.
        x, y = self.word_location(el2, 0)
        el1.tap()
        self._test_minimum_select_one_character(el2, self.assertEqual,
                                                x=x, y=y)

    def _test_focus_not_being_changed_by_long_press_on_non_selectable(self, el):
        # Goal: Focus remains on the editable element el after long pressing on
        # the non-selectable element.
        sel = SelectionManager(el)
        self.long_press_on_word(el, 0)
        self.long_press_on_location(self._non_selectable)
        active_sel = SelectionManager(self.marionette.get_active_element())
        self.assertEqual(sel.content, active_sel.content)

    def _test_handle_tilt_when_carets_overlap_to_each_other(self, el, assertFunc):
        '''Test tilt handling when carets overlap to each other.

        Let SelectionCarets overlap to each other. If SelectionCarets are set
        to tilted successfully, tapping the tilted carets should not cause the
        selection to be collapsed and the carets should be draggable.
        '''

        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(len(words) >= 1, 'Expect at least one word in the content.')

        # Goal: Select the first word.
        self.long_press_on_word(el, 0)
        target_content = sel.selected_content

        # Move the left caret to the position of the right caret to trigger
        # carets overlapping.
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
        self.actions.flick(el, caret1_x, caret1_y, caret2_x, caret2_y).perform()

        # We make two hit tests targeting the left edge of the left tilted caret
        # and the right edge of the right tilted caret. If either of the hits is
        # missed, selection would be collapsed and both carets should not be
        # draggable.
        (caret3_x, caret3_y), (caret4_x, caret4_y) = sel.selection_carets_location()

        # The following values are from ua.css and all.js
        if self.carets_tested_pref == 'selectioncaret.enabled':
            caret_width = 44
            caret_margin_left = -23
            tilt_right_margin_left = 18
            tilt_left_margin_left = -17
        elif self.carets_tested_pref == 'layout.accessiblecaret.enabled':
            caret_width = float(self.marionette.get_pref('layout.accessiblecaret.width'))
            caret_margin_left = float(self.marionette.get_pref('layout.accessiblecaret.margin-left'))
            tilt_right_margin_left = 0.41 * caret_width;
            tilt_left_margin_left = -0.39 * caret_width;

        left_caret_left_edge_x = caret3_x + caret_margin_left + tilt_left_margin_left
        el.tap(left_caret_left_edge_x + 2, caret3_y)

        right_caret_right_edge_x = (caret4_x + caret_margin_left +
                                    tilt_right_margin_left + caret_width)
        el.tap(right_caret_right_edge_x - 2, caret4_y)

        # Drag the left caret back to the initial selection, the first word.
        self.actions.flick(el, caret3_x, caret3_y, caret1_x, caret1_y).perform()

        assertFunc(target_content, sel.selected_content)

    def test_long_press_to_select_non_selectable_word(self):
        '''Testing long press on non selectable field.
        We should not select anything when long press on non selectable fields.'''

        self.open_test_html_multirange()
        halfY = self._nonsel1.size['height'] / 2
        self.long_press_on_location(self._nonsel1, 0, halfY)
        sel = SelectionManager(self._nonsel1)
        range_count = sel.range_count()
        self.assertEqual(range_count, 0)

    def test_drag_caret_over_non_selectable_field(self):
        '''Testing drag caret over non selectable field.
        So that the selected content should exclude non selectable field and
        end selection caret should appear in last range's position.'''
        self.open_test_html_multirange()

        # Select target element and get target caret location
        self.long_press_on_word(self._sel4, 3)
        sel = SelectionManager(self._body)
        (_, _), (end_caret_x, end_caret_y) = sel.selection_carets_location()

        self.long_press_on_word(self._sel6, 0)
        (_, _), (end_caret2_x, end_caret2_y) = sel.selection_carets_location()

        # Select start element
        self.long_press_on_word(self._sel3, 3)

        # Drag end caret to target location
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
        self.actions.flick(self._body, caret2_x, caret2_y, end_caret_x, end_caret_y, 1).perform()
        self.assertEqual(self.to_unix_line_ending(sel.selected_content.strip()),
                         'this 3\nuser can select this')

        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
        self.actions.flick(self._body, caret2_x, caret2_y, end_caret2_x, end_caret2_y, 1).perform()
        self.assertEqual(self.to_unix_line_ending(sel.selected_content.strip()),
                         'this 3\nuser can select this 4\nuser can select this 5\nuser')

        # Drag first caret to target location
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
        self.actions.flick(self._body, caret1_x, caret1_y, end_caret_x, end_caret_y, 1).perform()
        self.assertEqual(self.to_unix_line_ending(sel.selected_content.strip()),
                         '4\nuser can select this 5\nuser')

    def test_drag_caret_to_beginning_of_a_line(self):
        '''Bug 1094056
        Test caret visibility when caret is dragged to beginning of a line
        '''
        self.open_test_html_multirange()

        # Select the first word in the second line
        self.long_press_on_word(self._sel2, 0)
        sel = SelectionManager(self._body)
        (start_caret_x, start_caret_y), (end_caret_x, end_caret_y) = sel.selection_carets_location()

        # Select target word in the first line
        self.long_press_on_word(self._sel1, 2)

        # Drag end caret to the beginning of the second line
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
        self.actions.flick(self._body, caret2_x, caret2_y, start_caret_x, start_caret_y).perform()

        # Drag end caret back to the target word
        self.actions.flick(self._body, start_caret_x, start_caret_y, caret2_x, caret2_y).perform()

        self.assertEqual(self.to_unix_line_ending(sel.selected_content), 'select')

    @skip_if_not_rotatable
    def test_caret_position_after_changing_orientation_of_device(self):
        '''Bug 1094072
        If positions of carets are updated correctly, they should be draggable.
        '''
        self.open_test_html_long_text()

        # Select word in portrait mode, then change to landscape mode
        self.marionette.set_orientation('portrait')
        self.long_press_on_word(self._longtext, 12)
        sel = SelectionManager(self._body)
        (p_start_caret_x, p_start_caret_y), (p_end_caret_x, p_end_caret_y) = sel.selection_carets_location()
        self.marionette.set_orientation('landscape')
        (l_start_caret_x, l_start_caret_y), (l_end_caret_x, l_end_caret_y) = sel.selection_carets_location()

        # Drag end caret to the start caret to change the selected content
        self.actions.flick(self._body, l_end_caret_x, l_end_caret_y, l_start_caret_x, l_start_caret_y).perform()

        # Change orientation back to portrait mode to prevent affecting
        # other tests
        self.marionette.set_orientation('portrait')

        self.assertEqual(self.to_unix_line_ending(sel.selected_content), 'o')

    def test_select_word_inside_an_iframe(self):
        '''Bug 1088552
        The scroll offset in iframe should be taken into consideration properly.
        In this test, we scroll content in the iframe to the bottom to cause a
        huge offset. If we use the right coordinate system, selection should
        work. Otherwise, it would be hard to trigger select word.
        '''
        self.open_test_html_iframe()

        # switch to inner iframe and scroll to the bottom
        self.marionette.switch_to_frame(self._iframe)
        self.marionette.execute_script(
            'document.getElementById("bd").scrollTop += 999')

        # long press to select bottom text
        self._body = self.marionette.find_element(By.ID, 'bd')
        sel = SelectionManager(self._body)
        self._bottomtext = self.marionette.find_element(By.ID, 'bottomtext')
        self.long_press_on_location(self._bottomtext)

        self.assertNotEqual(self.to_unix_line_ending(sel.selected_content), '')

    ########################################################################
    # <input> test cases with selection carets enabled
    ########################################################################
    def test_input_long_press_to_select_a_word(self):
        self.open_test_html()
        self._test_long_press_to_select_a_word(self._input, self.assertEqual)

    def test_input_move_selection_carets(self):
        self.open_test_html()
        self._test_move_selection_carets(self._input, self.assertEqual)

    def test_input_minimum_select_one_character(self):
        self.open_test_html()
        self._test_minimum_select_one_character(self._input, self.assertEqual)

    def test_input_focus_obtained_by_long_press_from_textarea(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._textarea, self._input)

    def test_input_focus_obtained_by_long_press_from_contenteditable(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._contenteditable, self._input)

    def test_input_focus_obtained_by_long_press_from_content_non_editable(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._content, self._input)

    def test_input_handle_tilt_when_carets_overlap_to_each_other(self):
        self.open_test_html()
        self._test_handle_tilt_when_carets_overlap_to_each_other(self._input, self.assertEqual)

    def test_input_focus_not_changed_by_long_press_on_non_selectable(self):
        self.open_test_html()
        self._test_focus_not_being_changed_by_long_press_on_non_selectable(self._input)

    ########################################################################
    # <input> test cases with selection carets disabled
    ########################################################################
    def test_input_long_press_to_select_a_word_disabled(self):
        with self.marionette.using_prefs({self.carets_tested_pref: False}):
            self.open_test_html()
            self._test_long_press_to_select_a_word(self._input, self.assertNotEqual)

    def test_input_move_selection_carets_disabled(self):
        with self.marionette.using_prefs({self.carets_tested_pref: False}):
            self.open_test_html()
            self._test_move_selection_carets(self._input, self.assertNotEqual)

    ########################################################################
    # <textarea> test cases with selection carets enabled
    ########################################################################
    def test_textarea_long_press_to_select_a_word(self):
        self.open_test_html()
        self._test_long_press_to_select_a_word(self._textarea, self.assertEqual)

    def test_textarea_move_selection_carets(self):
        self.open_test_html()
        self._test_move_selection_carets(self._textarea, self.assertEqual)

    def test_textarea_minimum_select_one_character(self):
        self.open_test_html()
        self._test_minimum_select_one_character(self._textarea, self.assertEqual)

    def test_textarea_focus_obtained_by_long_press_from_input(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._input, self._textarea)

    def test_textarea_focus_obtained_by_long_press_from_contenteditable(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._contenteditable, self._textarea)

    def test_textarea_focus_obtained_by_long_press_from_content_non_editable(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._content, self._textarea)

    def test_textarea_handle_tilt_when_carets_overlap_to_each_other(self):
        self.open_test_html()
        self._test_handle_tilt_when_carets_overlap_to_each_other(self._textarea, self.assertEqual)

    def test_textarea_focus_not_changed_by_long_press_on_non_selectable(self):
        self.open_test_html()
        self._test_focus_not_being_changed_by_long_press_on_non_selectable(self._textarea)

    ########################################################################
    # <textarea> test cases with selection carets disabled
    ########################################################################
    def test_textarea_long_press_to_select_a_word_disabled(self):
        with self.marionette.using_prefs({self.carets_tested_pref: False}):
            self.open_test_html()
            self._test_long_press_to_select_a_word(self._textarea, self.assertNotEqual)

    def test_textarea_move_selection_carets_disable(self):
        with self.marionette.using_prefs({self.carets_tested_pref: False}):
            self.open_test_html()
            self._test_move_selection_carets(self._textarea, self.assertNotEqual)

    ########################################################################
    # <textarea> right-to-left test cases with selection carets enabled
    ########################################################################
    def test_textarea_rtl_long_press_to_select_a_word(self):
        self.open_test_html()
        self._test_long_press_to_select_a_word(self._textarea_rtl, self.assertEqual)

    def test_textarea_rtl_move_selection_carets(self):
        self.open_test_html()
        self._test_move_selection_carets(self._textarea_rtl, self.assertEqual)

    def test_textarea_rtl_minimum_select_one_character(self):
        self.open_test_html()
        self._test_minimum_select_one_character(self._textarea_rtl, self.assertEqual)

    def test_textarea_rtl_focus_not_changed_by_long_press_on_non_selectable(self):
        self.open_test_html()
        self._test_focus_not_being_changed_by_long_press_on_non_selectable(self._textarea_rtl)

    ########################################################################
    # <textarea> right-to-left test cases with selection carets disabled
    ########################################################################
    def test_textarea_rtl_long_press_to_select_a_word_disabled(self):
        with self.marionette.using_prefs({self.carets_tested_pref: False}):
            self.open_test_html()
            self._test_long_press_to_select_a_word(self._textarea_rtl, self.assertNotEqual)

    def test_textarea_rtl_move_selection_carets_disabled(self):
        with self.marionette.using_prefs({self.carets_tested_pref: False}):
            self.open_test_html()
            self._test_move_selection_carets(self._textarea_rtl, self.assertNotEqual)

    ########################################################################
    # <div> contenteditable test cases with selection carets enabled
    ########################################################################
    def test_contenteditable_long_press_to_select_a_word(self):
        self.open_test_html()
        self._test_long_press_to_select_a_word(self._contenteditable, self.assertEqual)

    def test_contenteditable_move_selection_carets(self):
        self.open_test_html()
        self._test_move_selection_carets(self._contenteditable, self.assertEqual)

    def test_contenteditable_minimum_select_one_character(self):
        self.open_test_html()
        self._test_minimum_select_one_character(self._contenteditable, self.assertEqual)

    def test_contenteditable_focus_obtained_by_long_press_from_input(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._input, self._contenteditable)

    def test_contenteditable_focus_obtained_by_long_press_from_textarea(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._textarea, self._contenteditable)

    def test_contenteditable_focus_obtained_by_long_press_from_content_non_editable(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._content, self._contenteditable)

    def test_contenteditable_handle_tilt_when_carets_overlap_to_each_other(self):
        self.open_test_html()
        self._test_handle_tilt_when_carets_overlap_to_each_other(self._contenteditable, self.assertEqual)

    def test_contenteditable_focus_not_changed_by_long_press_on_non_selectable(self):
        self.open_test_html()
        self._test_focus_not_being_changed_by_long_press_on_non_selectable(self._contenteditable)

    ########################################################################
    # <div> contenteditable test cases with selection carets disabled
    ########################################################################
    def test_contenteditable_long_press_to_select_a_word_disabled(self):
        with self.marionette.using_prefs({self.carets_tested_pref: False}):
            self.open_test_html()
            self._test_long_press_to_select_a_word(self._contenteditable, self.assertNotEqual)

    def test_contenteditable_move_selection_carets_disabled(self):
        with self.marionette.using_prefs({self.carets_tested_pref: False}):
            self.open_test_html()
            self._test_move_selection_carets(self._contenteditable, self.assertNotEqual)

    ########################################################################
    # <div> non-editable test cases with selection carets enabled
    ########################################################################
    def test_content_non_editable_long_press_to_select_a_word(self):
        self.open_test_html()
        self._test_long_press_to_select_a_word(self._content, self.assertEqual)

    def test_content_non_editable_move_selection_carets(self):
        self.open_test_html()
        self._test_move_selection_carets(self._content, self.assertEqual)

    def test_content_non_editable_minimum_select_one_character_by_selection(self):
        self.open_test_html()
        self._test_minimum_select_one_character(self._content, self.assertEqual)

    def test_content_non_editable_focus_obtained_by_long_press_from_input(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._input, self._content)

    def test_content_non_editable_focus_obtained_by_long_press_from_textarea(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._textarea, self._content)

    def test_content_non_editable_focus_obtained_by_long_press_from_contenteditable(self):
        self.open_test_html()
        self._test_focus_obtained_by_long_press(self._contenteditable, self._content)

    def test_content_non_editable_handle_tilt_when_carets_overlap_to_each_other(self):
        self.open_test_html()
        self._test_handle_tilt_when_carets_overlap_to_each_other(self._content, self.assertEqual)

    ########################################################################
    # <textarea> (multi-lines) test cases with selection carets enabled
    ########################################################################
    def test_textarea2_minimum_select_one_character(self):
        self.open_test_html2()
        self._test_minimum_select_one_character(self._textarea2, self.assertEqual)

    ########################################################################
    # <div> contenteditable2 (multi-lines) test cases with selection carets enabled
    ########################################################################
    def test_contenteditable2_minimum_select_one_character(self):
        self.open_test_html2()
        self._test_minimum_select_one_character(self._contenteditable2, self.assertEqual)

    ########################################################################
    # <div> non-editable2 (multi-lines) test cases with selection carets enabled
    ########################################################################
    def test_content_non_editable2_minimum_select_one_character(self):
        self.open_test_html2()
        self._test_minimum_select_one_character(self._content2, self.assertEqual)
Example #49
0
class TestKeyActions(WindowManagerMixin, MarionetteTestCase):
    def setUp(self):
        super(TestKeyActions, self).setUp()
        if self.marionette.session_capabilities["platformName"] == "darwin":
            self.mod_key = Keys.META
        else:
            self.mod_key = Keys.CONTROL
        test_html = self.marionette.absolute_url("keyboard.html")
        self.marionette.navigate(test_html)
        self.reporter_element = self.marionette.find_element(
            By.ID, "keyReporter")
        self.reporter_element.click()
        self.key_action = Actions(self.marionette)

    @property
    def key_reporter_value(self):
        return self.reporter_element.get_property("value")

    def test_key_action_basic_input(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")

    def test_upcase_input(self):
        (self.key_action.key_down(Keys.SHIFT).key_down("a").key_up(
            Keys.SHIFT).key_down("b").key_down("c").perform())
        self.assertEqual(self.key_reporter_value, "Abc")

    def test_replace_input(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")
        (self.key_action.key_down(self.mod_key).key_down("a").key_up(
            self.mod_key).key_down("x").perform())
        self.assertEqual(self.key_reporter_value, "x")

    def test_clear_input(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")
        (self.key_action.key_down(
            self.mod_key).key_down("a").key_down("x").perform())
        self.assertEqual(self.key_reporter_value, "")
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        self.assertEqual(self.key_reporter_value, "abc")

    def test_input_with_wait(self):
        self.key_action.key_down("a").key_down("b").key_down("c").perform()
        (self.key_action.key_down(
            self.mod_key).key_down("a").wait(.5).key_down("x").perform())
        self.assertEqual(self.key_reporter_value, "")

    @skip_if_mobile("Interacting with chrome windows not available for Fennec")
    def test_open_in_new_window_shortcut(self):
        def open_window_with_action():
            el = self.marionette.find_element(By.TAG_NAME, "a")
            (self.key_action.key_down(Keys.SHIFT).press(el).release().key_up(
                Keys.SHIFT).perform())

        self.marionette.navigate(inline("<a href='#'>Click</a>"))
        new_window = self.open_window(trigger=open_window_with_action)

        self.marionette.switch_to_window(new_window)
        self.marionette.close_chrome_window()

        self.marionette.switch_to_window(self.start_window)
class TestMouseAction(MarionetteTestCase):

    def setUp(self):
        MarionetteTestCase.setUp(self)
        if self.marionette.session_capabilities['platformName'] == 'DARWIN':
            self.mod_key = Keys.META
        else:
            self.mod_key = Keys.CONTROL
        self.action = Actions(self.marionette)

    def test_click_action(self):
        test_html = self.marionette.absolute_url("test.html")
        self.marionette.navigate(test_html)
        link = self.marionette.find_element(By.ID, "mozLink")
        self.action.click(link).perform()
        self.assertEqual("Clicked", self.marionette.execute_script("return document.getElementById('mozLink').innerHTML;"))

    def test_clicking_element_out_of_view_succeeds(self):
        # The action based click doesn't check for visibility.
        test_html = self.marionette.absolute_url('hidden.html')
        self.marionette.navigate(test_html)
        el = self.marionette.find_element(By.ID, 'child')
        self.action.click(el).perform()

    def test_double_click_action(self):
        test_html = self.marionette.absolute_url("javascriptPage.html")
        self.marionette.navigate(test_html)
        el = self.marionette.find_element(By.ID, 'displayed')
        # The first click just brings the element into view so text selection
        # works as expected. (A different test page could be used to isolate
        # this element and make sure it's always in view)
        el.click()
        self.action.double_click(el).perform()
        el.send_keys(self.mod_key + 'c')
        rel = self.marionette.find_element("id", "keyReporter")
        rel.send_keys(self.mod_key + 'v')
        self.assertEqual(rel.get_attribute('value'), 'Displayed')

    def test_context_click_action(self):
        test_html = self.marionette.absolute_url("javascriptPage.html")
        self.marionette.navigate(test_html)
        click_el = self.marionette.find_element(By.ID, 'resultContainer')

        def context_menu_state():
            with self.marionette.using_context('chrome'):
                cm_el = self.marionette.find_element(By.ID, 'contentAreaContextMenu')
                return cm_el.get_attribute('state')

        self.assertEqual('closed', context_menu_state())
        self.action.context_click(click_el).perform()
        self.wait_for_condition(lambda _: context_menu_state() == 'open')

        with self.marionette.using_context('chrome'):
            (self.marionette.find_element(By.ID, 'main-window')
                            .send_keys(Keys.ESCAPE))
        self.wait_for_condition(lambda _: context_menu_state() == 'closed')

    def test_middle_click_action(self):
        test_html = self.marionette.absolute_url("clicks.html")
        self.marionette.navigate(test_html)

        self.marionette.find_element(By.ID, "addbuttonlistener").click()

        el = self.marionette.find_element(By.ID, "showbutton")
        self.action.middle_click(el).perform()

        self.wait_for_condition(
            lambda _: el.get_attribute('innerHTML') == '1')

    def test_chrome_click(self):
        self.marionette.navigate("about:blank")
        data_uri = "data:text/html,<html></html>"
        with self.marionette.using_context('chrome'):
            urlbar = self.marionette.find_element(By.ID, "urlbar")
            urlbar.send_keys(data_uri)
            go_button = self.marionette.find_element(By.ID, "urlbar-go-button")
            self.action.click(go_button).perform()
        self.wait_for_condition(lambda mn: mn.get_url() == data_uri)

    def test_chrome_double_click(self):
        self.marionette.navigate("about:blank")
        test_word = "quux"
        with self.marionette.using_context('chrome'):
            urlbar = self.marionette.find_element(By.ID, "urlbar")
            self.assertEqual(urlbar.get_attribute('value'), '')

            urlbar.send_keys(test_word)
            self.assertEqual(urlbar.get_attribute('value'), test_word)
            (self.action.double_click(urlbar).perform()
                        .key_down(self.mod_key)
                        .key_down('x').perform())
            self.assertEqual(urlbar.get_attribute('value'), '')

    def test_chrome_context_click_action(self):
        self.marionette.set_context('chrome')
        def context_menu_state():
            cm_el = self.marionette.find_element(By.ID, 'tabContextMenu')
            return cm_el.get_attribute('state')

        currtab = self.marionette.execute_script("return gBrowser.selectedTab")
        self.assertEqual('closed', context_menu_state())
        self.action.context_click(currtab).perform()
        self.wait_for_condition(lambda _: context_menu_state() == 'open')

        (self.marionette.find_element(By.ID, 'main-window')
                        .send_keys(Keys.ESCAPE))

        self.wait_for_condition(lambda _: context_menu_state() == 'closed')
Example #51
0
 def clear_phone_number(self):
     delete_button = self.marionette.find_element(
         *self._keypad_delete_locator)
     Actions(self.marionette).long_press(delete_button, 1).perform()
Example #52
0
 def __init__(self, parent):
     self.parent = parent
     self.marionette = parent.marionette
     self.actions = Actions(self.marionette)
class CommonCaretTestCase(object):
    '''Common test cases for a collapsed selection with a single caret.

    To run these test cases, a subclass must inherit from both this class and
    MarionetteTestCase.

    '''
    def setUp(self):
        # Code to execute before a test is being run.
        super(CommonCaretTestCase, self).setUp()
        self.actions = Actions(self.marionette)

    def timeout_ms(self):
        'Return touch caret expiration time in milliseconds.'
        return self.marionette.get_pref(self.caret_timeout_ms_pref)

    def open_test_html(self):
        'Open html for testing and locate elements.'
        test_html = self.marionette.absolute_url('test_touchcaret.html')
        self.marionette.navigate(test_html)

        self._input = self.marionette.find_element(By.ID, 'input')
        self._textarea = self.marionette.find_element(By.ID, 'textarea')
        self._contenteditable = self.marionette.find_element(
            By.ID, 'contenteditable')

    def _test_move_caret_to_the_right_by_one_character(self, el, assertFunc):
        sel = SelectionManager(el)
        content_to_add = '!'
        target_content = sel.content
        target_content = target_content[:1] + content_to_add + target_content[
            1:]

        # Get touch caret (x, y) at position 1 and 2.
        el.tap()
        sel.move_caret_to_front()
        caret0_x, caret0_y = sel.caret_location()
        touch_caret0_x, touch_caret0_y = sel.touch_caret_location()
        sel.move_caret_by_offset(1)
        touch_caret1_x, touch_caret1_y = sel.touch_caret_location()

        # Tap the front of the input to make touch caret appear.
        el.tap(caret0_x, caret0_y)

        # Move touch caret
        self.actions.flick(el, touch_caret0_x, touch_caret0_y, touch_caret1_x,
                           touch_caret1_y).perform()

        self.actions.key_down(content_to_add).key_up(content_to_add).perform()
        assertFunc(target_content, sel.content)

    def _test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(
            self, el, assertFunc):
        sel = SelectionManager(el)
        content_to_add = '!'
        target_content = sel.content + content_to_add

        # Tap the front of the input to make touch caret appear.
        el.tap()
        sel.move_caret_to_front()
        el.tap(*sel.caret_location())

        # Move touch caret to the bottom-right corner of the element.
        src_x, src_y = sel.touch_caret_location()
        dest_x, dest_y = el.size['width'], el.size['height']
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        self.actions.key_down(content_to_add).key_up(content_to_add).perform()
        assertFunc(target_content, sel.content)

    def _test_move_caret_to_front_by_dragging_touch_caret_to_front_of_content(
            self, el, assertFunc):
        sel = SelectionManager(el)
        content_to_add = '!'
        target_content = content_to_add + sel.content

        # Get touch caret location at the front.
        el.tap()
        sel.move_caret_to_front()
        dest_x, dest_y = sel.touch_caret_location()

        # Tap to make touch caret appear. Note: it's strange that when the caret
        # is at the end, the rect of the caret in <textarea> cannot be obtained.
        # A bug perhaps.
        el.tap()
        sel.move_caret_to_end()
        sel.move_caret_by_offset(1, backward=True)
        el.tap(*sel.caret_location())
        src_x, src_y = sel.touch_caret_location()

        # Move touch caret to the front of the input box.
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        self.actions.key_down(content_to_add).key_up(content_to_add).perform()
        assertFunc(target_content, sel.content)

    def _test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(
            self, el, assertFunc):
        sel = SelectionManager(el)
        content_to_add = '!'
        non_target_content = content_to_add + sel.content

        # Get touch caret expiration time in millisecond, and convert it to second.
        timeout = self.timeout_ms() / 1000.0

        # Set a 3x timeout margin to prevent intermittent test failures.
        timeout *= 3

        # Tap to make touch caret appear. Note: it's strange that when the caret
        # is at the end, the rect of the caret in <textarea> cannot be obtained.
        # A bug perhaps.
        el.tap()
        sel.move_caret_to_end()
        sel.move_caret_by_offset(1, backward=True)
        el.tap(*sel.caret_location())

        # Wait until touch caret disappears, then pretend to move it to the
        # top-left corner of the input box.
        src_x, src_y = sel.touch_caret_location()
        dest_x, dest_y = 0, 0
        self.actions.wait(timeout).flick(el, src_x, src_y, dest_x,
                                         dest_y).perform()

        self.actions.key_down(content_to_add).key_up(content_to_add).perform()
        assertFunc(non_target_content, sel.content)

    def _test_touch_caret_hides_after_receiving_wheel_event(
            self, el, assertFunc):
        sel = SelectionManager(el)
        content_to_add = '!'
        non_target_content = content_to_add + sel.content

        # Tap to make touch caret appear. Note: it's strange that when the caret
        # is at the end, the rect of the caret in <textarea> cannot be obtained.
        # A bug perhaps.
        el.tap()
        sel.move_caret_to_end()
        sel.move_caret_by_offset(1, backward=True)
        el.tap(*sel.caret_location())

        # Send an arbitrary scroll-down-10px wheel event to the center of the
        # input box to hide touch caret. Then pretend to move it to the top-left
        # corner of the input box.
        src_x, src_y = sel.touch_caret_location()
        dest_x, dest_y = 0, 0
        el_center_x, el_center_y = el.rect['x'], el.rect['y']
        self.marionette.execute_script('''
            var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                              .getInterface(Components.interfaces.nsIDOMWindowUtils);
            utils.sendWheelEvent(arguments[0], arguments[1],
                                 0, 10, 0, WheelEvent.DOM_DELTA_PIXEL,
                                 0, 0, 0, 0);
            ''',
                                       script_args=[el_center_x, el_center_y],
                                       sandbox='system')
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        self.actions.key_down(content_to_add).key_up(content_to_add).perform()
        assertFunc(non_target_content, sel.content)

    def _test_caret_not_appear_when_typing_in_scrollable_content(
            self, el, assertFunc):
        sel = SelectionManager(el)

        content_to_add = '!'
        target_content = sel.content + string.ascii_letters + content_to_add

        el.tap()
        sel.move_caret_to_end()

        # Insert a long string to the end of the <input>, which triggers
        # ScrollPositionChanged event.
        el.send_keys(string.ascii_letters)

        # The caret should not be visible. If it does appear wrongly due to the
        # ScrollPositionChanged event, we can drag it to the front of the
        # <input> to change the cursor position.
        src_x, src_y = sel.touch_caret_location()
        dest_x, dest_y = 0, 0
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        # The content should be inserted at the end of the <input>.
        el.send_keys(content_to_add)

        assertFunc(target_content, sel.content)

    ########################################################################
    # <input> test cases with touch caret enabled
    ########################################################################
    def test_input_move_caret_to_the_right_by_one_character(self):
        self.open_test_html()
        self._test_move_caret_to_the_right_by_one_character(
            self._input, self.assertEqual)

    def test_input_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(
            self):
        self.open_test_html()
        self._test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(
            self._input, self.assertEqual)

    def test_input_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(
            self):
        self.open_test_html()
        self._test_move_caret_to_front_by_dragging_touch_caret_to_front_of_content(
            self._input, self.assertEqual)

    def test_input_caret_not_appear_when_typing_in_scrollable_content(self):
        self.open_test_html()
        self._test_caret_not_appear_when_typing_in_scrollable_content(
            self._input, self.assertEqual)

    def test_input_touch_caret_timeout(self):
        with self.marionette.using_prefs({self.caret_timeout_ms_pref: 1000}):
            self.open_test_html()
            self._test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(
                self._input, self.assertNotEqual)

    ########################################################################
    # <input> test cases with touch caret disabled
    ########################################################################
    def test_input_move_caret_to_the_right_by_one_character_disabled(self):
        with self.marionette.using_prefs({self.caret_tested_pref: False}):
            self.open_test_html()
            self._test_move_caret_to_the_right_by_one_character(
                self._input, self.assertNotEqual)

    def test_input_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner_disabled(
            self):
        with self.marionette.using_prefs({self.caret_tested_pref: False}):
            self.open_test_html()
            self._test_move_caret_to_front_by_dragging_touch_caret_to_front_of_content(
                self._input, self.assertNotEqual)

    ########################################################################
    # <textarea> test cases with touch caret enabled
    ########################################################################
    def test_textarea_move_caret_to_the_right_by_one_character(self):
        self.open_test_html()
        self._test_move_caret_to_the_right_by_one_character(
            self._textarea, self.assertEqual)

    def test_textarea_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(
            self):
        self.open_test_html()
        self._test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(
            self._textarea, self.assertEqual)

    def test_textarea_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(
            self):
        self.open_test_html()
        self._test_move_caret_to_front_by_dragging_touch_caret_to_front_of_content(
            self._textarea, self.assertEqual)

    def test_textarea_touch_caret_timeout(self):
        with self.marionette.using_prefs({self.caret_timeout_ms_pref: 1000}):
            self.open_test_html()
            self._test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(
                self._textarea, self.assertNotEqual)

    ########################################################################
    # <textarea> test cases with touch caret disabled
    ########################################################################
    def test_textarea_move_caret_to_the_right_by_one_character_disabled(self):
        with self.marionette.using_prefs({self.caret_tested_pref: False}):
            self.open_test_html()
            self._test_move_caret_to_the_right_by_one_character(
                self._textarea, self.assertNotEqual)

    def test_textarea_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner_disabled(
            self):
        with self.marionette.using_prefs({self.caret_tested_pref: False}):
            self.open_test_html()
            self._test_move_caret_to_front_by_dragging_touch_caret_to_front_of_content(
                self._textarea, self.assertNotEqual)

    ########################################################################
    # <div> contenteditable test cases with touch caret enabled
    ########################################################################
    def test_contenteditable_move_caret_to_the_right_by_one_character(self):
        self.open_test_html()
        self._test_move_caret_to_the_right_by_one_character(
            self._contenteditable, self.assertEqual)

    def test_contenteditable_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(
            self):
        self.open_test_html()
        self._test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(
            self._contenteditable, self.assertEqual)

    def test_contenteditable_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(
            self):
        self.open_test_html()
        self._test_move_caret_to_front_by_dragging_touch_caret_to_front_of_content(
            self._contenteditable, self.assertEqual)

    def test_contenteditable_touch_caret_timeout(self):
        with self.marionette.using_prefs({self.caret_timeout_ms_pref: 1000}):
            self.open_test_html()
            self._test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(
                self._contenteditable, self.assertNotEqual)

    ########################################################################
    # <div> contenteditable test cases with touch caret disabled
    ########################################################################
    def test_contenteditable_move_caret_to_the_right_by_one_character_disabled(
            self):
        with self.marionette.using_prefs({self.caret_tested_pref: False}):
            self.open_test_html()
            self._test_move_caret_to_the_right_by_one_character(
                self._contenteditable, self.assertNotEqual)

    def test_contenteditable_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner_disabled(
            self):
        with self.marionette.using_prefs({self.caret_tested_pref: False}):
            self.open_test_html()
            self._test_move_caret_to_front_by_dragging_touch_caret_to_front_of_content(
                self._contenteditable, self.assertNotEqual)
 def setUp(self):
     # Code to execute before a test is being run.
     super(CommonCaretTestCase, self).setUp()
     self.actions = Actions(self.marionette)
Example #55
0
class TouchCaretTest(MarionetteTestCase):
    _input_selector = (By.ID, 'input')
    _textarea_selector = (By.ID, 'textarea')
    _contenteditable_selector = (By.ID, 'contenteditable')
    _large_expiration_time = 3000 * 20  # 60 seconds

    def setUp(self):
        # Code to execute before a test is being run.
        MarionetteTestCase.setUp(self)
        self.actions = Actions(self.marionette)
        self.original_expiration_time = self.expiration_time

    def tearDown(self):
        # Code to execute after a test is being run.
        self.expiration_time = self.original_expiration_time
        MarionetteTestCase.tearDown(self)

    @property
    def expiration_time(self):
        'Return touch caret expiration time in milliseconds.'
        return self.marionette.execute_script(
            'return SpecialPowers.getIntPref("touchcaret.expiration.time");')

    @expiration_time.setter
    def expiration_time(self, expiration_time):
        'Set touch caret expiration time in milliseconds.'
        self.marionette.execute_script(
            'SpecialPowers.setIntPref("touchcaret.expiration.time", arguments[0]);',
            script_args=[expiration_time])

    def openTestHtml(self, enabled=True, expiration_time=None):
        '''Open html for testing and locate elements, enable/disable touch caret, and
        set touch caret expiration time in milliseconds).

        '''
        self.marionette.execute_async_script(
            'SpecialPowers.pushPrefEnv({"set": [["touchcaret.enabled", %s]]}, marionetteScriptFinished);' %
            ('true' if enabled else 'false'))

        # Set a larger expiration time to avoid intermittent test failures.
        if expiration_time is not None:
            self.expiration_time = expiration_time

        test_html = self.marionette.absolute_url('test_touchcaret.html')
        self.marionette.navigate(test_html)

        self._input = self.marionette.find_element(*self._input_selector)
        self._textarea = self.marionette.find_element(*self._textarea_selector)
        self._contenteditable = self.marionette.find_element(*self._contenteditable_selector)

    def _test_move_caret_to_the_right_by_one_character(self, el, assertFunc):
        sel = SelectionManager(el)
        content_to_add = '!'
        target_content = sel.content
        target_content = target_content[:1] + content_to_add + target_content[1:]

        # Get touch caret (x, y) at position 1 and 2.
        el.tap()
        sel.move_caret_to_front()
        caret0_x, caret0_y = sel.caret_location()
        touch_caret0_x, touch_caret0_y = sel.touch_caret_location()
        sel.move_caret_by_offset(1)
        touch_caret1_x, touch_caret1_y = sel.touch_caret_location()

        # Tap the front of the input to make touch caret appear.
        el.tap(caret0_x, caret0_y)

        # Move touch caret
        self.actions.flick(el, touch_caret0_x, touch_caret0_y,
                           touch_caret1_x, touch_caret1_y).perform()

        el.send_keys(content_to_add)
        assertFunc(target_content, sel.content)

    def _test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self, el, assertFunc):
        sel = SelectionManager(el)
        content_to_add = '!'
        target_content = sel.content + content_to_add

        # Tap the front of the input to make touch caret appear.
        el.tap()
        sel.move_caret_to_front()
        el.tap(*sel.caret_location())

        # Move touch caret to the bottom-right corner of the element.
        src_x, src_y = sel.touch_caret_location()
        dest_x, dest_y = el.size['width'], el.size['height']
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        el.send_keys(content_to_add)
        assertFunc(target_content, sel.content)

    def _test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self, el, assertFunc):
        sel = SelectionManager(el)
        content_to_add = '!'
        target_content = content_to_add + sel.content

        # Tap to make touch caret appear. Note: it's strange that when the caret
        # is at the end, the rect of the caret in <textarea> cannot be obtained.
        # A bug perhaps.
        el.tap()
        sel.move_caret_to_end()
        sel.move_caret_by_offset(1, backward=True)
        el.tap(*sel.caret_location())

        # Move touch caret to the top-left corner of the input box.
        src_x, src_y = sel.touch_caret_location()
        dest_x, dest_y = 0, 0
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        el.send_keys(content_to_add)
        assertFunc(target_content, sel.content)

    def _test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(self, el, assertFunc):
        sel = SelectionManager(el)
        content_to_add = '!'
        non_target_content = content_to_add + sel.content

        # Get touch caret expiration time in millisecond, and convert it to second.
        timeout = self.expiration_time / 1000.0

        # Tap to make touch caret appear. Note: it's strange that when the caret
        # is at the end, the rect of the caret in <textarea> cannot be obtained.
        # A bug perhaps.
        el.tap()
        sel.move_caret_to_end()
        sel.move_caret_by_offset(1, backward=True)
        el.tap(*sel.caret_location())

        # Wait until touch caret disappears, then pretend to move it to the
        # top-left corner of the input box.
        src_x, src_y = sel.touch_caret_location()
        dest_x, dest_y = 0, 0
        self.actions.wait(timeout).flick(el, src_x, src_y, dest_x, dest_y).perform()

        el.send_keys(content_to_add)
        assertFunc(non_target_content, sel.content)

    def _test_touch_caret_hides_after_receiving_wheel_event(self, el, assertFunc):
        sel = SelectionManager(el)
        content_to_add = '!'
        non_target_content = content_to_add + sel.content

        # Tap to make touch caret appear. Note: it's strange that when the caret
        # is at the end, the rect of the caret in <textarea> cannot be obtained.
        # A bug perhaps.
        el.tap()
        sel.move_caret_to_end()
        sel.move_caret_by_offset(1, backward=True)
        el.tap(*sel.caret_location())

        # Send an arbitrary scroll-down-10px wheel event to the center of the
        # input box to hide touch caret. Then pretend to move it to the top-left
        # corner of the input box.
        src_x, src_y = sel.touch_caret_location()
        dest_x, dest_y = 0, 0
        el_center_x, el_center_y = el.rect['x'], el.rect['y']
        self.marionette.execute_script(
            '''var utils = SpecialPowers.getDOMWindowUtils(window);
            utils.sendWheelEvent(arguments[0], arguments[1],
                                 0, 10, 0, WheelEvent.DOM_DELTA_PIXEL,
                                 0, 0, 0, 0);''',
            script_args=[el_center_x, el_center_y]
        )
        self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()

        el.send_keys(content_to_add)
        assertFunc(non_target_content, sel.content)


    ########################################################################
    # <input> test cases with touch caret enabled
    ########################################################################
    def test_input_move_caret_to_the_right_by_one_character(self):
        self.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
        self._test_move_caret_to_the_right_by_one_character(self._input, self.assertEqual)

    def test_input_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self):
        self.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
        self._test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self._input, self.assertEqual)

    def test_input_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self):
        self.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._input, self.assertEqual)

    def test_input_touch_caret_timeout(self):
        self.openTestHtml(enabled=True)
        self._test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(self._input, self.assertNotEqual)

    def test_input_touch_caret_hides_after_receiving_wheel_event(self):
        self.openTestHtml(enabled=True, expiration_time=0)
        self._test_touch_caret_hides_after_receiving_wheel_event(self._input, self.assertNotEqual)

    ########################################################################
    # <input> test cases with touch caret disabled
    ########################################################################
    def test_input_move_caret_to_the_right_by_one_character_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_move_caret_to_the_right_by_one_character(self._input, self.assertNotEqual)

    def test_input_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._input, self.assertNotEqual)

    ########################################################################
    # <textarea> test cases with touch caret enabled
    ########################################################################
    def test_textarea_move_caret_to_the_right_by_one_character(self):
        self.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
        self._test_move_caret_to_the_right_by_one_character(self._textarea, self.assertEqual)

    def test_textarea_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self):
        self.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
        self._test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self._textarea, self.assertEqual)

    def test_textarea_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self):
        self.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._textarea, self.assertEqual)

    def test_textarea_touch_caret_timeout(self):
        self.openTestHtml(enabled=True)
        self._test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(self._textarea, self.assertNotEqual)

    def test_textarea_touch_caret_hides_after_receiving_wheel_event(self):
        self.openTestHtml(enabled=True, expiration_time=0)
        self._test_touch_caret_hides_after_receiving_wheel_event(self._textarea, self.assertNotEqual)

    ########################################################################
    # <textarea> test cases with touch caret disabled
    ########################################################################
    def test_textarea_move_caret_to_the_right_by_one_character_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_move_caret_to_the_right_by_one_character(self._textarea, self.assertNotEqual)

    def test_textarea_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._textarea, self.assertNotEqual)

    ########################################################################
    # <div> contenteditable test cases with touch caret enabled
    ########################################################################
    def test_contenteditable_move_caret_to_the_right_by_one_character(self):
        self.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
        self._test_move_caret_to_the_right_by_one_character(self._contenteditable, self.assertEqual)

    def test_contenteditable_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self):
        self.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
        self._test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self._contenteditable, self.assertEqual)

    def test_contenteditable_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self):
        self.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._contenteditable, self.assertEqual)

    def test_contenteditable_touch_caret_timeout(self):
        self.openTestHtml(enabled=True)
        self._test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(self._contenteditable, self.assertNotEqual)

    def test_contenteditable_touch_caret_hides_after_receiving_wheel_event(self):
        self.openTestHtml(enabled=True, expiration_time=0)
        self._test_touch_caret_hides_after_receiving_wheel_event(self._contenteditable, self.assertNotEqual)

    ########################################################################
    # <div> contenteditable test cases with touch caret disabled
    ########################################################################
    def test_contenteditable_move_caret_to_the_right_by_one_character_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_move_caret_to_the_right_by_one_character(self._contenteditable, self.assertNotEqual)

    def test_contenteditable_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner_disabled(self):
        self.openTestHtml(enabled=False)
        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._contenteditable, self.assertNotEqual)
class SelectionCaretsMultipleRangeTest(MarionetteTestCase):
    _long_press_time = 1        # 1 second

    def setUp(self):
        # Code to execute before a tests are run.
        MarionetteTestCase.setUp(self)
        self.actions = Actions(self.marionette)

    def openTestHtml(self, enabled=True):
        # Open html for testing and enable selectioncaret and
        # non-editable support
        self.marionette.execute_script(
            'SpecialPowers.setBoolPref("selectioncaret.enabled", %s);' %
            ('true' if enabled else 'false'))
        self.marionette.execute_script(
            'SpecialPowers.setBoolPref("selectioncaret.noneditable", %s);' %
            ('true' if enabled else 'false'))

        test_html = self.marionette.absolute_url('test_selectioncarets_multiplerange.html')
        self.marionette.navigate(test_html)

        self._body = self.marionette.find_element(By.ID, 'bd')
        self._sel1 = self.marionette.find_element(By.ID, 'sel1')
        self._sel2 = self.marionette.find_element(By.ID, 'sel2')
        self._sel3 = self.marionette.find_element(By.ID, 'sel3')
        self._sel4 = self.marionette.find_element(By.ID, 'sel4')
        self._sel6 = self.marionette.find_element(By.ID, 'sel6')
        self._nonsel1 = self.marionette.find_element(By.ID, 'nonsel1')

    def _long_press_to_select_word(self, el, wordOrdinal):
        sel = SelectionManager(el)
        original_content = sel.content
        words = original_content.split()
        self.assertTrue(wordOrdinal < len(words),
            'Expect at least %d words in the content.' % wordOrdinal)

        # Calc offset
        offset = 0
        for i in range(wordOrdinal):
            offset += (len(words[i]) + 1)

        # Move caret inside the word.
        el.tap()
        sel.move_caret_to_front()
        sel.move_caret_by_offset(offset)
        x, y = sel.caret_location()

        # Long press the caret position. Selection carets should appear, and the
        # word will be selected. On Windows, those spaces after the word
        # will also be selected.
        long_press_without_contextmenu(self.marionette, el, self._long_press_time, x, y)

    def _to_unix_line_ending(self, s):
        """Changes all Windows/Mac line endings in s to UNIX line endings."""

        return s.replace('\r\n', '\n').replace('\r', '\n')

    def test_long_press_to_select_non_selectable_word(self):
        '''Testing long press on non selectable field.
        We should not select anything when long press on non selectable fields.'''

        self.openTestHtml(enabled=True)
        halfY = self._nonsel1.size['height'] / 2
        long_press_without_contextmenu(self.marionette, self._nonsel1, self._long_press_time, 0, halfY)
        sel = SelectionManager(self._nonsel1)
        range_count = sel.range_count()
        self.assertEqual(range_count, 0)

    def test_drag_caret_over_non_selectable_field(self):
        '''Testing drag caret over non selectable field.
        So that the selected content should exclude non selectable field and
        end selection caret should appear in last range's position.'''
        self.openTestHtml(enabled=True)

        # Select target element and get target caret location
        self._long_press_to_select_word(self._sel4, 3)
        sel = SelectionManager(self._body)
        (_, _), (end_caret_x, end_caret_y) = sel.selection_carets_location()

        self._long_press_to_select_word(self._sel6, 0)
        (_, _), (end_caret2_x, end_caret2_y) = sel.selection_carets_location()

        # Select start element
        self._long_press_to_select_word(self._sel3, 3)

        # Drag end caret to target location
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
        self.actions.flick(self._body, caret2_x, caret2_y, end_caret_x, end_caret_y, 1).perform()
        self.assertEqual(self._to_unix_line_ending(sel.selected_content.strip()),
            'this 3\nuser can select this')

        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
        self.actions.flick(self._body, caret2_x, caret2_y, end_caret2_x, end_caret2_y, 1).perform()
        self.assertEqual(self._to_unix_line_ending(sel.selected_content.strip()),
            'this 3\nuser can select this 4\nuser can select this 5\nuser')

    def test_drag_caret_to_beginning_of_a_line(self):
        '''Bug 1094056
        Test caret visibility when caret is dragged to beginning of a line
        '''
        self.openTestHtml(enabled=True)

        # Select the first word in the second line
        self._long_press_to_select_word(self._sel2, 0)
        sel = SelectionManager(self._body)
        (start_caret_x, start_caret_y), (end_caret_x, end_caret_y) = sel.selection_carets_location()

        # Select target word in the first line
        self._long_press_to_select_word(self._sel1, 2)

        # Drag end caret to the beginning of the second line
        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
        self.actions.flick(self._body, caret2_x, caret2_y, start_caret_x, start_caret_y).perform()

        # Drag end caret back to the target word
        self.actions.flick(self._body, start_caret_x, start_caret_y, caret2_x, caret2_y).perform()

        self.assertEqual(self._to_unix_line_ending(sel.selected_content.strip()), 'select')
Example #57
0
 def setUp(self):
     # Code to execute before a test is being run.
     MarionetteTestCase.setUp(self)
     self.actions = Actions(self.marionette)
     self.original_expiration_time = self.expiration_time
Example #58
0
class Gallery(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.UTILS.element.waitForNotElements(DOM.Gallery.loading_bar,
                                              "Loading bar", True, 10)
        return self.app

    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
        @param  int expected_duration   specifies the video duration in seconds
        """

        # Play the video and get total duration
        self.play_current_video()
        video_length = self.UTILS.element.getElement(
            DOM.Gallery.preview_current_video_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 click_on_thumbnail_at_position(self, position, preview=True):
        """
        Clicks on a thumbnail at a certain position from the gallery.
        @param  boolean     preview     specifies whether we have to check for the preview screen or not
        """
        self.parent.wait_for_element_displayed(*DOM.Gallery.thumbnail_items)
        thumb_list = self.marionette.find_elements(
            *DOM.Gallery.thumbnail_items)
        time.sleep(1)
        thumb = thumb_list[position]
        thumb.tap()

        self.UTILS.element.waitForNotElements(DOM.Gallery.thumbnail_items,
                                              "Thumbnail list", True, 10)
        if preview:
            self.UTILS.element.waitForElements(DOM.Gallery.preview,
                                               "Thumbnail preview", True, 10)

    def _click_on_thumb_external(self, position, frame_to_change):
        """
        Private method which handles image selection and image cropping
        @param  int     position            thumbnail to click
        @param  tuple   frame_to_change     frame to switch once the image has been cropped
        """
        time.sleep(1)
        self.click_on_thumbnail_at_position(position, preview=False)

        time.sleep(2)

        crop = self.UTILS.element.getElement(DOM.Gallery.crop_done,
                                             "Crop Done")
        crop.tap()

        self.UTILS.iframe.switchToFrame(*frame_to_change)

    def click_on_thumbnail_at_position_mms(self, position):
        """
        Clicks a thumbnail from the gallery in order to attach it to a MMS
        """
        self._click_on_thumb_external(position, DOM.Messages.frame_locator)

    def click_on_thumbnail_at_position_email(self, position):
        """
        Clicks a thumbnail from the gallery in order to attach it to an email
        """
        self._click_on_thumb_external(position, DOM.Email.frame_locator)

    def delete_thumbnails(self, num_array):
        """
        Deletes the thumbnails listed in num_array
        (following an index starting at number 0)
        The list must be numeric, i.e "delete_thumbnails([0,1,2])".
        """

        # Get the amount of thumbnails we currently have.
        before_thumbcount = self.get_number_of_thumbnails()
        delete_thumbcount = len(num_array)
        target_thumbcount = before_thumbcount - delete_thumbcount

        select_mode_btn = self.UTILS.element.getElement(
            DOM.Gallery.thumbnail_select_mode, "Select button")
        select_mode_btn.tap()

        # Select the target ones
        thumbs = self.UTILS.element.getElements(DOM.Gallery.thumbnail_items,
                                                "Thumbnails")
        for position in num_array:
            thumbs[position].tap()

        selected = self.UTILS.element.getElement(
            DOM.Gallery.thumbnail_number_selected, "Number selected header")
        self.UTILS.test.test(
            str(delete_thumbcount) in selected.text,
            "Right number of thumbs selected")

        trash_btn = self.UTILS.element.getElement(
            DOM.Gallery.thumbnail_trash_icon, "Trash icon")
        trash_btn.tap()

        confirm = self.UTILS.element.getElement(DOM.GLOBAL.modal_confirm_ok,
                                                "Delete")
        confirm.tap()

        if target_thumbcount < 1:
            self.UTILS.element.waitForElements(
                DOM.Gallery.no_thumbnails_message,
                "Message saying there are no thumbnails", False, 5)
        else:
            # Come out of 'select' mode.
            exit_select_mode_header = self.UTILS.element.getElement(
                DOM.Gallery.exit_select_mode_header, "Exit select mode button")
            exit_select_mode_header.tap(25, 25)

            current_thumbs = self.get_number_of_thumbnails()
            self.UTILS.test.test(current_thumbs == target_thumbcount,
                                 "After deleting [{}] pics, we have the expected number: {}".\
                                 format(delete_thumbcount, target_thumbcount))

    def get_gallery_items(self):
        """
        Returns a list of gallery item objects, with RAW info (date, metadata, size...)
        """
        self.UTILS.element.waitForElements(DOM.Gallery.thumbnail_items,
                                           "Thumbnails", True, 20, False)
        return self.marionette.execute_script(
            "return window.wrappedJSObject.files;")

    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.Gallery.preview_current_video_play, "Video play button")
        time.sleep(1)
        play_btn.tap()

        self.UTILS.element.waitForElements(
            DOM.Gallery.preview_current_video_pause, "Pause button", True, 20,
            False)

    def get_number_of_thumbnails(self):
        """
        Returns the number of thumbnails.
        """
        try:
            self.parent.wait_for_element_displayed(
                *DOM.Gallery.thumbnail_items)
            return len(
                self.marionette.find_elements(*DOM.Gallery.thumbnail_items))
        except:
            return 0

    def wait_for_thumbnails_number(self, number, timeout=10):
        """
        Waits untils @number thumbnails are present in the thumbnails screen
        """
        msg = "Waiting until we have the expected number of thumbnails"
        self.parent.wait_for_condition(lambda m: len(
            m.find_elements(*DOM.Gallery.thumbnail_items)) == number,
                                       timeout=timeout,
                                       message=msg)

    def swipe_between_gallery_items(self, steps):
        """
        Swipes over the gallery items (the preview screen must be displayed) a certain number of steps
        Important: there is no way of checking that the image is being shown each time we swipe,
        """
        current_frame = self.apps.displayed_app.frame
        x_start = current_frame.size['width']
        x_end = x_start // 4
        y_start = current_frame.size['height'] // 2

        for i in range(steps):
            self.actions.flick(current_frame,
                               x_start,
                               y_start,
                               x_end,
                               y_start,
                               duration=600).perform()
            time.sleep(1)
Example #59
0
class Calendar(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")
        return self.app

    def moveDayViewBy(self, num):
        """
        Switches to week view, then moves 'p_num' weeks in the future or past (if the p_num is
        positive or negative) relative to today.
        """
        self.UTILS.reporting.logResult(
            "info", "<b>Adjusting day view by {} screens ...</b>".format(num))
        self.setView("day")
        self.setView("today")

        if num == 0:
            return
        """
        Set the y-coordinate offset, depending on which
        direction we need to flick the display.
        """
        numMoves = num
        if numMoves > 0:
            _moveEl = 1
        else:
            _moveEl = 2
            numMoves = numMoves * -1

        # Now move to the desired screen.
        for i in range(numMoves):
            # Flick the screen to move it (tricky to find the element we can flick!).
            _el = self.marionette.find_elements(*DOM.Calendar.dview_events)

            _num = 0
            for i in range(len(_el)):
                if _el[i].is_displayed():
                    _num = i
                    break

            x_pos1 = 0
            x_pos2 = 0
            if _moveEl == 1:
                x_pos1 = _el[_num].size["width"]
            if _moveEl == 2:
                x_pos2 = _el[_num].size["width"]
            self.actions.flick(_el[_num], x_pos1, 0, x_pos2, 0).perform()

        time.sleep(0.3)

        # Check this is the expected day.
        _new_epoch = int(time.time()) + (num * 24 * 60 * 60)
        _new_now = self.UTILS.date_and_time.getDateTimeFromEpochSecs(
            _new_epoch)
        _expected_str = "{} {}, {}".format(_new_now.month_name[:3],
                                           _new_now.mday, _new_now.day_name)

        x = self.UTILS.element.getElement(DOM.Calendar.current_view_header,
                                          "Current view header")
        self.UTILS.test.test(
            x.text == _expected_str,
            "Header is '<b>%s</b>' (it was '%s')." % (_expected_str, x.text))

        x = self.UTILS.debug.screenShotOnErr()
        self.UTILS.reporting.logResult(
            "info", "Day view screen after moving {} pages: ".format(num), x)

    def getEventPreview(self, p_view, p_hour24, p_title, p_location=False):
        """
        Return object for an event in month / week or day view.
        The tag identifiers aren't consistent, so set them here.
        <type>: (<event preview identifier>, <event title identifier>)
        """
        event_view = {
            "month": (DOM.Calendar.view_events_block_m % p_hour24,
                      DOM.Calendar.view_events_title_month),
            "week": (DOM.Calendar.view_events_block_w % p_hour24,
                     DOM.Calendar.view_events_title_week),
            "day": (DOM.Calendar.view_events_block_d % p_hour24,
                    DOM.Calendar.view_events_title_day)
        }

        viewStr = event_view[p_view]
        """
        Switch to the desired view.
        For the life of me I can't get 'wait_for_element' ... to work in day view, so I'm
        just waiting a few seconds then checking with .is_displayed() instead.
        """
        self.setView(p_view)
        time.sleep(2)

        # Start by getting the parent element objects, which could contain event details.
        event_objects = self.UTILS.element.getElements(
            ('xpath', viewStr[0]), "'" + p_view + "' event details list",
            False, 20, False)
        if not event_objects:
            return False

        if len(event_objects) <= 0:
            return False

        for event_object in event_objects:
            if p_title in event_object.text:
                return event_object

        # If we get to here we failed to return the element we're after.
        return False

    def createEvent(self):
        x = self.UTILS.element.getElement(DOM.Calendar.add_event_btn,
                                          "Add event button")
        x.tap()

        title = ("xpath", "//input[@name='title']")
        where = ("xpath", "//input[@name='location']")
        # allday checkbox, True False (use tap())
        allday = ("xpath", "//li[@class='allday']")

        x = self.UTILS.element.getElement(title, "Title", True, 10)
        x.send_keys("hello title")

        x = self.UTILS.element.getElement(where, "Where")
        x.send_keys("hello where")

        x = self.UTILS.element.getElement(allday, "All day")
        x.tap()

        self.marionette.execute_script(
            "document.getElementById('start-date-locale').click()")

    def changeDay(self, numDays, viewType):
        """
        Changes the calendar day to a different day relative to 'today' - <b>uses the
        month view to do this, then switches back to whichever
        view you want (month, week, day)</b>.<br>
        <b>numDays</b> is a number (can be negative to go back, i.e. -5,-2,1,3,5 etc...).<br>
        <b>viewType</b> is the calendar view to return to (today / day / week / month)<br>
        Returns a modified DateTime object from <i>UTILS.getDateTimeFromEpochSecs()</i>.
        """
        self.setView("month")
        self.setView("today")

        now_secs = time.time()
        now_diff = int(now_secs) + (86400 * numDays)
        now_today = self.UTILS.date_and_time.getDateTimeFromEpochSecs(now_secs)
        new_today = self.UTILS.date_and_time.getDateTimeFromEpochSecs(now_diff)

        # Switch to month view and tap this day, then switch back to our view.
        if now_today.mon != new_today.mon:
            x = new_today.mon - now_today.mon
            self.moveMonthViewBy(x)

        el_id_str = "d-%s-%s-%s" % (new_today.year, new_today.mon - 1,
                                    new_today.mday)
        x = self.UTILS.element.getElement(
            ("xpath", "//li[@data-date='{}']".format(el_id_str)),
            "Cell for day {}/{}/{}".format(new_today.mday, new_today.mon,
                                           new_today.year))
        x.tap()
        self.setView(viewType.lower())
        return new_today

    def moveMonthViewBy(self, num):
        """
        Switches to month view, then moves 'num' months in the future or past (if the num is
        positive or negative) relative to today.
        """
        self.UTILS.reporting.logResult(
            "info", "<b>Adjusting month view by {} months ...</b>".format(num))
        self.setView("month")
        self.setView("today")

        if num == 0:
            return
        """
        Set the y-coordinate offset, depending on which
        direction we need to flick the display.
        """
        numMoves = num
        x2 = 0
        if numMoves > 0:
            el_num = -1
            x2 = -500
        if numMoves < 0:
            el_num = 0
            x2 = 500
            numMoves = numMoves * -1

        now = time.localtime(int(time.time()))
        month = now.tm_mon
        year = now.tm_year

        for i in range(numMoves):
            # Flick the display to show the date we're aiming for.
            el = self.marionette.find_elements(
                *DOM.Calendar.mview_first_row_for_flick)[el_num]
            self.actions.flick(el, 0, 0, x2, 0).perform()

            # Increment the month and year so we keep track of what's expected.
            if num < 0:
                month = month - 1
            else:
                month = month + 1

            if month <= 0:
                month = 12
                year = year - 1
            elif month >= 13:
                month = 1
                year = year + 1

        time.sleep(0.3)

        # Work out what the header should now be.
        month_names = [
            "January", "February", "March", "April", "May", "June", "July",
            "August", "September", "October", "November", "December"
        ]

        expect = "{} {}".format(month_names[month - 1], year)
        actual = self.UTILS.element.getElement(
            DOM.Calendar.current_view_header, "Header").text

        self.UTILS.test.test(
            expect.lower() in actual.lower(),
            "Expecting header to contain '{}' (received '{}')".format(
                expect, actual))

    def moveWeekViewBy(self, num):
        """
        Switches to week view, then moves 'num' weeks in the future or past (if the num is
        positive or negative) relative to today.
        """
        self.UTILS.reporting.logResult(
            "info", "<b>Adjusting week view by {} screens ...</b>".format(num))
        self.setView("week")
        self.setView("today")

        if num == 0:
            return
        """
        Set the y-coordinate offset, depending on which
        direction we need to flick the display.
        """
        numMoves = num
        x2 = 0
        if numMoves > 0:
            el = -1
            x2 = -500
        if numMoves < 0:
            el = 0
            x2 = 500
            numMoves = numMoves * -1
        """
        Keep track of how many days we're adjusting the display by (so we can check
        we're looking at the correct display at the end).
        """
        days_offset = 0
        now_epoch = int(time.time())
        now = self.UTILS.date_and_time.getDateTimeFromEpochSecs(now_epoch)
        now_str = "{} {}".format(now.day_name[:3].upper(), now.mday)

        displayed_days = self.UTILS.element.getElements(
            DOM.Calendar.wview_active_days, "Active days")
        startpos = 0
        for i in range(len(displayed_days)):
            x = displayed_days[i].text
            if x:
                if now_str in x:
                    startpos = i - 1
                    break

        if num < 0:
            days_offset = startpos
        else:
            days_offset = len(displayed_days) - startpos - 2

        # Now move to the desired screen.
        for i in range(numMoves):

            # Flick the screen to move it.
            self.actions.flick(displayed_days[el], 0, 0, x2, 0).perform()

            # Get the count of days we're adjusting (so we can check later).
            displayed_days = self.UTILS.element.getElements(
                DOM.Calendar.wview_active_days, "Active days")
            days_offset = days_offset + len(displayed_days)

        time.sleep(0.3)
        """
        Work out what the display should now be:
        1. Today + days_offset should be displayed.
        2. Header should be month + year, now + days_offset should be in active days.
        """
        if num < 0:
            new_epoch = now_epoch - (days_offset * 24 * 60 * 60)
        else:
            new_epoch = now_epoch + (days_offset * 24 * 60 * 60)

        new_now = self.UTILS.date_and_time.getDateTimeFromEpochSecs(new_epoch)

        new_now_str = "{} {}".format(new_now.day_name[:3].upper(),
                                     new_now.mday)

        x = self.UTILS.element.getElements(DOM.Calendar.wview_active_days,
                                           "Active days")
        boolOK = False
        for i in range(len(x)):
            x = displayed_days[i].text
            if x:
                if new_now_str in x:
                    boolOK = True
                    break

        self.UTILS.test.test(
            boolOK,
            "The column for date '<b>{}</b>' displayed.".format(new_now_str))

        x = self.UTILS.element.getElement(DOM.Calendar.current_view_header,
                                          "Current view header")
        self.UTILS.test.test(
            new_now.month_name in x.text,
            "'<b>{}</b>' is in header ('{}').".format(new_now.month_name,
                                                      x.text))
        self.UTILS.test.test(
            str(new_now.year) in x.text,
            "'<b>{}</b>' is in header ('{}').".format(new_now.year, x.text))

        x = self.UTILS.debug.screenShotOnErr()
        self.UTILS.reporting.logResult(
            "info", "Week view screen after moving {} pages: ".format(num), x)

    def setView(self, typ):
        """
        Set to view typ (today / day / week / month).
        """
        x = self.UTILS.element.getElement(
            (DOM.Calendar.view_type[0],
             DOM.Calendar.view_type[1] % typ.lower()),
            "'" + typ + "' view type selector")
        x.tap()

        if typ.lower() != 'today':
            viewTypes = {
                "month": DOM.Calendar.mview_container,
                "week": DOM.Calendar.wview_container,
                "day": DOM.Calendar.dview_container
            }

            self.UTILS.element.waitForElements(
                viewTypes[typ], "Container for '{}' view".format(typ))
        else:
            time.sleep(0.5)
def cnet(client):
    global dl_dir_abs
    url = 'http://download.cnet.com/'
    elementExists = True
    try:
        client.navigate(url)
    except timeout as texp:
        log.info("ignoring timeout: %s" % str(texp))
        pass
    element = client.find_element(By.ID, 'pop')
    elementList = element.find_elements(By.TAG_NAME, 'a')
    if (len(elementList) == 0):
        log.critical('no links found! cnet() function broken?')
        return Status.CRIT, None

    # remove blacklisted downloads
    # added self-link ("most-popular") to blacklist
    whiteList = [
        i for i in elementList
        if not any(b in i.get_attribute('href') for b in blacklist_dls)
    ]
    log.info("dls: %s" % str([i.get_attribute('href') for i in whiteList]))
    # select at random
    element = choice(whiteList)
    nextUrl = element.get_attribute('href')
    # random delay
    sleep(randint(1, 5))
    # open next page in dl process
    if nextUrl.startswith('/'): nextUrl = url + nextUrl
    try:
        client.navigate(nextUrl)
    except timeout as texp:
        log.info("ignoring timeout: %s" % str(texp))
        pass

    # random delay
    sleep(randint(1, 5))
    # click on donwload button
    element = client.find_element(By.CSS_SELECTOR, 'a.dln-a')
    finalUrl = None
    try:
        finalUrl = element.get_attribute('data-href')
    except errors.MarionetteException:
        log.warn('error on finalUrl.')
        return Status.NODL, None
    if finalUrl is None:
        log.warn('no finalUrl.')
        return Status.NODL, None
    action = Actions(client)
    action.click(element)
    assert (dl_dir_abs is not None)
    file_list = os.listdir(dl_dir_abs)
    log.info("files: %s" % str(file_list))
    action.perform()
    # wait until dl finishes
    fn = wait_for_dl_to_finish(dl_dir_abs, file_list, nextUrl, client)
    # hash downloaded file
    log.info('-----------------------')
    if fn is not None:
        tordl_hash = sha256sum(fn)
        log.info("file %s downloaded successfully from %s, hash: %s" %
                 (fn, finalUrl, sha256sum(fn)))
    else:
        return Status.NODL, None

    # dl same file over normal internet
    r = requests.get(finalUrl)
    soup = BeautifulSoup.BeautifulSoup(r.text)
    result = soup.find("meta", attrs={"http-equiv": "refresh"})
    dl_url = None
    if result:
        wait, text = result["content"].split(";")
        sleep(int(wait))
        dl_url = '='.join(text.split('=')[1:]).strip()
        if dl_url.startswith('/'): dl_url = url + dl_url
    else:
        dl_url = finalUrl
    log.info("file url %s" % dl_url)
    r = requests.get(dl_url)
    fo = open('test.exe', 'wb')
    fo.write(r.content)
    fo.close()
    # hash clearnet-downloaded file
    orig_hash = sha256sum('test.exe')
    if orig_hash == tordl_hash:
        return Status.IDENTICAL, fn
    else:
        return Status.NONIDENT, fn