browser_text_caret.js (20046B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 /* import-globals-from ../../mochitest/attributes.js */ 8 loadScripts({ name: "attributes.js", dir: MOCHITESTS_DIR }); 9 /* import-globals-from ../../mochitest/text.js */ 10 11 /** 12 * Test caret retrieval. 13 */ 14 addAccessibleTask( 15 ` 16 <textarea id="textarea" 17 spellcheck="false" 18 style="scrollbar-width: none; font-family: 'Liberation Mono', monospace;" 19 cols="6">ab cd e</textarea> 20 <textarea id="empty"></textarea> 21 <div id="contentEditable" contenteditable>a<span>b</span></div> 22 `, 23 async function (browser, docAcc) { 24 const textarea = findAccessibleChildByID(docAcc, "textarea", [ 25 nsIAccessibleText, 26 ]); 27 let caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 28 textarea.takeFocus(); 29 let evt = await caretMoved; 30 is(textarea.caretOffset, 0, "Initial caret offset is 0"); 31 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 32 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 33 testTextAtOffset( 34 kCaretOffset, 35 BOUNDARY_CHAR, 36 "a", 37 0, 38 1, 39 textarea, 40 kOk, 41 kOk, 42 kOk 43 ); 44 testTextAtOffset( 45 kCaretOffset, 46 BOUNDARY_WORD_START, 47 "ab ", 48 0, 49 3, 50 textarea, 51 kOk, 52 kOk, 53 kOk 54 ); 55 testTextAtOffset( 56 kCaretOffset, 57 BOUNDARY_LINE_START, 58 "ab cd ", 59 0, 60 6, 61 textarea, 62 kOk, 63 kOk, 64 kOk 65 ); 66 67 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 68 EventUtils.synthesizeKey("KEY_ArrowRight"); 69 evt = await caretMoved; 70 is(textarea.caretOffset, 1, "Caret offset is 1 after ArrowRight"); 71 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 72 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 73 testTextAtOffset( 74 kCaretOffset, 75 BOUNDARY_CHAR, 76 "b", 77 1, 78 2, 79 textarea, 80 kOk, 81 kOk, 82 kOk 83 ); 84 testTextAtOffset( 85 kCaretOffset, 86 BOUNDARY_WORD_START, 87 "ab ", 88 0, 89 3, 90 textarea, 91 kOk, 92 kOk, 93 kOk 94 ); 95 testTextAtOffset( 96 kCaretOffset, 97 BOUNDARY_LINE_START, 98 "ab cd ", 99 0, 100 6, 101 textarea, 102 kOk, 103 kOk, 104 kOk 105 ); 106 107 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 108 EventUtils.synthesizeKey("KEY_ArrowRight"); 109 evt = await caretMoved; 110 is(textarea.caretOffset, 2, "Caret offset is 2 after ArrowRight"); 111 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 112 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 113 testTextAtOffset( 114 kCaretOffset, 115 BOUNDARY_CHAR, 116 " ", 117 2, 118 3, 119 textarea, 120 kOk, 121 kOk, 122 kOk 123 ); 124 testTextAtOffset( 125 kCaretOffset, 126 BOUNDARY_WORD_START, 127 "ab ", 128 0, 129 3, 130 textarea, 131 kOk, 132 kOk, 133 kOk 134 ); 135 testTextAtOffset( 136 kCaretOffset, 137 BOUNDARY_LINE_START, 138 "ab cd ", 139 0, 140 6, 141 textarea, 142 kOk, 143 kOk, 144 kOk 145 ); 146 147 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 148 EventUtils.synthesizeKey("KEY_ArrowRight"); 149 evt = await caretMoved; 150 is(textarea.caretOffset, 3, "Caret offset is 3 after ArrowRight"); 151 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 152 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 153 testTextAtOffset( 154 kCaretOffset, 155 BOUNDARY_CHAR, 156 "c", 157 3, 158 4, 159 textarea, 160 kOk, 161 kOk, 162 kOk 163 ); 164 testTextAtOffset( 165 kCaretOffset, 166 BOUNDARY_WORD_START, 167 "cd ", 168 3, 169 6, 170 textarea, 171 kOk, 172 kOk, 173 kOk 174 ); 175 testTextAtOffset( 176 kCaretOffset, 177 BOUNDARY_LINE_START, 178 "ab cd ", 179 0, 180 6, 181 textarea, 182 kOk, 183 kOk, 184 kOk 185 ); 186 187 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 188 EventUtils.synthesizeKey("KEY_ArrowRight"); 189 evt = await caretMoved; 190 is(textarea.caretOffset, 4, "Caret offset is 4 after ArrowRight"); 191 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 192 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 193 testTextAtOffset( 194 kCaretOffset, 195 BOUNDARY_CHAR, 196 "d", 197 4, 198 5, 199 textarea, 200 kOk, 201 kOk, 202 kOk 203 ); 204 testTextAtOffset( 205 kCaretOffset, 206 BOUNDARY_WORD_START, 207 "cd ", 208 3, 209 6, 210 textarea, 211 kOk, 212 kOk, 213 kOk 214 ); 215 testTextAtOffset( 216 kCaretOffset, 217 BOUNDARY_LINE_START, 218 "ab cd ", 219 0, 220 6, 221 textarea, 222 kOk, 223 kOk, 224 kOk 225 ); 226 227 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 228 EventUtils.synthesizeKey("KEY_ArrowRight"); 229 evt = await caretMoved; 230 is(textarea.caretOffset, 5, "Caret offset is 5 after ArrowRight"); 231 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 232 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 233 testTextAtOffset( 234 kCaretOffset, 235 BOUNDARY_CHAR, 236 " ", 237 5, 238 6, 239 textarea, 240 kOk, 241 kOk, 242 kOk 243 ); 244 testTextAtOffset( 245 kCaretOffset, 246 BOUNDARY_WORD_START, 247 "cd ", 248 3, 249 6, 250 textarea, 251 kOk, 252 kOk, 253 kOk 254 ); 255 testTextAtOffset( 256 kCaretOffset, 257 BOUNDARY_LINE_START, 258 "ab cd ", 259 0, 260 6, 261 textarea, 262 kOk, 263 kOk, 264 kOk 265 ); 266 267 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 268 EventUtils.synthesizeKey("KEY_ArrowRight"); 269 evt = await caretMoved; 270 is(textarea.caretOffset, 6, "Caret offset is 6 after ArrowRight"); 271 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 272 ok(evt.isAtEndOfLine, "Caret is at end of line"); 273 testTextAtOffset( 274 kCaretOffset, 275 BOUNDARY_CHAR, 276 "", 277 6, 278 6, 279 textarea, 280 kOk, 281 kOk, 282 kOk 283 ); 284 testTextAtOffset( 285 kCaretOffset, 286 BOUNDARY_CLUSTER, 287 "", 288 6, 289 6, 290 textarea, 291 kOk, 292 kOk, 293 kOk 294 ); 295 testTextAtOffset( 296 kCaretOffset, 297 BOUNDARY_WORD_START, 298 "cd ", 299 3, 300 6, 301 textarea, 302 kOk, 303 kOk, 304 kOk 305 ); 306 testTextAtOffset( 307 kCaretOffset, 308 BOUNDARY_LINE_START, 309 "ab cd ", 310 0, 311 6, 312 textarea, 313 kOk, 314 kOk, 315 kOk 316 ); 317 318 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 319 EventUtils.synthesizeKey("KEY_ArrowRight"); 320 evt = await caretMoved; 321 is(textarea.caretOffset, 6, "Caret offset remains 6 after ArrowRight"); 322 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 323 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 324 // Caret is at start of second line. 325 testTextAtOffset( 326 kCaretOffset, 327 BOUNDARY_CHAR, 328 "e", 329 6, 330 7, 331 textarea, 332 kOk, 333 kOk, 334 kOk 335 ); 336 testTextAtOffset( 337 kCaretOffset, 338 BOUNDARY_WORD_START, 339 "e", 340 6, 341 7, 342 textarea, 343 kOk, 344 kOk, 345 kOk 346 ); 347 testTextAtOffset( 348 kCaretOffset, 349 BOUNDARY_LINE_START, 350 "e", 351 6, 352 7, 353 textarea, 354 kOk, 355 kOk, 356 kOk 357 ); 358 359 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 360 EventUtils.synthesizeKey("KEY_ArrowRight"); 361 evt = await caretMoved; 362 is(textarea.caretOffset, 7, "Caret offset is 7 after ArrowRight"); 363 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 364 ok(evt.isAtEndOfLine, "Caret is at end of line"); 365 // Caret is at end of textarea. 366 testTextAtOffset( 367 kCaretOffset, 368 BOUNDARY_CHAR, 369 "", 370 7, 371 7, 372 textarea, 373 kOk, 374 kOk, 375 kOk 376 ); 377 testTextAtOffset( 378 kCaretOffset, 379 BOUNDARY_WORD_START, 380 "e", 381 6, 382 7, 383 textarea, 384 kOk, 385 kOk, 386 kOk 387 ); 388 testTextAtOffset( 389 kCaretOffset, 390 BOUNDARY_LINE_START, 391 "e", 392 6, 393 7, 394 textarea, 395 kOk, 396 kOk, 397 kOk 398 ); 399 400 // BrowserTestUtils.synthesizeMouseAtPoint takes coordinates relative to the document. 401 const docX = {}; 402 const docY = {}; 403 docAcc.getBounds(docX, docY, {}, {}); 404 let charX = {}; 405 let charY = {}; 406 textarea.getCharacterExtents( 407 0, 408 charX, 409 charY, 410 {}, 411 {}, 412 COORDTYPE_SCREEN_RELATIVE 413 ); 414 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 415 await BrowserTestUtils.synthesizeMouseAtPoint( 416 charX.value - docX.value, 417 charY.value - docY.value, 418 {}, 419 docAcc.browsingContext 420 ); 421 evt = await caretMoved; 422 is(textarea.caretOffset, 0, "Caret offset is 0 after click"); 423 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 424 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 425 testTextAtOffset( 426 kCaretOffset, 427 BOUNDARY_CHAR, 428 "a", 429 0, 430 1, 431 textarea, 432 kOk, 433 kOk, 434 kOk 435 ); 436 textarea.getCharacterExtents( 437 1, 438 charX, 439 charY, 440 {}, 441 {}, 442 COORDTYPE_SCREEN_RELATIVE 443 ); 444 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 445 await BrowserTestUtils.synthesizeMouseAtPoint( 446 charX.value - docX.value, 447 charY.value - docY.value, 448 {}, 449 docAcc.browsingContext 450 ); 451 evt = await caretMoved; 452 is(textarea.caretOffset, 1, "Caret offset is 1 after click"); 453 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 454 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 455 testTextAtOffset( 456 kCaretOffset, 457 BOUNDARY_CHAR, 458 "b", 459 1, 460 2, 461 textarea, 462 kOk, 463 kOk, 464 kOk 465 ); 466 467 const empty = findAccessibleChildByID(docAcc, "empty", [nsIAccessibleText]); 468 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, empty); 469 empty.takeFocus(); 470 evt = await caretMoved; 471 is(empty.caretOffset, 0, "Caret offset in empty textarea is 0"); 472 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 473 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 474 475 const contentEditable = findAccessibleChildByID(docAcc, "contentEditable", [ 476 nsIAccessibleText, 477 ]); 478 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, contentEditable); 479 contentEditable.takeFocus(); 480 evt = await caretMoved; 481 is( 482 contentEditable.caretOffset, 483 0, 484 "Initial caret offset in contentEditable is 0" 485 ); 486 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 487 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 488 testTextAtOffset( 489 kCaretOffset, 490 BOUNDARY_CHAR, 491 "a", 492 0, 493 1, 494 contentEditable, 495 kOk, 496 kOk, 497 kOk 498 ); 499 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, contentEditable); 500 EventUtils.synthesizeKey("KEY_ArrowRight"); 501 evt = await caretMoved; 502 is(contentEditable.caretOffset, 1, "Caret offset is 1 after ArrowRight"); 503 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 504 ok(!evt.isAtEndOfLine, "Caret is not at end of line"); 505 testTextAtOffset( 506 kCaretOffset, 507 BOUNDARY_CHAR, 508 "b", 509 1, 510 2, 511 contentEditable, 512 kOk, 513 kOk, 514 kOk 515 ); 516 }, 517 { chrome: true, topLevel: true, iframe: true, remoteIframe: true } 518 ); 519 520 /** 521 * Test setting the caret. 522 */ 523 addAccessibleTask( 524 ` 525 <textarea id="textarea">ab\nc</textarea> 526 <div id="editable" contenteditable> 527 <p id="p">a<a id="link" href="https://example.com/">b</a></p> 528 </div> 529 `, 530 async function (browser, docAcc) { 531 const textarea = findAccessibleChildByID(docAcc, "textarea", [ 532 nsIAccessibleText, 533 ]); 534 info("textarea: Set caret offset to 0"); 535 let focused = waitForEvent(EVENT_FOCUS, textarea); 536 let caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 537 textarea.caretOffset = 0; 538 await focused; 539 await caretMoved; 540 is(textarea.caretOffset, 0, "textarea caret correct"); 541 // Test setting caret to another line. 542 info("textarea: Set caret offset to 3"); 543 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 544 textarea.caretOffset = 3; 545 await caretMoved; 546 is(textarea.caretOffset, 3, "textarea caret correct"); 547 // Test setting caret to the end. 548 info("textarea: Set caret offset to 4 (end)"); 549 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 550 textarea.caretOffset = 4; 551 await caretMoved; 552 is(textarea.caretOffset, 4, "textarea caret correct"); 553 554 const editable = findAccessibleChildByID(docAcc, "editable", [ 555 nsIAccessibleText, 556 ]); 557 focused = waitForEvent(EVENT_FOCUS, editable); 558 editable.takeFocus(); 559 await focused; 560 const p = findAccessibleChildByID(docAcc, "p", [nsIAccessibleText]); 561 info("p: Set caret offset to 0"); 562 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, p); 563 p.caretOffset = 0; 564 await focused; 565 await caretMoved; 566 is(p.caretOffset, 0, "p caret correct"); 567 const link = findAccessibleChildByID(docAcc, "link", [nsIAccessibleText]); 568 info("link: Set caret offset to 0"); 569 caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, link); 570 link.caretOffset = 0; 571 await caretMoved; 572 is(link.caretOffset, 0, "link caret correct"); 573 }, 574 { chrome: true, topLevel: true, iframe: true, remoteIframe: true } 575 ); 576 577 /** 578 * Test setting the caret in a contentEditable which is aria-hidden. Arguably, 579 * we shouldn't fire caret events at all in this case, but really, this is just 580 * bad authoring and shouldn't happen. We just need to make sure that the 581 * offsets we do fire are at least valid so we don't trigger assertions or 582 * confuse clients. 583 */ 584 addAccessibleTask( 585 ` 586 <div contenteditable id="editable" aria-hidden="true">abcd</div> 587 <p></p> 588 `, 589 async function testSetCaretInAriaHidden(browser, docAcc) { 590 info("Focusing editable"); 591 let moved = waitForEvent(EVENT_TEXT_CARET_MOVED, docAcc); 592 await invokeContentTask(browser, [], () => { 593 content.document.getElementById("editable").focus(); 594 }); 595 let evt = await moved; 596 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 597 is(evt.caretOffset, 0, "Caret event is for offset 0"); 598 599 info("Setting caret in editable to c"); 600 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, docAcc); 601 await invokeContentTask(browser, [], () => { 602 const text = content.document.getElementById("editable").firstChild; 603 content.getSelection().setBaseAndExtent(text, 3, text, 3); 604 }); 605 evt = await moved; 606 evt.QueryInterface(nsIAccessibleCaretMoveEvent); 607 is(evt.caretOffset, 0, "Caret event is for offset 0"); 608 } 609 ); 610 611 /** 612 * Test the caret when clicking in an empty area of a container immediately 613 * before/after a text input. 614 */ 615 addAccessibleTask( 616 ` 617 <div id="inputThenEmpty" style="padding-bottom: 10vh;"> 618 <input id="inputBeforeEmpty" value="ab"> 619 </div> 620 <div id="emptyThenInput" style="padding-top: 10vh;"> 621 <input id="inputAfterEmpty" value="cd"> 622 </div> 623 `, 624 async function testEmptyNearInput(browser, docAcc) { 625 info("Focusing inputBeforeEmpty"); 626 let input = findAccessibleChildByID(docAcc, "inputBeforeEmpty", [ 627 nsIAccessibleText, 628 ]); 629 let moved = waitForEvents([ 630 [EVENT_FOCUS, input], 631 [EVENT_TEXT_CARET_MOVED, input], 632 ]); 633 input.takeFocus(); 634 await moved; 635 is(input.caretOffset, 0, "caretOffset 0"); 636 637 info("Clicking at bottom of inputThenEmpty"); 638 // BrowserTestUtils.synthesizeMouseAtPoint takes coordinates relative to the 639 // document. 640 const docX = {}; 641 const docY = {}; 642 docAcc.getBounds(docX, docY, {}, {}); 643 let container = findAccessibleChildByID(docAcc, "inputThenEmpty", [ 644 nsIAccessibleText, 645 ]); 646 const containerX = {}; 647 const containerY = {}; 648 const containerH = {}; 649 container.getBounds(containerX, containerY, {}, containerH); 650 moved = waitForEvents([ 651 [EVENT_FOCUS, docAcc], 652 [EVENT_TEXT_CARET_MOVED, container], 653 ]); 654 await BrowserTestUtils.synthesizeMouseAtPoint( 655 containerX.value - docX.value, 656 containerY.value + containerH.value - 1 - docY.value, 657 {}, 658 docAcc.browsingContext 659 ); 660 await moved; 661 docAcc.QueryInterface(nsIAccessibleText); 662 is(input.caretOffset, -1, "No caret in inputBeforeEmpty"); 663 664 info("Focusing inputAfterEmpty"); 665 input = findAccessibleChildByID(docAcc, "inputAfterEmpty", [ 666 nsIAccessibleText, 667 ]); 668 moved = waitForEvents([ 669 [EVENT_FOCUS, input], 670 [EVENT_TEXT_CARET_MOVED, input], 671 ]); 672 input.takeFocus(); 673 await moved; 674 is(input.caretOffset, 0, "caretOffset 0"); 675 676 info("Clicking at top of emptyThenInput"); 677 container = findAccessibleChildByID(docAcc, "emptyThenInput", [ 678 nsIAccessibleText, 679 ]); 680 container.getBounds(containerX, containerY, {}, {}); 681 // The caret event fires in the input instead of the container, but this 682 // isn't really important. 683 moved = waitForEvents([ 684 [EVENT_FOCUS, docAcc], 685 [EVENT_TEXT_CARET_MOVED, input], 686 ]); 687 await BrowserTestUtils.synthesizeMouseAtPoint( 688 containerX.value - docX.value, 689 containerY.value - docY.value + 1, 690 {}, 691 docAcc.browsingContext 692 ); 693 await moved; 694 is(input.caretOffset, -1, "No caret in inputAfterEmpty"); 695 }, 696 { chrome: true, topLevel: true } 697 ); 698 699 /** 700 * Test retrieving the caret line number. 701 */ 702 addAccessibleTask( 703 ` 704 ab 705 <blockquote id="blockquote"> 706 cd<br> 707 ef 708 <p id="p">gh</p> 709 </blockquote> 710 ij 711 `, 712 async function testLineNumber(browser, docAcc) { 713 docAcc.QueryInterface(nsIAccessibleText); 714 testAttrs(docAcc, { "line-number": "1" }, true); 715 info("Moving caret to b"); 716 let moved = waitForEvent(EVENT_TEXT_CARET_MOVED, docAcc); 717 docAcc.caretOffset = 1; 718 await moved; 719 testAttrs(docAcc, { "line-number": "1" }, true); 720 info("Moving caret to c"); 721 const blockquote = findAccessibleChildByID(docAcc, "blockquote", [ 722 nsIAccessibleText, 723 ]); 724 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, blockquote); 725 blockquote.caretOffset = 0; 726 await moved; 727 testAttrs(docAcc, { "line-number": "2" }, true); 728 info("Moving caret to d"); 729 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, blockquote); 730 blockquote.caretOffset = 1; 731 await moved; 732 testAttrs(docAcc, { "line-number": "2" }, true); 733 info("Moving caret to e"); 734 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, blockquote); 735 blockquote.caretOffset = 3; 736 await moved; 737 testAttrs(docAcc, { "line-number": "3" }, true); 738 info("Moving caret to f"); 739 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, blockquote); 740 blockquote.caretOffset = 4; 741 await moved; 742 testAttrs(docAcc, { "line-number": "3" }, true); 743 info("moving caret to g"); 744 const p = findAccessibleChildByID(docAcc, "p", [nsIAccessibleText]); 745 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, p); 746 p.caretOffset = 0; 747 await moved; 748 testAttrs(docAcc, { "line-number": "4" }, true); 749 info("moving caret to h"); 750 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, p); 751 p.caretOffset = 1; 752 await moved; 753 testAttrs(docAcc, { "line-number": "4" }, true); 754 info("moving caret to i"); 755 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, docAcc); 756 docAcc.caretOffset = 4; 757 await moved; 758 testAttrs(docAcc, { "line-number": "5" }, true); 759 info("moving caret to j"); 760 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, docAcc); 761 docAcc.caretOffset = 5; 762 await moved; 763 testAttrs(docAcc, { "line-number": "5" }, true); 764 info("moving caret to end"); 765 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, docAcc); 766 // We end up with space at the end of the document, so use characterCount to 767 // ensure we really move to the end. 768 docAcc.caretOffset = docAcc.characterCount; 769 await moved; 770 testAttrs(docAcc, { "line-number": "5" }, true); 771 }, 772 { 773 // Bug 2007033: This is currently only supported for LocalAccessible. 774 chrome: true, 775 topLevel: false, 776 contentSetup: async function contentSetup() { 777 content.document.designMode = "on"; 778 }, 779 } 780 );