Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  window_nsITextInputProcessor.xhtml   Sprache: unbekannt

 
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
                 type="text/css"?>
<window title="Testing nsITextInputProcessor behavior"
  xmlns:html="http://www.w3.org/1999/xhtml"
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  onunload="onunload();">
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<body  xmlns="http://www.w3.org/1999/xhtml">
<div id="display">
<input id="input" type="text"/><input id="anotherInput" type="text"/><br/>
<textarea></textarea>
<iframe id="iframe" width="300" height="150"
        src="data:text/html,<textarea id='textarea' cols='20' rows='4'></textarea>"></iframe><br/>
<div contenteditable=""><br/></div>
</div>
<div id="content" style="display: none">

</div>
<pre id="test">
</pre>
</body>

<script class="testbody" type="application/javascript">
<![CDATA[

var SimpleTest = window.arguments[0].SimpleTest;

SimpleTest.waitForFocus(runTests, window);

function getHTMLEditor(aWindow) {
  return SpecialPowers.wrap(aWindow).docShell.editingSession?.getEditorForWindow(aWindow);
}

function ok(aCondition, aMessage)
{
  SimpleTest.ok(aCondition, aMessage);
}

function is(aLeft, aRight, aMessage)
{
  SimpleTest.is(aLeft, aRight, aMessage);
}

function isnot(aLeft, aRight, aMessage)
{
  SimpleTest.isnot(aLeft, aRight, aMessage);
}

function todo_is(aLeft, aRight, aMessage)
{
  SimpleTest.todo_is(aLeft, aRight, aMessage);
}

function info(aMessage) {
  SimpleTest.info(aMessage);
}

function finish()
{
  window.close();
}

function onunload()
{
  SimpleTest.finish();
}

function checkInputEvent(aEvent, aCancelable, aIsComposing, aInputType, aData, aDescription) {
  if (aEvent.type !== "input" && aEvent.type !== "beforeinput") {
    console.trace();
    throw new Error(`${aDescription}"${aEvent.type}" is not InputEvent`);
  }
  ok(InputEvent.isInstance(aEvent), `${aDescription}"${aEvent.type}" event should be dispatched with InputEvent interface`);
  is(aEvent.cancelable, aCancelable, `${aDescription}"${aEvent.type}" event should ${aCancelable ? "be" : "not be"} cancelable`);
  is(aEvent.bubbles, true, `${aDescription}"${aEvent.type}" event should always bubble`);
  is(aEvent.isComposing, aIsComposing, `${aDescription}isComposing of "${aEvent.type}" event should be ${aIsComposing}`);
  is(aEvent.inputType, aInputType, `${aDescription}inputType of "${aEvent.type}" event should be "${aInputType}"`);
  is(aEvent.data, aData, `${aDescription}data of "${aEvent.type}" event should be "${aData}"`);
  is(aEvent.dataTransfer, null, `${aDescription}dataTransfer of "${aEvent.type}" event should be null`);
  is(aEvent.getTargetRanges().length, 0, `${aDescription}getTargetRanges() of "${aEvent.type}" event should return empty array`);
}

const kIsMac = (navigator.platform.indexOf("Mac") == 0);

const iframe = document.getElementById("iframe");
let childWindow = iframe.contentWindow;
let textareaInFrame;
let input = document.getElementById("input");
const textarea = document.querySelector("textarea");
const otherWindow = window.arguments[0];
const otherDocument = otherWindow.document;
const inputInChildWindow = otherDocument.getElementById("input");
const contenteditable = document.querySelector("div[contenteditable]");
const { AppConstants } = ChromeUtils.importESModule(
  "resource://gre/modules/AppConstants.sys.mjs"
);
const kLF = "\n";
const kExpectInputBeforeCompositionEnd = SpecialPowers.getBoolPref("dom.input_events.dispatch_before_compositionend");

function getNativeText(aXPText)
{
  if (kLF == "\n") {
    return aXPText;
  }
  return aXPText.replace(/\n/g, kLF);
}

function createTIP()
{
  return Cc["@mozilla.org/text-input-processor;1"].
           createInstance(Ci.nsITextInputProcessor);
}

function runBeginInputTransactionMethodTests()
{
  var description = "runBeginInputTransactionMethodTests: ";
  input.value = "";
  input.focus();

  var simpleCallback = function (aTIP, aNotification)
  {
    switch (aNotification.type) {
      case "request-to-commit":
        aTIP.commitComposition();
        break;
      case "request-to-cancel":
        aTIP.cancelComposition();
        break;
    }
    return true;
  };

  var TIP1 = createTIP();
  var TIP2 = createTIP();
  isnot(TIP1, TIP2,
        description + "TIP instances should be different");

  // beginInputTransaction() and beginInputTransactionForTests() can take ownership if there is no composition.
  ok(TIP1.beginInputTransaction(window, simpleCallback),
     description + "TIP1.beginInputTransaction(window) should succeed because there is no composition");
  ok(TIP1.beginInputTransactionForTests(window),
     description + "TIP1.beginInputTransactionForTests(window) should succeed because there is no composition");
  ok(TIP2.beginInputTransaction(window, simpleCallback),
     description + "TIP2.beginInputTransaction(window) should succeed because there is no composition");
  ok(TIP2.beginInputTransactionForTests(window),
     description + "TIP2.beginInputTransactionForTests(window) should succeed because there is no composition");

  // Start composition with TIP1, then, other TIPs cannot take ownership during a composition.
  ok(TIP1.beginInputTransactionForTests(window),
     description + "TIP1.beginInputTransactionForTests() should succeed because there is no composition");
  var composingStr = "foo";
  TIP1.setPendingCompositionString(composingStr);
  TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
  ok(TIP1.flushPendingComposition(),
     description + "TIP1.flushPendingComposition() should return true becuase it should be valid composition");
  is(input.value, composingStr,
     description + "The input element should have composing string");

  // Composing nsITextInputProcessor instance shouldn't allow initialize it again.
  try {
    TIP1.beginInputTransaction(window, simpleCallback);
    ok(false,
       "TIP1.beginInputTransaction(window) should cause throwing an exception because it's composing with different purpose");
  } catch (e) {
    ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
       description + "TIP1.beginInputTransaction(window) should cause throwing an exception including NS_ERROR_ALREADY_INITIALIZED because it's composing for tests");
  }
  try {
    TIP1.beginInputTransactionForTests(otherWindow);
    ok(false,
       "TIP1.beginInputTransactionForTests(otherWindow) should cause throwing an exception because it's composing on different window");
  } catch (e) {
    ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
       description + "TIP1.beginInputTransaction(otherWindow) should cause throwing an exception including NS_ERROR_ALREADY_INITIALIZED because it's composing on this window");
  }
  ok(TIP1.beginInputTransactionForTests(window),
     description + "TIP1.beginInputTransactionForTests(window) should succeed because TextEventDispatcher was initialized with same purpose");
  ok(TIP1.beginInputTransactionForTests(childWindow),
     description + "TIP1.beginInputTransactionForTests(childWindow) should succeed because TextEventDispatcher was initialized with same purpose and is shared by window and childWindow");
  ok(!TIP2.beginInputTransaction(window, simpleCallback),
     description + "TIP2.beginInputTransaction(window) should not succeed because there is composition synthesized by TIP1");
  ok(!TIP2.beginInputTransactionForTests(window),
     description + "TIP2.beginInputTransactionForTests(window) should not succeed because there is composition synthesized by TIP1");
  ok(!TIP2.beginInputTransaction(childWindow, simpleCallback),
     description + "TIP2.beginInputTransaction(childWindow) should not succeed because there is composition synthesized by TIP1");
  ok(!TIP2.beginInputTransactionForTests(childWindow),
     description + "TIP2.beginInputTransactionForTests(childWindow) should not succeed because there is composition synthesized by TIP1");
  ok(TIP2.beginInputTransaction(otherWindow, simpleCallback),
     description + "TIP2.beginInputTransaction(otherWindow) should succeed because there is composition synthesized by TIP1 but it's in other window");
  ok(TIP2.beginInputTransactionForTests(otherWindow),
     description + "TIP2.beginInputTransactionForTests(otherWindow) should succeed because there is composition synthesized by TIP1 but it's in other window");

  // Let's confirm that the composing string is NOT committed by above tests.
  TIP1.commitComposition();
  is(input.value, composingStr,
     description + "TIP1.commitString() without specifying commit string should commit current composition with the last composing string");
  ok(!TIP1.hasComposition,
     description + "TIP1.commitString() without specifying commit string should've end composition");

  ok(TIP1.beginInputTransaction(window, simpleCallback),
     description + "TIP1.beginInputTransaction() should succeed because there is no composition #2");
  ok(TIP1.beginInputTransactionForTests(window),
     description + "TIP1.beginInputTransactionForTests() should succeed because there is no composition #2");
  ok(TIP2.beginInputTransactionForTests(window),
     description + "TIP2.beginInputTransactionForTests() should succeed because the composition was already committed #2");

  // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during startComposition().
  var events = [];
  input.addEventListener("compositionstart", function (aEvent) {
    events.push(aEvent);
    // eslint-disable-next-line no-caller
    input.removeEventListener(aEvent.type, arguments.callee);
    ok(!TIP2.beginInputTransaction(window, simpleCallback),
       description + "TIP2 shouldn't be able to begin input transaction from compositionstart event handler during TIP1.startComposition();");
  });
  TIP1.beginInputTransaction(window, simpleCallback);
  TIP1.startComposition();
  is(events.length, 1,
     description + "compositionstart event should be fired by TIP1.startComposition()");
  TIP1.cancelComposition();

  // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during flushPendingComposition().
  events = [];
  input.addEventListener("compositionstart", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransaction(window, simpleCallback),
       description + "TIP2 shouldn't be able to begin input transaction from compositionstart event handler during a call of TIP1.flushPendingComposition();");
  }, {once: true});
  input.addEventListener("compositionupdate", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransaction(window, simpleCallback),
       description + "TIP2 shouldn't be able to begin input transaction from compositionupdate event handler during a call of TIP1.flushPendingComposition();");
  }, {once: true});
  input.addEventListener("text", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransaction(window, simpleCallback),
       description + "TIP2 shouldn't be able to begin input transaction from text event handler during a call of TIP1.flushPendingComposition();");
  }, {once: true});
  input.addEventListener("beforeinput", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransaction(window, simpleCallback),
       description + "TIP2 shouldn't be able to begin input transaction from beforeinput event handler during a call of TIP1.flushPendingComposition();");
  }, {once: true});
  input.addEventListener("input", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransaction(window, simpleCallback),
       description + "TIP2 shouldn't be able to begin input transaction from input event handler during a call of TIP1.flushPendingComposition();");
  }, {once: true});
  TIP1.beginInputTransaction(window, simpleCallback);
  TIP1.setPendingCompositionString(composingStr);
  TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
  TIP1.flushPendingComposition();
  is(events.length, 5,
     description + "compositionstart, compositionupdate, text, beforeinput and input events should be fired by TIP1.flushPendingComposition()");
  is(events[0].type, "compositionstart",
     description + "events[0] should be compositionstart");
  is(events[1].type, "compositionupdate",
     description + "events[1] should be compositionupdate");
  is(events[2].type, "text",
     description + "events[2] should be text");
  is(events[3].type, "beforeinput",
     description + "events[3] should be beforeinput");
  checkInputEvent(events[3], false, true, "insertCompositionText", composingStr, description);
  is(events[4].type, "input",
     description + "events[4] should be input");
  checkInputEvent(events[4], false, true, "insertCompositionText", composingStr, description);
  TIP1.cancelComposition();

  // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during commitComposition().
  (() => {
    events = [];
    TIP1.beginInputTransaction(window, simpleCallback);
    TIP1.setPendingCompositionString(composingStr);
    TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
    TIP1.flushPendingComposition();
    input.addEventListener("text", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction from text event handler during a call of TIP1.commitComposition();");
    }, {once: true});
    input.addEventListener("compositionend", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction from compositionend event handler during a call of TIP1.commitComposition();");
    }, {once: true});
    input.addEventListener("beforeinput", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction from beforeinput event handler during a call of TIP1.commitComposition();");
    }, {once: true});
    function onInput(aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction from input event handler during a call of TIP1.commitComposition();");
    }
    input.addEventListener("input", onInput);
    TIP1.commitComposition();
    is(events.length, kExpectInputBeforeCompositionEnd ? 5 : 4,
      description + "text, beforeinput, compositionend and input events should be fired by TIP1.commitComposition()");
    let index = -1;
    is(events[++index].type, "text",
      `${description}events[${index}] should be text`);
    is(events[++index].type, "beforeinput",
      `${description}events[${index}] should be beforeinput`);
    checkInputEvent(events[index], false, true, "insertCompositionText", composingStr, description);
    if (kExpectInputBeforeCompositionEnd) {
      is(events[++index].type, "input",
        `${description}events[${index}] should be input`);
      checkInputEvent(events[index], false, true, "insertCompositionText", composingStr, description);
    }
    is(events[++index].type, "compositionend",
      `${description}events[${index}] should be compositionend`);
    is(events[++index].type, "input",
      `${description}events[${index}] should be input`);
    checkInputEvent(events[index], false, false, "insertCompositionText", composingStr, description);
    input.removeEventListener("input", onInput);
  })();

  // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during commitCompositionWith("bar").
  (() => {
    events = [];
    input.addEventListener("compositionstart", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction from compositionstart event handler during TIP1.commitCompositionWith(\"bar\");");
    }, {once: true});
    input.addEventListener("compositionupdate", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction during compositionupdate event handler TIP1.commitCompositionWith(\"bar\");");
    }, {once: true});
    input.addEventListener("text", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction during text event handler TIP1.commitCompositionWith(\"bar\");");
    }, {once: true});
    input.addEventListener("compositionend", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction during compositionend event handler TIP1.commitCompositionWith(\"bar\");");
    }, {once: true});
    input.addEventListener("beforeinput", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction during beforeinput event handler TIP1.commitCompositionWith(\"bar\");");
    }, {once: true});
    function onInput(aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction during input event handler TIP1.commitCompositionWith(\"bar\");");
    }
    input.addEventListener("input", onInput);
    TIP1.beginInputTransaction(window, simpleCallback);
    TIP1.commitCompositionWith("bar");
    is(events.length, kExpectInputBeforeCompositionEnd ? 7 : 6,
      description + "compositionstart, compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.commitCompositionWith(\"bar\")");
    let index = -1;
    is(events[++index].type, "compositionstart",
      `${description}events[${index}] should be compositionstart`);
    is(events[++index].type, "compositionupdate",
      `${description}events[${index}] should be compositionupdate`);
    is(events[++index].type, "text",
      `${description}events[${index}] should be text`);
    is(events[++index].type, "beforeinput",
      `${description}events[${index}] should be beforeinput`);
    checkInputEvent(events[3], false, true, "insertCompositionText", "bar", description);
    if (kExpectInputBeforeCompositionEnd) {
      is(events[++index].type, "input",
        `${description}events[${index}] should be input`);
      checkInputEvent(events[index], false, true, "insertCompositionText", "bar", description);
    }
    is(events[++index].type, "compositionend",
      `${description}events[${index}] should be compositionend`);
    is(events[++index].type, "input",
      `${description}events[${index}] should be input`);
    checkInputEvent(events[index], false, false, "insertCompositionText", "bar", description);
    input.removeEventListener("input", onInput);
  })();

  // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during cancelComposition().
  (() => {
    events = [];
    TIP1.beginInputTransaction(window, simpleCallback);
    TIP1.setPendingCompositionString(composingStr);
    TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
    TIP1.flushPendingComposition();
    input.addEventListener("compositionupdate", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction from compositionupdate event handler during a call of TIP1.cancelComposition();");
    }, {once: true});
    input.addEventListener("text", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction from text event handler during a call of TIP1.cancelComposition();");
    }, {once: true});
    input.addEventListener("compositionend", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction from compositionend event handler during a call of TIP1.cancelComposition();");
    }, {once: true});
    input.addEventListener("beforeinput", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction from beforeinput event handler during a call of TIP1.cancelComposition();");
    }, {once: true});
    function onInput(aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransaction(window, simpleCallback),
        description + "TIP2 shouldn't be able to begin input transaction from input event handler during a call of TIP1.cancelComposition();");
    }
    input.addEventListener("input", onInput);
    TIP1.cancelComposition();
    is(events.length, kExpectInputBeforeCompositionEnd ? 6 : 5,
      description + "compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.cancelComposition()");
    let index = -1;
    is(events[++index].type, "compositionupdate",
      `${description}events[${index}] should be compositionupdate`);
    is(events[++index].type, "text",
      `${description}events[${index}] should be text`);
    is(events[++index].type, "beforeinput",
      `${description}events[${index}] should be beforeinput`);
    checkInputEvent(events[index], false, true, "insertCompositionText", "", description);
    if (kExpectInputBeforeCompositionEnd) {
      is(events[++index].type, "input",
        `${description}events[${index}] should be input`);
      checkInputEvent(events[index], false, true, "insertCompositionText", "", description);
    }
    is(events[++index].type, "compositionend",
      `${description}events[${index}] should be compositionend`);
    is(events[++index].type, "input",
      `${description}events[${index}] should be input`);
    checkInputEvent(events[index], false, false, "insertCompositionText", "", description);
    input.removeEventListener("input", onInput);
  })();

  // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during keydown() and keyup().
  events = [];
  TIP1.beginInputTransaction(window, simpleCallback);
  input.addEventListener("keydown", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransaction(window, simpleCallback),
       description + "TIP2 shouldn't be able to begin input transaction from keydown event handler during a call of TIP1.keydown();");
  }, {once: true});
  input.addEventListener("keypress", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransaction(window, simpleCallback),
       description + "TIP2 shouldn't be able to begin input transaction from keypress event handler during a call of TIP1.keydown();");
  }, {once: true});
  input.addEventListener("beforeinput", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransaction(window, simpleCallback),
       description + "TIP2 shouldn't be able to begin input transaction from beforeinput event handler during a call of TIP1.keydown();");
  }, {once: true});
  input.addEventListener("input", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransaction(window, simpleCallback),
       description + "TIP2 shouldn't be able to begin input transaction from input event handler during a call of TIP1.keydown();");
  }, {once: true});
  input.addEventListener("keyup", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransaction(window, simpleCallback),
       description + "TIP2 shouldn't be able to begin input transaction from keyup event handler during a call of TIP1.keyup();");
  }, {once: true});
  var keyA = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
  TIP1.keydown(keyA);
  TIP1.keyup(keyA);
  is(events.length, 5,
     description + "keydown, keypress, beforeinput, input, keyup events should be fired by TIP1.keydown() and TIP1.keyup()");
  is(events[0].type, "keydown",
     description + "events[0] should be keydown");
  is(events[1].type, "keypress",
     description + "events[1] should be keypress");
  is(events[2].type, "beforeinput",
     description + "events[2] should be beforeinput");
  checkInputEvent(events[2], true, false, "insertText", "a", description);
  is(events[3].type, "input",
     description + "events[3] should be input");
  checkInputEvent(events[3], false, false, "insertText", "a", description);
  is(events[4].type, "keyup",
     description + "events[4] should be keyup");

  // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during startComposition().
  events = [];
  input.addEventListener("compositionstart", function (aEvent) {
    events.push(aEvent);
    // eslint-disable-next-line no-caller
    input.removeEventListener(aEvent.type, arguments.callee);
    ok(!TIP2.beginInputTransactionForTests(window),
       description + "TIP2 shouldn't be able to begin input transaction for tests from compositionstart event handler during TIP1.startComposition();");
  });
  TIP1.beginInputTransactionForTests(window);
  TIP1.startComposition();
  is(events.length, 1,
     description + "compositionstart event should be fired by TIP1.startComposition()");
  TIP1.cancelComposition();

  // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during flushPendingComposition().
  events = [];
  input.addEventListener("compositionstart", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransactionForTests(window),
       description + "TIP2 shouldn't be able to begin input transaction for tests from compositionstart event handler during a call of TIP1.flushPendingComposition();");
  }, {once: true});
  input.addEventListener("compositionupdate", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransactionForTests(window),
       description + "TIP2 shouldn't be able to begin input transaction for tests from compositionupdate event handler during a call of TIP1.flushPendingComposition();");
  }, {once: true});
  input.addEventListener("text", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransactionForTests(window),
       description + "TIP2 shouldn't be able to begin input transaction for tests from text event handler during a call of TIP1.flushPendingComposition();");
  }, {once: true});
  input.addEventListener("beforeinput", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransactionForTests(window),
       description + "TIP2 shouldn't be able to begin input transaction for tests from beforeinput event handler during a call of TIP1.flushPendingComposition();");
  }, {once: true});
  input.addEventListener("input", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransactionForTests(window),
       description + "TIP2 shouldn't be able to begin input transaction for tests from input event handler during a call of TIP1.flushPendingComposition();");
  }, {once: true});
  TIP1.beginInputTransactionForTests(window);
  TIP1.setPendingCompositionString(composingStr);
  TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
  TIP1.flushPendingComposition();
  is(events.length, 5,
     description + "compositionstart, compositionupdate, text, beforeinput and input events should be fired by TIP1.flushPendingComposition()");
  is(events[0].type, "compositionstart",
     description + "events[0] should be compositionstart");
  is(events[1].type, "compositionupdate",
     description + "events[1] should be compositionupdate");
  is(events[2].type, "text",
     description + "events[2] should be text");
  is(events[3].type, "beforeinput",
     description + "events[3] should be beforeinput");
  checkInputEvent(events[3], false, true, "insertCompositionText", composingStr, description);
  is(events[4].type, "input",
     description + "events[4] should be input");
  checkInputEvent(events[4], false, true, "insertCompositionText", composingStr, description);
  TIP1.cancelComposition();

  // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during commitComposition().
  (function () {
    events = [];
    TIP1.beginInputTransactionForTests(window, simpleCallback);
    TIP1.setPendingCompositionString(composingStr);
    TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
    TIP1.flushPendingComposition();
    input.addEventListener("text", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests from text event handler during a call of TIP1.commitComposition();");
    }, {once: true});
    input.addEventListener("compositionend", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests from compositionend event handler during a call of TIP1.commitComposition();");
    }, {once: true});
    input.addEventListener("beforeinput", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests from beforeinput event handler during a call of TIP1.commitComposition();");
    }, {once: true});
    function onInput(aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests from input event handler during a call of TIP1.commitComposition();");
    }
    input.addEventListener("input", onInput);
    TIP1.commitComposition();
    is(events.length, kExpectInputBeforeCompositionEnd ? 5 : 4,
      description + "text, beforeinput, compositionend and input events should be fired by TIP1.commitComposition()");
    let index = -1;
    is(events[++index].type, "text",
      `${description}events[${index}] should be text`);
    is(events[++index].type, "beforeinput",
      `${description}events[${index}] should be beforeinput`);
    checkInputEvent(events[index], false, true, "insertCompositionText", composingStr, description);
    if (kExpectInputBeforeCompositionEnd) {
      is(events[++index].type, "input",
        `${description}events[${index}] should be input`);
      checkInputEvent(events[index], false, true, "insertCompositionText", composingStr, description);
    }
    is(events[++index].type, "compositionend",
      `${description}events[${index}] should be compositionend`);
    is(events[++index].type, "input",
      `${description}events[${index}] should be input`);
    checkInputEvent(events[index], false, false, "insertCompositionText", composingStr, description);
    input.removeEventListener("input", onInput);
  })();

  // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during commitCompositionWith("bar").
  (() => {
    events = [];
    input.addEventListener("compositionstart", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests from compositionstart event handler during TIP1.commitCompositionWith(\"bar\");");
    }, {once: true});
    input.addEventListener("compositionupdate", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests during compositionupdate event handler TIP1.commitCompositionWith(\"bar\");");
    }, {once: true});
    input.addEventListener("text", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests during text event handler TIP1.commitCompositionWith(\"bar\");");
    }, {once: true});
    input.addEventListener("compositionend", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests during compositionend event handler TIP1.commitCompositionWith(\"bar\");");
    }, {once: true});
    input.addEventListener("beforeinput", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests during beforeinput event handler TIP1.commitCompositionWith(\"bar\");");
    }, {once: true});
    function onInput(aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests during input event handler TIP1.commitCompositionWith(\"bar\");");
    }
    input.addEventListener("input", onInput);
    TIP1.beginInputTransactionForTests(window);
    TIP1.commitCompositionWith("bar");
    is(events.length, kExpectInputBeforeCompositionEnd ? 7 : 6,
      description + "compositionstart, compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.commitCompositionWith(\"bar\")");
    let index = -1;
    is(events[++index].type, "compositionstart",
      `${description}events[${index}] should be compositionstart`);
    is(events[++index].type, "compositionupdate",
      `${description}events[${index}] should be compositionupdate`);
    is(events[++index].type, "text",
      `${description}events[${index}] should be text`);
    is(events[++index].type, "beforeinput",
      `${description}events[${index}] should be beforeinput`);
    checkInputEvent(events[index], false, true, "insertCompositionText", "bar", description);
    if (kExpectInputBeforeCompositionEnd) {
      is(events[++index].type, "input",
        `${description}events[${index}] should be input`);
      checkInputEvent(events[index], false, true, "insertCompositionText", "bar", description);
    }
    is(events[++index].type, "compositionend",
      `${description}events[${index}] should be compositionend`);
    is(events[++index].type, "input",
      `${description}events[${index}] should be input`);
    checkInputEvent(events[index], false, false, "insertCompositionText", "bar", description);
    input.removeEventListener("input", onInput);
  })();

  // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during cancelComposition().
  (() => {
    events = [];
    TIP1.beginInputTransactionForTests(window, simpleCallback);
    TIP1.setPendingCompositionString(composingStr);
    TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
    TIP1.flushPendingComposition();
    input.addEventListener("compositionupdate", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests from compositionupdate event handler during a call of TIP1.cancelComposition();");
    }, {once: true});
    input.addEventListener("text", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests from text event handler during a call of TIP1.cancelComposition();");
    }, {once: true});
    input.addEventListener("compositionend", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests from compositionend event handler during a call of TIP1.cancelComposition();");
    }, {once: true});
    input.addEventListener("beforeinput", function (aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests from beforeinput event handler during a call of TIP1.cancelComposition();");
    }, {once: true});
    function onInput(aEvent) {
      events.push(aEvent);
      ok(!TIP2.beginInputTransactionForTests(window),
        description + "TIP2 shouldn't be able to begin input transaction for tests from input event handler during a call of TIP1.cancelComposition();");
    }
    input.addEventListener("input", onInput);
    TIP1.cancelComposition();
    is(events.length, kExpectInputBeforeCompositionEnd ? 6 : 5,
      description + "compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.cancelComposition()");
    let index = -1;
    is(events[++index].type, "compositionupdate",
      `${description}events[${index}] should be compositionupdate`);
    is(events[++index].type, "text",
      `${description}events[${index}] should be text`);
    is(events[++index].type, "beforeinput",
      `${description}events[${index}] should be beforeinput`);
    checkInputEvent(events[index], false, true, "insertCompositionText", "", description);
    if (kExpectInputBeforeCompositionEnd) {
      is(events[++index].type, "input",
        `${description}events[${index}] should be input`);
      checkInputEvent(events[index], false, true, "insertCompositionText", "", description);
    }
    is(events[++index].type, "compositionend",
      `${description}events[${index}] should be compositionend`);
    is(events[++index].type, "input",
      `${description}events[${index}] should be input`);
    checkInputEvent(events[index], false, false, "insertCompositionText", "", description);
    input.removeEventListener("input", onInput);
  })();

  // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during keydown() and keyup().
  events = [];
  TIP1.beginInputTransactionForTests(window);
  input.addEventListener("keydown", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransactionForTests(window),
       description + "TIP2 shouldn't be able to begin input transaction for tests for tests from keydown event handler during a call of TIP1.keydown();");
  }, {once: true});
  input.addEventListener("keypress", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransactionForTests(window),
       description + "TIP2 shouldn't be able to begin input transaction for tests from keypress event handler during a call of TIP1.keydown();");
  }, {once: true});
  input.addEventListener("beforeinput", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransactionForTests(window),
       description + "TIP2 shouldn't be able to begin input transaction for tests from beforeinput event handler during a call of TIP1.keydown();");
  }, {once: true});
  input.addEventListener("input", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransactionForTests(window),
       description + "TIP2 shouldn't be able to begin input transaction for tests from input event handler during a call of TIP1.keydown();");
  }, {once: true});
  input.addEventListener("keyup", function (aEvent) {
    events.push(aEvent);
    ok(!TIP2.beginInputTransactionForTests(window),
       description + "TIP2 shouldn't be able to begin input transaction for tests from keyup event handler during a call of TIP1.keyup();");
  }, {once: true});
  keyA = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
  TIP1.keydown(keyA);
  TIP1.keyup(keyA);
  is(events.length, 5,
     description + "keydown, keypress, beforeinput, input, keyup events should be fired by TIP1.keydown() and TIP1.keyup()");
  is(events[0].type, "keydown",
     description + "events[0] should be keydown");
  is(events[1].type, "keypress",
     description + "events[1] should be keypress");
  is(events[2].type, "beforeinput",
     description + "events[2] should be beforeinput");
  checkInputEvent(events[2], true, false, "insertText", "a", description);
  is(events[3].type, "input",
     description + "events[3] should be input");
  checkInputEvent(events[3], false, false, "insertText", "a", description);
  is(events[4].type, "keyup",
     description + "events[4] should be keyup");

  // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during startComposition().
  events = [];
  input.addEventListener("compositionstart", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransaction(otherWindow, simpleCallback);
      ok(false,
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should throw an exception during startComposition()");
    } catch (e) {
      ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should cause NS_ERROR_ALREADY_INITIALIZED during startComposition()");
    }
  }, {once: true});
  TIP1.beginInputTransaction(window, simpleCallback);
  TIP1.startComposition();
  is(events.length, 1,
     description + "compositionstart event should be fired by TIP1.startComposition()");
  TIP1.cancelComposition();

  // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during flushPendingComposition().
  events = [];
  input.addEventListener("compositionstart", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransaction(otherWindow, simpleCallback);
      ok(false,
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should throw an exception during flushPendingComposition()");
    } catch (e) {
      ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
    }
  }, {once: true});
  input.addEventListener("compositionupdate", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransaction(otherWindow, simpleCallback);
      ok(false,
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should throw an exception during flushPendingComposition()");
    } catch (e) {
      ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
    }
  }, {once: true});
  input.addEventListener("text", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransaction(otherWindow, simpleCallback);
      ok(false,
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should throw an exception during flushPendingComposition()");
    } catch (e) {
      ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
    }
  }, {once: true});
  input.addEventListener("beforeinput", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransaction(otherWindow, simpleCallback);
      ok(false,
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during flushPendingComposition()");
    } catch (e) {
      ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
    }
  }, {once: true});
  input.addEventListener("input", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransaction(otherWindow, simpleCallback);
      ok(false,
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should throw an exception during flushPendingComposition()");
    } catch (e) {
      ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
    }
  }, {once: true});
  TIP1.beginInputTransaction(window, simpleCallback);
  TIP1.setPendingCompositionString(composingStr);
  TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
  TIP1.flushPendingComposition();
  is(events.length, 5,
     description + "compositionstart, compositionupdate, text, beforeinput and input events should be fired by TIP1.flushPendingComposition()");
  is(events[0].type, "compositionstart",
     description + "events[0] should be compositionstart");
  is(events[1].type, "compositionupdate",
     description + "events[1] should be compositionupdate");
  is(events[2].type, "text",
     description + "events[2] should be text");
  is(events[3].type, "beforeinput",
     description + "events[3] should be beforeinput");
  checkInputEvent(events[3], false, true, "insertCompositionText", composingStr, description);
  is(events[4].type, "input",
     description + "events[4] should be input");
  checkInputEvent(events[4], false, true, "insertCompositionText", composingStr, description);
  TIP1.cancelComposition();

  // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during commitComposition().
  (function () {
    events = [];
    TIP1.beginInputTransaction(window, simpleCallback);
    TIP1.setPendingCompositionString(composingStr);
    TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
    TIP1.flushPendingComposition();
    input.addEventListener("text", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should throw an exception during commitComposition()");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
      }
    }, {once: true});
    input.addEventListener("compositionend", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should throw an exception during commitComposition()");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
      }
    }, {once: true});
    input.addEventListener("beforeinput", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during commitComposition()");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
      }
    }, {once: true});
    function onInput(aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should throw an exception during commitComposition()");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
      }
    }
    input.addEventListener("input", onInput);
    TIP1.commitComposition();
    is(events.length, kExpectInputBeforeCompositionEnd ? 5 : 4,
      description + "text, beforeinput, compositionend and input events should be fired by TIP1.commitComposition()");
    let index = -1;
    is(events[++index].type, "text",
      `${description}events[${index}] should be text`);
    is(events[++index].type, "beforeinput",
      `${description}events[${index}] should be beforeinput`);
    checkInputEvent(events[index], false, true, "insertCompositionText", composingStr, description);
    if (kExpectInputBeforeCompositionEnd) {
      is(events[++index].type, "input",
        `${description}events[${index}] should be input`);
      checkInputEvent(events[index], false, true, "insertCompositionText", composingStr, description);
    }
    is(events[++index].type, "compositionend",
      `${description}events[${index}] should be compositionend`);
    is(events[++index].type, "input",
      `${description}events[${index}] should be input`);
    checkInputEvent(events[index], false, false, "insertCompositionText", composingStr, description);
    input.removeEventListener("input", onInput);
  })();

  // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during commitCompositionWith("bar");.
  (() => {
    events = [];
    input.addEventListener("compositionstart", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should throw an exception during commitCompositionWith(\"bar\")");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
      }
    }, {once: true});
    input.addEventListener("compositionupdate", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should throw an exception during commitCompositionWith(\"bar\")");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
      }
    }, {once: true});
    input.addEventListener("text", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should throw an exception during commitCompositionWith(\"bar\")");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
      }
    }, {once: true});
    input.addEventListener("compositionend", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should throw an exception during commitCompositionWith(\"bar\")");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
      }
    }, {once: true});
    input.addEventListener("beforeinput", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during commitCompositionWith(\"bar\")");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
      }
    }, {once: true});
    function onInput(aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should throw an exception during commitCompositionWith(\"bar\")");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
      }
    }
    input.addEventListener("input", onInput);
    TIP1.beginInputTransaction(window, simpleCallback);
    TIP1.commitCompositionWith("bar");
    is(events.length, kExpectInputBeforeCompositionEnd ? 7 : 6,
      description + "compositionstart, compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.commitCompositionWith(\"bar\")");
    let index = -1;
    is(events[++index].type, "compositionstart",
      `${description}events[${index}] should be compositionstart`);
    is(events[++index].type, "compositionupdate",
      `${description}events[${index}] should be compositionupdate`);
    is(events[++index].type, "text",
      `${description}events[${index}] should be text`);
    is(events[++index].type, "beforeinput",
      `${description}events[${index}] should be beforeinput`);
    checkInputEvent(events[index], false, true, "insertCompositionText", "bar", description);
    if (kExpectInputBeforeCompositionEnd) {
      is(events[++index].type, "input",
        `${description}events[${index}] should be input`);
      checkInputEvent(events[index], false, true, "insertCompositionText", "bar", description);
    }
    is(events[++index].type, "compositionend",
      `${description}events[${index}] should be compositionend`);
    is(events[++index].type, "input",
      `${description}events[${index}] should be input`);
    checkInputEvent(events[index], false, false, "insertCompositionText", "bar", description);
    input.removeEventListener("input", onInput);
  })();

  // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during cancelComposition();.
  (() => {
    events = [];
    TIP1.beginInputTransaction(window, simpleCallback);
    TIP1.setPendingCompositionString(composingStr);
    TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
    TIP1.flushPendingComposition();
    input.addEventListener("compositionupdate", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should throw an exception during cancelComposition()");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
      }
    }, {once: true});
    input.addEventListener("text", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should throw an exception during cancelComposition()");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
      }
    }, {once: true});
    input.addEventListener("compositionend", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should throw an exception during cancelComposition()");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
      }
    }, {once: true});
    input.addEventListener("beforeinput", function (aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during cancelComposition()");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
      }
    }, {once: true});
    function onInput(aEvent) {
      events.push(aEvent);
      try {
        TIP1.beginInputTransaction(otherWindow, simpleCallback);
        ok(false,
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should throw an exception during cancelComposition()");
      } catch (e) {
        ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
          description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
      }
    }
    input.addEventListener("input", onInput);
    TIP1.cancelComposition();
    is(events.length, kExpectInputBeforeCompositionEnd ? 6 : 5,
      description + "compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.cancelComposition()");
    let index = -1;
    is(events[++index].type, "compositionupdate",
      `${description}events[${index}] should be compositionupdate`);
    is(events[++index].type, "text",
      `${description}events[${index}] should be text`);
    is(events[++index].type, "beforeinput",
      `${description}events[${index}] should be beforeinput`);
    checkInputEvent(events[index], false, true, "insertCompositionText", "", description);
    if (kExpectInputBeforeCompositionEnd) {
      is(events[++index].type, "input",
        `${description}events[${index}] should be input`);
      checkInputEvent(events[index], false, true, "insertCompositionText", "", description);
    }
    is(events[++index].type, "compositionend",
      `${description}events[${index}] should be compositionend`);
    is(events[++index].type, "input",
      `${description}events[${index}] should be input`);
    checkInputEvent(events[index], false, false, "insertCompositionText", "", description);
    input.removeEventListener("input", onInput);
  })();

  // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during keydown() and keyup();.
  events = [];
  TIP1.beginInputTransaction(window, simpleCallback);
  input.addEventListener("keydown", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransaction(otherWindow, simpleCallback);
      ok(false,
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keydown\" should throw an exception during keydown()");
    } catch (e) {
      ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keydown\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
    }
  }, {once: true});
  input.addEventListener("keypress", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransaction(otherWindow, simpleCallback);
      ok(false,
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keypress\" should throw an exception during keydown()");
    } catch (e) {
      ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keypress\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
    }
  }, {once: true});
  input.addEventListener("beforeinput", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransaction(otherWindow, simpleCallback);
      ok(false,
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during keydown()");
    } catch (e) {
      ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
    }
  }, {once: true});
  input.addEventListener("input", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransaction(otherWindow, simpleCallback);
      ok(false,
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should throw an exception during keydown()");
    } catch (e) {
      ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
    }
  }, {once: true});
  input.addEventListener("keyup", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransaction(otherWindow, simpleCallback);
      ok(false,
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keyup\" should throw an exception during keyup()");
    } catch (e) {
      ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
         description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keyup\" should cause NS_ERROR_ALREADY_INITIALIZED during keyup()");
    }
  }, {once: true});
  keyA = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
  TIP1.keydown(keyA);
  TIP1.keyup(keyA);
  is(events.length, 5,
     description + "keydown, keypress, beforeinput, input, keyup events should be fired by TIP1.keydown() and TIP1.keyup()");
  is(events[0].type, "keydown",
     description + "events[0] should be keydown");
  is(events[1].type, "keypress",
     description + "events[1] should be keypress");
  is(events[2].type, "beforeinput",
     description + "events[2] should be beforeinput");
  checkInputEvent(events[2], true, false, "insertText", "a", description);
  is(events[3].type, "input",
     description + "events[3] should be input");
  checkInputEvent(events[3], false, false, "insertText", "a", description);
  is(events[4].type, "keyup",
     description + "events[4] should be keyup");

  // Let's check if beginInputTransactionForTests() with another window fails to begin new input transaction with different TextEventDispatcher during startComposition().
  events = [];
  input.addEventListener("compositionstart", function (aEvent) {
    events.push(aEvent);
    try {
      TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
      ok(false,
--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.32 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge