Bug 705057 part.5 Add automated tests for composition event management by nsIMEStateManager and TextComposition r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 26 Sep 2012 14:47:51 +0900
changeset 110737 b486c3782846bf28ff8b8b8e86d304317ec0537f
parent 110736 ce3c78a357ab896e2e446e46c4628b35472e0c45
child 110738 f7cb509ab5b063e1293fea5730ed7682e70347cf
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewerssmaug
bugs705057
milestone19.0a1
Bug 705057 part.5 Add automated tests for composition event management by nsIMEStateManager and TextComposition r=smaug
widget/tests/window_composition_text_querycontent.xul
--- a/widget/tests/window_composition_text_querycontent.xul
+++ b/widget/tests/window_composition_text_querycontent.xul
@@ -20,20 +20,24 @@
     <vbox id="vbox">
       <textbox id="textbox" onfocus="onFocusPanelTextbox(event);"
                multiline="true" cols="20" rows="4"/>
     </vbox>
   </panel>
 
 <body  xmlns="http://www.w3.org/1999/xhtml">
 <p id="display">
-<div style="margin: 0; padding: 0; font-size: 24px;">Here is a text frame.</div>
+<div id="div" style="margin: 0; padding: 0; font-size: 24px;">Here is a text frame.</div>
 <textarea style="margin: 0;" id="textarea" cols="20" rows="4"></textarea><br/>
 <iframe id="iframe" width="300" height="150"
         src="data:text/html,&lt;textarea id='textarea' cols='20' rows='4'&gt;&lt;/textarea&gt;"></iframe><br/>
+<iframe id="iframe2" width="300" height="150"
+        src="data:text/html,&lt;body onload='document.designMode=%22on%22'&gt;body content&lt;/body&gt;"></iframe><br/>
+<iframe id="iframe3" width="300" height="150"
+        src="data:text/html,&lt;body onload='document.designMode=%22on%22'&gt;body content&lt;/body&gt;"></iframe><br/>
 <input id="input" type="text"/><br/>
 </p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 </pre>
 </body>
@@ -63,24 +67,56 @@ function finish()
   window.close();
 }
 
 function onunload()
 {
   window.opener.wrappedJSObject.SimpleTest.finish();
 }
 
+var div = document.getElementById("div");
 var textarea = document.getElementById("textarea");
 var panel = document.getElementById("panel");
 var textbox = document.getElementById("textbox");
 var iframe = document.getElementById("iframe");
+var iframe2 = document.getElementById("iframe2");
+var iframe3 = document.getElementById("iframe3");
 var input = document.getElementById("input");
 var textareaInFrame;
 
 const nsIDOMWindowUtils = Components.interfaces.nsIDOMWindowUtils;
+const nsIDOMNSEditableElement = Components.interfaces.nsIDOMNSEditableElement;
+const nsIEditorIMESupport = Components.interfaces.nsIEditorIMESupport;
+const nsIInterfaceRequestor = Components.interfaces.nsIInterfaceRequestor;
+const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
+const nsIEditorDocShell = Components.interfaces.nsIEditorDocShell;
+
+function hitEventLoop(aFunc, aTimes)
+{
+  if (--aTimes) {
+    setTimeout(hitEventLoop, 0, aFunc, aTimes);
+  } else {
+    setTimeout(aFunc, 20);
+  }
+}
+
+function getEditorIMESupport(aNode)
+{
+  return aNode.QueryInterface(nsIDOMNSEditableElement).
+               editor.
+               QueryInterface(nsIEditorIMESupport);
+}
+
+function getHTMLEditorIMESupport(aWindow)
+{
+  return aWindow.QueryInterface(nsIInterfaceRequestor).
+                 getInterface(nsIWebNavigation).
+                 QueryInterface(nsIEditorDocShell).
+                 editor;
+}
 
 const kIsWin = (navigator.platform.indexOf("Win") == 0);
 const kIsMac = (navigator.platform.indexOf("Mac") == 0);
 
 const kLFLen = kIsWin ? 2 : 1;
 
 function checkQueryContentResult(aResult, aMessage)
 {
@@ -2235,16 +2271,610 @@ function runBug722639Test()
          "runBug722639Test: " + i + "th line's top is unexpected");
     }
     is(currentLine.left, firstLine.left,
        "runBug722639Test: " + i + "th line's left is unexpected");
     previousTop = currentLine.top;
   }
 }
 
+function runForceCommitTest()
+{
+  var events;
+  function eventHandler(aEvent)
+  {
+    events.push(aEvent);
+  }
+  window.addEventListener("compositionstart", eventHandler, true);
+  window.addEventListener("compositionupdate", eventHandler, true);
+  window.addEventListener("compositionend", eventHandler, true);
+  window.addEventListener("input", eventHandler, true);
+  window.addEventListener("text", eventHandler, true);
+
+  // Make the composition in textarea commit by click in the textarea
+  textarea.focus();
+  textarea.value = "";
+
+  events = [];
+  synthesizeComposition({ type: "compositionstart" });
+
+  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
+  synthesizeText(
+    { "composition":
+      { "string": "\u306E",
+        "clauses":
+        [
+          { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    });
+
+  is(events.length, 4,
+     "runForceCommitTest: wrong event count #1");
+  is(events[0].type, "compositionstart",
+     "runForceCommitTest: the 1st event must be compositionstart #1");
+  is(events[1].type, "compositionupdate",
+     "runForceCommitTest: the 2nd event must be compositionupdate #1");
+  is(events[2].type, "text",
+     "runForceCommitTest: the 3rd event must be text #1");
+  is(events[3].type, "input",
+     "runForceCommitTest: the 4th event must be input #1");
+
+  events = [];
+  synthesizeMouseAtCenter(textarea, {});
+
+  is(events.length, 3,
+     "runForceCommitTest: wrong event count #2");
+  is(events[0].type, "text",
+     "runForceCommitTest: the 1st event must be text #2");
+  is(events[1].type, "compositionend",
+     "runForceCommitTest: the 2nd event must be compositionend #2");
+  is(events[2].type, "input",
+     "runForceCommitTest: the 3rd event must be input #2");
+  is(events[1].data, "\u306E",
+     "runForceCommitTest: compositionend has wrong data #2");
+  is(events[0].target, textarea,
+     "runForceCommitTest: The 1st event was fired on wrong event target #2");
+  is(events[1].target, textarea,
+     "runForceCommitTest: The 2nd event was fired on wrong event target #2");
+  is(events[2].target, textarea,
+     "runForceCommitTest: The 3rd event was fired on wrong event target #2");
+  ok(!getEditorIMESupport(textarea).isComposing,
+     "runForceCommitTest: the textarea still has composition #2");
+  is(textarea.value, "\u306E",
+     "runForceCommitTest: the textarea doesn't have the committed text #2");
+
+  // Make the composition in textarea commit by click in another editor (input)
+  textarea.focus();
+  textarea.value = "";
+  input.value = "";
+
+  synthesizeComposition({ type: "compositionstart" });
+
+  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
+  synthesizeText(
+    { "composition":
+      { "string": "\u306E",
+        "clauses":
+        [
+          { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    });
+
+  events = [];
+  synthesizeMouseAtCenter(input, {});
+
+  is(events.length, 3,
+     "runForceCommitTest: wrong event count #3");
+  is(events[0].type, "text",
+     "runForceCommitTest: the 1st event must be text #3");
+  is(events[1].type, "compositionend",
+     "runForceCommitTest: the 2nd event must be compositionend #3");
+  is(events[2].type, "input",
+     "runForceCommitTest: the 3rd event must be input #3");
+  is(events[1].data, "\u306E",
+     "runForceCommitTest: compositionend has wrong data #3");
+  is(events[0].target, textarea,
+     "runForceCommitTest: The 1st event was fired on wrong event target #3");
+  is(events[1].target, textarea,
+     "runForceCommitTest: The 2nd event was fired on wrong event target #3");
+  is(events[2].target, textarea,
+     "runForceCommitTest: The 3rd event was fired on wrong event target #3");
+  ok(!getEditorIMESupport(textarea).isComposing,
+     "runForceCommitTest: the textarea still has composition #3");
+  ok(!getEditorIMESupport(input).isComposing,
+     "runForceCommitTest: the input has composition #3");
+  is(textarea.value, "\u306E",
+     "runForceCommitTest: the textarea doesn't have the committed text #3");
+  is(input.value, "",
+     "runForceCommitTest: the input has the committed text? #3");
+
+  // Make the composition in textarea commit by blur()
+  textarea.focus();
+  textarea.value = "";
+
+  synthesizeComposition({ type: "compositionstart" });
+
+  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
+  synthesizeText(
+    { "composition":
+      { "string": "\u306E",
+        "clauses":
+        [
+          { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    });
+
+  events = [];
+  textarea.blur();
+
+  is(events.length, 3,
+     "runForceCommitTest: wrong event count #4");
+  is(events[0].type, "text",
+     "runForceCommitTest: the 1st event must be text #4");
+  is(events[1].type, "compositionend",
+     "runForceCommitTest: the 2nd event must be compositionend #4");
+  is(events[2].type, "input",
+     "runForceCommitTest: the 3rd event must be input #4");
+  is(events[1].data, "\u306E",
+     "runForceCommitTest: compositionend has wrong data #4");
+  is(events[0].target, textarea,
+     "runForceCommitTest: The 1st event was fired on wrong event target #4");
+  is(events[1].target, textarea,
+     "runForceCommitTest: The 2nd event was fired on wrong event target #4");
+  is(events[2].target, textarea,
+     "runForceCommitTest: The 3rd event was fired on wrong event target #4");
+  ok(!getEditorIMESupport(textarea).isComposing,
+     "runForceCommitTest: the textarea still has composition #4");
+  is(textarea.value, "\u306E",
+     "runForceCommitTest: the textarea doesn't have the committed text #4");
+
+  // Make the composition in textarea commit by input.focus()
+  textarea.focus();
+  textarea.value = "";
+  input.value = "";
+
+  synthesizeComposition({ type: "compositionstart" });
+
+  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
+  synthesizeText(
+    { "composition":
+      { "string": "\u306E",
+        "clauses":
+        [
+          { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    });
+
+  events = [];
+  input.focus();
+
+  is(events.length, 3,
+     "runForceCommitTest: wrong event count #5");
+  is(events[0].type, "text",
+     "runForceCommitTest: the 1st event must be text #5");
+  is(events[1].type, "compositionend",
+     "runForceCommitTest: the 2nd event must be compositionend #5");
+  is(events[2].type, "input",
+     "runForceCommitTest: the 3rd event must be input #5");
+  is(events[1].data, "\u306E",
+     "runForceCommitTest: compositionend has wrong data #5");
+  is(events[0].target, textarea,
+     "runForceCommitTest: The 1st event was fired on wrong event target #5");
+  is(events[1].target, textarea,
+     "runForceCommitTest: The 2nd event was fired on wrong event target #5");
+  is(events[2].target, textarea,
+     "runForceCommitTest: The 3rd event was fired on wrong event target #5");
+  ok(!getEditorIMESupport(textarea).isComposing,
+     "runForceCommitTest: the textarea still has composition #5");
+  ok(!getEditorIMESupport(input).isComposing,
+     "runForceCommitTest: the input has composition #5");
+  is(textarea.value, "\u306E",
+     "runForceCommitTest: the textarea doesn't have the committed text #5");
+  is(input.value, "",
+     "runForceCommitTest: the input has the committed text? #5");
+
+  // Make the composition in textarea commit by click in another document's editor
+  textarea.focus();
+  textarea.value = "";
+  textareaInFrame.value = "";
+
+  synthesizeComposition({ type: "compositionstart" });
+
+  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
+  synthesizeText(
+    { "composition":
+      { "string": "\u306E",
+        "clauses":
+        [
+          { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    });
+
+  events = [];
+  synthesizeMouseAtCenter(textareaInFrame, {}, iframe.contentWindow);
+
+  is(events.length, 3,
+     "runForceCommitTest: wrong event count #6");
+  is(events[0].type, "text",
+     "runForceCommitTest: the 1st event must be text #6");
+  is(events[1].type, "compositionend",
+     "runForceCommitTest: the 2nd event must be compositionend #6");
+  is(events[2].type, "input",
+     "runForceCommitTest: the 3rd event must be input #6");
+  is(events[1].data, "\u306E",
+     "runForceCommitTest: compositionend has wrong data #6");
+  is(events[0].target, textarea,
+     "runForceCommitTest: The 1st event was fired on wrong event target #6");
+  is(events[1].target, textarea,
+     "runForceCommitTest: The 2nd event was fired on wrong event target #6");
+  is(events[2].target, textarea,
+     "runForceCommitTest: The 3rd event was fired on wrong event target #6");
+  ok(!getEditorIMESupport(textarea).isComposing,
+     "runForceCommitTest: the textarea still has composition #6");
+  ok(!getEditorIMESupport(textareaInFrame).isComposing,
+     "runForceCommitTest: the textarea in frame has composition #6");
+  is(textarea.value, "\u306E",
+     "runForceCommitTest: the textarea doesn't have the committed text #6");
+  is(textareaInFrame.value, "",
+     "runForceCommitTest: the textarea in frame has the committed text? #6");
+
+  // Make the composition in textarea commit by another document's editor's focus()
+  textarea.focus();
+  textarea.value = "";
+  textareaInFrame.value = "";
+
+  synthesizeComposition({ type: "compositionstart" });
+
+  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
+  synthesizeText(
+    { "composition":
+      { "string": "\u306E",
+        "clauses":
+        [
+          { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    });
+
+  events = [];
+  textareaInFrame.focus();
+
+  is(events.length, 3,
+     "runForceCommitTest: wrong event count #7");
+  is(events[0].type, "text",
+     "runForceCommitTest: the 1st event must be text #7");
+  is(events[1].type, "compositionend",
+     "runForceCommitTest: the 2nd event must be compositionend #7");
+  is(events[2].type, "input",
+     "runForceCommitTest: the 3rd event must be input #7");
+  is(events[1].data, "\u306E",
+     "runForceCommitTest: compositionend has wrong data #7");
+  is(events[0].target, textarea,
+     "runForceCommitTest: The 1st event was fired on wrong event target #7");
+  is(events[1].target, textarea,
+     "runForceCommitTest: The 2nd event was fired on wrong event target #7");
+  is(events[2].target, textarea,
+     "runForceCommitTest: The 3rd event was fired on wrong event target #7");
+  ok(!getEditorIMESupport(textarea).isComposing,
+     "runForceCommitTest: the textarea still has composition #7");
+  ok(!getEditorIMESupport(textareaInFrame).isComposing,
+     "runForceCommitTest: the textarea in frame has composition #7");
+  is(textarea.value, "\u306E",
+     "runForceCommitTest: the textarea doesn't have the committed text #7");
+  is(textareaInFrame.value, "",
+     "runForceCommitTest: the textarea in frame has the committed text? #7");
+
+  // Make the composition in a textarea commit by click in another editable document
+  textarea.focus();
+  textarea.value = "";
+  iframe2.contentDocument.body.innerHTML = "Text in the Body";
+  var iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
+
+  synthesizeComposition({ type: "compositionstart" });
+
+  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
+  synthesizeText(
+    { "composition":
+      { "string": "\u306E",
+        "clauses":
+        [
+          { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    });
+
+  events = [];
+  synthesizeMouseAtCenter(iframe2.contentDocument.body, {}, iframe2.contentWindow);
+
+  is(events.length, 3,
+     "runForceCommitTest: wrong event count #8");
+  is(events[0].type, "text",
+     "runForceCommitTest: the 1st event must be text #8");
+  is(events[1].type, "compositionend",
+     "runForceCommitTest: the 2nd event must be compositionend #8");
+  is(events[2].type, "input",
+     "runForceCommitTest: the 3rd event must be input #8");
+  is(events[1].data, "\u306E",
+     "runForceCommitTest: compositionend has wrong data #8");
+  is(events[0].target, textarea,
+     "runForceCommitTest: The 1st event was fired on wrong event target #8");
+  is(events[1].target, textarea,
+     "runForceCommitTest: The 2nd event was fired on wrong event target #8");
+  is(events[2].target, textarea,
+     "runForceCommitTest: The 3rd event was fired on wrong event target #8");
+  ok(!getEditorIMESupport(textarea).isComposing,
+     "runForceCommitTest: the textarea still has composition #8");
+  ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
+     "runForceCommitTest: the editable document has composition #8");
+  is(textarea.value, "\u306E",
+     "runForceCommitTest: the textarea doesn't have the committed text #8");
+  is(iframe2.contentDocument.body.innerHTML, iframe2BodyInnerHTML,
+     "runForceCommitTest: the editable document has the committed text? #8");
+
+  // Make the composition in an editable document commit by click in it
+  iframe2.contentWindow.focus();
+  iframe2.contentDocument.body.innerHTML = "Text in the Body";
+  iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
+
+  synthesizeComposition({ type: "compositionstart" }, iframe2.contentWindow);
+
+  synthesizeComposition({ type: "compositionupdate", data: "\u306E" }, iframe2.contentWindow);
+  synthesizeText(
+    { "composition":
+      { "string": "\u306E",
+        "clauses":
+        [
+          { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    }, iframe2.contentWindow);
+
+  events = [];
+  synthesizeMouseAtCenter(iframe2.contentDocument.body, {}, iframe2.contentWindow);
+
+  is(events.length, 3,
+     "runForceCommitTest: wrong event count #9");
+  is(events[0].type, "text",
+     "runForceCommitTest: the 1st event must be text #9");
+  is(events[1].type, "compositionend",
+     "runForceCommitTest: the 2nd event must be compositionend #9");
+  is(events[2].type, "input",
+     "runForceCommitTest: the 3rd event must be input #9");
+  is(events[1].data, "\u306E",
+     "runForceCommitTest: compositionend has wrong data #9");
+  is(events[0].target, iframe2.contentDocument.body,
+     "runForceCommitTest: The 1st event was fired on wrong event target #9");
+  is(events[1].target, iframe2.contentDocument.body,
+     "runForceCommitTest: The 2nd event was fired on wrong event target #9");
+  is(events[2].target, iframe2.contentDocument.body,
+     "runForceCommitTest: The 3rd event was fired on wrong event target #9");
+  ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
+     "runForceCommitTest: the editable document still has composition #9");
+  ok(iframe2.contentDocument.body.innerHTML != iframe2BodyInnerHTML &&
+     iframe2.contentDocument.body.innerHTML.indexOf("\u306E") >= 0,
+     "runForceCommitTest: the editable document doesn't have the committed text #9");
+
+  // Make the composition in an editable document commit by click in another document's editor
+  textarea.value = "";
+  iframe2.contentWindow.focus();
+  iframe2.contentDocument.body.innerHTML = "Text in the Body";
+  iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
+
+  synthesizeComposition({ type: "compositionstart" }, iframe2.contentWindow);
+
+  synthesizeComposition({ type: "compositionupdate", data: "\u306E" }, iframe2.contentWindow);
+  synthesizeText(
+    { "composition":
+      { "string": "\u306E",
+        "clauses":
+        [
+          { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    }, iframe2.contentWindow);
+
+  events = [];
+  synthesizeMouseAtCenter(textarea, {});
+
+  is(events.length, 3,
+     "runForceCommitTest: wrong event count #10");
+  is(events[0].type, "text",
+     "runForceCommitTest: the 1st event must be text #10");
+  is(events[1].type, "compositionend",
+     "runForceCommitTest: the 2nd event must be compositionend #10");
+  is(events[2].type, "input",
+     "runForceCommitTest: the 3rd event must be input #10");
+  is(events[1].data, "\u306E",
+     "runForceCommitTest: compositionend has wrong data #10");
+  is(events[0].target, iframe2.contentDocument.body,
+     "runForceCommitTest: The 1st event was fired on wrong event target #10");
+  is(events[1].target, iframe2.contentDocument.body,
+     "runForceCommitTest: The 2nd event was fired on wrong event target #10");
+  is(events[2].target, iframe2.contentDocument.body,
+     "runForceCommitTest: The 3rd event was fired on wrong event target #10");
+  ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
+     "runForceCommitTest: the editable document still has composition #10");
+  ok(!getEditorIMESupport(textarea).isComposing,
+     "runForceCommitTest: the textarea has composition #10");
+  ok(iframe2.contentDocument.body.innerHTML != iframe2BodyInnerHTML &&
+     iframe2.contentDocument.body.innerHTML.indexOf("\u306E") >= 0,
+     "runForceCommitTest: the editable document doesn't have the committed text #10");
+  is(textarea.value, "",
+     "runForceCommitTest: the textarea has the committed text? #10");
+
+  // Make the composition in an editable document commit by click in the another editable document
+  iframe2.contentWindow.focus();
+  iframe2.contentDocument.body.innerHTML = "Text in the Body";
+  iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
+  iframe3.contentDocument.body.innerHTML = "Text in the Body";
+  iframe3BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
+
+  synthesizeComposition({ type: "compositionstart" }, iframe2.contentWindow);
+
+  synthesizeComposition({ type: "compositionupdate", data: "\u306E" }, iframe2.contentWindow);
+  synthesizeText(
+    { "composition":
+      { "string": "\u306E",
+        "clauses":
+        [
+          { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    }, iframe2.contentWindow);
+
+  events = [];
+  synthesizeMouseAtCenter(iframe3.contentDocument.body, {}, iframe3.contentWindow);
+
+  is(events.length, 3,
+     "runForceCommitTest: wrong event count #11");
+  is(events[0].type, "text",
+     "runForceCommitTest: the 1st event must be text #11");
+  is(events[1].type, "compositionend",
+     "runForceCommitTest: the 2nd event must be compositionend #11");
+  is(events[2].type, "input",
+     "runForceCommitTest: the 3rd event must be input #11");
+  is(events[1].data, "\u306E",
+     "runForceCommitTest: compositionend has wrong data #11");
+  is(events[0].target, iframe2.contentDocument.body,
+     "runForceCommitTest: The 1st event was fired on wrong event target #11");
+  is(events[1].target, iframe2.contentDocument.body,
+     "runForceCommitTest: The 2nd event was fired on wrong event target #11");
+  is(events[2].target, iframe2.contentDocument.body,
+     "runForceCommitTest: The 3rd event was fired on wrong event target #11");
+  ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
+     "runForceCommitTest: the editable document still has composition #11");
+  ok(!getHTMLEditorIMESupport(iframe3.contentWindow).isComposing,
+     "runForceCommitTest: the other editable document has composition #11");
+  ok(iframe2.contentDocument.body.innerHTML != iframe2BodyInnerHTML &&
+     iframe2.contentDocument.body.innerHTML.indexOf("\u306E") >= 0,
+     "runForceCommitTest: the editable document doesn't have the committed text #11");
+  is(iframe3.contentDocument.body.innerHTML, iframe3BodyInnerHTML,
+     "runForceCommitTest: the other editable document has the committed text? #11");
+
+  window.removeEventListener("compositionstart", eventHandler, true);
+  window.removeEventListener("compositionupdate", eventHandler, true);
+  window.removeEventListener("compositionend", eventHandler, true);
+  window.removeEventListener("input", eventHandler, true);
+  window.removeEventListener("text", eventHandler, true);
+}
+
+function runRemoveContentTest(aCallback)
+{
+  var events = [];
+  function eventHandler(aEvent)
+  {
+    events.push(aEvent);
+  }
+  textarea.addEventListener("compositionstart", eventHandler, true);
+  textarea.addEventListener("compositionupdate", eventHandler, true);
+  textarea.addEventListener("compositionend", eventHandler, true);
+  textarea.addEventListener("input", eventHandler, true);
+  textarea.addEventListener("text", eventHandler, true);
+
+  textarea.focus();
+  textarea.value = "";
+
+  synthesizeComposition({ type: "compositionstart" });
+
+  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
+  synthesizeText(
+    { "composition":
+      { "string": "\u306E",
+        "clauses":
+        [
+          { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    });
+
+  var nextSibling = textarea.nextSibling;
+  var parent = textarea.parentElement;
+
+  events = [];
+  parent.removeChild(textarea);
+
+  hitEventLoop(function () {
+    // XXX Currently, "input" event isn't fired on removed content.
+    is(events.length, 3,
+       "runRemoveContentTest: wrong event count #1");
+    is(events[0].type, "compositionupdate",
+       "runRemoveContentTest: the 1st event must be compositionupdate #1");
+    is(events[1].type, "text",
+       "runRemoveContentTest: the 2nd event must be text #1");
+    is(events[2].type, "compositionend",
+       "runRemoveContentTest: the 3rd event must be compositionend #1");
+    is(events[0].data, "",
+       "runRemoveContentTest: compositionupdate has wrong data #1");
+    is(events[2].data, "",
+       "runRemoveContentTest: compositionend has wrong data #1");
+    is(events[0].target, textarea,
+       "runRemoveContentTest: The 1st event was fired on wrong event target #1");
+    is(events[1].target, textarea,
+       "runRemoveContentTest: The 2nd event was fired on wrong event target #1");
+    is(events[2].target, textarea,
+       "runRemoveContentTest: The 3rd event was fired on wrong event target #1");
+    ok(!getEditorIMESupport(textarea).isComposing,
+       "runRemoveContentTest: the textarea still has composition #1");
+    todo_is(textarea.value, "",
+       "runRemoveContentTest: the textarea has the committed text? #1");
+
+    parent.insertBefore(textarea, nextSibling);
+
+    textarea.focus();
+    textarea.value = "";
+
+    synthesizeComposition({ type: "compositionstart" });
+
+    events = [];
+    parent.removeChild(textarea);
+
+    hitEventLoop(function () {
+      // XXX Currently, "input" event isn't fired on removed content.
+      is(events.length, 1,
+         "runRemoveContentTest: wrong event count #2");
+      is(events[0].type, "compositionend",
+         "runRemoveContentTest: the 1st event must be compositionend #2");
+      is(events[0].data, "",
+         "runRemoveContentTest: compositionupdate has wrong data #2");
+      is(events[0].target, textarea,
+         "runRemoveContentTest: The 1st event was fired on wrong event target #2");
+      ok(!getEditorIMESupport(textarea).isComposing,
+         "runRemoveContentTest: the textarea still has composition #2");
+      is(textarea.value, "",
+         "runRemoveContentTest: the textarea has the committed text? #2");
+
+      parent.insertBefore(textarea, nextSibling);
+
+      textarea.removeEventListener("compositionstart", eventHandler, true);
+      textarea.removeEventListener("compositionupdate", eventHandler, true);
+      textarea.removeEventListener("compositionend", eventHandler, true);
+      textarea.removeEventListener("input", eventHandler, true);
+      textarea.removeEventListener("text", eventHandler, true);
+
+      SimpleTest.executeSoon(aCallback);
+    }, 50);
+  }, 50);
+}
+
 function runTestOnAnotherContext(aPanelOrFrame, aFocusedEditor, aTestName)
 {
   aFocusedEditor.value = "";
 
   var editorRect = synthesizeQueryEditorRect();
   if (!checkQueryContentResult(editorRect, aTestName + ": editorRect")) {
     return;
   }
@@ -2349,17 +2979,16 @@ function runTestOnAnotherContext(aPanelO
     return;
   }
   checkRectContainsRect(textRect, editorRect, aTestName + ":testRect");
   checkRectContainsRect(caretRect, editorRect, aTestName + ":caretRect");
 }
 
 function runFrameTest()
 {
-  var textareaInFrame = iframe.contentDocument.getElementById("textarea");
   textareaInFrame.focus();
   runTestOnAnotherContext(iframe, textareaInFrame, "runFrameTest");
   runCharAtPointTest(textareaInFrame, "textarea in the iframe");
 }
 
 var gPanelShown = false;
 var gPanelFocused = false;
 function onPanelShown(aEvent)
@@ -2714,23 +3343,28 @@ function runMaxLengthTest()
   if (!checkContent("\u30E9", kDesc, "#3-4") ||
       !checkSelection(1 + 0, "", kDesc, "#3-4")) {
     return;
   }
 }
 
 function runTest()
 {
+  textareaInFrame = iframe.contentDocument.getElementById("textarea");
+
   runUndoRedoTest();
   runCompositionTest();
   runCompositionEventTest();
   runCharAtPointTest(textarea, "textarea in the document");
   runCharAtPointAtOutsideTest();
   runBug722639Test();
-  runFrameTest();
-  runPanelTest();
-  runMaxLengthTest();
+  runForceCommitTest();
+  runRemoveContentTest(function () {
+    runFrameTest();
+    runPanelTest();
+    runMaxLengthTest();
+  });
 }
 
 ]]>
 </script>
 
 </window>