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()
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. ''' _input_selector = (By.ID, 'input') _textarea_selector = (By.ID, 'textarea') _contenteditable_selector = (By.ID, 'contenteditable') 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 def set_pref(self, pref_name, value): '''Set a preference to value. For example: >>> set_pref('layout.accessiblecaret.enabled', True) ''' pref_name = repr(pref_name) if isinstance(value, bool): value = 'true' if value else 'false' func = 'setBoolPref' elif isinstance(value, int): value = str(value) func = 'setIntPref' else: value = repr(value) func = 'setCharPref' with self.marionette.using_context('chrome'): script = 'Services.prefs.%s(%s, %s)' % (func, pref_name, value) self.marionette.execute_script(script) def timeout_ms(self): 'Return touch caret expiration time in milliseconds.' with self.marionette.using_context('chrome'): return self.marionette.execute_script( 'return Services.prefs.getIntPref("%s");' % self.caret_timeout_ms_pref) def open_test_html(self, enabled=True, timeout_ms=0): '''Open html for testing and locate elements, enable/disable touch caret, and set touch caret expiration time in milliseconds). ''' self.set_pref(self.caret_tested_pref, enabled) self.set_pref(self.caret_disabled_pref, False) self.set_pref(self.caret_timeout_ms_pref, timeout_ms) 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() 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): self.open_test_html(timeout_ms=1000) 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): self.open_test_html(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.open_test_html(enabled=False) 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): self.open_test_html(timeout_ms=1000) 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): self.open_test_html(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.open_test_html(enabled=False) 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): self.open_test_html(timeout_ms=1000) 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): self.open_test_html(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.open_test_html(enabled=False) self._test_move_caret_to_front_by_dragging_touch_caret_to_front_of_content( self._contenteditable, self.assertNotEqual)
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 )
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, "") @skip_if_b2g 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, "")
class TestKeyActions(WindowManagerMixin, MarionetteTestCase): def setUp(self): super(TestKeyActions, self).setUp() if self.marionette.session_capabilities["platformName"] == "mac": 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, "")
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("id", "keyReporter") self.reporter_element.click() self.key_action = Actions(self.marionette) @property def key_reporter_value(self): return self.reporter_element.get_attribute('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_b2g def test_open_in_new_window_shortcut(self): el = self.marionette.find_element('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, "")
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 = '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.caret_timeout_ms_pref = 'layout.accessiblecaret.timeout_ms' self.hide_carets_for_mouse = 'layout.accessiblecaret.hide_carets_for_mouse_input' self.prefs = { self.caret_tested_pref: True, self.caret_timeout_ms_pref: 0, 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.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() 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) @parameterized(_input_id, el_id=_input_id) @parameterized(_textarea_id, el_id=_textarea_id) @parameterized(_contenteditable_id, el_id=_contenteditable_id) def test_dragging_caret_to_top_left_corner_after_timeout(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 # Set caret timeout to be 1 second. timeout = 1 self.marionette.set_pref(self.caret_timeout_ms_pref, timeout * 1000) # Set a 3x timeout margin to prevent intermittent test failures. timeout *= 3 # 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()) # Wait until first caret disappears, then pretend to move it to the # top-left corner of the input box. src_x, src_y = sel.first_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() self.assertNotEqual(non_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 = '!' target_content = sel.content + string.ascii_letters + content_to_add 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 be inserted at the end of the <input>. el.send_keys(content_to_add) self.assertEqual(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('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.size['width'], el.size['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)
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, "") 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, "")
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 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 = '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.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() 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('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.size['width'], el.size['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)
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): start_win = self.marionette.current_chrome_window_handle 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()) 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, "")
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, "")
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 AccessibleCaretCursorModeTestCase(MarionetteTestCase): '''Test cases for AccessibleCaret under cursor mode, aka touch caret. ''' def setUp(self): # Code to execute before a test is being run. 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) 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 test_caret_does_not_jump_when_dragging_to_editable_content_boundary(self): self.open_test_html() el = self._input sel = SelectionManager(el) content_to_add = '!' non_target_content = sel.content + content_to_add # Goal: the cursor position does not being changed after dragging the # caret down on the Y-axis. el.tap() sel.move_caret_to_front() el.tap(*sel.caret_location()) x, y = sel.touch_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)
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. ''' _input_selector = (By.ID, 'input') _textarea_selector = (By.ID, 'textarea') _contenteditable_selector = (By.ID, 'contenteditable') 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 def set_pref(self, pref_name, value): '''Set a preference to value. For example: >>> set_pref('layout.accessiblecaret.enabled', True) ''' pref_name = repr(pref_name) if isinstance(value, bool): value = 'true' if value else 'false' func = 'setBoolPref' elif isinstance(value, int): value = str(value) func = 'setIntPref' else: value = repr(value) func = 'setCharPref' with self.marionette.using_context('chrome'): script = 'Services.prefs.%s(%s, %s)' % (func, pref_name, value) self.marionette.execute_script(script) def timeout_ms(self): 'Return touch caret expiration time in milliseconds.' with self.marionette.using_context('chrome'): return self.marionette.execute_script( 'return Services.prefs.getIntPref("%s");' % self.caret_timeout_ms_pref) def open_test_html(self, enabled=True, timeout_ms=0): '''Open html for testing and locate elements, enable/disable touch caret, and set touch caret expiration time in milliseconds). ''' self.set_pref(self.caret_tested_pref, enabled) self.set_pref(self.caret_disabled_pref, False) self.set_pref(self.caret_timeout_ms_pref, timeout_ms) 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() 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): self.open_test_html(timeout_ms=1000) 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): self.open_test_html(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.open_test_html(enabled=False) 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): self.open_test_html(timeout_ms=1000) 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): self.open_test_html(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.open_test_html(enabled=False) 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): self.open_test_html(timeout_ms=1000) 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): self.open_test_html(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.open_test_html(enabled=False) self._test_move_caret_to_front_by_dragging_touch_caret_to_front_of_content(self._contenteditable, self.assertNotEqual)
class AccessibleCaretCursorModeTestCase(MarionetteTestCase): '''Test cases for AccessibleCaret under cursor mode, aka touch caret. ''' def setUp(self): # Code to execute before a test is being run. 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) 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 test_caret_does_not_jump_when_dragging_to_editable_content_boundary( self): self.open_test_html() el = self._input sel = SelectionManager(el) content_to_add = '!' non_target_content = sel.content + content_to_add # Goal: the cursor position does not being changed after dragging the # caret down on the Y-axis. el.tap() sel.move_caret_to_front() el.tap(*sel.caret_location()) x, y = sel.touch_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)