Bug 1883912: Enable Intl.ListFormat test for "unit" style. r=spidermonkey-reviewers...
[gecko.git] / editor / libeditor / tests / test_dom_input_event_on_texteditor.html
blobe3d9eb3e5c4e06a486ca47272b147d2e5e5c1cb1
1 <html>
2 <head>
3 <title>Test for input event of text editor</title>
4 <script src="/tests/SimpleTest/SimpleTest.js"></script>
5 <script src="/tests/SimpleTest/EventUtils.js"></script>
6 <link rel="stylesheet" type="text/css"
7 href="/tests/SimpleTest/test.css" />
8 </head>
9 <body>
10 <div id="display">
11 <input type="text" id="input">
12 <textarea id="textarea"></textarea>
13 </div>
14 <div id="content" style="display: none">
16 </div>
17 <pre id="test">
18 </pre>
20 <script class="testbody" type="application/javascript">
21 "use strict";
23 SimpleTest.waitForExplicitFinish();
24 SimpleTest.expectAssertions(0, 1); // In a11y module
25 SimpleTest.waitForFocus(runTests, window);
27 function runTests() {
28 const kWordSelectEatSpaceToNextWord = SpecialPowers.getBoolPref("layout.word_select.eat_space_to_next_word");
30 function doTests(aElement, aDescription, aIsTextarea) {
31 aDescription += ": ";
32 aElement.focus();
33 aElement.value = "";
35 /**
36 * Tester function.
38 * @param aTestData Class like object to run a set of tests.
39 * - action:
40 * Short explanation what it does.
41 * - cancelBeforeInput:
42 * true if preventDefault() of "beforeinput" should be
43 * called.
44 * @param aFunc Function to run test.
45 * @param aExpected Object which has:
46 * - value [optional]:
47 * Set string value if the test needs to check value of
48 * aElement.
49 * Set undefined if the test does not need to check it.
50 * - valueForCanceled [optional]:
51 * Set string value if canceling "beforeinput" does not
52 * keep the value before calling aFunc.
53 * - beforeInputEvent [optional]:
54 * Set object which has `cancelable`, `inputType` and `data`
55 * if a "beforeinput" event should be fired.
56 * Set null if "beforeinput" event shouldn't be fired.
57 * - inputEvent [optional]:
58 * Set object which has `inputType` and `data` if an "input" event
59 * should be fired if aTestData.cancelBeforeInput is not true.
60 * Set null if "input" event shouldn't be fired.
61 * Note that if expected "beforeinput" event is cancelable and
62 * aTestData.cancelBeforeInput is true, this is ignored.
64 function runTest(aTestData, aFunc, aExpected) {
65 let initializing = false;
66 let beforeInputEvent = null;
67 let inputEvent = null;
68 let beforeInputHandler = (aEvent) => {
69 if (initializing) {
70 return;
72 ok(!beforeInputEvent,
73 `${aDescription}Multiple "beforeinput" events are fired at ${aTestData.action} (inputType: "${aEvent.inputType}", data: ${aEvent.data})`);
74 if (aTestData.cancelBeforeInput) {
75 aEvent.preventDefault();
77 ok(aEvent.isTrusted,
78 `${aDescription}"beforeinput" event at ${aTestData.action} must be trusted`);
79 is(aEvent.target, aElement,
80 `${aDescription}"beforeinput" event at ${aTestData.action} is fired on unexpected element: ${aEvent.target.tagName}`);
81 ok(aEvent instanceof InputEvent,
82 `${aDescription}"beforeinput" event at ${aTestData.action} should be dispatched with InputEvent interface`);
83 ok(aEvent.bubbles,
84 `${aDescription}"beforeinput" event at ${aTestData.action} must be bubbles`);
85 beforeInputEvent = aEvent;
87 let inputHandler = (aEvent) => {
88 if (initializing) {
89 return;
91 ok(!inputEvent,
92 `${aDescription}Multiple "input" events are fired at ${aTestData.action} (inputType: "${aEvent.inputType}", data: ${aEvent.data})`);
93 ok(aEvent.isTrusted,
94 `${aDescription}"input" event at ${aTestData.action} must be trusted`);
95 is(aEvent.target, aElement, `"input" event at ${aTestData.action} is fired on unexpected element: ${aEvent.target.tagName}`);
96 ok(aEvent instanceof InputEvent,
97 `${aDescription}"input" event at ${aTestData.action} should be dispatched with InputEvent interface`);
98 ok(!aEvent.cancelable,
99 `${aDescription}"input" event at ${aTestData.action} must not be cancelable`);
100 ok(aEvent.bubbles,
101 `${aDescription}"input" event at ${aTestData.action} must be bubbles`);
102 let duration = Math.abs(window.performance.now() - aEvent.timeStamp);
103 ok(duration < 30 * 1000,
104 `${aDescription}perhaps, timestamp wasn't set correctly :${aEvent.timeStamp} (expected it to be within 30s of ` +
105 `the current time but it differed by ${duration}ms)`);
106 inputEvent = aEvent;
109 if (aTestData.cancelBeforeInput &&
110 (aExpected.beforeInputEvent === null || aExpected.beforeInputEvent === undefined)) {
111 ok(false,
112 `${aDescription}cancelBeforeInput must not be true for ${aTestData.action} because "beforeinput" event is not expected`);
113 return;
116 try {
117 aElement.addEventListener("beforeinput", beforeInputHandler, true);
118 aElement.addEventListener("input", inputHandler, true);
120 let initialValue = aElement.value;
122 aFunc();
124 (function verify() {
125 try {
126 if (aExpected.value !== undefined) {
127 if (aTestData.cancelBeforeInput && aExpected.valueForCanceled === undefined) {
128 is(aElement.value, initialValue,
129 `${aDescription}the value should be "${initialValue}" after ${aTestData.action}`);
130 } else {
131 let expectedValue =
132 aTestData.cancelBeforeInput ? aExpected.valueForCanceled : aExpected.value;
133 is(aElement.value, expectedValue,
134 `${aDescription}the value should be "${expectedValue}" after ${aTestData.action}`);
137 if (aExpected.beforeInputEvent === null || aExpected.beforeInputEvent === undefined) {
138 ok(!beforeInputEvent,
139 `${aDescription}"beforeinput" event shouldn't have been fired at ${aTestData.action}`);
140 } else {
141 ok(beforeInputEvent,
142 `${aDescription}"beforeinput" event should've been fired at ${aTestData.action}`);
143 is(beforeInputEvent.cancelable, aExpected.beforeInputEvent.cancelable,
144 `${aDescription}"beforeinput" event by ${aTestData.action} should be ${
145 aExpected.beforeInputEvent.cancelable ? "cancelable" : "not cancelable"
146 }`);
147 is(beforeInputEvent.inputType, aExpected.beforeInputEvent.inputType,
148 `${aDescription}inputType of "beforeinput" event by ${aTestData.action} should be "${aExpected.beforeInputEvent.inputType}"`);
149 is(beforeInputEvent.data, aExpected.beforeInputEvent.data,
150 `${aDescription}data of "beforeinput" event by ${aTestData.action} should be ${
151 aExpected.beforeInputEvent.data === null ? "null" : `"${aExpected.beforeInputEvent.data}"`
152 }`);
153 is(beforeInputEvent.dataTransfer, null,
154 `${aDescription}dataTransfer of "beforeinput" event by ${aTestData.action} should be null`);
155 is(beforeInputEvent.getTargetRanges().length, 0,
156 `${aDescription}getTargetRanges() of "beforeinput" event by ${aTestData.action} should return empty array`);
158 if ((
159 aTestData.cancelBeforeInput === true &&
160 aExpected.beforeInputEvent &&
161 aExpected.beforeInputEvent.cancelable
162 ) || aExpected.inputEvent === null || aExpected.inputEvent === undefined) {
163 ok(!inputEvent,
164 `${aDescription}"input" event shouldn't have been fired at ${aTestData.action}`);
165 } else {
166 ok(inputEvent,
167 `${aDescription}"input" event should've been fired at ${aTestData.action}`);
168 is(inputEvent.cancelable, false,
169 `${aDescription}"input" event by ${aTestData.action} should be not be cancelable`);
170 is(inputEvent.inputType, aExpected.inputEvent.inputType,
171 `${aDescription}inputType of "input" event by ${aTestData.action} should be "${aExpected.inputEvent.inputType}"`);
172 is(inputEvent.data, aExpected.inputEvent.data,
173 `${aDescription}data of "input" event by ${aTestData.action} should be ${
174 aExpected.inputEvent.data === null ? "null" : `"${aExpected.inputEvent.data}"`
175 }`);
176 is(inputEvent.dataTransfer, null,
177 `${aDescription}dataTransfer of "input" event by ${aTestData.action} should be null`);
178 is(inputEvent.getTargetRanges().length, 0,
179 `${aDescription}getTargetRanges() of "input" event by ${aTestData.action} should return empty array`);
181 } catch (ex) {
182 ok(false, `${aDescription}unexpected exception at verifying test result of "${aTestData.action}": ${ex.toString()}`);
184 })();
185 } finally {
186 aElement.removeEventListener("beforeinput", beforeInputHandler, true);
187 aElement.removeEventListener("input", inputHandler, true);
191 function test_typing_a_in_empty_editor(aTestData) {
192 aElement.value = "";
193 aElement.focus();
195 runTest(
196 aTestData,
197 () => {
198 sendString("a");
201 value: "a",
202 beforeInputEvent: {
203 cancelable: true,
204 inputType: "insertText",
205 data: "a",
207 inputEvent: {
208 inputType: "insertText",
209 data: "a",
214 test_typing_a_in_empty_editor({
215 action: 'typing "a" and canceling beforeinput',
216 cancelBeforeInput: true,
218 test_typing_a_in_empty_editor({
219 action: 'typing "a"',
220 cancelBeforeInput: false,
223 function test_typing_backspace_to_delete_last_character(aTestData) {
224 aElement.value = "a";
225 aElement.focus();
226 aElement.setSelectionStart = "a".length;
228 runTest(
229 aTestData,
230 () => {
231 synthesizeKey("KEY_Backspace");
234 value: "",
235 beforeInputEvent: {
236 cancelable: true,
237 inputType: "deleteContentBackward",
238 data: null,
240 inputEvent: {
241 inputType: "deleteContentBackward",
242 data: null,
247 test_typing_backspace_to_delete_last_character({
248 actin: 'typing "Backspace" to delete "a" and canceling "beforeinput"',
249 cancelBeforeInput: true,
251 test_typing_backspace_to_delete_last_character({
252 actin: 'typing "Backspace" to delete "a"',
253 cancelBeforeInput: false,
256 function test_typing_enter_in_empty_editor(aTestData) {
257 aElement.value = "";
258 aElement.focus();
260 runTest(
261 aTestData,
262 () => {
263 synthesizeKey("KEY_Enter");
265 aIsTextarea
267 value: "\n",
268 beforeInputEvent: {
269 cancelable: true,
270 inputType: "insertLineBreak",
271 data: null,
273 inputEvent: {
274 inputType: "insertLineBreak",
275 data: null,
279 value: "",
280 beforeInputEvent: {
281 cancelable: true,
282 inputType: "insertLineBreak",
283 data: null,
288 test_typing_enter_in_empty_editor({
289 action: 'typing "Enter" in empty editor and canceling "beforeinput"',
290 cancelBeforeInput: true,
292 test_typing_enter_in_empty_editor({
293 action: 'typing "Enter" in empty editor',
294 cancelBeforeInput: false,
297 (function test_setting_value(aTestData) {
298 aElement.value = "";
299 aElement.focus();
301 runTest(
302 aTestData,
303 () => {
304 aElement.value = "foo-bar";
306 { value: "foo-bar" }
308 })({
309 action: "setting non-empty value",
312 (function test_setting_empty_value(aTestData) {
313 aElement.value = "foo-bar";
314 aElement.focus();
316 runTest(
317 aTestData,
318 () => {
319 aElement.value = "";
321 { value: "" }
323 })({
324 action: "setting empty value",
327 (function test_typing_space_in_empty_editor(aTestData) {
328 aElement.value = "";
329 aElement.focus();
331 runTest(
332 aTestData,
333 () => {
334 sendString(" ");
337 value: " ",
338 beforeInputEvent: {
339 cancelable: true,
340 inputType: "insertText",
341 data: " ",
343 inputEvent: {
344 inputType: "insertText",
345 data: " ",
349 })({
350 action: "typing space",
353 (function test_typing_delete_at_end_of_editor(aTestData) {
354 aElement.value = " ";
355 aElement.focus();
357 runTest(
358 aTestData,
359 () => {
360 synthesizeKey("KEY_Delete");
363 value: " ",
364 beforeInputEvent: {
365 cancelable: true,
366 inputType: "deleteContentForward",
367 data: null,
371 })({
372 action: 'typing "Delete" at end of editor',
375 (function test_typing_arrow_left_to_move_caret(aTestData) {
376 aElement.value = " ";
377 aElement.focus();
378 aElement.selectionStart = 1;
380 runTest(
381 aTestData,
382 () => {
383 synthesizeKey("KEY_ArrowLeft");
385 { value: " " }
387 })({
388 action: 'typing "ArrowLeft" to move caret',
391 function test_typing_delete_to_delete_last_character(aTestData) {
392 aElement.value = " ";
393 aElement.focus();
394 aElement.selectionStart = 0;
396 runTest(
397 aTestData,
398 () => {
399 synthesizeKey("KEY_Delete");
402 value: "",
403 beforeInputEvent: {
404 cancelable: true,
405 inputType: "deleteContentForward",
406 data: null,
408 inputEvent: {
409 inputType: "deleteContentForward",
410 data: null,
415 test_typing_delete_to_delete_last_character({
416 action: 'typing "Delete" to delete space and canceling "beforeinput"',
417 cancelBeforeInput: true,
419 test_typing_delete_to_delete_last_character({
420 action: 'typing "Delete" to delete space',
421 cancelBeforeInput: false,
424 function test_undoing_deleting_last_character(aTestData) {
425 aElement.value = "a";
426 aElement.focus();
427 aElement.selectionStart = 0;
428 synthesizeKey("KEY_Delete");
430 runTest(
431 aTestData,
432 () => {
433 synthesizeKey("z", {accelKey: true});
436 value: "a",
437 beforeInputEvent: {
438 cancelable: true,
439 inputType: "historyUndo",
440 data: null,
442 inputEvent: {
443 inputType: "historyUndo",
444 data: null,
449 test_undoing_deleting_last_character({
450 action: 'undoing deleting last character and canceling "beforeinput"',
451 cancelBeforeInput: true,
453 test_undoing_deleting_last_character({
454 action: "undoing deleting last character",
455 cancelBeforeInput: false,
458 (function test_undoing_without_undoable_transaction(aTestData) {
459 aElement.value = "a";
460 aElement.focus();
461 aElement.selectionStart = 0;
462 synthesizeKey("KEY_Delete");
463 synthesizeKey("z", {accelKey: true});
465 runTest(
466 aTestData,
467 () => {
468 synthesizeKey("z", {accelKey: true});
470 { value: "a" }
472 })({
473 action: "trying to undo without undoable transaction"
476 function test_redoing_deleting_last_character(aTestData) {
477 aElement.value = "a";
478 aElement.focus();
479 aElement.selectionStart = 0;
480 synthesizeKey("KEY_Delete");
481 synthesizeKey("z", {accelKey: true});
483 runTest(
484 aTestData,
485 () => {
486 synthesizeKey("Z", {accelKey: true, shiftKey: true});
489 value: "",
490 beforeInputEvent: {
491 cancelable: true,
492 inputType: "historyRedo",
493 data: null,
495 inputEvent: {
496 inputType: "historyRedo",
497 data: null,
502 test_redoing_deleting_last_character({
503 action: 'redoing deleting last character and canceling "beforeinput"',
504 cancelBeforeInput: true,
506 test_redoing_deleting_last_character({
507 action: "redoing deleting last character",
508 cancelBeforeInput: false,
511 (function test_redoing_without_redoable_transaction(aTestData) {
512 aElement.value = "a";
513 aElement.focus();
514 aElement.selectionStart = 0;
515 synthesizeKey("KEY_Delete");
516 synthesizeKey("z", {accelKey: true});
517 synthesizeKey("Z", {accelKey: true, shiftKey: true});
519 runTest(
520 aTestData,
521 () => {
522 synthesizeKey("Z", {accelKey: true, shiftKey: true});
524 { value: "" }
526 })({
527 action: "trying to redo without redoable transaction"
530 function test_typing_backspace_with_selecting_all_characters(aTestData) {
531 aElement.value = "abc";
532 aElement.focus();
533 aElement.select();
535 runTest(
536 aTestData,
537 () => {
538 synthesizeKey("KEY_Backspace");
541 value: "",
542 beforeInputEvent: {
543 cancelable: true,
544 inputType: "deleteContentBackward",
545 data: null,
547 inputEvent: {
548 inputType: "deleteContentBackward",
549 data: null,
554 test_typing_backspace_with_selecting_all_characters({
555 action: 'typing "Backspace" to delete all selected characters and canceling "beforeinput"',
556 cancelBeforeInput: true,
558 test_typing_backspace_with_selecting_all_characters({
559 action: 'typing "Backspace" to delete all selected characters',
560 cancelBeforeInput: false,
563 function test_typing_delete_with_selecting_all_characters(aTestData) {
564 aElement.value = "abc";
565 aElement.focus();
566 aElement.select();
568 runTest(
569 aTestData,
570 () => {
571 synthesizeKey("KEY_Delete");
574 value: "",
575 beforeInputEvent: {
576 cancelable: true,
577 inputType: "deleteContentForward",
578 data: null,
580 inputEvent: {
581 inputType: "deleteContentForward",
582 data: null,
587 test_typing_delete_with_selecting_all_characters({
588 action: 'typing "Delete" to delete all selected characters and canceling "beforeinput"',
589 cancelBeforeInput: true,
591 test_typing_delete_with_selecting_all_characters({
592 action: 'typing "Delete" to delete all selected characters and canceling "beforeinput"',
593 cancelBeforeInput: false,
596 function test_deleting_word_backward_from_its_end(aTestData) {
597 aElement.value = "abc def";
598 aElement.focus();
599 document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
600 aElement.setSelectionRange("abc def".length, "abc def".length);
602 runTest(
603 aTestData,
604 () => {
605 SpecialPowers.doCommand(window, "cmd_deleteWordBackward");
608 value: "abc ",
609 beforeInputEvent: {
610 cancelable: true,
611 inputType: "deleteWordBackward",
612 data: null,
614 inputEvent: {
615 inputType: "deleteWordBackward",
616 data: null,
621 test_deleting_word_backward_from_its_end({
622 action: 'deleting word backward from its end and canceling "beforeinput"',
623 cancelBeforeInput: true,
625 test_deleting_word_backward_from_its_end({
626 action: 'deleting word backward from its end',
627 cancelBeforeInput: false,
630 function test_deleting_word_forward_from_its_start(aTestData) {
631 aElement.value = "abc def";
632 aElement.focus();
633 document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
634 aElement.setSelectionRange(0, 0);
636 runTest(
637 aTestData,
638 () => {
639 SpecialPowers.doCommand(window, "cmd_deleteWordForward");
642 value: kWordSelectEatSpaceToNextWord ? "def" : " def",
643 beforeInputEvent: {
644 cancelable: true,
645 inputType: "deleteWordForward",
646 data: null,
648 inputEvent: {
649 inputType: "deleteWordForward",
650 data: null,
655 test_deleting_word_forward_from_its_start({
656 action: 'deleting word forward from its start and canceling "beforeinput"',
657 cancelBeforeInput: true,
659 test_deleting_word_forward_from_its_start({
660 action: "deleting word forward from its start",
661 cancelBeforeInput: false,
664 (function test_deleting_word_backward_from_middle_of_second_word(aTestData) {
665 aElement.value = "abc def";
666 aElement.focus();
667 document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
668 aElement.setSelectionRange("abc d".length, "abc de".length);
670 runTest(
671 aTestData,
672 () => {
673 SpecialPowers.doCommand(window, "cmd_deleteWordBackward");
676 value: "abc df",
677 beforeInputEvent: {
678 cancelable: true,
679 inputType: "deleteContentBackward",
680 data: null,
682 inputEvent: {
683 inputType: "deleteContentBackward",
684 data: null,
688 })({
689 action: "removing characters backward from middle of second word",
692 (function test_deleting_word_forward_from_middle_of_first_word(aTestData) {
693 aElement.value = "abc def";
694 aElement.focus();
695 document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
696 aElement.setSelectionRange("a".length, "ab".length);
698 runTest(
699 aTestData,
700 () => {
701 SpecialPowers.doCommand(window, "cmd_deleteWordForward");
704 value: "ac def",
705 beforeInputEvent: {
706 cancelable: true,
707 inputType: "deleteContentForward",
708 data: null,
710 inputEvent: {
711 inputType: "deleteContentForward",
712 data: null,
716 })({
717 action: "removing characters forward from middle of first word",
720 (function test_deleting_characters_backward_to_start_of_line(aTestData) {
721 aElement.value = "abc def";
722 aElement.focus();
723 document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
724 aElement.setSelectionRange("abc d".length, "abc d".length);
726 runTest(
727 aTestData,
728 () => {
729 SpecialPowers.doCommand(window, "cmd_deleteToBeginningOfLine");
732 value: "ef",
733 beforeInputEvent: {
734 cancelable: true,
735 inputType: "deleteSoftLineBackward",
736 data: null,
738 inputEvent: {
739 inputType: "deleteSoftLineBackward",
740 data: null,
744 })({
745 action: "removing characters backward to start of line"
748 (function test_deleting_characters_forward_to_end_of_line(aTestData) {
749 aElement.value = "abc def";
750 aElement.focus();
751 document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
752 aElement.setSelectionRange("ab".length, "ab".length);
754 runTest(
755 aTestData,
756 () => {
757 SpecialPowers.doCommand(window, "cmd_deleteToEndOfLine");
760 value: "ab",
761 beforeInputEvent: {
762 cancelable: true,
763 inputType: "deleteSoftLineForward",
764 data: null,
766 inputEvent: {
767 inputType: "deleteSoftLineForward",
768 data: null,
772 })({
773 action: "removing characters forward to end of line",
776 (function test_deleting_characters_backward_to_start_of_line_with_non_collapsed_selection(aTestData) {
777 aElement.value = "abc def";
778 aElement.focus();
779 document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
780 aElement.setSelectionRange("abc d".length, "abc_de".length);
782 runTest(
783 aTestData,
784 () => {
785 SpecialPowers.doCommand(window, "cmd_deleteToBeginningOfLine");
788 value: "abc df",
789 beforeInputEvent: {
790 cancelable: true,
791 inputType: "deleteContentBackward",
792 data: null,
794 inputEvent: {
795 inputType: "deleteContentBackward",
796 data: null,
800 })({
801 action: "removing characters backward to start of line (with selection in second word)",
804 (function test_deleting_characters_forward_to_end_of_line_with_non_collapsed_selection(aTestData) {
805 aElement.value = "abc def";
806 aElement.focus();
807 document.documentElement.scrollTop; // XXX Needs reflow here for working with nsFrameSelection, must be a bug.
808 aElement.setSelectionRange("a".length, "ab".length);
810 runTest(
811 aTestData,
812 () => {
813 SpecialPowers.doCommand(window, "cmd_deleteToEndOfLine");
816 value: "ac def",
817 beforeInputEvent: {
818 cancelable: true,
819 inputType: "deleteContentForward",
820 data: null,
822 inputEvent: {
823 inputType: "deleteContentForward",
824 data: null,
828 })({
829 action: "removing characters forward to end of line (with selection in second word)",
832 function test_switching_text_direction_from_default(aTestData) {
833 try {
834 aElement.removeAttribute("dir");
835 aElement.scrollTop; // XXX Update the root frame
836 aElement.focus();
838 runTest(
839 aTestData,
840 () => {
841 SpecialPowers.doCommand(window, "cmd_switchTextDirection");
842 if (aTestData.cancelBeforeInput) {
843 is(aElement.getAttribute("dir"), null,
844 `${aDescription}dir attribute of the element shouldn't have been set by ${aTestData.action}`);
845 } else {
846 is(aElement.getAttribute("dir"), "rtl",
847 `${aDescription}dir attribute of the element should've been set to "rtl" by ${aTestData.action}`);
851 beforeInputEvent: {
852 cancelable: true,
853 inputType: "formatSetBlockTextDirection",
854 data: "rtl",
856 inputEvent: {
857 inputType: "formatSetBlockTextDirection",
858 data: "rtl",
862 } finally {
863 aElement.removeAttribute("dir");
864 aElement.scrollTop; // XXX Update the root frame
867 test_switching_text_direction_from_default({
868 action: 'switching text direction from default to "rtl" and canceling "beforeinput"',
869 cancelBeforeInput: true,
871 test_switching_text_direction_from_default({
872 action: 'switching text direction from default to "rtl"',
873 cancelBeforeInput: false,
876 function test_switching_text_direction_from_rtl_to_ltr(aTestData) {
877 try {
878 aElement.setAttribute("dir", "rtl");
879 aElement.scrollTop; // XXX Update the root frame
880 aElement.focus();
882 runTest(
883 aTestData,
884 () => {
885 SpecialPowers.doCommand(window, "cmd_switchTextDirection");
886 let expectedDirValue = aTestData.cancelBeforeInput ? "rtl" : "ltr";
887 is(aElement.getAttribute("dir"), expectedDirValue,
888 `${aDescription}dir attribute of the element should be "${expectedDirValue}" after ${aTestData.action}`);
891 beforeInputEvent: {
892 cancelable: true,
893 inputType: "formatSetBlockTextDirection",
894 data: "ltr",
896 inputEvent: {
897 inputType: "formatSetBlockTextDirection",
898 data: "ltr",
902 } finally {
903 aElement.removeAttribute("dir");
904 aElement.scrollTop; // XXX Update the root frame
907 test_switching_text_direction_from_rtl_to_ltr({
908 action: 'switching text direction from "rtl" to "ltr" and canceling "beforeinput"',
909 cancelBeforeInput: true,
911 test_switching_text_direction_from_rtl_to_ltr({
912 action: 'switching text direction from "rtl" to "ltr" and canceling "beforeinput"',
913 cancelBeforeInput: false,
917 doTests(document.getElementById("input"), "<input type=\"text\">", false);
918 doTests(document.getElementById("textarea"), "<textarea>", true);
920 SimpleTest.finish();
923 </script>
924 </body>
926 </html>