summaryrefslogtreecommitdiffstats
path: root/editor/libeditor/tests/test_dom_input_event_on_texteditor.html
diff options
context:
space:
mode:
Diffstat (limited to 'editor/libeditor/tests/test_dom_input_event_on_texteditor.html')
-rw-r--r--editor/libeditor/tests/test_dom_input_event_on_texteditor.html926
1 files changed, 926 insertions, 0 deletions
diff --git a/editor/libeditor/tests/test_dom_input_event_on_texteditor.html b/editor/libeditor/tests/test_dom_input_event_on_texteditor.html
new file mode 100644
index 0000000000..e3d9eb3e5c
--- /dev/null
+++ b/editor/libeditor/tests/test_dom_input_event_on_texteditor.html
@@ -0,0 +1,926 @@
+<html>
+<head>
+ <title>Test for input event of text editor</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<div id="display">
+ <input type="text" id="input">
+ <textarea id="textarea"></textarea>
+</div>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+
+<script class="testbody" type="application/javascript">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.expectAssertions(0, 1); // In a11y module
+SimpleTest.waitForFocus(runTests, window);
+
+function runTests() {
+ const kWordSelectEatSpaceToNextWord = SpecialPowers.getBoolPref("layout.word_select.eat_space_to_next_word");
+
+ function doTests(aElement, aDescription, aIsTextarea) {
+ aDescription += ": ";
+ aElement.focus();
+ aElement.value = "";
+
+ /**
+ * Tester function.
+ *
+ * @param aTestData Class like object to run a set of tests.
+ * - action:
+ * Short explanation what it does.
+ * - cancelBeforeInput:
+ * true if preventDefault() of "beforeinput" should be
+ * called.
+ * @param aFunc Function to run test.
+ * @param aExpected Object which has:
+ * - value [optional]:
+ * Set string value if the test needs to check value of
+ * aElement.
+ * Set undefined if the test does not need to check it.
+ * - valueForCanceled [optional]:
+ * Set string value if canceling "beforeinput" does not
+ * keep the value before calling aFunc.
+ * - beforeInputEvent [optional]:
+ * Set object which has `cancelable`, `inputType` and `data`
+ * if a "beforeinput" event should be fired.
+ * Set null if "beforeinput" event shouldn't be fired.
+ * - inputEvent [optional]:
+ * Set object which has `inputType` and `data` if an "input" event
+ * should be fired if aTestData.cancelBeforeInput is not true.
+ * Set null if "input" event shouldn't be fired.
+ * Note that if expected "beforeinput" event is cancelable and
+ * aTestData.cancelBeforeInput is true, this is ignored.
+ */
+ function runTest(aTestData, aFunc, aExpected) {
+ let initializing = false;
+ let beforeInputEvent = null;
+ let inputEvent = null;
+ let beforeInputHandler = (aEvent) => {
+ if (initializing) {
+ return;
+ }
+ ok(!beforeInputEvent,
+ `${aDescription}Multiple "beforeinput" events are fired at ${aTestData.action} (inputType: "${aEvent.inputType}", data: ${aEvent.data})`);
+ if (aTestData.cancelBeforeInput) {
+ aEvent.preventDefault();
+ }
+ ok(aEvent.isTrusted,
+ `${aDescription}"beforeinput" event at ${aTestData.action} must be trusted`);
+ is(aEvent.target, aElement,
+ `${aDescription}"beforeinput" event at ${aTestData.action} is fired on unexpected element: ${aEvent.target.tagName}`);
+ ok(aEvent instanceof InputEvent,
+ `${aDescription}"beforeinput" event at ${aTestData.action} should be dispatched with InputEvent interface`);
+ ok(aEvent.bubbles,
+ `${aDescription}"beforeinput" event at ${aTestData.action} must be bubbles`);
+ beforeInputEvent = aEvent;
+ };
+ let inputHandler = (aEvent) => {
+ if (initializing) {
+ return;
+ }
+ ok(!inputEvent,
+ `${aDescription}Multiple "input" events are fired at ${aTestData.action} (inputType: "${aEvent.inputType}", data: ${aEvent.data})`);
+ ok(aEvent.isTrusted,
+ `${aDescription}"input" event at ${aTestData.action} must be trusted`);
+ is(aEvent.target, aElement, `"input" event at ${aTestData.action} is fired on unexpected element: ${aEvent.target.tagName}`);
+ ok(aEvent instanceof InputEvent,
+ `${aDescription}"input" event at ${aTestData.action} should be dispatched with InputEvent interface`);
+ ok(!aEvent.cancelable,
+ `${aDescription}"input" event at ${aTestData.action} must not be cancelable`);
+ ok(aEvent.bubbles,
+ `${aDescription}"input" event at ${aTestData.action} must be bubbles`);
+ let duration = Math.abs(window.performance.now() - aEvent.timeStamp);
+ ok(duration < 30 * 1000,
+ `${aDescription}perhaps, timestamp wasn't set correctly :${aEvent.timeStamp} (expected it to be within 30s of ` +
+ `the current time but it differed by ${duration}ms)`);
+ inputEvent = aEvent;
+ };
+
+ if (aTestData.cancelBeforeInput &&
+ (aExpected.beforeInputEvent === null || aExpected.beforeInputEvent === undefined)) {
+ ok(false,
+ `${aDescription}cancelBeforeInput must not be true for ${aTestData.action} because "beforeinput" event is not expected`);
+ return;
+ }
+
+ try {
+ aElement.addEventListener("beforeinput", beforeInputHandler, true);
+ aElement.addEventListener("input", inputHandler, true);
+
+ let initialValue = aElement.value;
+
+ aFunc();
+
+ (function verify() {
+ try {
+ if (aExpected.value !== undefined) {
+ if (aTestData.cancelBeforeInput && aExpected.valueForCanceled === undefined) {
+ is(aElement.value, initialValue,
+ `${aDescription}the value should be "${initialValue}" after ${aTestData.action}`);
+ } else {
+ let expectedValue =
+ aTestData.cancelBeforeInput ? aExpected.valueForCanceled : aExpected.value;
+ is(aElement.value, expectedValue,
+ `${aDescription}the value should be "${expectedValue}" after ${aTestData.action}`);
+ }
+ }
+ if (aExpected.beforeInputEvent === null || aExpected.beforeInputEvent === undefined) {
+ ok(!beforeInputEvent,
+ `${aDescription}"beforeinput" event shouldn't have been fired at ${aTestData.action}`);
+ } else {
+ ok(beforeInputEvent,
+ `${aDescription}"beforeinput" event should've been fired at ${aTestData.action}`);
+ is(beforeInputEvent.cancelable, aExpected.beforeInputEvent.cancelable,
+ `${aDescription}"beforeinput" event by ${aTestData.action} should be ${
+ aExpected.beforeInputEvent.cancelable ? "cancelable" : "not cancelable"
+ }`);
+ is(beforeInputEvent.inputType, aExpected.beforeInputEvent.inputType,
+ `${aDescription}inputType of "beforeinput" event by ${aTestData.action} should be "${aExpected.beforeInputEvent.inputType}"`);
+ is(beforeInputEvent.data, aExpected.beforeInputEvent.data,
+ `${aDescription}data of "beforeinput" event by ${aTestData.action} should be ${
+ aExpected.beforeInputEvent.data === null ? "null" : `"${aExpected.beforeInputEvent.data}"`
+ }`);
+ is(beforeInputEvent.dataTransfer, null,
+ `${aDescription}dataTransfer of "beforeinput" event by ${aTestData.action} should be null`);
+ is(beforeInputEvent.getTargetRanges().length, 0,
+ `${aDescription}getTargetRanges() of "beforeinput" event by ${aTestData.action} should return empty array`);
+ }
+ if ((
+ aTestData.cancelBeforeInput === true &&
+ aExpected.beforeInputEvent &&
+ aExpected.beforeInputEvent.cancelable
+ ) || aExpected.inputEvent === null || aExpected.inputEvent === undefined) {
+ ok(!inputEvent,
+ `${aDescription}"input" event shouldn't have been fired at ${aTestData.action}`);
+ } else {
+ ok(inputEvent,
+ `${aDescription}"input" event should've been fired at ${aTestData.action}`);
+ is(inputEvent.cancelable, false,
+ `${aDescription}"input" event by ${aTestData.action} should be not be cancelable`);
+ is(inputEvent.inputType, aExpected.inputEvent.inputType,
+ `${aDescription}inputType of "input" event by ${aTestData.action} should be "${aExpected.inputEvent.inputType}"`);
+ is(inputEvent.data, aExpected.inputEvent.data,
+ `${aDescription}data of "input" event by ${aTestData.action} should be ${
+ aExpected.inputEvent.data === null ? "null" : `"${aExpected.inputEvent.data}"`
+ }`);
+ is(inputEvent.dataTransfer, null,
+ `${aDescription}dataTransfer of "input" event by ${aTestData.action} should be null`);
+ is(inputEvent.getTargetRanges().length, 0,
+ `${aDescription}getTargetRanges() of "input" event by ${aTestData.action} should return empty array`);
+ }
+ } catch (ex) {
+ ok(false, `${aDescription}unexpected exception at verifying test result of "${aTestData.action}": ${ex.toString()}`);
+ }
+ })();
+ } finally {
+ aElement.removeEventListener("beforeinput", beforeInputHandler, true);
+ aElement.removeEventListener("input", inputHandler, true);
+ }
+ }
+
+ function test_typing_a_in_empty_editor(aTestData) {
+ aElement.value = "";
+ aElement.focus();
+
+ runTest(
+ aTestData,
+ () => {
+ sendString("a");
+ },
+ {
+ value: "a",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "insertText",
+ data: "a",
+ },
+ inputEvent: {
+ inputType: "insertText",
+ data: "a",
+ },
+ }
+ );
+ }
+ test_typing_a_in_empty_editor({
+ action: 'typing "a" and canceling beforeinput',
+ cancelBeforeInput: true,
+ });
+ test_typing_a_in_empty_editor({
+ action: 'typing "a"',
+ cancelBeforeInput: false,
+ });
+
+ function test_typing_backspace_to_delete_last_character(aTestData) {
+ aElement.value = "a";
+ aElement.focus();
+ aElement.setSelectionStart = "a".length;
+
+ runTest(
+ aTestData,
+ () => {
+ synthesizeKey("KEY_Backspace");
+ },
+ {
+ value: "",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteContentBackward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteContentBackward",
+ data: null,
+ },
+ }
+ );
+ }
+ test_typing_backspace_to_delete_last_character({
+ actin: 'typing "Backspace" to delete "a" and canceling "beforeinput"',
+ cancelBeforeInput: true,
+ });
+ test_typing_backspace_to_delete_last_character({
+ actin: 'typing "Backspace" to delete "a"',
+ cancelBeforeInput: false,
+ });
+
+ function test_typing_enter_in_empty_editor(aTestData) {
+ aElement.value = "";
+ aElement.focus();
+
+ runTest(
+ aTestData,
+ () => {
+ synthesizeKey("KEY_Enter");
+ },
+ aIsTextarea
+ ? {
+ value: "\n",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "insertLineBreak",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "insertLineBreak",
+ data: null,
+ },
+ }
+ : {
+ value: "",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "insertLineBreak",
+ data: null,
+ },
+ }
+ );
+ }
+ test_typing_enter_in_empty_editor({
+ action: 'typing "Enter" in empty editor and canceling "beforeinput"',
+ cancelBeforeInput: true,
+ });
+ test_typing_enter_in_empty_editor({
+ action: 'typing "Enter" in empty editor',
+ cancelBeforeInput: false,
+ });
+
+ (function test_setting_value(aTestData) {
+ aElement.value = "";
+ aElement.focus();
+
+ runTest(
+ aTestData,
+ () => {
+ aElement.value = "foo-bar";
+ },
+ { value: "foo-bar" }
+ );
+ })({
+ action: "setting non-empty value",
+ });
+
+ (function test_setting_empty_value(aTestData) {
+ aElement.value = "foo-bar";
+ aElement.focus();
+
+ runTest(
+ aTestData,
+ () => {
+ aElement.value = "";
+ },
+ { value: "" }
+ );
+ })({
+ action: "setting empty value",
+ });
+
+ (function test_typing_space_in_empty_editor(aTestData) {
+ aElement.value = "";
+ aElement.focus();
+
+ runTest(
+ aTestData,
+ () => {
+ sendString(" ");
+ },
+ {
+ value: " ",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "insertText",
+ data: " ",
+ },
+ inputEvent: {
+ inputType: "insertText",
+ data: " ",
+ },
+ }
+ );
+ })({
+ action: "typing space",
+ });
+
+ (function test_typing_delete_at_end_of_editor(aTestData) {
+ aElement.value = " ";
+ aElement.focus();
+
+ runTest(
+ aTestData,
+ () => {
+ synthesizeKey("KEY_Delete");
+ },
+ {
+ value: " ",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteContentForward",
+ data: null,
+ },
+ }
+ );
+ })({
+ action: 'typing "Delete" at end of editor',
+ });
+
+ (function test_typing_arrow_left_to_move_caret(aTestData) {
+ aElement.value = " ";
+ aElement.focus();
+ aElement.selectionStart = 1;
+
+ runTest(
+ aTestData,
+ () => {
+ synthesizeKey("KEY_ArrowLeft");
+ },
+ { value: " " }
+ );
+ })({
+ action: 'typing "ArrowLeft" to move caret',
+ });
+
+ function test_typing_delete_to_delete_last_character(aTestData) {
+ aElement.value = " ";
+ aElement.focus();
+ aElement.selectionStart = 0;
+
+ runTest(
+ aTestData,
+ () => {
+ synthesizeKey("KEY_Delete");
+ },
+ {
+ value: "",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteContentForward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteContentForward",
+ data: null,
+ },
+ }
+ );
+ }
+ test_typing_delete_to_delete_last_character({
+ action: 'typing "Delete" to delete space and canceling "beforeinput"',
+ cancelBeforeInput: true,
+ });
+ test_typing_delete_to_delete_last_character({
+ action: 'typing "Delete" to delete space',
+ cancelBeforeInput: false,
+ });
+
+ function test_undoing_deleting_last_character(aTestData) {
+ aElement.value = "a";
+ aElement.focus();
+ aElement.selectionStart = 0;
+ synthesizeKey("KEY_Delete");
+
+ runTest(
+ aTestData,
+ () => {
+ synthesizeKey("z", {accelKey: true});
+ },
+ {
+ value: "a",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "historyUndo",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "historyUndo",
+ data: null,
+ },
+ }
+ );
+ }
+ test_undoing_deleting_last_character({
+ action: 'undoing deleting last character and canceling "beforeinput"',
+ cancelBeforeInput: true,
+ });
+ test_undoing_deleting_last_character({
+ action: "undoing deleting last character",
+ cancelBeforeInput: false,
+ });
+
+ (function test_undoing_without_undoable_transaction(aTestData) {
+ aElement.value = "a";
+ aElement.focus();
+ aElement.selectionStart = 0;
+ synthesizeKey("KEY_Delete");
+ synthesizeKey("z", {accelKey: true});
+
+ runTest(
+ aTestData,
+ () => {
+ synthesizeKey("z", {accelKey: true});
+ },
+ { value: "a" }
+ );
+ })({
+ action: "trying to undo without undoable transaction"
+ });
+
+ function test_redoing_deleting_last_character(aTestData) {
+ aElement.value = "a";
+ aElement.focus();
+ aElement.selectionStart = 0;
+ synthesizeKey("KEY_Delete");
+ synthesizeKey("z", {accelKey: true});
+
+ runTest(
+ aTestData,
+ () => {
+ synthesizeKey("Z", {accelKey: true, shiftKey: true});
+ },
+ {
+ value: "",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "historyRedo",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "historyRedo",
+ data: null,
+ },
+ }
+ );
+ }
+ test_redoing_deleting_last_character({
+ action: 'redoing deleting last character and canceling "beforeinput"',
+ cancelBeforeInput: true,
+ });
+ test_redoing_deleting_last_character({
+ action: "redoing deleting last character",
+ cancelBeforeInput: false,
+ });
+
+ (function test_redoing_without_redoable_transaction(aTestData) {
+ aElement.value = "a";
+ aElement.focus();
+ aElement.selectionStart = 0;
+ synthesizeKey("KEY_Delete");
+ synthesizeKey("z", {accelKey: true});
+ synthesizeKey("Z", {accelKey: true, shiftKey: true});
+
+ runTest(
+ aTestData,
+ () => {
+ synthesizeKey("Z", {accelKey: true, shiftKey: true});
+ },
+ { value: "" }
+ );
+ })({
+ action: "trying to redo without redoable transaction"
+ });
+
+ function test_typing_backspace_with_selecting_all_characters(aTestData) {
+ aElement.value = "abc";
+ aElement.focus();
+ aElement.select();
+
+ runTest(
+ aTestData,
+ () => {
+ synthesizeKey("KEY_Backspace");
+ },
+ {
+ value: "",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteContentBackward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteContentBackward",
+ data: null,
+ },
+ }
+ );
+ }
+ test_typing_backspace_with_selecting_all_characters({
+ action: 'typing "Backspace" to delete all selected characters and canceling "beforeinput"',
+ cancelBeforeInput: true,
+ });
+ test_typing_backspace_with_selecting_all_characters({
+ action: 'typing "Backspace" to delete all selected characters',
+ cancelBeforeInput: false,
+ });
+
+ function test_typing_delete_with_selecting_all_characters(aTestData) {
+ aElement.value = "abc";
+ aElement.focus();
+ aElement.select();
+
+ runTest(
+ aTestData,
+ () => {
+ synthesizeKey("KEY_Delete");
+ },
+ {
+ value: "",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteContentForward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteContentForward",
+ data: null,
+ },
+ }
+ );
+ }
+ test_typing_delete_with_selecting_all_characters({
+ action: 'typing "Delete" to delete all selected characters and canceling "beforeinput"',
+ cancelBeforeInput: true,
+ });
+ test_typing_delete_with_selecting_all_characters({
+ action: 'typing "Delete" to delete all selected characters and canceling "beforeinput"',
+ cancelBeforeInput: false,
+ });
+
+ function test_deleting_word_backward_from_its_end(aTestData) {
+ aElement.value = "abc def";
+ aElement.focus();
+ document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
+ aElement.setSelectionRange("abc def".length, "abc def".length);
+
+ runTest(
+ aTestData,
+ () => {
+ SpecialPowers.doCommand(window, "cmd_deleteWordBackward");
+ },
+ {
+ value: "abc ",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteWordBackward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteWordBackward",
+ data: null,
+ },
+ }
+ );
+ }
+ test_deleting_word_backward_from_its_end({
+ action: 'deleting word backward from its end and canceling "beforeinput"',
+ cancelBeforeInput: true,
+ });
+ test_deleting_word_backward_from_its_end({
+ action: 'deleting word backward from its end',
+ cancelBeforeInput: false,
+ });
+
+ function test_deleting_word_forward_from_its_start(aTestData) {
+ aElement.value = "abc def";
+ aElement.focus();
+ document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
+ aElement.setSelectionRange(0, 0);
+
+ runTest(
+ aTestData,
+ () => {
+ SpecialPowers.doCommand(window, "cmd_deleteWordForward");
+ },
+ {
+ value: kWordSelectEatSpaceToNextWord ? "def" : " def",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteWordForward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteWordForward",
+ data: null,
+ },
+ }
+ );
+ }
+ test_deleting_word_forward_from_its_start({
+ action: 'deleting word forward from its start and canceling "beforeinput"',
+ cancelBeforeInput: true,
+ });
+ test_deleting_word_forward_from_its_start({
+ action: "deleting word forward from its start",
+ cancelBeforeInput: false,
+ });
+
+ (function test_deleting_word_backward_from_middle_of_second_word(aTestData) {
+ aElement.value = "abc def";
+ aElement.focus();
+ document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
+ aElement.setSelectionRange("abc d".length, "abc de".length);
+
+ runTest(
+ aTestData,
+ () => {
+ SpecialPowers.doCommand(window, "cmd_deleteWordBackward");
+ },
+ {
+ value: "abc df",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteContentBackward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteContentBackward",
+ data: null,
+ },
+ }
+ );
+ })({
+ action: "removing characters backward from middle of second word",
+ });
+
+ (function test_deleting_word_forward_from_middle_of_first_word(aTestData) {
+ aElement.value = "abc def";
+ aElement.focus();
+ document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
+ aElement.setSelectionRange("a".length, "ab".length);
+
+ runTest(
+ aTestData,
+ () => {
+ SpecialPowers.doCommand(window, "cmd_deleteWordForward");
+ },
+ {
+ value: "ac def",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteContentForward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteContentForward",
+ data: null,
+ },
+ }
+ );
+ })({
+ action: "removing characters forward from middle of first word",
+ });
+
+ (function test_deleting_characters_backward_to_start_of_line(aTestData) {
+ aElement.value = "abc def";
+ aElement.focus();
+ document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
+ aElement.setSelectionRange("abc d".length, "abc d".length);
+
+ runTest(
+ aTestData,
+ () => {
+ SpecialPowers.doCommand(window, "cmd_deleteToBeginningOfLine");
+ },
+ {
+ value: "ef",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteSoftLineBackward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteSoftLineBackward",
+ data: null,
+ },
+ }
+ );
+ })({
+ action: "removing characters backward to start of line"
+ });
+
+ (function test_deleting_characters_forward_to_end_of_line(aTestData) {
+ aElement.value = "abc def";
+ aElement.focus();
+ document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
+ aElement.setSelectionRange("ab".length, "ab".length);
+
+ runTest(
+ aTestData,
+ () => {
+ SpecialPowers.doCommand(window, "cmd_deleteToEndOfLine");
+ },
+ {
+ value: "ab",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteSoftLineForward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteSoftLineForward",
+ data: null,
+ },
+ }
+ );
+ })({
+ action: "removing characters forward to end of line",
+ });
+
+ (function test_deleting_characters_backward_to_start_of_line_with_non_collapsed_selection(aTestData) {
+ aElement.value = "abc def";
+ aElement.focus();
+ document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
+ aElement.setSelectionRange("abc d".length, "abc_de".length);
+
+ runTest(
+ aTestData,
+ () => {
+ SpecialPowers.doCommand(window, "cmd_deleteToBeginningOfLine");
+ },
+ {
+ value: "abc df",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteContentBackward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteContentBackward",
+ data: null,
+ },
+ }
+ );
+ })({
+ action: "removing characters backward to start of line (with selection in second word)",
+ });
+
+ (function test_deleting_characters_forward_to_end_of_line_with_non_collapsed_selection(aTestData) {
+ aElement.value = "abc def";
+ aElement.focus();
+ document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
+ aElement.setSelectionRange("a".length, "ab".length);
+
+ runTest(
+ aTestData,
+ () => {
+ SpecialPowers.doCommand(window, "cmd_deleteToEndOfLine");
+ },
+ {
+ value: "ac def",
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "deleteContentForward",
+ data: null,
+ },
+ inputEvent: {
+ inputType: "deleteContentForward",
+ data: null,
+ },
+ }
+ );
+ })({
+ action: "removing characters forward to end of line (with selection in second word)",
+ });
+
+ function test_switching_text_direction_from_default(aTestData) {
+ try {
+ aElement.removeAttribute("dir");
+ aElement.scrollTop; // XXX Update the root frame
+ aElement.focus();
+
+ runTest(
+ aTestData,
+ () => {
+ SpecialPowers.doCommand(window, "cmd_switchTextDirection");
+ if (aTestData.cancelBeforeInput) {
+ is(aElement.getAttribute("dir"), null,
+ `${aDescription}dir attribute of the element shouldn't have been set by ${aTestData.action}`);
+ } else {
+ is(aElement.getAttribute("dir"), "rtl",
+ `${aDescription}dir attribute of the element should've been set to "rtl" by ${aTestData.action}`);
+ }
+ },
+ {
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "formatSetBlockTextDirection",
+ data: "rtl",
+ },
+ inputEvent: {
+ inputType: "formatSetBlockTextDirection",
+ data: "rtl",
+ },
+ }
+ );
+ } finally {
+ aElement.removeAttribute("dir");
+ aElement.scrollTop; // XXX Update the root frame
+ }
+ }
+ test_switching_text_direction_from_default({
+ action: 'switching text direction from default to "rtl" and canceling "beforeinput"',
+ cancelBeforeInput: true,
+ });
+ test_switching_text_direction_from_default({
+ action: 'switching text direction from default to "rtl"',
+ cancelBeforeInput: false,
+ });
+
+ function test_switching_text_direction_from_rtl_to_ltr(aTestData) {
+ try {
+ aElement.setAttribute("dir", "rtl");
+ aElement.scrollTop; // XXX Update the root frame
+ aElement.focus();
+
+ runTest(
+ aTestData,
+ () => {
+ SpecialPowers.doCommand(window, "cmd_switchTextDirection");
+ let expectedDirValue = aTestData.cancelBeforeInput ? "rtl" : "ltr";
+ is(aElement.getAttribute("dir"), expectedDirValue,
+ `${aDescription}dir attribute of the element should be "${expectedDirValue}" after ${aTestData.action}`);
+ },
+ {
+ beforeInputEvent: {
+ cancelable: true,
+ inputType: "formatSetBlockTextDirection",
+ data: "ltr",
+ },
+ inputEvent: {
+ inputType: "formatSetBlockTextDirection",
+ data: "ltr",
+ },
+ }
+ );
+ } finally {
+ aElement.removeAttribute("dir");
+ aElement.scrollTop; // XXX Update the root frame
+ }
+ }
+ test_switching_text_direction_from_rtl_to_ltr({
+ action: 'switching text direction from "rtl" to "ltr" and canceling "beforeinput"',
+ cancelBeforeInput: true,
+ });
+ test_switching_text_direction_from_rtl_to_ltr({
+ action: 'switching text direction from "rtl" to "ltr" and canceling "beforeinput"',
+ cancelBeforeInput: false,
+ });
+ }
+
+ doTests(document.getElementById("input"), "<input type=\"text\">", false);
+ doTests(document.getElementById("textarea"), "<textarea>", true);
+
+ SimpleTest.finish();
+}
+
+</script>
+</body>
+
+</html>