Bug 1110039 - Part 5 - Reuse marionette tests for AccessibleCaret. r=roc
authorTing-Yu Lin <tlin@mozilla.com>
Thu, 07 May 2015 07:55:00 +0200
changeset 275830 48b7fceaeea9153b4db5ba31012360dc0d92e3ab
parent 275829 88a289fcb214707063e95749c98817d0a97f5d76
child 275831 aaa0f79dfefedb19368b17002cafcc0432a28490
push id897
push userjlund@mozilla.com
push dateMon, 14 Sep 2015 18:56:12 +0000
treeherdermozilla-release@9411e2d2b214 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1110039
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1110039 - Part 5 - Reuse marionette tests for AccessibleCaret. r=roc AccessibleCaret should behave like TouchCaret and SelectionCarets. I refactor the setUp() to support both the old and new preferences. Rename test_selectioncarets_multiplerange.py to test_selectioncarets2.py since it now contains more than just multirange tests. _test_handle_tilt_when_carets_overlap_to_each_other() is modified because AccessibleCaret does not inflate the caret hit rectangle as TouchCaret/SelectionCarets did. The point for tilt caret edges need to shrink a bit. In test_touchcaret.py, instead of setting _large_expiration_time, I just disable caret timeout by default for every test. For those timeout tests, use one second timeout to reduce test running time, and allow 1.5x margin to prevent intermittent failures. Refine test case that move touch caret to front by using the real position at the front rather than (0, 0). Use skip_if_not_rotatable decorator for better log message.
layout/base/tests/marionette/manifest.ini
layout/base/tests/marionette/test_selectioncarets.py
layout/base/tests/marionette/test_selectioncarets2.py
layout/base/tests/marionette/test_selectioncarets_multiplerange.py
layout/base/tests/marionette/test_touchcaret.py
--- a/layout/base/tests/marionette/manifest.ini
+++ b/layout/base/tests/marionette/manifest.ini
@@ -8,9 +8,9 @@ browser = true
 ; true if the test is compatible with b2g, otherwise false
 b2g = true
 
 ; true if the test should be skipped
 skip = false
 
 [test_touchcaret.py]
 [test_selectioncarets.py]
-[test_selectioncarets_multiplerange.py]
+[test_selectioncarets2.py]
--- a/layout/base/tests/marionette/test_selectioncarets.py
+++ b/layout/base/tests/marionette/test_selectioncarets.py
@@ -4,56 +4,85 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from marionette_driver.by import By
 from marionette_driver.marionette import Actions
 from marionette import MarionetteTestCase
 from marionette_driver.selection import SelectionManager
 from marionette_driver.gestures import long_press_without_contextmenu
 
-from math import ceil, floor
+
+class CommonCaretsTestCase(object):
+    '''Common test cases for a selection with a two carets.
 
+    To run these test cases, a subclass must inherit from both this class and
+    MarionetteTestCase.
 
-class SelectionCaretsTest(MarionetteTestCase):
+    '''
     _long_press_time = 1        # 1 second
     _input_selector = (By.ID, 'input')
     _textarea_selector = (By.ID, 'textarea')
     _textarea_rtl_selector = (By.ID, 'textarea_rtl')
     _contenteditable_selector = (By.ID, 'contenteditable')
     _content_selector = (By.ID, 'content')
     _textarea2_selector = (By.ID, 'textarea2')
     _contenteditable2_selector = (By.ID, 'contenteditable2')
     _content2_selector = (By.ID, 'content2')
 
     def setUp(self):
         # Code to execute before a tests are run.
-        MarionetteTestCase.setUp(self)
+        super(CommonCaretsTestCase, self).setUp()
         self.actions = Actions(self.marionette)
 
-    def openTestHtml(self, enabled=True):
+        # The carets to be tested.
+        self.carets_tested_pref = None
+
+        # The carets to be disabled in this test suite.
+        self.carets_disabled_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'
+        elif isinstance(value, int):
+            value = str(value)
+        else:
+            value = repr(value)
+
+        script = '''SpecialPowers.pushPrefEnv({"set": [[%s, %s]]}, marionetteScriptFinished);''' % (
+            pref_name, value)
+
+        self.marionette.execute_async_script(script)
+
+    def open_test_html(self, enabled=True):
         '''Open html for testing and locate elements, and enable/disable touch
         caret.'''
-        self.marionette.execute_async_script(
-            'SpecialPowers.pushPrefEnv({"set": [["selectioncaret.enabled", %s]]}, marionetteScriptFinished);' %
-            ('true' if enabled else 'false'))
+        self.set_pref(self.carets_tested_pref, enabled)
+        self.set_pref(self.carets_disabled_pref, False)
+
         test_html = self.marionette.absolute_url('test_selectioncarets.html')
         self.marionette.navigate(test_html)
 
         self._input = self.marionette.find_element(*self._input_selector)
         self._textarea = self.marionette.find_element(*self._textarea_selector)
         self._textarea_rtl = self.marionette.find_element(*self._textarea_rtl_selector)
         self._contenteditable = self.marionette.find_element(*self._contenteditable_selector)
         self._content = self.marionette.find_element(*self._content_selector)
 
-    def openTestHtml2(self, enabled=True):
+    def open_test_html2(self, enabled=True):
         '''Open html for testing and locate elements, and enable/disable touch
         caret.'''
-        self.marionette.execute_script(
-            'SpecialPowers.setBoolPref("selectioncaret.enabled", %s);' %
-            ('true' if enabled else 'false'))
+        self.set_pref(self.carets_tested_pref, enabled)
+        self.set_pref(self.carets_disabled_pref, False)
 
         test_html2 = self.marionette.absolute_url('test_selectioncarets_multipleline.html')
         self.marionette.navigate(test_html2)
 
         self._textarea2 = self.marionette.find_element(*self._textarea2_selector)
         self._contenteditable2 = self.marionette.find_element(*self._contenteditable2_selector)
         self._content2 = self.marionette.find_element(*self._content2_selector)
 
@@ -209,222 +238,236 @@ class SelectionCaretsTest(MarionetteTest
 
         # The following values are from ua.css.
         caret_width = 44
         caret_margin_left = -23
         tilt_right_margin_left = 18
         tilt_left_margin_left = -17
 
         left_caret_left_edge_x = caret3_x + caret_margin_left + tilt_left_margin_left
-        el.tap(ceil(left_caret_left_edge_x), caret3_y)
+        el.tap(left_caret_left_edge_x + 2, caret3_y)
 
         right_caret_right_edge_x = (caret4_x + caret_margin_left +
                                     tilt_right_margin_left + caret_width)
-        el.tap(floor(right_caret_right_edge_x), caret4_y)
+        el.tap(right_caret_right_edge_x - 2, caret4_y)
 
         # Drag the left caret back to the initial selection, the first word.
         self.actions.flick(el, caret3_x, caret3_y, caret1_x, caret1_y).perform()
 
         assertFunc(target_content, sel.selected_content)
 
     ########################################################################
     # <input> test cases with selection carets enabled
     ########################################################################
     def test_input_long_press_to_select_a_word(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_long_press_to_select_a_word(self._input, self.assertEqual)
 
     def test_input_move_selection_carets(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_move_selection_carets(self._input, self.assertEqual)
 
     def test_input_minimum_select_one_character(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_minimum_select_one_character(self._input, self.assertEqual)
 
     def test_input_focus_obtained_by_long_press_from_textarea(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._textarea, self._input)
 
     def test_input_focus_obtained_by_long_press_from_contenteditable(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._contenteditable, self._input)
 
     def test_input_focus_obtained_by_long_press_from_content_non_editable(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._content, self._input)
 
     def test_input_handle_tilt_when_carets_overlap_to_each_other(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_handle_tilt_when_carets_overlap_to_each_other(self._input, self.assertEqual)
 
     ########################################################################
     # <input> test cases with selection carets disabled
     ########################################################################
     def test_input_long_press_to_select_a_word_disabled(self):
-        self.openTestHtml(enabled=False)
+        self.open_test_html(enabled=False)
         self._test_long_press_to_select_a_word(self._input, self.assertNotEqual)
 
     def test_input_move_selection_carets_disabled(self):
-        self.openTestHtml(enabled=False)
+        self.open_test_html(enabled=False)
         self._test_move_selection_carets(self._input, self.assertNotEqual)
 
     ########################################################################
     # <textarea> test cases with selection carets enabled
     ########################################################################
     def test_textarea_long_press_to_select_a_word(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_long_press_to_select_a_word(self._textarea, self.assertEqual)
 
     def test_textarea_move_selection_carets(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_move_selection_carets(self._textarea, self.assertEqual)
 
     def test_textarea_minimum_select_one_character(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_minimum_select_one_character(self._textarea, self.assertEqual)
 
     def test_textarea_focus_obtained_by_long_press_from_input(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._input, self._textarea)
 
     def test_textarea_focus_obtained_by_long_press_from_contenteditable(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._contenteditable, self._textarea)
 
     def test_textarea_focus_obtained_by_long_press_from_content_non_editable(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._content, self._textarea)
 
     def test_textarea_handle_tilt_when_carets_overlap_to_each_other(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_handle_tilt_when_carets_overlap_to_each_other(self._textarea, self.assertEqual)
 
     ########################################################################
     # <textarea> test cases with selection carets disabled
     ########################################################################
     def test_textarea_long_press_to_select_a_word_disabled(self):
-        self.openTestHtml(enabled=False)
+        self.open_test_html(enabled=False)
         self._test_long_press_to_select_a_word(self._textarea, self.assertNotEqual)
 
     def test_textarea_move_selection_carets_disable(self):
-        self.openTestHtml(enabled=False)
+        self.open_test_html(enabled=False)
         self._test_move_selection_carets(self._textarea, self.assertNotEqual)
 
     ########################################################################
     # <textarea> right-to-left test cases with selection carets enabled
     ########################################################################
     def test_textarea_rtl_long_press_to_select_a_word(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_long_press_to_select_a_word(self._textarea_rtl, self.assertEqual)
 
     def test_textarea_rtl_move_selection_carets(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_move_selection_carets(self._textarea_rtl, self.assertEqual)
 
     def test_textarea_rtl_minimum_select_one_character(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_minimum_select_one_character(self._textarea_rtl, self.assertEqual)
 
     ########################################################################
     # <textarea> right-to-left test cases with selection carets disabled
     ########################################################################
     def test_textarea_rtl_long_press_to_select_a_word_disabled(self):
-        self.openTestHtml(enabled=False)
+        self.open_test_html(enabled=False)
         self._test_long_press_to_select_a_word(self._textarea_rtl, self.assertNotEqual)
 
     def test_textarea_rtl_move_selection_carets_disabled(self):
-        self.openTestHtml(enabled=False)
+        self.open_test_html(enabled=False)
         self._test_move_selection_carets(self._textarea_rtl, self.assertNotEqual)
 
     ########################################################################
     # <div> contenteditable test cases with selection carets enabled
     ########################################################################
     def test_contenteditable_long_press_to_select_a_word(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_long_press_to_select_a_word(self._contenteditable, self.assertEqual)
 
     def test_contenteditable_move_selection_carets(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_move_selection_carets(self._contenteditable, self.assertEqual)
 
     def test_contenteditable_minimum_select_one_character(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_minimum_select_one_character(self._contenteditable, self.assertEqual)
 
     def test_contenteditable_focus_obtained_by_long_press_from_input(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._input, self._contenteditable)
 
     def test_contenteditable_focus_obtained_by_long_press_from_textarea(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._textarea, self._contenteditable)
 
     def test_contenteditable_focus_obtained_by_long_press_from_content_non_editable(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._content, self._contenteditable)
 
     def test_contenteditable_handle_tilt_when_carets_overlap_to_each_other(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_handle_tilt_when_carets_overlap_to_each_other(self._contenteditable, self.assertEqual)
 
     ########################################################################
     # <div> contenteditable test cases with selection carets disabled
     ########################################################################
     def test_contenteditable_long_press_to_select_a_word_disabled(self):
-        self.openTestHtml(enabled=False)
+        self.open_test_html(enabled=False)
         self._test_long_press_to_select_a_word(self._contenteditable, self.assertNotEqual)
 
     def test_contenteditable_move_selection_carets_disabled(self):
-        self.openTestHtml(enabled=False)
+        self.open_test_html(enabled=False)
         self._test_move_selection_carets(self._contenteditable, self.assertNotEqual)
 
     ########################################################################
     # <div> non-editable test cases with selection carets enabled
     ########################################################################
     def test_content_non_editable_long_press_to_select_a_word(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_long_press_to_select_a_word(self._content, self.assertEqual)
 
     def test_content_non_editable_move_selection_carets(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_move_selection_carets(self._content, self.assertEqual)
 
     def test_content_non_editable_minimum_select_one_character_by_selection(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_minimum_select_one_character(self._content, self.assertEqual)
 
     def test_content_non_editable_focus_obtained_by_long_press_from_input(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._input, self._content)
 
     def test_content_non_editable_focus_obtained_by_long_press_from_textarea(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._textarea, self._content)
 
     def test_content_non_editable_focus_obtained_by_long_press_from_contenteditable(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_focus_obtained_by_long_press(self._contenteditable, self._content)
 
     def test_content_non_editable_handle_tilt_when_carets_overlap_to_each_other(self):
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         self._test_handle_tilt_when_carets_overlap_to_each_other(self._content, self.assertEqual)
 
     ########################################################################
     # <textarea> (multi-lines) test cases with selection carets enabled
     ########################################################################
     def test_textarea2_minimum_select_one_character(self):
-        self.openTestHtml2(enabled=True)
+        self.open_test_html2()
         self._test_minimum_select_one_character(self._textarea2, self.assertEqual)
 
     ########################################################################
     # <div> contenteditable2 (multi-lines) test cases with selection carets enabled
     ########################################################################
     def test_contenteditable2_minimum_select_one_character(self):
-        self.openTestHtml2(enabled=True)
+        self.open_test_html2()
         self._test_minimum_select_one_character(self._contenteditable2, self.assertEqual)
 
     ########################################################################
     # <div> non-editable2 (multi-lines) test cases with selection carets enabled
     ########################################################################
     def test_content_non_editable2_minimum_select_one_character(self):
-        self.openTestHtml2(enabled=True)
+        self.open_test_html2()
         self._test_minimum_select_one_character(self._content2, self.assertEqual)
+
+
+class SelectionCaretsTestCase(CommonCaretsTestCase, MarionetteTestCase):
+    def setUp(self):
+        super(SelectionCaretsTestCase, self).setUp()
+        self.carets_tested_pref = 'selectioncaret.enabled'
+        self.carets_disabled_pref = 'layout.accessiblecaret.enabled'
+
+
+class AccessibleCaretSelectionModeTestCase(CommonCaretsTestCase, MarionetteTestCase):
+    def setUp(self):
+        super(AccessibleCaretSelectionModeTestCase, self).setUp()
+        self.carets_tested_pref = 'layout.accessiblecaret.enabled'
+        self.carets_disabled_pref = 'selectioncaret.enabled'
rename from layout/base/tests/marionette/test_selectioncarets_multiplerange.py
rename to layout/base/tests/marionette/test_selectioncarets2.py
--- a/layout/base/tests/marionette/test_selectioncarets_multiplerange.py
+++ b/layout/base/tests/marionette/test_selectioncarets2.py
@@ -1,63 +1,99 @@
 # -*- coding: utf-8 -*-
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from marionette_driver.by import By
 from marionette_driver.marionette import Actions
-from marionette import MarionetteTestCase
+from marionette import MarionetteTestCase, SkipTest
 from marionette_driver.selection import SelectionManager
 from marionette_driver.gestures import long_press_without_contextmenu
 
 
-class SelectionCaretsMultipleRangeTest(MarionetteTestCase):
+def skip_if_not_rotatable(target):
+    def wrapper(self, *args, **kwargs):
+        if not self.marionette.session_capabilities.get('rotatable'):
+            raise SkipTest('skipping due to device not rotatable')
+        return target(self, *args, **kwargs)
+    return wrapper
+
+
+class CommonCaretsTestCase2(object):
+    '''Common test cases for a selection with a two carets.
+
+    To run these test cases, a subclass must inherit from both this class and
+    MarionetteTestCase.
+
+    '''
     _long_press_time = 1        # 1 second
 
     def setUp(self):
         # Code to execute before a tests are run.
         MarionetteTestCase.setUp(self)
         self.actions = Actions(self.marionette)
 
-    def openTestHtml(self, enabled=True):
-        # Open html for testing and enable selectioncaret and
-        # non-editable support
-        self.marionette.execute_async_script(
-            'SpecialPowers.pushPrefEnv({"set": [["selectioncaret.enabled", %s],["selectioncaret.noneditable", %s]]}, marionetteScriptFinished);' %
-            ( ('true' if enabled else 'false'),  ('true' if enabled else 'false')))
+        # The carets to be tested.
+        self.carets_tested_pref = None
+
+        # The carets to be disabled in this test suite.
+        self.carets_disabled_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'
+        elif isinstance(value, int):
+            value = str(value)
+        else:
+            value = repr(value)
+
+        script = '''SpecialPowers.pushPrefEnv({"set": [[%s, %s]]}, marionetteScriptFinished);''' % (
+            pref_name, value)
+
+        self.marionette.execute_async_script(script)
+
+    def open_test_html(self, enabled=True):
+        'Open html for testing and enable selectioncaret and non-editable support'
+        self.set_pref(self.carets_tested_pref, enabled)
+        self.set_pref(self.carets_disabled_pref, False)
 
         test_html = self.marionette.absolute_url('test_selectioncarets_multiplerange.html')
         self.marionette.navigate(test_html)
 
         self._body = self.marionette.find_element(By.ID, 'bd')
         self._sel1 = self.marionette.find_element(By.ID, 'sel1')
         self._sel2 = self.marionette.find_element(By.ID, 'sel2')
         self._sel3 = self.marionette.find_element(By.ID, 'sel3')
         self._sel4 = self.marionette.find_element(By.ID, 'sel4')
         self._sel6 = self.marionette.find_element(By.ID, 'sel6')
         self._nonsel1 = self.marionette.find_element(By.ID, 'nonsel1')
 
-    def openTestHtmlLongText(self, enabled=True):
-        # Open html for testing and enable selectioncaret
-        self.marionette.execute_script(
-            'SpecialPowers.setBoolPref("selectioncaret.enabled", %s);' %
-            ('true' if enabled else 'false'))
+    def open_test_html_long_text(self, enabled=True):
+        'Open html for testing and enable selectioncaret'
+        self.set_pref(self.carets_tested_pref, enabled)
+        self.set_pref(self.carets_disabled_pref, False)
 
         test_html = self.marionette.absolute_url('test_selectioncarets_longtext.html')
         self.marionette.navigate(test_html)
 
         self._body = self.marionette.find_element(By.ID, 'bd')
         self._longtext = self.marionette.find_element(By.ID, 'longtext')
 
-    def openTestHtmlIframe(self, enabled=True):
-        # Open html for testing and enable selectioncaret
-        self.marionette.execute_script(
-            'SpecialPowers.setBoolPref("selectioncaret.enabled", %s);' %
-            ('true' if enabled else 'false'))
+    def open_test_html_iframe(self, enabled=True):
+        'Open html for testing and enable selectioncaret'
+        self.set_pref(self.carets_tested_pref, enabled)
+        self.set_pref(self.carets_disabled_pref, False)
 
         test_html = self.marionette.absolute_url('test_selectioncarets_iframe.html')
         self.marionette.navigate(test_html)
 
         self._iframe = self.marionette.find_element(By.ID, 'frame')
 
     def _long_press_to_select_word(self, el, wordOrdinal):
         sel = SelectionManager(el)
@@ -86,28 +122,28 @@ class SelectionCaretsMultipleRangeTest(M
         """Changes all Windows/Mac line endings in s to UNIX line endings."""
 
         return s.replace('\r\n', '\n').replace('\r', '\n')
 
     def test_long_press_to_select_non_selectable_word(self):
         '''Testing long press on non selectable field.
         We should not select anything when long press on non selectable fields.'''
 
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
         halfY = self._nonsel1.size['height'] / 2
         long_press_without_contextmenu(self.marionette, self._nonsel1, self._long_press_time, 0, halfY)
         sel = SelectionManager(self._nonsel1)
         range_count = sel.range_count()
         self.assertEqual(range_count, 0)
 
     def test_drag_caret_over_non_selectable_field(self):
         '''Testing drag caret over non selectable field.
         So that the selected content should exclude non selectable field and
         end selection caret should appear in last range's position.'''
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
 
         # Select target element and get target caret location
         self._long_press_to_select_word(self._sel4, 3)
         sel = SelectionManager(self._body)
         (_, _), (end_caret_x, end_caret_y) = sel.selection_carets_location()
 
         self._long_press_to_select_word(self._sel6, 0)
         (_, _), (end_caret2_x, end_caret2_y) = sel.selection_carets_location()
@@ -131,17 +167,17 @@ class SelectionCaretsMultipleRangeTest(M
         self.actions.flick(self._body, caret1_x, caret1_y, end_caret_x, end_caret_y, 1).perform()
         self.assertEqual(self._to_unix_line_ending(sel.selected_content.strip()),
             '4\nuser can select this 5\nuser')
 
     def test_drag_caret_to_beginning_of_a_line(self):
         '''Bug 1094056
         Test caret visibility when caret is dragged to beginning of a line
         '''
-        self.openTestHtml(enabled=True)
+        self.open_test_html()
 
         # Select the first word in the second line
         self._long_press_to_select_word(self._sel2, 0)
         sel = SelectionManager(self._body)
         (start_caret_x, start_caret_y), (end_caret_x, end_caret_y) = sel.selection_carets_location()
 
         # Select target word in the first line
         self._long_press_to_select_word(self._sel1, 2)
@@ -150,25 +186,22 @@ class SelectionCaretsMultipleRangeTest(M
         (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
         self.actions.flick(self._body, caret2_x, caret2_y, start_caret_x, start_caret_y).perform()
 
         # Drag end caret back to the target word
         self.actions.flick(self._body, start_caret_x, start_caret_y, caret2_x, caret2_y).perform()
 
         self.assertEqual(self._to_unix_line_ending(sel.selected_content.strip()), 'select')
 
+    @skip_if_not_rotatable
     def test_caret_position_after_changing_orientation_of_device(self):
         '''Bug 1094072
         If positions of carets are updated correctly, they should be draggable.
         '''
-        # Skip running test on non-rotatable device ex.desktop browser
-        if not self.marionette.session_capabilities['rotatable']:
-            return
-
-        self.openTestHtmlLongText(enabled=True)
+        self.open_test_html_long_text()
 
         # Select word in portrait mode, then change to landscape mode
         self.marionette.set_orientation('portrait')
         self._long_press_to_select_word(self._longtext, 12)
         sel = SelectionManager(self._body)
         (p_start_caret_x, p_start_caret_y), (p_end_caret_x, p_end_caret_y) = sel.selection_carets_location()
         self.marionette.set_orientation('landscape')
         (l_start_caret_x, l_start_caret_y), (l_end_caret_x, l_end_caret_y) = sel.selection_carets_location()
@@ -184,22 +217,36 @@ class SelectionCaretsMultipleRangeTest(M
 
     def test_select_word_inside_an_iframe(self):
         '''Bug 1088552
         The scroll offset in iframe should be taken into consideration properly.
         In this test, we scroll content in the iframe to the bottom to cause a
         huge offset. If we use the right coordinate system, selection should
         work. Otherwise, it would be hard to trigger select word.
         '''
-        self.openTestHtmlIframe(enabled=True)
+        self.open_test_html_iframe()
 
         # switch to inner iframe and scroll to the bottom
         self.marionette.switch_to_frame(self._iframe)
         self.marionette.execute_script(
          'document.getElementById("bd").scrollTop += 999')
 
         # long press to select bottom text
         self._body = self.marionette.find_element(By.ID, 'bd')
         sel = SelectionManager(self._body)
         self._bottomtext = self.marionette.find_element(By.ID, 'bottomtext')
         long_press_without_contextmenu(self.marionette, self._bottomtext, self._long_press_time)
 
         self.assertNotEqual(self._to_unix_line_ending(sel.selected_content.strip()), '')
+
+
+class SelectionCaretsTestCase2(CommonCaretsTestCase2, MarionetteTestCase):
+    def setUp(self):
+        super(SelectionCaretsTestCase2, self).setUp()
+        self.carets_tested_pref = 'selectioncaret.enabled'
+        self.carets_disabled_pref = 'layout.accessiblecaret.enabled'
+
+
+class AccessibleCaretSelectionModeTestCase2(CommonCaretsTestCase2, MarionetteTestCase):
+    def setUp(self):
+        super(AccessibleCaretSelectionModeTestCase2, self).setUp()
+        self.carets_tested_pref = 'layout.accessiblecaret.enabled'
+        self.carets_disabled_pref = 'selectioncaret.enabled'
--- a/layout/base/tests/marionette/test_touchcaret.py
+++ b/layout/base/tests/marionette/test_touchcaret.py
@@ -4,58 +4,72 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from marionette_driver.by import By
 from marionette_driver.marionette import Actions
 from marionette_driver.selection import SelectionManager
 from marionette import MarionetteTestCase
 
 
-class TouchCaretTest(MarionetteTestCase):
+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')
-    _large_expiration_time = 3000 * 20  # 60 seconds
 
     def setUp(self):
         # Code to execute before a test is being run.
-        MarionetteTestCase.setUp(self)
+        super(CommonCaretTestCase, self).setUp()
         self.actions = Actions(self.marionette)
-        self.original_expiration_time = self.expiration_time
+
+        # 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)
 
-    def tearDown(self):
-        # Code to execute after a test is being run.
-        self.expiration_time = self.original_expiration_time
-        MarionetteTestCase.tearDown(self)
+        '''
+        pref_name = repr(pref_name)
+        if isinstance(value, bool):
+            value = 'true' if value else 'false'
+        elif isinstance(value, int):
+            value = str(value)
+        else:
+            value = repr(value)
 
-    @property
-    def expiration_time(self):
+        script = '''SpecialPowers.pushPrefEnv({"set": [[%s, %s]]}, marionetteScriptFinished);''' % (
+            pref_name, value)
+
+        self.marionette.execute_async_script(script)
+
+    def timeout_ms(self):
         'Return touch caret expiration time in milliseconds.'
         return self.marionette.execute_script(
-            'return SpecialPowers.getIntPref("touchcaret.expiration.time");')
+            'return SpecialPowers.getIntPref("%s");' % self.caret_timeout_ms_pref)
 
-    @expiration_time.setter
-    def expiration_time(self, expiration_time):
-        'Set touch caret expiration time in milliseconds.'
-        self.marionette.execute_script(
-            'SpecialPowers.setIntPref("touchcaret.expiration.time", arguments[0]);',
-            script_args=[expiration_time])
-
-    def openTestHtml(self, enabled=True, expiration_time=None):
+    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.marionette.execute_async_script(
-            'SpecialPowers.pushPrefEnv({"set": [["touchcaret.enabled", %s]]}, marionetteScriptFinished);' %
-            ('true' if enabled else 'false'))
-
-        # Set a larger expiration time to avoid intermittent test failures.
-        if expiration_time is not None:
-            self.expiration_time = expiration_time
+        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)
 
@@ -96,44 +110,51 @@ class TouchCaretTest(MarionetteTestCase)
         # Move touch caret to the bottom-right corner of the element.
         src_x, src_y = sel.touch_caret_location()
         dest_x, dest_y = el.size['width'], el.size['height']
         self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()
 
         el.send_keys(content_to_add)
         assertFunc(target_content, sel.content)
 
-    def _test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self, el, assertFunc):
+    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 top-left corner of the input box.
-        src_x, src_y = sel.touch_caret_location()
-        dest_x, dest_y = 0, 0
+        # Move touch caret to the front of the input box.
         self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()
 
         el.send_keys(content_to_add)
         assertFunc(target_content, sel.content)
 
     def _test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(self, el, assertFunc):
         sel = SelectionManager(el)
         content_to_add = '!'
         non_target_content = content_to_add + sel.content
 
         # Get touch caret expiration time in millisecond, and convert it to second.
-        timeout = self.expiration_time / 1000.0
+        timeout = self.timeout_ms() / 1000.0
+
+        # Set a 1.5x timeout margin to prevent intermittent test failures.
+        timeout *= 1.5
 
         # 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())
@@ -173,110 +194,125 @@ class TouchCaretTest(MarionetteTestCase)
                                  0, 0, 0, 0);''',
             script_args=[el_center_x, el_center_y]
         )
         self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()
 
         el.send_keys(content_to_add)
         assertFunc(non_target_content, sel.content)
 
-
     ########################################################################
     # <input> test cases with touch caret enabled
     ########################################################################
     def test_input_move_caret_to_the_right_by_one_character(self):
-        self.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
+        self.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.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
+        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.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
-        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._input, self.assertEqual)
+        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_touch_caret_timeout(self):
-        self.openTestHtml(enabled=True)
+        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)
 
     def test_input_touch_caret_hides_after_receiving_wheel_event(self):
-        self.openTestHtml(enabled=True, expiration_time=0)
+        self.open_test_html()
         self._test_touch_caret_hides_after_receiving_wheel_event(self._input, self.assertNotEqual)
 
     ########################################################################
     # <input> test cases with touch caret disabled
     ########################################################################
     def test_input_move_caret_to_the_right_by_one_character_disabled(self):
-        self.openTestHtml(enabled=False)
+        self.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.openTestHtml(enabled=False)
-        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._input, self.assertNotEqual)
+        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.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
+        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.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
+        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.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
-        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._textarea, self.assertEqual)
+        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.openTestHtml(enabled=True)
+        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)
 
     def test_textarea_touch_caret_hides_after_receiving_wheel_event(self):
-        self.openTestHtml(enabled=True, expiration_time=0)
+        self.open_test_html()
         self._test_touch_caret_hides_after_receiving_wheel_event(self._textarea, self.assertNotEqual)
 
     ########################################################################
     # <textarea> test cases with touch caret disabled
     ########################################################################
     def test_textarea_move_caret_to_the_right_by_one_character_disabled(self):
-        self.openTestHtml(enabled=False)
+        self.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.openTestHtml(enabled=False)
-        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._textarea, self.assertNotEqual)
+        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.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
+        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.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
+        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.openTestHtml(enabled=True, expiration_time=self._large_expiration_time)
-        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._contenteditable, self.assertEqual)
+        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.openTestHtml(enabled=True)
+        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)
 
     def test_contenteditable_touch_caret_hides_after_receiving_wheel_event(self):
-        self.openTestHtml(enabled=True, expiration_time=0)
+        self.open_test_html()
         self._test_touch_caret_hides_after_receiving_wheel_event(self._contenteditable, self.assertNotEqual)
 
     ########################################################################
     # <div> contenteditable test cases with touch caret disabled
     ########################################################################
     def test_contenteditable_move_caret_to_the_right_by_one_character_disabled(self):
-        self.openTestHtml(enabled=False)
+        self.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.openTestHtml(enabled=False)
-        self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._contenteditable, self.assertNotEqual)
+        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 TouchCaretTestCase(CommonCaretTestCase, MarionetteTestCase):
+    def setUp(self):
+        super(TouchCaretTestCase, self).setUp()
+        self.caret_tested_pref = 'touchcaret.enabled'
+        self.caret_disabled_pref = 'layout.accessiblecaret.enabled'
+        self.caret_timeout_ms_pref = 'touchcaret.expiration.time'
+
+
+class AccessibleCaretCursorModeTestCase(CommonCaretTestCase, MarionetteTestCase):
+    def setUp(self):
+        super(AccessibleCaretCursorModeTestCase, self).setUp()
+        self.caret_tested_pref = 'layout.accessiblecaret.enabled'
+        self.caret_disabled_pref = 'touchcaret.enabled'
+        self.caret_timeout_ms_pref = 'layout.accessiblecaret.timeout_ms'