diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /editor/libeditor/tests/test_dom_input_event_on_texteditor.html | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | editor/libeditor/tests/test_dom_input_event_on_texteditor.html | 926 |
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> |