test_accessiblecaret_cursor_mode.py (11659B)
1 # -*- coding: utf-8 -*- 2 # This Source Code Form is subject to the terms of the Mozilla Public 3 # License, v. 2.0. If a copy of the MPL was not distributed with this 4 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 6 import string 7 import sys 8 import os 9 10 # Add this directory to the import path. 11 sys.path.append(os.path.dirname(__file__)) 12 13 from selection import ( 14 CaretActions, 15 SelectionManager, 16 ) 17 from marionette_driver.by import By 18 from marionette_harness.marionette_test import ( 19 MarionetteTestCase, 20 parameterized, 21 ) 22 23 24 class AccessibleCaretCursorModeTestCase(MarionetteTestCase): 25 """Test cases for AccessibleCaret under cursor mode. 26 27 We call the blinking cursor (nsCaret) as cursor, and call AccessibleCaret as 28 caret for short. 29 30 """ 31 32 # Element IDs. 33 _input_id = "input" 34 _input_padding_id = "input-padding" 35 _textarea_id = "textarea" 36 _textarea_one_line_id = "textarea-one-line" 37 _contenteditable_id = "contenteditable" 38 39 # Test html files. 40 _cursor_html = "layout/test_carets_cursor.html" 41 42 def setUp(self): 43 # Code to execute before every test is running. 44 super(AccessibleCaretCursorModeTestCase, self).setUp() 45 self.caret_tested_pref = "layout.accessiblecaret.enabled" 46 self.hide_carets_for_mouse = ( 47 "layout.accessiblecaret.hide_carets_for_mouse_input" 48 ) 49 self.prefs = { 50 self.caret_tested_pref: True, 51 self.hide_carets_for_mouse: False, 52 # To disable transition, or the caret may not be the desired 53 # location yet, we cannot press a caret successfully. 54 "layout.accessiblecaret.transition-duration": "0.0", 55 # Enabled hapticfeedback on all platforms. The tests shouldn't crash 56 # on platforms without hapticfeedback support. 57 "layout.accessiblecaret.hapticfeedback": True, 58 } 59 self.marionette.set_prefs(self.prefs) 60 self.actions = CaretActions(self.marionette) 61 62 def tearDown(self): 63 self.marionette.actions.release() 64 super(AccessibleCaretCursorModeTestCase, self).tearDown() 65 66 def open_test_html(self, test_html): 67 self.marionette.navigate(self.marionette.absolute_url(test_html)) 68 69 @parameterized(_input_id, el_id=_input_id) 70 @parameterized(_textarea_id, el_id=_textarea_id) 71 @parameterized(_contenteditable_id, el_id=_contenteditable_id) 72 def test_move_cursor_to_the_right_by_one_character(self, el_id): 73 self.open_test_html(self._cursor_html) 74 el = self.marionette.find_element(By.ID, el_id) 75 sel = SelectionManager(el) 76 content_to_add = "!" 77 target_content = sel.content 78 target_content = target_content[:1] + content_to_add + target_content[1:] 79 80 # Get first caret (x, y) at position 1 and 2. 81 self.actions.click(element=el).perform() 82 sel.move_cursor_to_front() 83 cursor0_x, cursor0_y = sel.cursor_location() 84 first_caret0_x, first_caret0_y = sel.first_caret_location() 85 sel.move_cursor_by_offset(1) 86 first_caret1_x, first_caret1_y = sel.first_caret_location() 87 88 # Click the front of the input to make first caret appear. 89 self.actions.move(el, cursor0_x, cursor0_y).click().perform() 90 91 # Move first caret. 92 self.actions.flick( 93 el, first_caret0_x, first_caret0_y, first_caret1_x, first_caret1_y 94 ).perform() 95 96 self.actions.send_keys(content_to_add).perform() 97 self.assertEqual(target_content, sel.content) 98 99 @parameterized(_input_id, el_id=_input_id) 100 @parameterized(_textarea_id, el_id=_textarea_id) 101 @parameterized(_contenteditable_id, el_id=_contenteditable_id) 102 def test_move_cursor_to_end_by_dragging_caret_to_bottom_right_corner(self, el_id): 103 self.open_test_html(self._cursor_html) 104 el = self.marionette.find_element(By.ID, el_id) 105 sel = SelectionManager(el) 106 content_to_add = "!" 107 target_content = sel.content + content_to_add 108 109 # Click the front of the input to make first caret appear. 110 self.actions.click(element=el).perform() 111 sel.move_cursor_to_front() 112 self.actions.move(el, *sel.cursor_location()).click().perform() 113 114 # Move first caret to the bottom-right corner of the element. 115 src_x, src_y = sel.first_caret_location() 116 dest_x, dest_y = el.rect["width"], el.rect["height"] 117 self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform() 118 119 self.actions.send_keys(content_to_add).perform() 120 self.assertEqual(target_content, sel.content) 121 122 @parameterized(_input_id, el_id=_input_id) 123 @parameterized(_textarea_id, el_id=_textarea_id) 124 @parameterized(_contenteditable_id, el_id=_contenteditable_id) 125 def test_move_cursor_to_front_by_dragging_caret_to_front(self, el_id): 126 self.open_test_html(self._cursor_html) 127 el = self.marionette.find_element(By.ID, el_id) 128 sel = SelectionManager(el) 129 content_to_add = "!" 130 target_content = content_to_add + sel.content 131 132 # Get first caret location at the front. 133 self.actions.click(element=el).perform() 134 sel.move_cursor_to_front() 135 dest_x, dest_y = sel.first_caret_location() 136 137 # Click to make first caret appear. 138 self.actions.click(element=el).perform() 139 sel.move_cursor_to_end() 140 self.actions.move(el, *sel.cursor_location()).click().perform() 141 src_x, src_y = sel.first_caret_location() 142 143 # Move first caret to the front of the input box. 144 self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform() 145 146 self.actions.send_keys(content_to_add).perform() 147 self.assertEqual(target_content, sel.content) 148 149 def test_caret_not_appear_when_typing_in_scrollable_content(self): 150 self.open_test_html(self._cursor_html) 151 el = self.marionette.find_element(By.ID, self._input_id) 152 sel = SelectionManager(el) 153 content_to_add = "!" 154 non_target_content = content_to_add + sel.content + string.ascii_letters 155 156 self.actions.click(element=el).perform() 157 sel.move_cursor_to_end() 158 159 # Insert a long string to the end of the <input>, which triggers 160 # ScrollPositionChanged event. 161 el.send_keys(string.ascii_letters) 162 163 # The caret should not be visible. If it does appear wrongly due to the 164 # ScrollPositionChanged event, we can drag it to the front of the 165 # <input> to change the cursor position. 166 src_x, src_y = sel.first_caret_location() 167 dest_x, dest_y = 0, 0 168 self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform() 169 170 # The content should not be inserted at the front of the <input>. 171 el.send_keys(content_to_add) 172 173 self.assertNotEqual(non_target_content, sel.content) 174 175 @parameterized(_input_id, el_id=_input_id) 176 @parameterized(_input_padding_id, el_id=_input_padding_id) 177 @parameterized(_textarea_one_line_id, el_id=_textarea_one_line_id) 178 @parameterized(_contenteditable_id, el_id=_contenteditable_id) 179 def test_caret_not_jump_when_dragging_to_editable_content_boundary(self, el_id): 180 self.open_test_html(self._cursor_html) 181 el = self.marionette.find_element(By.ID, el_id) 182 sel = SelectionManager(el) 183 content_to_add = "!" 184 non_target_content = sel.content + content_to_add 185 186 # Goal: the cursor position is not changed after dragging the caret down 187 # on the Y-axis. 188 self.actions.click(element=el).perform() 189 sel.move_cursor_to_front() 190 self.actions.move(el, *sel.cursor_location()).click().perform() 191 x, y = sel.first_caret_location() 192 193 # Drag the caret down by 50px, and insert '!'. 194 self.actions.flick(el, x, y, x, y + 50).perform() 195 self.actions.send_keys(content_to_add).perform() 196 self.assertNotEqual(non_target_content, sel.content) 197 198 @parameterized(_input_id, el_id=_input_id) 199 @parameterized(_input_padding_id, el_id=_input_padding_id) 200 @parameterized(_textarea_one_line_id, el_id=_textarea_one_line_id) 201 @parameterized(_contenteditable_id, el_id=_contenteditable_id) 202 def test_caret_not_jump_to_front_when_dragging_up_to_editable_content_boundary( 203 self, el_id 204 ): 205 self.open_test_html(self._cursor_html) 206 el = self.marionette.find_element(By.ID, el_id) 207 sel = SelectionManager(el) 208 content_to_add = "!" 209 non_target_content = content_to_add + sel.content 210 211 # Goal: the cursor position is not changed after dragging the caret down 212 # on the Y-axis. 213 self.actions.click(element=el).perform() 214 sel.move_cursor_to_end() 215 self.actions.move(el, *sel.cursor_location()).click().perform() 216 x, y = sel.first_caret_location() 217 218 # Drag the caret up by 40px, and insert '!'. 219 self.actions.flick(el, x, y, x, y - 40).perform() 220 self.actions.send_keys(content_to_add).perform() 221 self.assertNotEqual(non_target_content, sel.content) 222 223 def test_drag_caret_from_front_to_end_across_columns(self): 224 self.open_test_html("layout/test_carets_columns.html") 225 el = self.marionette.find_element(By.ID, "columns") 226 sel = SelectionManager(el) 227 content_to_add = "!" 228 target_content = sel.content + content_to_add 229 230 # Goal: the cursor position can be changed by dragging the caret from 231 # the front to the end of the content. 232 233 # Click to make the cursor appear. 234 before_image_1 = self.marionette.find_element(By.ID, "before-image-1") 235 self.actions.click(element=before_image_1).perform() 236 237 # Click the front of the content to make first caret appear. 238 sel.move_cursor_to_front() 239 self.actions.move(el, *sel.cursor_location()).click().perform() 240 src_x, src_y = sel.first_caret_location() 241 dest_x, dest_y = el.rect["width"], el.rect["height"] 242 243 # Drag the first caret to the bottom-right corner of the element. 244 self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform() 245 246 self.actions.send_keys(content_to_add).perform() 247 self.assertEqual(target_content, sel.content) 248 249 def test_move_cursor_to_front_by_dragging_caret_to_front_br_element(self): 250 self.open_test_html(self._cursor_html) 251 el = self.marionette.find_element(By.ID, self._contenteditable_id) 252 sel = SelectionManager(el) 253 content_to_add_1 = "!" 254 content_to_add_2 = "\n\n" 255 target_content = content_to_add_1 + content_to_add_2 + sel.content 256 257 # Goal: the cursor position can be changed by dragging the caret from 258 # the end of the content to the front br element. Because we cannot get 259 # caret location if it's on a br element, we need to get the first caret 260 # location then adding the new lines. 261 262 # Get first caret location at the front. 263 self.actions.click(element=el).perform() 264 sel.move_cursor_to_front() 265 dest_x, dest_y = sel.first_caret_location() 266 267 # Append new line to the front of the content. 268 el.send_keys(content_to_add_2) 269 270 # Click to make first caret appear. 271 self.actions.click(element=el).perform() 272 sel.move_cursor_to_end() 273 self.actions.move(el, *sel.cursor_location()).click().perform() 274 src_x, src_y = sel.first_caret_location() 275 276 # Move first caret to the front of the input box. 277 self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform() 278 279 self.actions.send_keys(content_to_add_1).perform() 280 self.assertEqual(target_content, sel.content)