Bug 1255586 - Add test cases for more input types in testInputConnection; r=esawin
authorJim Chen <nchen@mozilla.com>
Wed, 16 Mar 2016 14:20:30 -0400
changeset 312819 ffb463de8bab7c924da29b1f315197b2c634c963
parent 312818 cf76c73b91dda644c5347ee751560c9894084e9f
child 312820 1123bee884d29108951b6659220665a849d2a7d1
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersesawin
bugs1255586
milestone48.0a1
Bug 1255586 - Add test cases for more input types in testInputConnection; r=esawin Add test cases for text areas, content editables, and design mode editors.
mobile/android/tests/browser/robocop/robocop_input.html
mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java
--- a/mobile/android/tests/browser/robocop/robocop_input.html
+++ b/mobile/android/tests/browser/robocop/robocop_input.html
@@ -1,61 +1,134 @@
 <!DOCTYPE html>
 <html>
   <head>
     <title>Robocop Input</title>
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
   </head>
   <body>
     <p>Input: <input id="input" type="text"></p>
+    <p>Text area: <textarea id="text-area"></textarea></p>
+    <p>Content editable: <div id="content-editable" contentEditable="true"></div></p>
+    <p>Design mode: <iframe id="design-mode" src="data:text/html;charset=utf-8,<html><body></body></html>"></iframe></p>
     <p>Resetting input: <input id="resetting-input" type="text"></p>
     <p>Hiding input: <input id="hiding-input" type="text"></p>
     <script type="application/javascript;version=1.8" src="robocop_head.js"></script>
     <script type="application/javascript;version=1.8">
       let input = document.getElementById("input");
+      let textArea = document.getElementById("text-area");
+      let contentEditable = document.getElementById("content-editable");
+
+      let designMode = document.getElementById("design-mode");
+      designMode.contentDocument.designMode = "on";
+
+      // Spatial navigation interferes with design-mode key event tests.
+      SpecialPowers.setBoolPref("snav.enabled", false);
 
       // An input that resets the editor on every input by resetting the value property.
       let resetting_input = document.getElementById("resetting-input");
       resetting_input.addEventListener('input', function() {
         this.value = this.value;
       });
 
       // An input that hides on input.
       let hiding_input = document.getElementById("hiding-input");
       hiding_input.addEventListener('keydown', function(e) {
         if (e.key === "!") { // '!' key event as sent by testInputConnection.java.
           this.value = "";
           this.style.display = "none";
         }
       });
 
+      let getEditor, setValue, setSelection;
+
       let test = {
         focus_input: function(val) {
-          input.value = val;
+          getEditor = function() {
+            return SpecialPowers.wrap(input).QueryInterface(
+                SpecialPowers.Ci.nsIDOMNSEditableElement).editor;
+          };
+          setValue = function(val) {
+            input.value = val;
+          };
+          setSelection = function(pos) {
+            input.setSelectionRange(pos, pos);
+          };
+          setValue(val);
           input.focus();
         },
 
+        focus_text_area: function(val) {
+          getEditor = function() {
+            return SpecialPowers.wrap(textArea).QueryInterface(
+                SpecialPowers.Ci.nsIDOMNSEditableElement).editor;
+          };
+          setValue = function(val) {
+            textArea.value = val;
+          };
+          setSelection = function(pos) {
+            textArea.setSelectionRange(pos, pos);
+          };
+          setValue(val);
+          textArea.focus();
+        },
+
+        focus_content_editable: function(val) {
+          getEditor = function() {
+            return SpecialPowers.wrap(window).QueryInterface(
+                SpecialPowers.Ci.nsIInterfaceRequestor).getInterface(
+                SpecialPowers.Ci.nsIWebNavigation).QueryInterface(
+                SpecialPowers.Ci.nsIDocShell).editor;
+          };
+          setValue = function(val) {
+            contentEditable.innerHTML = val;
+          };
+          setSelection = function(pos) {
+            window.getSelection().collapse(contentEditable.firstChild, pos);
+          };
+          setValue(val);
+          contentEditable.focus();
+        },
+
+        focus_design_mode: function(val) {
+          getEditor = function() {
+            return SpecialPowers.wrap(designMode.contentWindow).QueryInterface(
+                SpecialPowers.Ci.nsIInterfaceRequestor).getInterface(
+                SpecialPowers.Ci.nsIWebNavigation).QueryInterface(
+                SpecialPowers.Ci.nsIDocShell).editor;
+          };
+          setValue = function(val) {
+            designMode.contentDocument.body.innerHTML = val;
+          };
+          setSelection = function(pos) {
+            designMode.contentWindow.getSelection().collapse(
+                designMode.contentDocument.body.firstChild, pos);
+          };
+          setValue(val);
+          designMode.contentWindow.focus();
+          designMode.contentDocument.body.focus();
+        },
+
         test_reflush_changes: function() {
-          let inputEditable = SpecialPowers.wrap(input).QueryInterface(SpecialPowers.Ci.nsIDOMNSEditableElement);
-          let inputIme = inputEditable.editor.QueryInterface(SpecialPowers.Ci.nsIEditorIMESupport);
+          let inputIme = getEditor().QueryInterface(SpecialPowers.Ci.nsIEditorIMESupport);
           do_check_true(inputIme.composing);
 
           // Ending the composition then setting the input value triggers the bug.
           inputIme.forceCompositionEnd();
-          input.value = "good"; // Value that testInputConnection.java expects.
+          setValue("good"); // Value that testInputConnection.java expects.
+          setSelection(4);
         },
 
         test_set_selection: function() {
-          let inputEditable = SpecialPowers.wrap(input).QueryInterface(SpecialPowers.Ci.nsIDOMNSEditableElement);
-          let inputIme = inputEditable.editor.QueryInterface(SpecialPowers.Ci.nsIEditorIMESupport);
+          let inputIme = getEditor().QueryInterface(SpecialPowers.Ci.nsIEditorIMESupport);
           do_check_true(inputIme.composing);
 
           // Ending the composition then setting the selection triggers the bug.
           inputIme.forceCompositionEnd();
-          input.setSelectionRange(3, 3); // Offsets that testInputConnection.java expects.
+          setSelection(3); // Offsets that testInputConnection.java expects.
         },
 
         focus_resetting_input: function(val) {
           resetting_input.value = val;
           resetting_input.focus();
         },
 
         focus_hiding_input: function(val) {
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java
+++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java
@@ -38,16 +38,34 @@ public class testInputConnection extends
         mToolbar.assertTitle(url);
 
         // First run tests inside the normal input field.
         getJS().syncCall("focus_input", INITIAL_TEXT);
         mGeckoView.mTextInput
             .waitForInputConnection()
             .testInputConnection(new BasicInputConnectionTest());
 
+        // Then switch focus to the text area and rerun tests.
+        getJS().syncCall("focus_text_area", INITIAL_TEXT);
+        mGeckoView.mTextInput
+            .waitForInputConnection()
+            .testInputConnection(new BasicInputConnectionTest());
+
+        // Then switch focus to the content editable and rerun tests.
+        getJS().syncCall("focus_content_editable", INITIAL_TEXT);
+        mGeckoView.mTextInput
+            .waitForInputConnection()
+            .testInputConnection(new BasicInputConnectionTest());
+
+        // Then switch focus to the design mode document and rerun tests.
+        getJS().syncCall("focus_design_mode", INITIAL_TEXT);
+        mGeckoView.mTextInput
+            .waitForInputConnection()
+            .testInputConnection(new BasicInputConnectionTest());
+
         // Then switch focus to the resetting input field, and run tests there.
         getJS().syncCall("focus_resetting_input", "");
         mGeckoView.mTextInput
             .waitForInputConnection()
             .testInputConnection(new ResettingInputConnectionTest());
 
         // Then switch focus to the hiding input field, and run tests there.
         getJS().syncCall("focus_hiding_input", "");
@@ -55,19 +73,23 @@ public class testInputConnection extends
             .waitForInputConnection()
             .testInputConnection(new HidingInputConnectionTest());
 
         getJS().syncCall("finish_test");
     }
 
     private class BasicInputConnectionTest extends InputConnectionTest {
         @Override
-        public void test(InputConnection ic, EditorInfo info) {
-            // Test initial text provided by the hash in the test page URL
-            assertText("Initial text matches URL hash", ic, INITIAL_TEXT);
+        public void test(final InputConnection ic, EditorInfo info) {
+            waitFor("focus change", new Condition() {
+                @Override
+                public boolean isSatisfied() {
+                    return INITIAL_TEXT.equals(getText(ic));
+                }
+            });
 
             // Test setSelection
             ic.setSelection(0, 3);
             assertSelection("Can set selection to range", ic, 0, 3);
             ic.setSelection(-3, 6);
             // Test both forms of assert
             assertTextAndSelection("Can handle invalid range", ic, INITIAL_TEXT, 0, 3);
             ic.setSelection(3, 3);
@@ -253,16 +275,20 @@ public class testInputConnection extends
             processGeckoEvents(ic);
             assertTextAndSelectionAt("Can reset composing text (resetting)", ic, "baz", 3);
 
             ic.finishComposingText();
             assertTextAndSelectionAt("Can finish composing text (resetting)", ic, "baz", 3);
 
             ic.deleteSurroundingText(3, 0);
             assertTextAndSelectionAt("Can clear text", ic, "", 0);
+
+            // Make sure we don't leave behind stale events for the following test.
+            processGeckoEvents(ic);
+            processInputConnectionEvents();
         }
     }
 
     /**
      * HidingInputConnectionTest performs tests on the hiding input in
      * robocop_input.html. Any test that uses the normal input should be put in
      * BasicInputConnectionTest.
      */