browser_textPatterns.js (106479B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 "use strict"; 7 8 /* import-globals-from ../../../mochitest/text.js */ 9 loadScripts({ name: "text.js", dir: MOCHITESTS_DIR }); 10 11 /* eslint-disable camelcase */ 12 const SupportedTextSelection_None = 0; 13 const SupportedTextSelection_Multiple = 2; 14 /* eslint-enable camelcase */ 15 16 /** 17 * Test the Text pattern's DocumentRange property. This also tests where the 18 * Text pattern is exposed. 19 */ 20 addUiaTask( 21 ` 22 <div><input id="input" value="input"></div> 23 <textarea id="textarea">textarea</textarea> 24 <div id="contentEditable" contenteditable><p>content</p><p>editable</p></div> 25 <p id="p">p</p> 26 <a id="link" href="#">link</a> 27 `, 28 async function testTextDocumentRange() { 29 await definePyVar("doc", `getDocUia()`); 30 await definePyVar("pattern", `getUiaPattern(doc, "Text")`); 31 ok(await runPython(`bool(pattern)`), "doc has Text pattern"); 32 // The IA2 -> UIA proxy adds spaces between elements that don't exist. 33 if (gIsUiaEnabled) { 34 is( 35 await runPython(`pattern.DocumentRange.GetText(-1)`), 36 "inputtextareacontenteditableplink", 37 "document DocumentRange Text correct" 38 ); 39 } 40 41 await assignPyVarToUiaWithId("input"); 42 await definePyVar("pattern", `getUiaPattern(input, "Text")`); 43 ok(await runPython(`bool(pattern)`), "input has Text pattern"); 44 is( 45 await runPython(`pattern.DocumentRange.GetText(-1)`), 46 "input", 47 "input DocumentRange Text correct" 48 ); 49 50 await assignPyVarToUiaWithId("textarea"); 51 await definePyVar("pattern", `getUiaPattern(textarea, "Text")`); 52 ok(await runPython(`bool(pattern)`), "textarea has Text pattern"); 53 is( 54 await runPython(`pattern.DocumentRange.GetText(-1)`), 55 "textarea", 56 "textarea DocumentRange Text correct" 57 ); 58 59 // The IA2 -> UIA proxy doesn't expose the Text pattern on contentEditables 60 // without role="textbox". 61 if (gIsUiaEnabled) { 62 await assignPyVarToUiaWithId("contentEditable"); 63 await definePyVar("pattern", `getUiaPattern(contentEditable, "Text")`); 64 ok(await runPython(`bool(pattern)`), "contentEditable has Text pattern"); 65 is( 66 await runPython(`pattern.DocumentRange.GetText(-1)`), 67 "contenteditable", 68 "contentEditable DocumentRange Text correct" 69 ); 70 } 71 72 await testPatternAbsent("p", "Text"); 73 // The IA2 -> UIA proxy doesn't expose the Text pattern on this text leaf. 74 if (gIsUiaEnabled) { 75 await runPython(` 76 global pLeaf 77 p = findUiaByDomId(doc, "p") 78 pLeaf = uiaClient.RawViewWalker.GetFirstChildElement(p) 79 `); 80 await definePyVar("pattern", `getUiaPattern(pLeaf, "Text")`); 81 ok(await runPython(`bool(pattern)`), "pLeaf has Text pattern"); 82 is( 83 await runPython(`pattern.DocumentRange.GetText(-1)`), 84 "p", 85 "pLeaf DocumentRange Text correct" 86 ); 87 } 88 89 await testPatternAbsent("link", "Text"); 90 // The IA2 -> UIA proxy doesn't expose this text leaf at all. 91 if (gIsUiaEnabled) { 92 await runPython(` 93 global linkLeaf 94 link = findUiaByDomId(doc, "link") 95 linkLeaf = uiaClient.RawViewWalker.GetFirstChildElement(link) 96 `); 97 await definePyVar("pattern", `getUiaPattern(linkLeaf, "Text")`); 98 ok(await runPython(`bool(pattern)`), "linkLeaf has Text pattern"); 99 is( 100 await runPython(`pattern.DocumentRange.GetText(-1)`), 101 "link", 102 "linkLeaf DocumentRange Text correct" 103 ); 104 } 105 } 106 ); 107 108 /** 109 * Test the TextRange pattern's GetText method. 110 */ 111 addUiaTask( 112 `<div id="editable" contenteditable role="textbox">a <span>b</span>`, 113 async function testTextRangeGetText() { 114 await runPython(` 115 doc = getDocUia() 116 editable = findUiaByDomId(doc, "editable") 117 text = getUiaPattern(editable, "Text") 118 global range 119 range = text.DocumentRange 120 `); 121 is(await runPython(`range.GetText(-1)`), "a b", "GetText(-1) correct"); 122 is(await runPython(`range.GetText(0)`), "", "GetText(0) correct"); 123 is(await runPython(`range.GetText(1)`), "a", "GetText(1) correct"); 124 is(await runPython(`range.GetText(2)`), "a ", "GetText(2) correct"); 125 is(await runPython(`range.GetText(3)`), "a b", "GetText(3) correct"); 126 is(await runPython(`range.GetText(4)`), "a b", "GetText(4) correct"); 127 } 128 ); 129 130 /** 131 * Test the TextRange pattern's Clone method. 132 */ 133 addUiaTask( 134 `<input id="input" type="text" value="testing">`, 135 async function testTextRangeClone() { 136 await runPython(` 137 doc = getDocUia() 138 input = findUiaByDomId(doc, "input") 139 text = getUiaPattern(input, "Text") 140 global origRange 141 origRange = text.DocumentRange 142 `); 143 is( 144 await runPython(`origRange.GetText(-1)`), 145 "testing", 146 "origRange text correct" 147 ); 148 await runPython(` 149 global clonedRange 150 clonedRange = origRange.Clone() 151 `); 152 is( 153 await runPython(`clonedRange.GetText(-1)`), 154 "testing", 155 "clonedRange text correct" 156 ); 157 158 // Test that modifying clonedRange doesn't impact origRange. 159 info("Collapsing clonedRange to start"); 160 await runPython( 161 `clonedRange.MoveEndpointByRange(TextPatternRangeEndpoint_End, clonedRange, TextPatternRangeEndpoint_Start)` 162 ); 163 is( 164 await runPython(`clonedRange.GetText(-1)`), 165 "", 166 "clonedRange text correct" 167 ); 168 is( 169 await runPython(`origRange.GetText(-1)`), 170 "testing", 171 "origRange text correct" 172 ); 173 } 174 ); 175 176 /** 177 * Test the TextRange pattern's Compare method. 178 */ 179 addUiaTask( 180 `<input id="input" type="text" value="testing">`, 181 async function testTextRangeCompare() { 182 await runPython(` 183 doc = getDocUia() 184 input = findUiaByDomId(doc, "input") 185 text = getUiaPattern(input, "Text") 186 global range1, range2 187 range1 = text.DocumentRange 188 range2 = text.DocumentRange 189 `); 190 ok( 191 await runPython(`range1.Compare(range2)`), 192 "range1 Compare range2 correct" 193 ); 194 ok( 195 await runPython(`range2.Compare(range1)`), 196 "range2 Compare range1 correct" 197 ); 198 info("Collapsing range2 to start"); 199 await runPython( 200 `range2.MoveEndpointByRange(TextPatternRangeEndpoint_End, range2, TextPatternRangeEndpoint_Start)` 201 ); 202 ok( 203 !(await runPython(`range1.Compare(range2)`)), 204 "range1 Compare range2 correct" 205 ); 206 ok( 207 !(await runPython(`range2.Compare(range1)`)), 208 "range2 Compare range1 correct" 209 ); 210 } 211 ); 212 213 /** 214 * Test the TextRange pattern's CompareEndpoints method. 215 */ 216 addUiaTask( 217 ` 218 <p>before</p> 219 <div><input id="input" type="text" value="input"></div> 220 <p>after</p> 221 `, 222 async function testTextRangeCompareEndpoints() { 223 await runPython(` 224 global doc, range1, range2 225 doc = getDocUia() 226 input = findUiaByDomId(doc, "input") 227 text = getUiaPattern(input, "Text") 228 range1 = text.DocumentRange 229 range2 = text.DocumentRange 230 `); 231 is( 232 await runPython( 233 `range1.CompareEndpoints(TextPatternRangeEndpoint_Start, range1, TextPatternRangeEndpoint_Start)` 234 ), 235 0, 236 "Compare range1 start to range1 start correct" 237 ); 238 is( 239 await runPython( 240 `range1.CompareEndpoints(TextPatternRangeEndpoint_End, range1, TextPatternRangeEndpoint_End)` 241 ), 242 0, 243 "Compare range1 end to range1 end correct" 244 ); 245 is( 246 await runPython( 247 `range1.CompareEndpoints(TextPatternRangeEndpoint_Start, range1, TextPatternRangeEndpoint_End)` 248 ), 249 -1, 250 "Compare range1 start to range1 end correct" 251 ); 252 is( 253 await runPython( 254 `range1.CompareEndpoints(TextPatternRangeEndpoint_End, range1, TextPatternRangeEndpoint_Start)` 255 ), 256 1, 257 "Compare range1 end to range1 start correct" 258 ); 259 // Compare different ranges. 260 is( 261 await runPython( 262 `range1.CompareEndpoints(TextPatternRangeEndpoint_Start, range2, TextPatternRangeEndpoint_Start)` 263 ), 264 0, 265 "Compare range1 start to range2 start correct" 266 ); 267 is( 268 await runPython( 269 `range1.CompareEndpoints(TextPatternRangeEndpoint_End, range2, TextPatternRangeEndpoint_End)` 270 ), 271 0, 272 "Compare range1 end to range2 end correct" 273 ); 274 is( 275 await runPython( 276 `range1.CompareEndpoints(TextPatternRangeEndpoint_Start, range2, TextPatternRangeEndpoint_End)` 277 ), 278 -1, 279 "Compare range1 start to range2 end correct" 280 ); 281 is( 282 await runPython( 283 `range1.CompareEndpoints(TextPatternRangeEndpoint_End, range2, TextPatternRangeEndpoint_Start)` 284 ), 285 1, 286 "Compare range1 end to range2 start correct" 287 ); 288 // Compare ranges created using different elements. 289 await definePyVar("range3", `getUiaPattern(doc, "Text").DocumentRange`); 290 is( 291 await runPython( 292 `range1.CompareEndpoints(TextPatternRangeEndpoint_Start, range3, TextPatternRangeEndpoint_Start)` 293 ), 294 1, 295 "Compare range1 start to range3 start correct" 296 ); 297 is( 298 await runPython( 299 `range1.CompareEndpoints(TextPatternRangeEndpoint_End, range3, TextPatternRangeEndpoint_End)` 300 ), 301 -1, 302 "Compare range1 end to range3 end correct" 303 ); 304 } 305 ); 306 307 /** 308 * Test the TextRange pattern's ExpandToEnclosingUnit method. 309 */ 310 addUiaTask( 311 ` 312 <p>before</p> 313 <div><textarea id="textarea" cols="5">ab cd ef gh</textarea></div> 314 <div>after <input id="input" value="input"></div> 315 `, 316 async function testTextRangeExpandToEnclosingUnit() { 317 info("Getting DocumentRange from textarea"); 318 await runPython(` 319 global doc, range 320 doc = getDocUia() 321 textarea = findUiaByDomId(doc, "textarea") 322 text = getUiaPattern(textarea, "Text") 323 range = text.DocumentRange 324 `); 325 is( 326 await runPython(`range.GetText(-1)`), 327 "ab cd ef gh", 328 "range text correct" 329 ); 330 // Expand should shrink the range because it's too big. 331 info("Expanding to character"); 332 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 333 is(await runPython(`range.GetText(-1)`), "a", "range text correct"); 334 info("Collapsing to end"); 335 await runPython( 336 `range.MoveEndpointByRange(TextPatternRangeEndpoint_Start, range, TextPatternRangeEndpoint_End)` 337 ); 338 is(await runPython(`range.GetText(-1)`), "", "range text correct"); 339 // range is now collapsed at "b". 340 info("Expanding to character"); 341 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 342 is(await runPython(`range.GetText(-1)`), "b", "range text correct"); 343 info("Expanding to word"); 344 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Word)`); 345 is(await runPython(`range.GetText(-1)`), "ab ", "range text correct"); 346 info("Collapsing to end"); 347 await runPython( 348 `range.MoveEndpointByRange(TextPatternRangeEndpoint_Start, range, TextPatternRangeEndpoint_End)` 349 ); 350 // range is now collapsed at "c". 351 info("Expanding to word"); 352 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Word)`); 353 is(await runPython(`range.GetText(-1)`), "cd ", "range text correct"); 354 info("Expanding to line"); 355 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Line)`); 356 is(await runPython(`range.GetText(-1)`), "ab cd ", "range text correct"); 357 info("Collapsing to end"); 358 await runPython( 359 `range.MoveEndpointByRange(TextPatternRangeEndpoint_Start, range, TextPatternRangeEndpoint_End)` 360 ); 361 // range is now collapsed at "e". 362 info("Expanding to line"); 363 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Line)`); 364 // The IA2 -> UIA proxy gets most things below this wrong. 365 if (!gIsUiaEnabled) { 366 return; 367 } 368 is(await runPython(`range.GetText(-1)`), "ef gh", "range text correct"); 369 info("Expanding to document"); 370 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Document)`); 371 is( 372 await runPython(`range.GetText(-1)`), 373 "beforeab cd ef ghafter input", 374 "range text correct" 375 ); 376 377 // Test expanding to a line which crosses elements. 378 info("Getting DocumentRange from input"); 379 await runPython(` 380 input = findUiaByDomId(doc, "input") 381 text = getUiaPattern(input, "Text") 382 global range 383 range = text.DocumentRange 384 `); 385 info("Expanding to line"); 386 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Line)`); 387 is( 388 await runPython(`range.GetText(-1)`), 389 "after input", 390 "range text correct" 391 ); 392 info("Collapsing to end"); 393 await runPython( 394 `range.MoveEndpointByRange(TextPatternRangeEndpoint_Start, range, TextPatternRangeEndpoint_End)` 395 ); 396 // range is now collapsed at the end of the document. 397 info("Expanding to line"); 398 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Line)`); 399 is( 400 await runPython(`range.GetText(-1)`), 401 "after input", 402 "range text correct" 403 ); 404 } 405 ); 406 407 /** 408 * Test the Format TextUnit. Exercises ExpandToEnclosingUnit, Move, and 409 * MoveEndpointByUnit. Tested here separately since the setup and implementation 410 * is somewhat different from other TextUnits. 411 */ 412 addUiaTask( 413 ` 414 <div id="bold-container">a <b>bcd</b> ef</div> 415 <div id="container-container">a <span tabindex="0">bcd</span> ef</div> 416 <textarea id="textarea" spellcheck="true">test tset test</textarea> 417 `, 418 async function testTextRangeMove(browser, docAcc) { 419 info("Constructing range on bold text run"); 420 await runPython(` 421 global doc, docText, range 422 doc = getDocUia() 423 docText = getUiaPattern(doc, "Text") 424 boldContainerAcc = findUiaByDomId(doc, "bold-container") 425 range = docText.RangeFromChild(boldContainerAcc) 426 `); 427 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 428 info("Moving to bold text run"); 429 is( 430 await runPython(`range.Move(TextUnit_Format, 1)`), 431 1, 432 "Move return correct" 433 ); 434 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 435 436 // Testing ExpandToEnclosingUnit (on formatting boundaries) 437 info("Expanding to character (shrinking the range)"); 438 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 439 is(await runPython(`range.GetText(-1)`), "b", "range text correct"); 440 info("Expanding to Format"); 441 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Format)`); 442 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 443 444 info("Making range larger than the Format unit"); 445 is( 446 await runPython( 447 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Character, 1)` 448 ), 449 1, 450 "MoveEndpointByUnit return correct" 451 ); 452 is(await runPython(`range.GetText(-1)`), "bcd ", "range text correct"); 453 454 info("Expanding to Format (shrinking the range)"); 455 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Format)`); 456 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 457 458 // Testing Move (on formatting boundaries) 459 info("Moving 1 Format unit"); 460 is( 461 await runPython(`range.Move(TextUnit_Format, 1)`), 462 1, 463 "Move return correct" 464 ); 465 is(await runPython(`range.GetText(-1)`), " ef", "range text correct"); 466 info("Moving -3 Format units (but only -2 are left)"); 467 is( 468 await runPython(`range.Move(TextUnit_Format, -3)`), 469 -2, 470 "Move return correct" 471 ); 472 is(await runPython(`range.GetText(-1)`), "a ", "range text correct"); 473 474 // Testing MoveEndpointByUnit (on formatting boundaries) 475 info("Moving end 1 Format unit"); 476 is( 477 await runPython( 478 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Format, 1)` 479 ), 480 1, 481 "MoveEndpointByUnit return correct" 482 ); 483 is(await runPython(`range.GetText(-1)`), "a bcd", "range text correct"); 484 info("Moving start 1 Format unit"); 485 is( 486 await runPython( 487 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_Start, TextUnit_Format, 1)` 488 ), 489 1, 490 "MoveEndpointByUnit return correct" 491 ); 492 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 493 494 // Testing above three methods on text runs defined by container boundaries 495 info("Constructing range on text run defined by container boundaries"); 496 await runPython(` 497 global doc, docText, range 498 containerContainer = findUiaByDomId(doc, "container-container") 499 range = docText.RangeFromChild(containerContainer) 500 `); 501 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 502 info("Expanding to Format"); 503 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Format)`); 504 is(await runPython(`range.GetText(-1)`), "a ", "range text correct"); 505 info("Moving 1 Format unit"); 506 is( 507 await runPython(`range.Move(TextUnit_Format, 1)`), 508 1, 509 "Move return correct" 510 ); 511 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 512 info("Moving start -1 Format unit"); 513 is( 514 await runPython( 515 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_Start, TextUnit_Format, -1)` 516 ), 517 -1, 518 "MoveEndpointByUnit return correct" 519 ); 520 is(await runPython(`range.GetText(-1)`), "a bcd", "range text correct"); 521 522 // Trigger spelling errors so we can test text offset attributes 523 const textarea = findAccessibleChildByID(docAcc, "textarea"); 524 textarea.takeFocus(); 525 await waitForEvent(EVENT_TEXT_ATTRIBUTE_CHANGED); 526 527 // Testing above three methods on text offset attributes 528 info("Constructing range on italic text run"); 529 await runPython(` 530 global doc, docText, range 531 textarea = findUiaByDomId(doc, "textarea") 532 range = docText.RangeFromChild(textarea) 533 `); 534 is( 535 await runPython(`range.GetText(-1)`), 536 "test tset test", 537 "range text correct" 538 ); 539 info("Expanding to Format"); 540 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Format)`); 541 is(await runPython(`range.GetText(-1)`), "test ", "range text correct"); 542 info("Moving 1 Format unit"); 543 is( 544 await runPython(`range.Move(TextUnit_Format, 1)`), 545 1, 546 "Move return correct" 547 ); 548 is(await runPython(`range.GetText(-1)`), "tset", "range text correct"); 549 info("Moving start -1 Format unit"); 550 is( 551 await runPython( 552 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_Start, TextUnit_Format, -1)` 553 ), 554 -1, 555 "MoveEndpointByUnit return correct" 556 ); 557 is(await runPython(`range.GetText(-1)`), "test tset", "range text correct"); 558 } 559 ); 560 561 /** 562 * Test the GetAttributeValue method. Verify the behavior of various UIA 563 * Attribute IDs. 564 */ 565 addUiaTask( 566 ` 567 <div id="font-weight-container">a <span tabindex="0"><b>bcd</b></span><b> ef</b></div> 568 <div id="font-size-container">a <span style="font-size:20px">bcd</span> ef</div> 569 <div id="font-family-container">a <span style="font-family:Arial">bcd</span> ef</div> 570 <div id="italic-container">a <span style="font-style:italic">bcd</span> ef</div> 571 <div id="subscript-container">a <sub>bcd</sub> ef</div> 572 <div id="superscript-container">a <sup>bcd</sup> ef</div> 573 <div id="not-hidden-container">a bcd ef</div> 574 <div id="readonly-container">a <span contenteditable="true">bcd</span> ef</div> 575 <input id="text-input"/> 576 <div id="spelling-error-container">a <span aria-invalid="spelling">bcd</span> ef</div> 577 <div id="grammar-error-container">a <span aria-invalid="grammar">bcd</span> ef</div> 578 <div id="data-validation-error-container">a <span aria-invalid="true">bcd</span> ef</div> 579 <div id="highlight-container">a highlighted phrase ef</div> 580 <div id="heading-container">ab<h3>h3</h3>cd</div> 581 <div id="blockquote-container">ab<blockquote>quote</blockquote>cd</div> 582 <div id="emphasis-container">ab<em>emph</em>cd</div> 583 `, 584 async function testTextRangeGetAttributeValue() { 585 // ================== UIA_FontWeightAttributeId ================== 586 info("Constructing range on bold text run"); 587 await runPython(` 588 global doc, docText, range 589 doc = getDocUia() 590 docText = getUiaPattern(doc, "Text") 591 fontWeightContainerAcc = findUiaByDomId(doc, "font-weight-container") 592 range = docText.RangeFromChild(fontWeightContainerAcc) 593 `); 594 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 595 596 info("checking mixed font weights"); 597 ok( 598 await runPython(` 599 val = range.GetAttributeValue(UIA_FontWeightAttributeId) 600 return val == uiaClient.ReservedMixedAttributeValue 601 `), 602 "FontWeight correct (mixed)" 603 ); 604 605 info("Moving to bold text run"); 606 is( 607 await runPython(`range.Move(TextUnit_Format, 1)`), 608 1, 609 "Move return correct" 610 ); 611 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 612 613 info("checking FontWeight"); 614 is( 615 await runPython(`range.GetAttributeValue(UIA_FontWeightAttributeId)`), 616 700, 617 "FontWeight correct" 618 ); 619 620 info("Moving end 1 Format unit"); 621 is( 622 await runPython( 623 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Format, 1)` 624 ), 625 1, 626 "MoveEndpointByUnit return correct" 627 ); 628 is(await runPython(`range.GetText(-1)`), "bcd ef", "range text correct"); 629 info( 630 "checking font weight (across equivalent container-separated Format runs)" 631 ); 632 is( 633 await runPython(`range.GetAttributeValue(UIA_FontWeightAttributeId)`), 634 700, 635 "FontWeight correct" 636 ); 637 638 // ================== UIA_FontSizeAttributeId ================== 639 await runPython(` 640 global range 641 fontSizeContainerAcc = findUiaByDomId(doc, "font-size-container") 642 range = docText.RangeFromChild(fontSizeContainerAcc) 643 `); 644 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 645 info("checking mixed font weights"); 646 ok( 647 await runPython(` 648 val = range.GetAttributeValue(UIA_FontSizeAttributeId) 649 return val == uiaClient.ReservedMixedAttributeValue 650 `), 651 "FontSize correct (mixed)" 652 ); 653 info("Moving to increased font-size text run"); 654 is( 655 await runPython(`range.Move(TextUnit_Format, 1)`), 656 1, 657 "Move return correct" 658 ); 659 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 660 info("checking FontSize"); 661 is( 662 await runPython(`range.GetAttributeValue(UIA_FontSizeAttributeId)`), 663 15, 664 "FontSize correct" 665 ); 666 667 // ================== UIA_FontNameAttributeId ================== 668 await runPython(` 669 global range 670 fontFamilyContainerAcc = findUiaByDomId(doc, "font-family-container") 671 range = docText.RangeFromChild(fontFamilyContainerAcc) 672 `); 673 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 674 info("checking mixed font families"); 675 ok( 676 await runPython(` 677 val = range.GetAttributeValue(UIA_FontNameAttributeId) 678 return val == uiaClient.ReservedMixedAttributeValue 679 `), 680 "FontName correct (mixed)" 681 ); 682 info("Moving to sans-serif font-family text run"); 683 is( 684 await runPython(`range.Move(TextUnit_Format, 1)`), 685 1, 686 "Move return correct" 687 ); 688 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 689 info("checking FontName"); 690 is( 691 await runPython(`range.GetAttributeValue(UIA_FontNameAttributeId)`), 692 "Arial", 693 "FontName correct" 694 ); 695 696 // ================== UIA_IsItalicAttributeId ================== 697 await runPython(` 698 global range 699 italicContainerAcc = findUiaByDomId(doc, "italic-container") 700 range = docText.RangeFromChild(italicContainerAcc) 701 `); 702 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 703 info("checking mixed IsItalic properties"); 704 ok( 705 await runPython(` 706 val = range.GetAttributeValue(UIA_IsItalicAttributeId) 707 return val == uiaClient.ReservedMixedAttributeValue 708 `), 709 "IsItalic correct (mixed)" 710 ); 711 info("Moving to italic text run"); 712 is( 713 await runPython(`range.Move(TextUnit_Format, 1)`), 714 1, 715 "Move return correct" 716 ); 717 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 718 info("checking IsItalic"); 719 is( 720 await runPython(`range.GetAttributeValue(UIA_IsItalicAttributeId)`), 721 true, 722 "IsItalic correct" 723 ); 724 725 // ================== UIA_IsSubscriptAttributeId ================== 726 await runPython(` 727 global range 728 subscriptContainerAcc = findUiaByDomId(doc, "subscript-container") 729 range = docText.RangeFromChild(subscriptContainerAcc) 730 `); 731 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 732 info("checking mixed IsSubscript properties"); 733 ok( 734 await runPython(` 735 val = range.GetAttributeValue(UIA_IsSubscriptAttributeId) 736 return val == uiaClient.ReservedMixedAttributeValue 737 `), 738 "IsSubscript correct (mixed)" 739 ); 740 info("Moving to subscript text run"); 741 is( 742 await runPython(`range.Move(TextUnit_Format, 1)`), 743 1, 744 "Move return correct" 745 ); 746 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 747 info("checking IsSubscript"); 748 is( 749 await runPython(`range.GetAttributeValue(UIA_IsSubscriptAttributeId)`), 750 true, 751 "IsSubscript correct" 752 ); 753 754 // ================== UIA_IsSuperscriptAttributeId ================== 755 await runPython(` 756 global range 757 superscriptContainerAcc = findUiaByDomId(doc, "superscript-container") 758 range = docText.RangeFromChild(superscriptContainerAcc) 759 `); 760 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 761 info("checking mixed IsSuperscript properties"); 762 ok( 763 await runPython(` 764 val = range.GetAttributeValue(UIA_IsSuperscriptAttributeId) 765 return val == uiaClient.ReservedMixedAttributeValue 766 `), 767 "IsSuperscript correct (mixed)" 768 ); 769 info("Moving to superscript text run"); 770 is( 771 await runPython(`range.Move(TextUnit_Format, 1)`), 772 1, 773 "Move return correct" 774 ); 775 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 776 info("checking IsSuperscript"); 777 is( 778 await runPython(`range.GetAttributeValue(UIA_IsSuperscriptAttributeId)`), 779 true, 780 "IsSuperscript correct" 781 ); 782 783 // ================== UIA_IsHiddenAttributeId ================== 784 // Testing the "true" case is not really possible since these Accessible 785 // nodes are not present in the tree. Verify the "false" case. 786 await runPython(` 787 global range 788 notHiddenContainerAcc = findUiaByDomId(doc, "not-hidden-container") 789 range = docText.RangeFromChild(notHiddenContainerAcc) 790 `); 791 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 792 info("checking mixed IsHidden properties"); 793 ok( 794 await runPython(` 795 val = range.GetAttributeValue(UIA_IsHiddenAttributeId) 796 return val != uiaClient.ReservedMixedAttributeValue 797 `), 798 "IsHidden correct (not mixed)" 799 ); 800 801 // ================== UIA_IsReadOnlyAttributeId ================== 802 await runPython(` 803 global range 804 readonlyContainerAcc = findUiaByDomId(doc, "readonly-container") 805 range = docText.RangeFromChild(readonlyContainerAcc) 806 `); 807 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 808 info("checking mixed ReadOnly properties"); 809 ok( 810 await runPython(` 811 val = range.GetAttributeValue(UIA_IsReadOnlyAttributeId) 812 return val == uiaClient.ReservedMixedAttributeValue 813 `), 814 "ReadOnly correct (mixed)" 815 ); 816 info("Moving to editable text run"); 817 is( 818 await runPython(`range.Move(TextUnit_Format, 1)`), 819 1, 820 "Move return correct" 821 ); 822 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 823 info("checking IsReadOnly"); 824 is( 825 await runPython(`range.GetAttributeValue(UIA_IsReadOnlyAttributeId)`), 826 false, 827 "IsReadOnly correct" 828 ); 829 830 // Verify that text inputs are not read-only by default. 831 await runPython(` 832 global range 833 textInputAcc = findUiaByDomId(doc, "text-input") 834 range = docText.RangeFromChild(textInputAcc) 835 `); 836 info("checking IsReadOnly"); 837 is( 838 await runPython(`range.GetAttributeValue(UIA_IsReadOnlyAttributeId)`), 839 false, 840 "IsReadOnly correct for text input" 841 ); 842 843 // ================== UIA_AnnotationTypesAttributeId - AnnotationType_SpellingError ================== 844 await runPython(` 845 global range 846 spellingErrorContainerAcc = findUiaByDomId(doc, "spelling-error-container") 847 range = docText.RangeFromChild(spellingErrorContainerAcc) 848 `); 849 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 850 info("checking mixed SpellingError properties"); 851 ok( 852 await runPython(` 853 val = range.GetAttributeValue(UIA_AnnotationTypesAttributeId) 854 return val == uiaClient.ReservedMixedAttributeValue 855 `), 856 "SpellingError correct (mixed)" 857 ); 858 info('Moving to aria-invalid="spelling" text run'); 859 is( 860 await runPython(`range.Move(TextUnit_Format, 1)`), 861 1, 862 "Move return correct" 863 ); 864 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 865 info("checking SpellingError"); 866 ok( 867 await runPython(` 868 annotations = range.GetAttributeValue(UIA_AnnotationTypesAttributeId) 869 return annotations == (AnnotationType_SpellingError,) 870 `), 871 "SpellingError correct" 872 ); 873 874 // ================== UIA_AnnotationTypesAttributeId - AnnotationType_GrammarError ================== 875 await runPython(` 876 global range 877 grammarErrorContainerAcc = findUiaByDomId(doc, "grammar-error-container") 878 range = docText.RangeFromChild(grammarErrorContainerAcc) 879 `); 880 is(await runPython(`range.GetText(-1)`), "a bcd ef", "range text correct"); 881 info("checking mixed GrammarError properties"); 882 ok( 883 await runPython(` 884 val = range.GetAttributeValue(UIA_AnnotationTypesAttributeId) 885 return val == uiaClient.ReservedMixedAttributeValue 886 `), 887 "GrammarError correct (mixed)" 888 ); 889 info('Moving to aria-invalid="grammar" text run'); 890 is( 891 await runPython(`range.Move(TextUnit_Format, 1)`), 892 1, 893 "Move return correct" 894 ); 895 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 896 info("checking GrammarError"); 897 ok( 898 await runPython(` 899 annotations = range.GetAttributeValue(UIA_AnnotationTypesAttributeId) 900 return annotations == (AnnotationType_GrammarError,) 901 `), 902 "GrammarError correct" 903 ); 904 905 // ================== UIA_AnnotationTypesAttributeId - AnnotationType_DataValidationError ================== 906 // The IA2 -> UIA bridge does not work for aria-invalid=true or highlights. 907 if (gIsUiaEnabled) { 908 await runPython(` 909 global range 910 dataValidationErrorContainerAcc = findUiaByDomId(doc, "data-validation-error-container") 911 range = docText.RangeFromChild(dataValidationErrorContainerAcc) 912 `); 913 is( 914 await runPython(`range.GetText(-1)`), 915 "a bcd ef", 916 "range text correct" 917 ); 918 info("checking mixed DataValidationError properties"); 919 ok( 920 await runPython(` 921 val = range.GetAttributeValue(UIA_AnnotationTypesAttributeId) 922 return val == uiaClient.ReservedMixedAttributeValue 923 `), 924 "DataValidationError correct (mixed)" 925 ); 926 info('Moving to aria-invalid="true" text run'); 927 is( 928 await runPython(`range.Move(TextUnit_Format, 1)`), 929 1, 930 "Move return correct" 931 ); 932 is(await runPython(`range.GetText(-1)`), "bcd", "range text correct"); 933 info("checking DataValidationError"); 934 ok( 935 await runPython(` 936 annotations = range.GetAttributeValue(UIA_AnnotationTypesAttributeId) 937 return annotations == (AnnotationType_DataValidationError,) 938 `), 939 "DataValidationError correct" 940 ); 941 942 // ================== UIA_AnnotationTypesAttributeId - AnnotationType_Highlighted ================== 943 await runPython(` 944 global range 945 highlightContainerAcc = findUiaByDomId(doc, "highlight-container") 946 range = docText.RangeFromChild(highlightContainerAcc) 947 `); 948 is( 949 await runPython(`range.GetText(-1)`), 950 "a highlighted phrase ef", 951 "range text correct" 952 ); 953 info("checking mixed Highlighted properties"); 954 ok( 955 await runPython(` 956 val = range.GetAttributeValue(UIA_AnnotationTypesAttributeId) 957 return val == uiaClient.ReservedMixedAttributeValue 958 `), 959 "Highlighted correct (mixed)" 960 ); 961 info("Moving to highlighted text run"); 962 is( 963 await runPython(`range.Move(TextUnit_Format, 1)`), 964 1, 965 "Move return correct" 966 ); 967 is( 968 await runPython(`range.GetText(-1)`), 969 "highlighted phrase", 970 "range text correct" 971 ); 972 info("checking Highlighted"); 973 ok( 974 await runPython(` 975 annotations = range.GetAttributeValue(UIA_AnnotationTypesAttributeId) 976 return annotations == (AnnotationType_Highlighted,) 977 `), 978 "Highlighted correct" 979 ); 980 } 981 982 // The IA2 -> UIA bridge does not work correctly here. 983 if (gIsUiaEnabled) { 984 // ================== UIA_StyleIdAttributeId - StyleId_Heading* ================== 985 await runPython(` 986 global range 987 headingContainerAcc = findUiaByDomId(doc, "heading-container") 988 range = docText.RangeFromChild(headingContainerAcc) 989 `); 990 is(await runPython(`range.GetText(-1)`), "abh3cd", "range text correct"); 991 info("checking mixed StyleId properties"); 992 ok( 993 await runPython(` 994 val = range.GetAttributeValue(UIA_StyleIdAttributeId) 995 return val == uiaClient.ReservedMixedAttributeValue 996 `), 997 "StyleId correct (mixed)" 998 ); 999 info("Moving to h3 text run"); 1000 is( 1001 await runPython(`range.Move(TextUnit_Format, 1)`), 1002 1, 1003 "Move return correct" 1004 ); 1005 is(await runPython(`range.GetText(-1)`), "h3", "range text correct"); 1006 info("checking StyleId"); 1007 ok( 1008 await runPython(` 1009 styleId = range.GetAttributeValue(UIA_StyleIdAttributeId) 1010 return styleId == StyleId_Heading3 1011 `), 1012 "StyleId correct" 1013 ); 1014 1015 // ================== UIA_StyleIdAttributeId - StyleId_Quote ================== 1016 await runPython(` 1017 global range 1018 blockquoteContainerAcc = findUiaByDomId(doc, "blockquote-container") 1019 range = docText.RangeFromChild(blockquoteContainerAcc) 1020 `); 1021 is( 1022 await runPython(`range.GetText(-1)`), 1023 "abquotecd", 1024 "range text correct" 1025 ); 1026 info("checking mixed StyleId properties"); 1027 ok( 1028 await runPython(` 1029 val = range.GetAttributeValue(UIA_StyleIdAttributeId) 1030 return val == uiaClient.ReservedMixedAttributeValue 1031 `), 1032 "StyleId correct (mixed)" 1033 ); 1034 info("Moving to blockquote text run"); 1035 is( 1036 await runPython(`range.Move(TextUnit_Format, 1)`), 1037 1, 1038 "Move return correct" 1039 ); 1040 is(await runPython(`range.GetText(-1)`), "quote", "range text correct"); 1041 info("checking StyleId"); 1042 ok( 1043 await runPython(` 1044 styleId = range.GetAttributeValue(UIA_StyleIdAttributeId) 1045 return styleId == StyleId_Quote 1046 `), 1047 "StyleId correct" 1048 ); 1049 1050 // ================== UIA_StyleIdAttributeId - StyleId_Emphasis ================== 1051 await runPython(` 1052 global range 1053 emphasisContainerAcc = findUiaByDomId(doc, "emphasis-container") 1054 range = docText.RangeFromChild(emphasisContainerAcc) 1055 `); 1056 is( 1057 await runPython(`range.GetText(-1)`), 1058 "abemphcd", 1059 "range text correct" 1060 ); 1061 info("checking mixed StyleId properties"); 1062 ok( 1063 await runPython(` 1064 val = range.GetAttributeValue(UIA_StyleIdAttributeId) 1065 return val == uiaClient.ReservedMixedAttributeValue 1066 `), 1067 "StyleId correct (mixed)" 1068 ); 1069 info("Moving to emphasized text run"); 1070 is( 1071 await runPython(`range.Move(TextUnit_Format, 1)`), 1072 1, 1073 "Move return correct" 1074 ); 1075 is(await runPython(`range.GetText(-1)`), "emph", "range text correct"); 1076 info("checking StyleId"); 1077 ok( 1078 await runPython(` 1079 styleId = range.GetAttributeValue(UIA_StyleIdAttributeId) 1080 return styleId == StyleId_Emphasis 1081 `), 1082 "StyleId correct" 1083 ); 1084 } 1085 }, 1086 { urlSuffix: "#:~:text=highlighted%20phrase" } 1087 ); 1088 1089 /** 1090 * Test the GetAttributeValue method when backspacing a character at the end of 1091 * a document. 1092 */ 1093 addUiaTask( 1094 `a<input id="input" value="bc">`, 1095 async function testTextRangeGetAttributeValueBackspaceAtDocEnd( 1096 browser, 1097 docAcc 1098 ) { 1099 const input = findAccessibleChildByID(docAcc, "input"); 1100 info("Focusing input"); 1101 let moved = waitForEvent(EVENT_TEXT_CARET_MOVED, input); 1102 input.takeFocus(); 1103 await moved; 1104 info("Pressing end"); 1105 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, input); 1106 EventUtils.synthesizeKey("KEY_End"); 1107 await moved; 1108 await runPython(` 1109 global doc, range 1110 doc = getDocUia() 1111 input = findUiaByDomId(doc, "input") 1112 text = getUiaPattern(input, "Text") 1113 range = text.GetSelection().GetElement(0) 1114 `); 1115 // `range` is collapsed at the end of the input, after "c". 1116 is( 1117 await runPython(`range.GetAttributeValue(UIA_IsReadOnlyAttributeId)`), 1118 false, 1119 "IsReadOnly correct" 1120 ); 1121 info("Backspacing c"); 1122 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, input); 1123 EventUtils.synthesizeKey("KEY_Backspace"); 1124 await moved; 1125 is( 1126 await runPython(`range.GetAttributeValue(UIA_IsReadOnlyAttributeId)`), 1127 false, 1128 "IsReadOnly correct" 1129 ); 1130 } 1131 ); 1132 1133 /** 1134 * Test the TextRange pattern's Move method. 1135 */ 1136 addUiaTask( 1137 ` 1138 <p>ab</p> 1139 <textarea id="textarea">cd ef gh</textarea> 1140 <p>ij</p> 1141 `, 1142 async function testTextRangeMove() { 1143 await runPython(` 1144 doc = getDocUia() 1145 textarea = findUiaByDomId(doc, "textarea") 1146 text = getUiaPattern(textarea, "Text") 1147 global range 1148 range = text.DocumentRange 1149 `); 1150 is(await runPython(`range.GetText(-1)`), "cd ef gh", "range text correct"); 1151 info("Moving 1 word"); 1152 is( 1153 await runPython(`range.Move(TextUnit_Word, 1)`), 1154 1, 1155 "Move return correct" 1156 ); 1157 is(await runPython(`range.GetText(-1)`), "ef ", "range text correct"); 1158 info("Moving 3 words"); 1159 // There are only 2 words after. 1160 is( 1161 await runPython(`range.Move(TextUnit_Word, 3)`), 1162 2, 1163 "Move return correct" 1164 ); 1165 // The IA2 -> UIA proxy gets most things below this wrong. 1166 if (!gIsUiaEnabled) { 1167 return; 1168 } 1169 is(await runPython(`range.GetText(-1)`), "ij", "range text correct"); 1170 info("Moving -5 words"); 1171 // There are only 4 words before. 1172 is( 1173 await runPython(`range.Move(TextUnit_Word, -5)`), 1174 -4, 1175 "Move return correct" 1176 ); 1177 is(await runPython(`range.GetText(-1)`), "ab", "range text correct"); 1178 info("Moving 1 word"); 1179 is( 1180 await runPython(`range.Move(TextUnit_Word, 1)`), 1181 1, 1182 "Move return correct" 1183 ); 1184 is(await runPython(`range.GetText(-1)`), "cd ", "range text correct"); 1185 info("Moving 1 character"); 1186 is( 1187 await runPython(`range.Move(TextUnit_Character, 1)`), 1188 1, 1189 "Move return correct" 1190 ); 1191 is(await runPython(`range.GetText(-1)`), "d", "range text correct"); 1192 // When the range is not collapsed, Move moves backward to the start of the 1193 // unit before moving to the requested unit. 1194 info("Moving -1 word"); 1195 is( 1196 await runPython(`range.Move(TextUnit_Word, -1)`), 1197 -1, 1198 "Move return correct" 1199 ); 1200 is(await runPython(`range.GetText(-1)`), "ab", "range text correct"); 1201 info("Collapsing to start"); 1202 await runPython( 1203 `range.MoveEndpointByRange(TextPatternRangeEndpoint_End, range, TextPatternRangeEndpoint_Start)` 1204 ); 1205 is(await runPython(`range.GetText(-1)`), "", "range text correct"); 1206 // range is now collapsed at "a". 1207 info("Moving 1 word"); 1208 is( 1209 await runPython(`range.Move(TextUnit_Word, 1)`), 1210 1, 1211 "Move return correct" 1212 ); 1213 // range is now collapsed at "c". 1214 is(await runPython(`range.GetText(-1)`), "", "range text correct"); 1215 info("Expanding to character"); 1216 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 1217 is(await runPython(`range.GetText(-1)`), "c", "range text correct"); 1218 info("Collapsing to end"); 1219 await runPython( 1220 `range.MoveEndpointByRange(TextPatternRangeEndpoint_Start, range, TextPatternRangeEndpoint_End)` 1221 ); 1222 // range is now collapsed at "d". 1223 // When the range is collapsed, Move does *not* first move back to the start 1224 // of the unit. 1225 info("Moving -1 word"); 1226 is( 1227 await runPython(`range.Move(TextUnit_Word, -1)`), 1228 -1, 1229 "Move return correct" 1230 ); 1231 // range is collapsed at "c". 1232 is(await runPython(`range.GetText(-1)`), "", "range text correct"); 1233 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Word)`); 1234 is(await runPython(`range.GetText(-1)`), "cd ", "range text correct"); 1235 } 1236 ); 1237 1238 /** 1239 * Test the TextRange pattern's MoveEndpointByRange method. 1240 */ 1241 addUiaTask( 1242 ` 1243 <p>ab</p> 1244 <div><textarea id="textarea">cd ef gh</textarea></div> 1245 <p>ij</p> 1246 `, 1247 async function testTextRangeMoveEndpointByRange() { 1248 await runPython(` 1249 global doc, taRange, range 1250 doc = getDocUia() 1251 textarea = findUiaByDomId(doc, "textarea") 1252 text = getUiaPattern(textarea, "Text") 1253 taRange = text.DocumentRange 1254 range = text.DocumentRange 1255 `); 1256 is(await runPython(`range.GetText(-1)`), "cd ef gh", "range text correct"); 1257 info("Expanding to character"); 1258 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 1259 is(await runPython(`range.GetText(-1)`), "c", "range text correct"); 1260 is( 1261 await runPython( 1262 `range.CompareEndpoints(TextPatternRangeEndpoint_Start, range, TextPatternRangeEndpoint_End)` 1263 ), 1264 -1, 1265 "start < end" 1266 ); 1267 info("Moving end to start"); 1268 await runPython( 1269 `range.MoveEndpointByRange(TextPatternRangeEndpoint_End, range, TextPatternRangeEndpoint_Start)` 1270 ); 1271 is( 1272 await runPython( 1273 `range.CompareEndpoints(TextPatternRangeEndpoint_Start, range, TextPatternRangeEndpoint_End)` 1274 ), 1275 0, 1276 "start == end" 1277 ); 1278 info("Moving range end to textarea end"); 1279 await runPython( 1280 `range.MoveEndpointByRange(TextPatternRangeEndpoint_End, taRange, TextPatternRangeEndpoint_End)` 1281 ); 1282 is(await runPython(`range.GetText(-1)`), "cd ef gh", "range text correct"); 1283 info("Expanding to character"); 1284 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 1285 is(await runPython(`range.GetText(-1)`), "c", "range text correct"); 1286 info("Moving range start to textarea end"); 1287 await runPython( 1288 `range.MoveEndpointByRange(TextPatternRangeEndpoint_Start, taRange, TextPatternRangeEndpoint_End)` 1289 ); 1290 is( 1291 await runPython( 1292 `range.CompareEndpoints(TextPatternRangeEndpoint_Start, taRange, TextPatternRangeEndpoint_End)` 1293 ), 1294 0, 1295 "range start == textarea end" 1296 ); 1297 is( 1298 await runPython( 1299 `range.CompareEndpoints(TextPatternRangeEndpoint_End, taRange, TextPatternRangeEndpoint_End)` 1300 ), 1301 0, 1302 "range end == textarea end" 1303 ); 1304 info("Moving range end to textarea start"); 1305 await runPython( 1306 `range.MoveEndpointByRange(TextPatternRangeEndpoint_End, taRange, TextPatternRangeEndpoint_Start)` 1307 ); 1308 is( 1309 await runPython( 1310 `range.CompareEndpoints(TextPatternRangeEndpoint_Start, taRange, TextPatternRangeEndpoint_Start)` 1311 ), 1312 0, 1313 "range start == textarea start" 1314 ); 1315 is( 1316 await runPython( 1317 `range.CompareEndpoints(TextPatternRangeEndpoint_End, taRange, TextPatternRangeEndpoint_Start)` 1318 ), 1319 0, 1320 "range end == textarea start" 1321 ); 1322 await definePyVar("docRange", `getUiaPattern(doc, "Text").DocumentRange`); 1323 info("Moving range start to document start"); 1324 await runPython( 1325 `range.MoveEndpointByRange(TextPatternRangeEndpoint_Start, docRange, TextPatternRangeEndpoint_Start)` 1326 ); 1327 info("Moving range end to document end"); 1328 await runPython( 1329 `range.MoveEndpointByRange(TextPatternRangeEndpoint_End, docRange, TextPatternRangeEndpoint_End)` 1330 ); 1331 is( 1332 await runPython( 1333 `range.CompareEndpoints(TextPatternRangeEndpoint_Start, docRange, TextPatternRangeEndpoint_Start)` 1334 ), 1335 0, 1336 "range start == document start" 1337 ); 1338 is( 1339 await runPython( 1340 `range.CompareEndpoints(TextPatternRangeEndpoint_End, docRange, TextPatternRangeEndpoint_End)` 1341 ), 1342 0, 1343 "range end == document end" 1344 ); 1345 } 1346 ); 1347 1348 /** 1349 * Test the TextRange pattern's MoveEndpointByUnit method. 1350 */ 1351 addUiaTask( 1352 ` 1353 <p>ab</p> 1354 <textarea id="textarea">cd ef gh</textarea> 1355 <p>ij</p> 1356 `, 1357 async function testTextRangeMoveEndpointByUnit() { 1358 await runPython(` 1359 doc = getDocUia() 1360 textarea = findUiaByDomId(doc, "textarea") 1361 text = getUiaPattern(textarea, "Text") 1362 global range 1363 range = text.DocumentRange 1364 `); 1365 is(await runPython(`range.GetText(-1)`), "cd ef gh", "range text correct"); 1366 info("Moving end -1 word"); 1367 is( 1368 await runPython( 1369 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Word, -1)` 1370 ), 1371 -1, 1372 "MoveEndpointByUnit return correct" 1373 ); 1374 is(await runPython(`range.GetText(-1)`), "cd ef ", "range text correct"); 1375 info("Moving end -4 words"); 1376 // There are only 3 words before. 1377 is( 1378 await runPython( 1379 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Word, -4)` 1380 ), 1381 -3, 1382 "MoveEndpointByUnit return correct" 1383 ); 1384 is(await runPython(`range.GetText(-1)`), "", "range text correct"); 1385 info("Moving start 1 word"); 1386 is( 1387 await runPython( 1388 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_Start, TextUnit_Word, 1)` 1389 ), 1390 1, 1391 "MoveEndpointByUnit return correct" 1392 ); 1393 is(await runPython(`range.GetText(-1)`), "", "range text correct"); 1394 info("Moving end 1 character"); 1395 is( 1396 await runPython( 1397 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Character, 1)` 1398 ), 1399 1, 1400 "MoveEndpointByUnit return correct" 1401 ); 1402 is(await runPython(`range.GetText(-1)`), "c", "range text correct"); 1403 info("Moving start 5 words"); 1404 // There are only 4 word boundaries after. 1405 is( 1406 await runPython( 1407 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_Start, TextUnit_Word, 5)` 1408 ), 1409 4, 1410 "MoveEndpointByUnit return correct" 1411 ); 1412 is(await runPython(`range.GetText(-1)`), "", "range text correct"); 1413 info("Moving end -1 word"); 1414 is( 1415 await runPython( 1416 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Word, -1)` 1417 ), 1418 -1, 1419 "MoveEndpointByUnit return correct" 1420 ); 1421 is(await runPython(`range.GetText(-1)`), "", "range text correct"); 1422 info("Moving end 1 character"); 1423 is( 1424 await runPython( 1425 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Character, 1)` 1426 ), 1427 1, 1428 "MoveEndpointByUnit return correct" 1429 ); 1430 is(await runPython(`range.GetText(-1)`), "i", "range text correct"); 1431 } 1432 ); 1433 1434 /** 1435 * Test the Text pattern's SupportedTextSelection property. 1436 */ 1437 addUiaTask( 1438 ` 1439 <style> 1440 body { 1441 user-select: none; 1442 } 1443 </style> 1444 <input id="input"> 1445 <p id="p">p</p> 1446 `, 1447 async function testTextSupportedTextSelection() { 1448 let result = await runPython(` 1449 global doc 1450 doc = getDocUia() 1451 input = findUiaByDomId(doc, "input") 1452 text = getUiaPattern(input, "Text") 1453 return text.SupportedTextSelection 1454 `); 1455 is( 1456 result, 1457 SupportedTextSelection_Multiple, 1458 "input SupportedTextSelection correct" 1459 ); 1460 if (gIsUiaEnabled) { 1461 // The IA2 -> UIA proxy doesn't expose the Text pattern on this text leaf. 1462 is( 1463 await runPython(` 1464 p = findUiaByDomId(doc, "p") 1465 pLeaf = uiaClient.RawViewWalker.GetFirstChildElement(p) 1466 text = getUiaPattern(pLeaf, "Text") 1467 return text.SupportedTextSelection 1468 `), 1469 SupportedTextSelection_None, 1470 "pLeaf SupportedTextSelection correct" 1471 ); 1472 // The IA2 -> UIA proxy doesn't understand that text isn't selectable in 1473 // this document. 1474 is( 1475 await runPython(`getUiaPattern(doc, "Text").SupportedTextSelection`), 1476 SupportedTextSelection_None, 1477 "doc SupportedTextSelection correct" 1478 ); 1479 } 1480 } 1481 ); 1482 1483 /** 1484 * Test the Text pattern's SupportedTextSelection property on a document with a 1485 * selectable body. 1486 */ 1487 addUiaTask( 1488 `<p id="p">p</p>`, 1489 async function testTextSupportedTextSelectionSelectableBody() { 1490 is( 1491 await runPython(` 1492 global doc 1493 doc = getDocUia() 1494 text = getUiaPattern(doc, "Text") 1495 return text.SupportedTextSelection 1496 `), 1497 SupportedTextSelection_Multiple, 1498 "doc SupportedTextSelection correct" 1499 ); 1500 // The IA2 -> UIA proxy doesn't expose the Text pattern on this text leaf. 1501 if (gIsUiaEnabled) { 1502 is( 1503 await runPython(` 1504 p = findUiaByDomId(doc, "p") 1505 pLeaf = uiaClient.RawViewWalker.GetFirstChildElement(p) 1506 text = getUiaPattern(pLeaf, "Text") 1507 return text.SupportedTextSelection 1508 `), 1509 SupportedTextSelection_Multiple, 1510 "pLeaf SupportedTextSelection correct" 1511 ); 1512 } 1513 } 1514 ); 1515 1516 /** 1517 * Test the Text pattern's GetSelection method with the caret. 1518 */ 1519 addUiaTask( 1520 `<textarea id="textarea" cols="2">ab cd</textarea>`, 1521 async function testTextGetSelectionCaret(browser, docAcc) { 1522 await runPython(` 1523 doc = getDocUia() 1524 textarea = findUiaByDomId(doc, "textarea") 1525 global text 1526 text = getUiaPattern(textarea, "Text") 1527 `); 1528 is(await runPython(`text.GetSelection().Length`), 0, "No selection"); 1529 info("Focusing textarea"); 1530 const textarea = findAccessibleChildByID(docAcc, "textarea", [ 1531 nsIAccessibleText, 1532 ]); 1533 let moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 1534 textarea.takeFocus(); 1535 await moved; 1536 is(await runPython(`text.GetSelection().Length`), 1, "1 selection"); 1537 await definePyVar("range", `text.GetSelection().GetElement(0)`); 1538 ok(await runPython(`bool(range)`), "Got selection range 0"); 1539 info("Expanding to character"); 1540 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 1541 is(await runPython(`range.GetText(-1)`), "a", "range text correct"); 1542 1543 info("Pressing ArrowRight"); 1544 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 1545 EventUtils.synthesizeKey("KEY_ArrowRight"); 1546 await moved; 1547 is(await runPython(`text.GetSelection().Length`), 1, "1 selection"); 1548 await definePyVar("range", `text.GetSelection().GetElement(0)`); 1549 ok(await runPython(`bool(range)`), "Got selection range 0"); 1550 info("Expanding to character"); 1551 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 1552 is(await runPython(`range.GetText(-1)`), "b", "range text correct"); 1553 1554 // The IA2 -> UIA proxy doesn't handle the insertion point at the end of a 1555 // line correctly. 1556 if (!gIsUiaEnabled) { 1557 return; 1558 } 1559 1560 // Test the insertion point at the end of a wrapped line. 1561 info("Pressing End"); 1562 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 1563 EventUtils.synthesizeKey("KEY_End"); 1564 await moved; 1565 is(await runPython(`text.GetSelection().Length`), 1, "1 selection"); 1566 await definePyVar("range", `text.GetSelection().GetElement(0)`); 1567 ok(await runPython(`bool(range)`), "Got selection range 0"); 1568 info("Expanding to character"); 1569 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 1570 is(await runPython(`range.GetText(-1)`), "", "range text correct"); 1571 info("Moving end 1 character"); 1572 await runPython( 1573 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Character, 1)` 1574 ); 1575 is(await runPython(`range.GetText(-1)`), "c", "range text correct"); 1576 info("Expanding to line at caret"); 1577 await definePyVar("range", `text.GetSelection().GetElement(0)`); 1578 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Line)`); 1579 is(await runPython(`range.GetText(-1)`), "ab ", "range text correct"); 1580 1581 // Test the insertion point at the end of the textarea. 1582 info("Pressing Ctrl+End"); 1583 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 1584 EventUtils.synthesizeKey("KEY_End", { ctrlKey: true }); 1585 await moved; 1586 is(await runPython(`text.GetSelection().Length`), 1, "1 selection"); 1587 await definePyVar("range", `text.GetSelection().GetElement(0)`); 1588 ok(await runPython(`bool(range)`), "Got selection range 0"); 1589 info("Expanding to character"); 1590 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 1591 is(await runPython(`range.GetText(-1)`), "", "range text correct"); 1592 info("Expanding to line"); 1593 await definePyVar("range", `text.GetSelection().GetElement(0)`); 1594 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Line)`); 1595 is(await runPython(`range.GetText(-1)`), "cd", "range text correct"); 1596 1597 info("Clicking mouse at b"); 1598 // BrowserTestUtils.synthesizeMouseAtPoint takes coordinates relative to the document. 1599 const docX = {}; 1600 const docY = {}; 1601 docAcc.getBounds(docX, docY, {}, {}); 1602 let charX = {}; 1603 let charY = {}; 1604 textarea.getCharacterExtents( 1605 1, 1606 charX, 1607 charY, 1608 {}, 1609 {}, 1610 COORDTYPE_SCREEN_RELATIVE 1611 ); 1612 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 1613 await BrowserTestUtils.synthesizeMouseAtPoint( 1614 charX.value - docX.value, 1615 charY.value - docY.value, 1616 {}, 1617 docAcc.browsingContext 1618 ); 1619 await moved; 1620 is(await runPython(`text.GetSelection().Length`), 1, "1 selection"); 1621 await definePyVar("range", `text.GetSelection().GetElement(0)`); 1622 ok(await runPython(`bool(range)`), "Got selection range 0"); 1623 info("Expanding to character"); 1624 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 1625 is(await runPython(`range.GetText(-1)`), "b", "range text correct"); 1626 } 1627 ); 1628 1629 /** 1630 * Test the Text pattern's GetSelection method with selection. 1631 */ 1632 addUiaTask( 1633 `<textarea id="textarea" cols="3">ab cd</textarea>`, 1634 async function testTextGetSelectionSelection(browser, docAcc) { 1635 await runPython(` 1636 doc = getDocUia() 1637 textarea = findUiaByDomId(doc, "textarea") 1638 global text 1639 text = getUiaPattern(textarea, "Text") 1640 `); 1641 is(await runPython(`text.GetSelection().Length`), 0, "No selection"); 1642 info("Focusing textarea"); 1643 const textarea = findAccessibleChildByID(docAcc, "textarea", [ 1644 nsIAccessibleText, 1645 ]); 1646 let moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 1647 textarea.takeFocus(); 1648 await moved; 1649 is(await runPython(`text.GetSelection().Length`), 1, "1 selection"); 1650 await definePyVar("range", `text.GetSelection().GetElement(0)`); 1651 ok(await runPython(`bool(range)`), "Got selection range 0"); 1652 is(await runPython(`range.GetText(-1)`), "", "range text correct"); 1653 1654 info("Selecting ab"); 1655 moved = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, textarea); 1656 textarea.addSelection(0, 2); 1657 await moved; 1658 is(await runPython(`text.GetSelection().Length`), 1, "1 selection"); 1659 await definePyVar("range", `text.GetSelection().GetElement(0)`); 1660 ok(await runPython(`bool(range)`), "Got selection range 0"); 1661 is(await runPython(`range.GetText(-1)`), "ab", "range text correct"); 1662 1663 info("Adding cd to selection"); 1664 moved = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, textarea); 1665 textarea.addSelection(3, 5); 1666 await moved; 1667 is(await runPython(`text.GetSelection().Length`), 2, "2 selections"); 1668 await definePyVar("range", `text.GetSelection().GetElement(0)`); 1669 ok(await runPython(`bool(range)`), "Got selection range 0"); 1670 is(await runPython(`range.GetText(-1)`), "ab", "range text correct"); 1671 await definePyVar("range", `text.GetSelection().GetElement(1)`); 1672 ok(await runPython(`bool(range)`), "Got selection range 1"); 1673 is(await runPython(`range.GetText(-1)`), "cd", "range text correct"); 1674 } 1675 ); 1676 1677 /** 1678 * Test the Text pattern's TextSelectionChanged event. 1679 */ 1680 addUiaTask( 1681 ` 1682 <input id="input" value="abc"> 1683 <div id="editable" contenteditable role="textbox"><p>de</p><p>f</p></div> 1684 `, 1685 async function testTextTextSelectionChanged(browser) { 1686 info("Focusing input"); 1687 await setUpWaitForUiaEvent("Text_TextSelectionChanged", "input"); 1688 await invokeContentTask(browser, [], () => { 1689 content.document.getElementById("input").focus(); 1690 }); 1691 await waitForUiaEvent(); 1692 ok(true, "input got TextSelectionChanged event"); 1693 info("Moving caret to b"); 1694 await setUpWaitForUiaEvent("Text_TextSelectionChanged", "input"); 1695 await invokeContentTask(browser, [], () => { 1696 content.document.getElementById("input").setSelectionRange(1, 1); 1697 }); 1698 await waitForUiaEvent(); 1699 ok(true, "input got TextSelectionChanged event"); 1700 info("Selecting bc"); 1701 await setUpWaitForUiaEvent("Text_TextSelectionChanged", "input"); 1702 await invokeContentTask(browser, [], () => { 1703 content.document.getElementById("input").setSelectionRange(1, 3); 1704 }); 1705 await waitForUiaEvent(); 1706 ok(true, "input got TextSelectionChanged event"); 1707 1708 info("Focusing editable"); 1709 await setUpWaitForUiaEvent("Text_TextSelectionChanged", "editable"); 1710 await invokeContentTask(browser, [], () => { 1711 content._editable = content.document.getElementById("editable"); 1712 content._editable.focus(); 1713 }); 1714 await waitForUiaEvent(); 1715 ok(true, "editable got TextSelectionChanged event"); 1716 info("Moving caret to e"); 1717 await setUpWaitForUiaEvent("Text_TextSelectionChanged", "editable"); 1718 await invokeContentTask(browser, [], () => { 1719 content._de = content._editable.firstChild.firstChild; 1720 content.getSelection().setBaseAndExtent(content._de, 1, content._de, 1); 1721 }); 1722 await waitForUiaEvent(); 1723 ok(true, "editable got TextSelectionChanged event"); 1724 info("Selecting ef"); 1725 await setUpWaitForUiaEvent("Text_TextSelectionChanged", "editable"); 1726 await invokeContentTask(browser, [], () => { 1727 const f = content._editable.children[1].firstChild; 1728 content.getSelection().setBaseAndExtent(content._de, 1, f, 1); 1729 }); 1730 await waitForUiaEvent(); 1731 ok(true, "editable got TextSelectionChanged event"); 1732 } 1733 ); 1734 1735 /** 1736 * Test the Text pattern's TextChanged event. 1737 */ 1738 addUiaTask( 1739 ` 1740 <input id="input" value="abc"> 1741 <div id="editable" contenteditable role="textbox"> 1742 <p id="de">de</p> 1743 <p>f</p> 1744 </div> 1745 `, 1746 async function testTextTextChanged(browser) { 1747 info("Focusing input"); 1748 let moved = waitForEvent(EVENT_TEXT_CARET_MOVED, "input"); 1749 await invokeContentTask(browser, [], () => { 1750 content.document.getElementById("input").focus(); 1751 }); 1752 await moved; 1753 info("Deleting a"); 1754 await setUpWaitForUiaEvent("Text_TextChanged", "input"); 1755 await invokeContentTask(browser, [], () => { 1756 content.document.execCommand("forwardDelete"); 1757 }); 1758 await waitForUiaEvent(); 1759 ok(true, "input got TextChanged event"); 1760 info("Inserting a"); 1761 await setUpWaitForUiaEvent("Text_TextChanged", "input"); 1762 await invokeContentTask(browser, [], () => { 1763 content.document.execCommand("insertText", false, "a"); 1764 }); 1765 await waitForUiaEvent(); 1766 ok(true, "input got TextChanged event"); 1767 1768 info("Focusing editable"); 1769 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, "de"); 1770 await invokeContentTask(browser, [], () => { 1771 content.document.getElementById("editable").focus(); 1772 }); 1773 await moved; 1774 info("Deleting a"); 1775 await setUpWaitForUiaEvent("Text_TextChanged", "editable"); 1776 await invokeContentTask(browser, [], () => { 1777 content.document.execCommand("forwardDelete"); 1778 }); 1779 await waitForUiaEvent(); 1780 ok(true, "editable got TextChanged event"); 1781 info("Inserting a"); 1782 await setUpWaitForUiaEvent("Text_TextChanged", "editable"); 1783 await invokeContentTask(browser, [], () => { 1784 content.document.execCommand("insertText", false, "a"); 1785 }); 1786 await waitForUiaEvent(); 1787 ok(true, "editable got TextChanged event"); 1788 } 1789 ); 1790 1791 /** 1792 * Test the TextRange pattern's GetEnclosingElement method. 1793 */ 1794 addUiaTask( 1795 ` 1796 <div id="editable" contenteditable role="textbox"> 1797 ab 1798 <mark id="cdef"><span>cd</span> <a id="ef" href="/">ef</a></mark> 1799 <a href="/"><img id="g" src="https://example.com/a11y/accessible/tests/mochitest/moz.png" alt="g"></a> 1800 <p><button id="h">h</button></p> 1801 </div> 1802 `, 1803 async function testTextRangeGetEnclosingElement() { 1804 info("Getting editable DocumentRange"); 1805 await runPython(` 1806 doc = getDocUia() 1807 editable = findUiaByDomId(doc, "editable") 1808 text = getUiaPattern(editable, "Text") 1809 global range 1810 range = text.DocumentRange 1811 `); 1812 is( 1813 await runPython(`range.GetEnclosingElement().CurrentAutomationId`), 1814 "editable", 1815 "EnclosingElement is editable" 1816 ); 1817 info("Expanding to word"); 1818 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Word)`); 1819 // Range is now "ab ". 1820 // The IA2 -> UIA proxy gets this wrong. 1821 if (gIsUiaEnabled) { 1822 is( 1823 await runPython(`range.GetEnclosingElement().CurrentName`), 1824 "ab ", 1825 "EnclosingElement is ab text leaf" 1826 ); 1827 } 1828 info("Moving 1 word"); 1829 await runPython(`range.Move(TextUnit_Word, 1)`); 1830 // Range is now "cd ". 1831 // The "cd" text leaf doesn't include the space, so the enclosing element is 1832 // its parent. 1833 is( 1834 await runPython(`range.GetEnclosingElement().CurrentAutomationId`), 1835 "cdef", 1836 "EnclosingElement is cdef" 1837 ); 1838 info("Moving end -1 character"); 1839 await runPython( 1840 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Character, -1)` 1841 ); 1842 // Range is now "cd". 1843 // The IA2 -> UIA proxy gets this wrong. 1844 if (gIsUiaEnabled) { 1845 is( 1846 await runPython(`range.GetEnclosingElement().CurrentName`), 1847 "cd", 1848 "EnclosingElement is cd text leaf" 1849 ); 1850 } 1851 info("Moving 1 word"); 1852 await runPython(`range.Move(TextUnit_Word, 1)`); 1853 // Range is now "ef ". 1854 // Neither the "ef" text leaf/link nor the "cdef" mark include the trailing 1855 // space, so the enclosing element is cdef's parent. 1856 is( 1857 await runPython(`range.GetEnclosingElement().CurrentAutomationId`), 1858 "editable", 1859 "EnclosingElement is editable" 1860 ); 1861 info("Moving end -1 character"); 1862 await runPython( 1863 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Character, -1)` 1864 ); 1865 // Range is now "ef". The innermost element is the text leaf, but "ef" is a 1866 // link and that's what Narrator wants. 1867 is( 1868 await runPython(`range.GetEnclosingElement().CurrentAutomationId`), 1869 "ef", 1870 "EnclosingElement is ef" 1871 ); 1872 // The IA2 -> UIA proxy gets the rest of this wrong. 1873 if (!gIsUiaEnabled) { 1874 return; 1875 } 1876 info("Moving 1 word"); 1877 await runPython(`range.Move(TextUnit_Word, 1)`); 1878 // Range is now the embedded object character for the img (g). 1879 is( 1880 await runPython(`range.GetEnclosingElement().CurrentAutomationId`), 1881 "g", 1882 "EnclosingElement is g" 1883 ); 1884 info("Moving 1 word"); 1885 await runPython(`range.Move(TextUnit_Word, 1)`); 1886 // Range is now "h". "h" is a button and buttons prune their children, so 1887 // UIA doesn't see the text leaf. 1888 is( 1889 await runPython(`range.GetEnclosingElement().CurrentAutomationId`), 1890 "h", 1891 "EnclosingElement is h" 1892 ); 1893 } 1894 ); 1895 1896 /** 1897 * Test the TextRange pattern's GetChildren method. 1898 */ 1899 addUiaTask( 1900 `<div id="editable" contenteditable role="textbox">ab <span id="cdef" role="button"><span>cd</span> <a id="ef" href="/">ef</a> </span><img id="g" src="https://example.com/a11y/accessible/tests/mochitest/moz.png" alt="g"></div>`, 1901 async function testTextRangeGetChildren() { 1902 info("Getting editable DocumentRange"); 1903 await runPython(` 1904 doc = getDocUia() 1905 editable = findUiaByDomId(doc, "editable") 1906 text = getUiaPattern(editable, "Text") 1907 global r 1908 r = text.DocumentRange 1909 `); 1910 await isUiaElementArray( 1911 `r.GetChildren()`, 1912 ["cdef", "g"], 1913 "Children are correct" 1914 ); 1915 info("Expanding to word"); 1916 await runPython(`r.ExpandToEnclosingUnit(TextUnit_Word)`); 1917 // Range is now "ab ". 1918 await isUiaElementArray(`r.GetChildren()`, [], "Children are correct"); 1919 info("Moving 1 word"); 1920 await runPython(`r.Move(TextUnit_Word, 1)`); 1921 // Range is now "cd ". 1922 await isUiaElementArray(`r.GetChildren()`, [], "Children are correct"); 1923 info("Moving 1 word"); 1924 await runPython(`r.Move(TextUnit_Word, 1)`); 1925 // Range is now "ef ". The range includes the link but is not completely 1926 // enclosed by the link. 1927 await isUiaElementArray(`r.GetChildren()`, ["ef"], "Children are correct"); 1928 info("Moving end -1 character"); 1929 await runPython( 1930 `r.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Character, -1)` 1931 ); 1932 // Range is now "ef". The range encloses the link, so there are no children. 1933 await isUiaElementArray(`r.GetChildren()`, [], "Children are correct"); 1934 info("Moving 1 word"); 1935 await runPython(`r.Move(TextUnit_Word, 1)`); 1936 // Range is now the embedded object character for the img (g). The range is 1937 // completely enclosed by the image. 1938 // The IA2 -> UIA proxy gets this wrong. 1939 if (gIsUiaEnabled) { 1940 await isUiaElementArray(`r.GetChildren()`, [], "Children are correct"); 1941 } 1942 } 1943 ); 1944 1945 /** 1946 * Test the Text pattern's RangeFromChild method. 1947 */ 1948 addUiaTask( 1949 `<div id="editable" contenteditable role="textbox">ab <mark id="cdef"><span>cd</span> <a id="ef" href="/">ef</a></mark> <img id="g" src="https://example.com/a11y/accessible/tests/mochitest/moz.png" alt="g"></div>`, 1950 async function testTextRangeFromChild() { 1951 await runPython(` 1952 global doc, docText, editable, edText 1953 doc = getDocUia() 1954 docText = getUiaPattern(doc, "Text") 1955 editable = findUiaByDomId(doc, "editable") 1956 edText = getUiaPattern(editable, "Text") 1957 `); 1958 is( 1959 await runPython(`docText.RangeFromChild(editable).GetText(-1)`), 1960 `ab cd ef ${kEmbedChar}`, 1961 "doc returned correct range for editable" 1962 ); 1963 await testPythonRaises( 1964 `edText.RangeFromChild(editable)`, 1965 "editable correctly failed to return range for editable" 1966 ); 1967 is( 1968 await runPython(`docText.RangeFromChild(editable).GetText(-1)`), 1969 `ab cd ef ${kEmbedChar}`, 1970 "doc returned correct range for editable" 1971 ); 1972 let text = await runPython(` 1973 ab = uiaClient.RawViewWalker.GetFirstChildElement(editable) 1974 range = docText.RangeFromChild(ab) 1975 return range.GetText(-1) 1976 `); 1977 is(text, "ab ", "doc returned correct range for ab"); 1978 text = await runPython(` 1979 global cdef 1980 cdef = findUiaByDomId(doc, "cdef") 1981 range = docText.RangeFromChild(cdef) 1982 return range.GetText(-1) 1983 `); 1984 is(text, "cd ef", "doc returned correct range for cdef"); 1985 text = await runPython(` 1986 cd = uiaClient.RawViewWalker.GetFirstChildElement(cdef) 1987 range = docText.RangeFromChild(cd) 1988 return range.GetText(-1) 1989 `); 1990 is(text, "cd", "doc returned correct range for cd"); 1991 text = await runPython(` 1992 global efLink 1993 efLink = findUiaByDomId(doc, "ef") 1994 range = docText.RangeFromChild(efLink) 1995 return range.GetText(-1) 1996 `); 1997 is(text, "ef", "doc returned correct range for ef link"); 1998 text = await runPython(` 1999 efLeaf = uiaClient.RawViewWalker.GetFirstChildElement(efLink) 2000 range = docText.RangeFromChild(efLeaf) 2001 return range.GetText(-1) 2002 `); 2003 is(text, "ef", "doc returned correct range for ef leaf"); 2004 text = await runPython(` 2005 g = findUiaByDomId(doc, "g") 2006 range = docText.RangeFromChild(g) 2007 return range.GetText(-1) 2008 `); 2009 is(text, kEmbedChar, "doc returned correct range for g"); 2010 }, 2011 // The IA2 -> UIA proxy has too many quirks/bugs here. 2012 { uiaEnabled: true, uiaDisabled: false } 2013 ); 2014 2015 /** 2016 * Test the Text pattern's RangeFromPoint method. 2017 */ 2018 addUiaTask( 2019 `<div id="test">a <span>b </span>c</div>`, 2020 async function testTextRangeFromPoint(browser, docAcc) { 2021 const acc = findAccessibleChildByID(docAcc, "test", [nsIAccessibleText]); 2022 await runPython(` 2023 global doc, docText 2024 doc = getDocUia() 2025 docText = getUiaPattern(doc, "Text") 2026 `); 2027 2028 // Walk through every offset in the accessible and hit test each. Verify 2029 // that the returned range is empty, and that it hit the right character. 2030 for (let offset = 0; offset < acc.characterCount; ++offset) { 2031 const x = {}; 2032 const y = {}; 2033 acc.getCharacterExtents(offset, x, y, {}, {}, COORDTYPE_SCREEN_RELATIVE); 2034 await runPython(` 2035 global range 2036 range = docText.RangeFromPoint(POINT(${x.value}, ${y.value}))`); 2037 is( 2038 await runPython(`range.GetText(-1)`), 2039 ``, 2040 "doc returned correct empty range" 2041 ); 2042 await runPython(`range.ExpandToEnclosingUnit(TextUnit_Character)`); 2043 const charAtOffset = acc.getCharacterAtOffset(offset); 2044 is( 2045 await runPython(`range.GetText(-1)`), 2046 `${charAtOffset}`, 2047 "doc returned correct range" 2048 ); 2049 } 2050 2051 // An arbitrary invalid point should cause an invalid argument error. 2052 await testPythonRaises( 2053 `docText.RangeFromPoint(POINT(9999999999, 9999999999))`, 2054 "no text leaves at invalid point" 2055 ); 2056 }, 2057 { uiaEnabled: true, uiaDisabled: true } 2058 ); 2059 2060 /** 2061 * Test the TextRange pattern's GetBoundingRectangles method. 2062 */ 2063 addUiaTask( 2064 ` 2065 <div id="test"><p id="line1">abc</p><p id="line2">d</p><p id="line3"></p></div> 2066 <div id="offscreen" style="position:absolute; left:200vw;">xyz</div> 2067 `, 2068 async function testTextRangeGetBoundingRectangles(browser, docAcc) { 2069 const line1 = findAccessibleChildByID(docAcc, "line1", [nsIAccessibleText]); 2070 const line2 = findAccessibleChildByID(docAcc, "line2", [nsIAccessibleText]); 2071 2072 const lineRects = await runPython(` 2073 global doc, docText, testAcc, range 2074 doc = getDocUia() 2075 docText = getUiaPattern(doc, "Text") 2076 testAcc = findUiaByDomId(doc, "test") 2077 range = docText.RangeFromChild(testAcc) 2078 return range.GetBoundingRectangles() 2079 `); 2080 2081 is(lineRects.length, 8, "GetBoundingRectangles returned two rectangles"); 2082 const firstLineRect = [ 2083 lineRects[0], 2084 lineRects[1], 2085 lineRects[2], 2086 lineRects[3], 2087 ]; 2088 const secondLineRect = [ 2089 lineRects[4], 2090 lineRects[5], 2091 lineRects[6], 2092 lineRects[7], 2093 ]; 2094 testTextBounds(line1, 0, -1, firstLineRect, COORDTYPE_SCREEN_RELATIVE); 2095 testTextBounds(line2, 0, -1, secondLineRect, COORDTYPE_SCREEN_RELATIVE); 2096 // line3 has no rectangle - GetBoundingRectangles shouldn't return anything for empty lines. 2097 2098 // GetBoundingRectangles shouldn't return anything for offscreen lines. 2099 const offscreenRects = await runPython(` 2100 global offscreenAcc, range 2101 offscreenAcc = findUiaByDomId(doc, "offscreen") 2102 range = docText.RangeFromChild(offscreenAcc) 2103 return range.GetBoundingRectangles() 2104 `); 2105 is( 2106 offscreenRects.length, 2107 0, 2108 "GetBoundingRectangles returned no rectangles" 2109 ); 2110 }, 2111 { uiaEnabled: true, uiaDisabled: true, chrome: true } 2112 ); 2113 2114 /** 2115 * Test char bounds with the TextRange pattern's GetBoundingRectangles method. 2116 */ 2117 addUiaTask( 2118 `<div id="test">abc</div>`, 2119 async function testTextRangeGetBoundingRectanglesChar(browser, docAcc) { 2120 const testAcc = findAccessibleChildByID(docAcc, "test", [ 2121 nsIAccessibleText, 2122 ]); 2123 const charX = {}; 2124 const charY = {}; 2125 const charW = {}; 2126 const charH = {}; 2127 testAcc.getCharacterExtents( 2128 0, 2129 charX, 2130 charY, 2131 charW, 2132 charH, 2133 COORDTYPE_SCREEN_RELATIVE 2134 ); 2135 2136 await runPython(` 2137 global doc, docText, testAcc, range 2138 doc = getDocUia() 2139 docText = getUiaPattern(doc, "Text") 2140 testAcc = findUiaByDomId(doc, "test") 2141 range = docText.RangeFromChild(testAcc) 2142 range.ExpandToEnclosingUnit(TextUnit_Character) 2143 `); 2144 is(await runPython(`range.GetText(-1)`), "a", "range text correct"); 2145 2146 const uiaRect = await runPython(`range.GetBoundingRectangles()`); 2147 is(uiaRect.length, 4, "GetBoundingRectangles returned one rectangle"); 2148 is(uiaRect[0], charX.value, "UIA char rect X matches core char rect X"); 2149 is(uiaRect[1], charY.value, "UIA char rect Y matches core char rect Y"); 2150 is(uiaRect[2], charW.value, "UIA char rect W matches core char rect W"); 2151 is(uiaRect[3], charH.value, "UIA char rect H matches core char rect H"); 2152 }, 2153 { uiaEnabled: true, uiaDisabled: true, chrome: true } 2154 ); 2155 2156 /** 2157 * Test special case line bounds with the TextRange pattern's 2158 * GetBoundingRectangles method. 2159 */ 2160 addUiaTask( 2161 ` 2162 <div><span id="line-break" tabindex="-1">ABC<br/></span>DEF</div> 2163 <p style="width: 1px;"><span id="wrapping" tabindex="-1">ABC</span> DEF</p> 2164 `, 2165 async function testTextRangeGetBoundingRectanglesLine(browser, docAcc) { 2166 const lineBreakAcc = findAccessibleChildByID(docAcc, "line-break", [ 2167 nsIAccessibleText, 2168 ]); 2169 const wrappingAcc = findAccessibleChildByID(docAcc, "wrapping", [ 2170 nsIAccessibleText, 2171 ]); 2172 2173 let lineRects = await runPython(` 2174 global doc, docText, testAcc 2175 doc = getDocUia() 2176 docText = getUiaPattern(doc, "Text") 2177 testAcc = findUiaByDomId(doc, "line-break") 2178 range = docText.RangeFromChild(testAcc) 2179 return range.GetBoundingRectangles() 2180 `); 2181 2182 is(lineRects.length, 4, "GetBoundingRectangles returned one rectangle"); 2183 const lineBreakLineRect = [ 2184 lineRects[0], 2185 lineRects[1], 2186 lineRects[2], 2187 lineRects[3], 2188 ]; 2189 testTextBounds( 2190 lineBreakAcc, 2191 0, 2192 -1, 2193 lineBreakLineRect, 2194 COORDTYPE_SCREEN_RELATIVE 2195 ); 2196 2197 lineRects = await runPython(` 2198 global doc, docText, testAcc 2199 testAcc = findUiaByDomId(doc, "wrapping") 2200 range = docText.RangeFromChild(testAcc) 2201 return range.GetBoundingRectangles() 2202 `); 2203 is(lineRects.length, 4, "GetBoundingRectangles returned one rectangle"); 2204 const wrappingLineRect = [ 2205 lineRects[0], 2206 lineRects[1], 2207 lineRects[2], 2208 lineRects[3], 2209 ]; 2210 testTextBounds( 2211 wrappingAcc, 2212 0, 2213 -1, 2214 wrappingLineRect, 2215 COORDTYPE_SCREEN_RELATIVE 2216 ); 2217 }, 2218 { uiaEnabled: true, uiaDisabled: true, chrome: true } 2219 ); 2220 2221 /** 2222 * Test the Text pattern's GetBoundingRectangles method with the caret. 2223 */ 2224 addUiaTask( 2225 ` 2226 <style> 2227 @font-face { 2228 font-family: Ahem; 2229 src: url(${CURRENT_CONTENT_DIR}e10s/fonts/Ahem.sjs); 2230 } 2231 textarea { 2232 font: 10px/10px Ahem; 2233 width: 10px; 2234 height: 80px; 2235 } 2236 </style> 2237 <div id="editable" contenteditable role="textbox"> 2238 <div id="ce0">a</div> 2239 <div id="ce1"><br></div> 2240 <div id="ce2">b</div> 2241 </div> 2242 <textarea id="textarea">ab 2243 2244 </textarea> 2245 <input id="empty"> 2246 `, 2247 async function testTextRangeGetBoundingRectanglesCaret(browser, docAcc) { 2248 info("Focusing editable"); 2249 const editable = findAccessibleChildByID(docAcc, "editable"); 2250 const ce0 = findAccessibleChildByID(docAcc, "ce0"); 2251 let moved = waitForEvent(EVENT_TEXT_CARET_MOVED, ce0); 2252 editable.takeFocus(); 2253 await moved; 2254 await runPython(` 2255 global doc, text 2256 doc = getDocUia() 2257 editable = findUiaByDomId(doc, "editable") 2258 text = getUiaPattern(editable, "Text") 2259 `); 2260 let uiaRects = await runPython( 2261 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2262 ); 2263 testTextPos(ce0, 0, [uiaRects[0], uiaRects[1]], COORDTYPE_SCREEN_RELATIVE); 2264 let [prevX, prevY] = uiaRects; 2265 2266 info("ArrowRight to end of line"); 2267 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, ce0); 2268 EventUtils.synthesizeKey("KEY_ArrowRight"); 2269 await moved; 2270 uiaRects = await runPython( 2271 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2272 ); 2273 Assert.greater(uiaRects[0], prevX, "x > prevX"); 2274 is(uiaRects[1], prevY, "y == prevY"); 2275 2276 info("ArrowRight to line feed on blank line"); 2277 const ce1 = findAccessibleChildByID(docAcc, "ce1"); 2278 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, ce1); 2279 EventUtils.synthesizeKey("KEY_ArrowRight"); 2280 await moved; 2281 uiaRects = await runPython( 2282 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2283 ); 2284 testTextPos(ce1, 0, [uiaRects[0], uiaRects[1]], COORDTYPE_SCREEN_RELATIVE); 2285 2286 info("ArrowRight to b"); 2287 const ce2 = findAccessibleChildByID(docAcc, "ce2"); 2288 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, ce2); 2289 EventUtils.synthesizeKey("KEY_ArrowRight"); 2290 await moved; 2291 uiaRects = await runPython( 2292 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2293 ); 2294 testTextPos(ce2, 0, [uiaRects[0], uiaRects[1]], COORDTYPE_SCREEN_RELATIVE); 2295 [prevX, prevY] = uiaRects; 2296 2297 info("ArrowRight to end of line"); 2298 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, ce2); 2299 EventUtils.synthesizeKey("KEY_ArrowRight"); 2300 await moved; 2301 uiaRects = await runPython( 2302 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2303 ); 2304 Assert.greater(uiaRects[0], prevX, "x > prevX"); 2305 is(uiaRects[1], prevY, "y == prevY"); 2306 2307 info("Focusing textarea"); 2308 const textarea = findAccessibleChildByID(docAcc, "textarea"); 2309 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 2310 textarea.takeFocus(); 2311 await moved; 2312 await runPython(` 2313 global text 2314 textarea = findUiaByDomId(doc, "textarea") 2315 text = getUiaPattern(textarea, "Text") 2316 `); 2317 uiaRects = await runPython( 2318 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2319 ); 2320 testTextPos( 2321 textarea, 2322 0, 2323 [uiaRects[0], uiaRects[1]], 2324 COORDTYPE_SCREEN_RELATIVE 2325 ); 2326 [prevX, prevY] = uiaRects; 2327 2328 info("ArrowRight to end of line"); 2329 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 2330 EventUtils.synthesizeKey("KEY_ArrowRight"); 2331 await moved; 2332 uiaRects = await runPython( 2333 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2334 ); 2335 Assert.greater(uiaRects[0], prevX, "x > prevX"); 2336 is(uiaRects[1], prevY, "y == prevY"); 2337 2338 info("ArrowRight to b"); 2339 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 2340 EventUtils.synthesizeKey("KEY_ArrowRight"); 2341 await moved; 2342 uiaRects = await runPython( 2343 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2344 ); 2345 testTextPos( 2346 textarea, 2347 1, 2348 [uiaRects[0], uiaRects[1]], 2349 COORDTYPE_SCREEN_RELATIVE 2350 ); 2351 2352 info("ArrowRight to line feed"); 2353 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 2354 EventUtils.synthesizeKey("KEY_ArrowRight"); 2355 await moved; 2356 uiaRects = await runPython( 2357 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2358 ); 2359 testTextPos( 2360 textarea, 2361 2, 2362 [uiaRects[0], uiaRects[1]], 2363 COORDTYPE_SCREEN_RELATIVE 2364 ); 2365 2366 info("ArrowRight to line feed on first blank line"); 2367 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 2368 EventUtils.synthesizeKey("KEY_ArrowRight"); 2369 await moved; 2370 uiaRects = await runPython( 2371 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2372 ); 2373 testTextPos( 2374 textarea, 2375 3, 2376 [uiaRects[0], uiaRects[1]], 2377 COORDTYPE_SCREEN_RELATIVE 2378 ); 2379 [prevX, prevY] = uiaRects; 2380 2381 info("ArrowRight to second blank line (end of textarea)"); 2382 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); 2383 EventUtils.synthesizeKey("KEY_ArrowRight"); 2384 await moved; 2385 uiaRects = await runPython( 2386 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2387 ); 2388 is(uiaRects[0], prevX, "x == prevX"); 2389 Assert.greater(uiaRects[1], prevY, "y > prevY"); 2390 2391 info("Focusing empty"); 2392 const empty = findAccessibleChildByID(docAcc, "empty", [nsIAccessibleText]); 2393 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, empty); 2394 empty.takeFocus(); 2395 await moved; 2396 await runPython(` 2397 global text 2398 empty = findUiaByDomId(doc, "empty") 2399 text = getUiaPattern(empty, "Text") 2400 `); 2401 uiaRects = await runPython( 2402 `text.GetSelection().GetElement(0).GetBoundingRectangles()` 2403 ); 2404 const caretX = {}; 2405 const caretY = {}; 2406 const caretW = {}; 2407 const caretH = {}; 2408 empty.getCaretRect(caretX, caretY, caretW, caretH); 2409 is(uiaRects[0], caretX.value, "x == caretX"); 2410 is(uiaRects[1], caretY.value, "y == caretY"); 2411 is(uiaRects[2], caretW.value, "w == caretW"); 2412 is(uiaRects[3], caretH.value, "h == caretH"); 2413 }, 2414 // The IA2 -> UIA proxy doesn't support this. 2415 { uiaEnabled: true, uiaDisabled: false } 2416 ); 2417 2418 /** 2419 * Test the TextRange pattern's ScrollIntoView method. 2420 */ 2421 addUiaTask( 2422 ` 2423 <style> 2424 body { 2425 margin: 0; 2426 } 2427 </style> 2428 <p>p1</p> 2429 <hr style="height: 200vh;"> 2430 <p id="p2">p2</p> 2431 <hr style="height: 200vh;"> 2432 <p>p3</p> 2433 `, 2434 async function testTextRangeScrollIntoView(browser, docAcc) { 2435 const [docLeft, docTop, , docBottom] = await runPython(` 2436 global doc 2437 doc = getDocUia() 2438 rect = doc.CurrentBoundingRectangle 2439 return (rect.left, rect.top, rect.right, rect.bottom) 2440 `); 2441 2442 info("Scrolling p2 to top"); 2443 let scrolled = waitForEvent(EVENT_SCROLLING_END, docAcc); 2444 await runPython(` 2445 global docText, p2, range 2446 docText = getUiaPattern(doc, "Text") 2447 p2 = findUiaByDomId(doc, "p2") 2448 range = docText.RangeFromChild(p2) 2449 range.ScrollIntoView(True) 2450 `); 2451 await scrolled; 2452 let [left, top, , height] = await runPython( 2453 `range.GetBoundingRectangles()` 2454 ); 2455 is(left, docLeft, "range is at left of document"); 2456 is(top, docTop, "range is at top of document"); 2457 2458 info("Scrolling p2 to bottom"); 2459 scrolled = waitForEvent(EVENT_SCROLLING_END, docAcc); 2460 await runPython(` 2461 range.ScrollIntoView(False) 2462 `); 2463 await scrolled; 2464 [left, top, , height] = await runPython(`range.GetBoundingRectangles()`); 2465 is(left, docLeft, "range is at left of document"); 2466 is(top + height, docBottom, "range is at bottom of document"); 2467 } 2468 ); 2469 2470 /** 2471 * Test the TextRange pattern's Select method. 2472 */ 2473 addUiaTask( 2474 ` 2475 <p id="p">ab<a id="link" href="/">c</a></p> 2476 <input id="input" type="text" value="ab"> 2477 <div id="contenteditable" contenteditable role="textbox">ab</div> 2478 `, 2479 async function testTextRangeSelect(browser, docAcc) { 2480 info("Moving caret to b in p"); 2481 const p = findAccessibleChildByID(docAcc, "p", [nsIAccessibleText]); 2482 let moved = waitForEvent(EVENT_TEXT_CARET_MOVED, p); 2483 await runPython(` 2484 global doc 2485 doc = getDocUia() 2486 p = findUiaByDomId(doc, "p") 2487 textChild = getUiaPattern(p, "TextChild") 2488 global pbRange 2489 pbRange = textChild.TextRange 2490 # Encompass "b". 2491 pbRange.Move(TextUnit_Character, 1) 2492 # Collapse. 2493 pbRange.MoveEndpointByRange(TextPatternRangeEndpoint_End, pbRange, TextPatternRangeEndpoint_Start) 2494 pbRange.Select() 2495 `); 2496 await moved; 2497 testTextSelectionCount(p, 0); 2498 is(p.caretOffset, 1, "caret at 1"); 2499 // When using the IA2 -> UIA proxy, the focus changes when moving the caret, 2500 // but this isn't what UIA clients want. 2501 if (gIsUiaEnabled) { 2502 info("Moving caret to c in link"); 2503 const link = findAccessibleChildByID(docAcc, "link", [nsIAccessibleText]); 2504 moved = waitForEvents({ 2505 expected: [[EVENT_TEXT_CARET_MOVED, link]], 2506 unexpected: [[EVENT_FOCUS, link]], 2507 }); 2508 await runPython(` 2509 link = findUiaByDomId(doc, "link") 2510 textChild = getUiaPattern(link, "TextChild") 2511 range = textChild.TextRange 2512 # Collapse to "a". 2513 range.MoveEndpointByRange(TextPatternRangeEndpoint_End, range, TextPatternRangeEndpoint_Start) 2514 range.Select() 2515 `); 2516 await moved; 2517 testTextSelectionCount(link, 0); 2518 is(p.caretOffset, 2, "p caret at 2"); 2519 is(link.caretOffset, 0, "link caret at 0"); 2520 info("Focusing link"); 2521 moved = waitForEvent(EVENT_FOCUS, link); 2522 link.takeFocus(); 2523 await moved; 2524 info("Moving caret back to b in p"); 2525 moved = waitForEvents({ 2526 expected: [[EVENT_TEXT_CARET_MOVED, p]], 2527 unexpected: [[EVENT_FOCUS, docAcc]], 2528 }); 2529 await runPython(` 2530 pbRange.Select() 2531 `); 2532 await moved; 2533 testTextSelectionCount(p, 0); 2534 is(p.caretOffset, 1, "p caret at 1"); 2535 } 2536 2537 // <input> and contentEditable should behave the same. 2538 for (const id of ["input", "contenteditable"]) { 2539 info(`Focusing ${id}`); 2540 const acc = findAccessibleChildByID(docAcc, id, [nsIAccessibleText]); 2541 moved = waitForEvents([ 2542 [EVENT_FOCUS, acc], 2543 [EVENT_TEXT_CARET_MOVED, acc], 2544 ]); 2545 acc.takeFocus(); 2546 await moved; 2547 2548 info("Selecting a"); 2549 moved = waitForEvents([ 2550 [EVENT_TEXT_SELECTION_CHANGED, acc], 2551 [EVENT_TEXT_CARET_MOVED, acc], 2552 ]); 2553 await runPython(` 2554 acc = findUiaByDomId(doc, "${id}") 2555 text = getUiaPattern(acc, "Text") 2556 global range 2557 range = text.DocumentRange 2558 range.ExpandToEnclosingUnit(TextUnit_Character) 2559 range.Select() 2560 `); 2561 await moved; 2562 testTextSelectionCount(acc, 1); 2563 testTextGetSelection(acc, 0, 1, 0); 2564 2565 info("Moving caret to b"); 2566 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, acc); 2567 await runPython(` 2568 # Collapse to b. 2569 range.MoveEndpointByUnit(TextPatternRangeEndpoint_Start, TextUnit_Character, 1) 2570 range.Select() 2571 `); 2572 await moved; 2573 testTextSelectionCount(acc, 0); 2574 is(acc.caretOffset, 1, "caret at 1"); 2575 } 2576 } 2577 ); 2578 2579 /** 2580 * Test the TextRange pattern's AddToSelection method. 2581 */ 2582 addUiaTask( 2583 ` 2584 <input id="input" type="text" value="abc"> 2585 <div id="contenteditable" contenteditable role="textbox">abc</div> 2586 `, 2587 async function testTextRangeAddToSelection(browser, docAcc) { 2588 // <input> and contentEditable should behave the same. 2589 for (const id of ["input", "contenteditable"]) { 2590 info(`Focusing ${id}`); 2591 const acc = findAccessibleChildByID(docAcc, id, [nsIAccessibleText]); 2592 let moved = waitForEvents([ 2593 [EVENT_FOCUS, acc], 2594 [EVENT_TEXT_CARET_MOVED, acc], 2595 ]); 2596 acc.takeFocus(); 2597 await moved; 2598 2599 info("Adding a to selection"); 2600 moved = waitForEvents([ 2601 [EVENT_TEXT_SELECTION_CHANGED, acc], 2602 [EVENT_TEXT_CARET_MOVED, acc], 2603 ]); 2604 await runPython(` 2605 doc = getDocUia() 2606 acc = findUiaByDomId(doc, "${id}") 2607 text = getUiaPattern(acc, "Text") 2608 global range 2609 range = text.DocumentRange 2610 range.ExpandToEnclosingUnit(TextUnit_Character) 2611 range.AddToSelection() 2612 `); 2613 await moved; 2614 testTextSelectionCount(acc, 1); 2615 testTextGetSelection(acc, 0, 1, 0); 2616 2617 info("Adding c to selection"); 2618 moved = waitForEvent(EVENT_TEXT_CARET_MOVED, acc); 2619 await runPython(` 2620 # Move start to c. 2621 range.MoveEndpointByUnit(TextPatternRangeEndpoint_Start, TextUnit_Character, 2) 2622 range.ExpandToEnclosingUnit(TextUnit_Character) 2623 range.AddToSelection() 2624 `); 2625 await moved; 2626 testTextSelectionCount(acc, 2); 2627 testTextGetSelection(acc, 0, 1, 0); 2628 testTextGetSelection(acc, 2, 3, 1); 2629 } 2630 } 2631 ); 2632 2633 /** 2634 * Test the TextRange pattern's RemoveFromSelection method. 2635 */ 2636 addUiaTask( 2637 ` 2638 <input id="input" type="text" value="abc"> 2639 <div id="contenteditable" contenteditable role="textbox">abc</div> 2640 `, 2641 async function testTextRangeRemoveFromSelection(browser, docAcc) { 2642 // <input> and contentEditable should behave the same. 2643 for (const id of ["input", "contenteditable"]) { 2644 info(`Focusing ${id}`); 2645 const acc = findAccessibleChildByID(docAcc, id, [nsIAccessibleText]); 2646 let moved = waitForEvents([ 2647 [EVENT_FOCUS, acc], 2648 [EVENT_TEXT_CARET_MOVED, acc], 2649 ]); 2650 acc.takeFocus(); 2651 await moved; 2652 2653 info("Adding a to selection"); 2654 moved = waitForEvents([ 2655 [EVENT_TEXT_SELECTION_CHANGED, acc], 2656 [EVENT_TEXT_CARET_MOVED, acc], 2657 ]); 2658 acc.addSelection(0, 1); 2659 await moved; 2660 info("Adding c to selection"); 2661 moved = waitForEvents([ 2662 [EVENT_TEXT_SELECTION_CHANGED, acc], 2663 [EVENT_TEXT_CARET_MOVED, acc], 2664 ]); 2665 acc.addSelection(2, 3); 2666 await moved; 2667 2668 info("Removing a from selection"); 2669 moved = waitForEvents([ 2670 [EVENT_TEXT_SELECTION_CHANGED, acc], 2671 [EVENT_TEXT_CARET_MOVED, acc], 2672 ]); 2673 await runPython(` 2674 doc = getDocUia() 2675 acc = findUiaByDomId(doc, "${id}") 2676 text = getUiaPattern(acc, "Text") 2677 global range 2678 range = text.DocumentRange 2679 range.ExpandToEnclosingUnit(TextUnit_Character) 2680 range.RemoveFromSelection() 2681 `); 2682 await moved; 2683 testTextSelectionCount(acc, 1); 2684 testTextGetSelection(acc, 2, 3, 0); 2685 2686 info("Removing b from selection even though it isn't selected"); 2687 await runPython(` 2688 # Move start to b. 2689 range.MoveEndpointByUnit(TextPatternRangeEndpoint_Start, TextUnit_Character, 1) 2690 range.ExpandToEnclosingUnit(TextUnit_Character) 2691 `); 2692 await testPythonRaises( 2693 `range.RemoveFromSelection()`, 2694 "RemoveFromSelection failed" 2695 ); 2696 2697 info("Removing c from selection"); 2698 moved = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, acc); 2699 await runPython(` 2700 # Move start to c. 2701 range.MoveEndpointByUnit(TextPatternRangeEndpoint_Start, TextUnit_Character, 1) 2702 range.ExpandToEnclosingUnit(TextUnit_Character) 2703 range.RemoveFromSelection() 2704 `); 2705 await moved; 2706 testTextSelectionCount(acc, 0); 2707 } 2708 }, 2709 // The IA2 -> UIA proxy doesn't support RemoveFromSelection correctly. 2710 { uiaEnabled: true, uiaDisabled: false } 2711 ); 2712 2713 /** 2714 * Test the TextRange pattern's FindAttribute method. 2715 */ 2716 addUiaTask( 2717 ` 2718 <div id="font-weight-container">a <span tabindex="0"><b>bcd</b></span><b> ef</b> ghi</div> 2719 `, 2720 async function testTextRangeFindAttribute(_browser, _docAcc) { 2721 info("Constructing range on bold text run"); 2722 await runPython(` 2723 global doc, docText, range, fontWeightContainerAcc 2724 doc = getDocUia() 2725 docText = getUiaPattern(doc, "Text") 2726 fontWeightContainerAcc = findUiaByDomId(doc, "font-weight-container") 2727 range = docText.RangeFromChild(fontWeightContainerAcc) 2728 `); 2729 is( 2730 await runPython(`range.GetText(-1)`), 2731 "a bcd ef ghi", 2732 "range text correct" 2733 ); 2734 2735 info("Finding first font-weight 400 text range"); 2736 await runPython(` 2737 global subrange 2738 subrange = range.FindAttribute(UIA_FontWeightAttributeId, 400, False) 2739 `); 2740 is(await runPython(`subrange.GetText(-1)`), "a ", "range text correct"); 2741 2742 info("Finding first font-weight 700 text range"); 2743 await runPython(` 2744 global subrange 2745 subrange = range.FindAttribute(UIA_FontWeightAttributeId, 700, False) 2746 `); 2747 is(await runPython(`subrange.GetText(-1)`), "bcd ef", "range text correct"); 2748 2749 info("Finding last font-weight 700 text range"); 2750 await runPython(` 2751 global subrange 2752 subrange = range.FindAttribute(UIA_FontWeightAttributeId, 700, True) 2753 `); 2754 is(await runPython(`subrange.GetText(-1)`), "bcd ef", "range text correct"); 2755 2756 info("Finding last font-weight 400 text range"); 2757 await runPython(` 2758 global subrange 2759 subrange = range.FindAttribute(UIA_FontWeightAttributeId, 400, True) 2760 `); 2761 is(await runPython(`subrange.GetText(-1)`), " ghi", "range text correct"); 2762 2763 // The IA2 -> UIA proxy gets things below this wrong. 2764 if (!gIsUiaEnabled) { 2765 return; 2766 } 2767 info("Moving range to the middle of a text attribute run"); 2768 is( 2769 await runPython( 2770 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_Start, TextUnit_Character, 4)` 2771 ), 2772 4, 2773 "MoveEndpointByUnit return correct" 2774 ); 2775 is(await runPython(`range.GetText(-1)`), "cd ef ghi", "range text correct"); 2776 2777 info( 2778 "Finding first font-weight 700 text range (range starts in middle of text attribute run)" 2779 ); 2780 await runPython(` 2781 global subrange 2782 subrange = range.FindAttribute(UIA_FontWeightAttributeId, 700, False) 2783 `); 2784 is(await runPython(`subrange.GetText(-1)`), "cd ef", "range text correct"); 2785 2786 await runPython(` 2787 global range 2788 range = docText.RangeFromChild(fontWeightContainerAcc) 2789 `); 2790 is( 2791 await runPython(`range.GetText(-1)`), 2792 "a bcd ef ghi", 2793 "range text correct" 2794 ); 2795 is( 2796 await runPython( 2797 `range.MoveEndpointByUnit(TextPatternRangeEndpoint_End, TextUnit_Character, -5)` 2798 ), 2799 -5, 2800 "MoveEndpointByUnit return correct" 2801 ); 2802 is(await runPython(`range.GetText(-1)`), "a bcd e", "range text correct"); 2803 2804 info( 2805 "Finding last font-weight 700 text range (range ends in middle of text attribute run)" 2806 ); 2807 await runPython(` 2808 global subrange 2809 subrange = range.FindAttribute(UIA_FontWeightAttributeId, 700, True) 2810 `); 2811 is(await runPython(`subrange.GetText(-1)`), "bcd e", "range text correct"); 2812 2813 info("Collapsing range at start"); 2814 await runPython(` 2815 global subrange 2816 subrange = range.Clone() 2817 subrange.MoveEndpointByRange(TextPatternRangeEndpoint_End, subrange, TextPatternRangeEndpoint_Start) 2818 `); 2819 is(await runPython(`subrange.GetText(-1)`), "", "subrange text correct"); 2820 info("Finding last font-weight 400 text range on collapsed range"); 2821 await runPython(` 2822 global subrange 2823 subrange = subrange.FindAttribute(UIA_FontWeightAttributeId, 400, True) 2824 `); 2825 is(await runPython(`subrange.GetText(-1)`), "", "subrange text correct"); 2826 }, 2827 { uiaEnabled: true, uiaDisabled: true } 2828 ); 2829 2830 /** 2831 * Test the Text pattern's GetVisibleRanges method. 2832 */ 2833 addUiaTask( 2834 ` 2835 <div id="div"> 2836 <p>line1</p> 2837 <p><strong id="strong">line</strong>2</p> 2838 <p style="position: absolute; left: -10000px; width: 1px;">line3</p> 2839 <p>line4</p> 2840 </div> 2841 <!-- We use 0.5lh so the second line is definitely fully scrolled out. 2842 With 1lh, it could be partially visible and thus included. --> 2843 <textarea id="textarea" style="height: 0.5lh;">line5 2844 line6 2845 line7</textarea> 2846 <hr aria-hidden="true" style="height: 100vh;"> 2847 <p>line8</p> 2848 `, 2849 async function testTextGetVisibleRanges() { 2850 await runPython(` 2851 global doc, docText, ranges 2852 doc = getDocUia() 2853 docText = getUiaPattern(doc, "Text") 2854 ranges = docText.GetVisibleRanges() 2855 `); 2856 // XXX This should be 4 once we fix the scrolling case below. 2857 is( 2858 await runPython(`ranges.Length`), 2859 6, 2860 "doc has correct number of visible ranges" 2861 ); 2862 is( 2863 await runPython(`ranges.GetElement(0).GetText(-1)`), 2864 "line1", 2865 "range 0 text correct" 2866 ); 2867 is( 2868 await runPython(`ranges.GetElement(1).GetText(-1)`), 2869 "line2", 2870 "range 1 text correct" 2871 ); 2872 // line3 is off-screen and thus not visible. 2873 is( 2874 await runPython(`ranges.GetElement(2).GetText(-1)`), 2875 "line4", 2876 "range 2 text correct" 2877 ); 2878 is( 2879 await runPython(`ranges.GetElement(3).GetText(-1)`), 2880 "line5\n", 2881 "range 3 text correct" 2882 ); 2883 // XXX line6 and line7 are scrolled off screen by the textarea, but we 2884 // incorrectly return them for now (ranges 4 and 5). 2885 // line8 is scrolled off screen by the document. 2886 2887 await runPython(` 2888 textarea = findUiaByDomId(doc, "textarea") 2889 textareaText = getUiaPattern(textarea, "Text") 2890 global ranges 2891 ranges = textareaText.GetVisibleRanges() 2892 `); 2893 is( 2894 await runPython(`ranges.Length`), 2895 1, 2896 "textarea has correct number of visible ranges" 2897 ); 2898 is( 2899 await runPython(`ranges.GetElement(0).GetText(-1)`), 2900 "line5\n", 2901 "range 0 text correct" 2902 ); 2903 // line6 and line7 are scrolled off screen by the textarea. 2904 2905 await runPython(` 2906 strong = findUiaByDomId(doc, "strong") 2907 strongLeaf = uiaClient.RawViewWalker.GetFirstChildElement(strong) 2908 strongText = getUiaPattern(strongLeaf, "Text") 2909 global ranges 2910 ranges = strongText.GetVisibleRanges() 2911 `); 2912 is( 2913 await runPython(`ranges.Length`), 2914 1, 2915 "strong leaf has correct number of visible ranges" 2916 ); 2917 is( 2918 await runPython(`ranges.GetElement(0).GetText(-1)`), 2919 "line", 2920 "range 0 text correct" 2921 ); 2922 }, 2923 // The IA2 -> UIA proxy doesn't support GetVisibleRanges. 2924 { uiaEnabled: true, uiaDisabled: false } 2925 ); 2926 2927 /** 2928 * Test the TextRange pattern's FindText method. 2929 */ 2930 addUiaTask( 2931 ` 2932 <div id="container"><b>abc</b>TEST<div id="inner">def</div>TEST<p>ghi</p></div> 2933 <textarea id="textarea">This is a test.</textarea> 2934 `, 2935 async function testTextRangeFindText() { 2936 info("container tests"); 2937 await runPython(` 2938 global doc, docText, container, range 2939 doc = getDocUia() 2940 docText = getUiaPattern(doc, "Text") 2941 container = findUiaByDomId(doc, "container") 2942 range = docText.RangeFromChild(container) 2943 `); 2944 // The IA2 -> UIA bridge inserts a space at the end of the text. 2945 if (gIsUiaEnabled) { 2946 is( 2947 await runPython(`range.GetText(-1)`), 2948 `abcTESTdefTESTghi`, 2949 "doc returned correct range for container" 2950 ); 2951 } 2952 info("Finding 'abc', searching from the start"); 2953 await runPython(` 2954 global subrange 2955 subrange = range.FindText("abc", False, False) 2956 `); 2957 is(await runPython(`subrange.GetText(-1)`), "abc", "range text correct"); 2958 2959 info("Finding 'abc', searching from the end"); 2960 await runPython(` 2961 global subrange 2962 subrange = range.FindText("abc", True, False) 2963 `); 2964 is(await runPython(`subrange.GetText(-1)`), "abc", "range text correct"); 2965 2966 info("Finding 'ghi', searching from the start"); 2967 await runPython(` 2968 global subrange 2969 subrange = range.FindText("ghi", False, False) 2970 `); 2971 is(await runPython(`subrange.GetText(-1)`), "ghi", "range text correct"); 2972 2973 info("Finding 'ghi', searching from the end"); 2974 await runPython(` 2975 global subrange 2976 subrange = range.FindText("ghi", True, False) 2977 `); 2978 is(await runPython(`subrange.GetText(-1)`), "ghi", "range text correct"); 2979 2980 info("Finding 'TEST', searching from the start"); 2981 await runPython(` 2982 global subrange 2983 subrange = range.FindText("TEST", False, False) 2984 `); 2985 is(await runPython(`subrange.GetText(-1)`), "TEST", "range text correct"); 2986 info("Finding 'TEST', searching from the end"); 2987 await runPython(` 2988 global subrange2 2989 subrange2 = range.FindText("TEST", True, False) 2990 `); 2991 is(await runPython(`subrange2.GetText(-1)`), "TEST", "range text correct"); 2992 ok( 2993 !(await runPython(`subrange.compare(subrange2)`)), 2994 "ranges are not equal" 2995 ); 2996 2997 info("Finding 'test', searching from the start, case-sensitive"); 2998 await runPython(` 2999 global subrange 3000 subrange = range.FindText("test", False, False) 3001 `); 3002 ok(await runPython(`not subrange`), "range not found"); 3003 info("Finding 'test', searching from the start, case-insensitive"); 3004 await runPython(` 3005 global subrange 3006 subrange = range.FindText("test", False, True) 3007 `); 3008 is(await runPython(`subrange.GetText(-1)`), "TEST", "range text correct"); 3009 3010 info("textarea tests"); 3011 await runPython(` 3012 global range 3013 textarea = findUiaByDomId(doc, "textarea") 3014 range = docText.RangeFromChild(textarea) 3015 `); 3016 is( 3017 await runPython(`range.GetText(-1)`), 3018 "This is a test.", 3019 "doc returned correct range for textarea" 3020 ); 3021 3022 info("Finding 'is', searching from the start"); 3023 await runPython(` 3024 global subrange 3025 subrange = range.FindText("is", False, False) 3026 `); 3027 is(await runPython(`subrange.GetText(-1)`), "is", "range text correct"); 3028 info("Expanding to word"); 3029 await runPython(`subrange.ExpandToEnclosingUnit(TextUnit_Word)`); 3030 is(await runPython(`subrange.GetText(-1)`), "This ", "range text correct"); 3031 3032 info("Creating range for 'is a test.'"); 3033 await runPython(` 3034 global partRange 3035 partRange = range.Clone() 3036 partRange.MoveEndpointByRange(TextPatternRangeEndpoint_Start, subrange, TextPatternRangeEndpoint_End) 3037 `); 3038 is( 3039 await runPython(`partRange.GetText(-1)`), 3040 "is a test.", 3041 "range text correct" 3042 ); 3043 3044 info("Finding 'is', searching forward in 'is a test.'"); 3045 await runPython(` 3046 global subrange 3047 subrange = partRange.FindText("is", False, False) 3048 `); 3049 is(await runPython(`subrange.GetText(-1)`), "is", "range text correct"); 3050 info("Expanding to word"); 3051 await runPython(`subrange.ExpandToEnclosingUnit(TextUnit_Word)`); 3052 is(await runPython(`subrange.GetText(-1)`), "is ", "range text correct"); 3053 }, 3054 { uiaEnabled: true, uiaDisabled: true } 3055 ); 3056 3057 const textChildSnippet = ` 3058 <p id="p">p</p> 3059 <a id="a" href="/">a</a> 3060 <img id="img" src="https://example.com/a11y/accessible/tests/mochitest/moz.png" alt="img"> 3061 <div id="textbox" contenteditable role="textbox">textboxLeaf 3062 <p id="textboxP">textboxP</p> 3063 </div> 3064 `; 3065 3066 /** 3067 * Test the TextChild pattern's TextContainer property. 3068 */ 3069 addUiaTask(textChildSnippet, async function testTextChildTextContainer() { 3070 ok( 3071 await runPython(` 3072 global doc, p 3073 doc = getDocUia() 3074 p = findUiaByDomId(doc, "p") 3075 tc = getUiaPattern(p, "TextChild") 3076 return uiaClient.CompareElements(tc.TextContainer, doc) 3077 `), 3078 "p TextContainer is doc" 3079 ); 3080 // The IA2 -> UIA proxy doesn't support the TextChild pattern on text 3081 // leaves. 3082 if (gIsUiaEnabled) { 3083 ok( 3084 await runPython(` 3085 pLeaf = uiaClient.RawViewWalker.GetFirstChildElement(p) 3086 tc = getUiaPattern(pLeaf, "TextChild") 3087 return uiaClient.CompareElements(tc.TextContainer, doc) 3088 `), 3089 "p leaf TextContainer is doc" 3090 ); 3091 } 3092 ok( 3093 await runPython(` 3094 a = findUiaByDomId(doc, "a") 3095 tc = getUiaPattern(a, "TextChild") 3096 return uiaClient.CompareElements(tc.TextContainer, doc) 3097 `), 3098 "a TextContainer is doc" 3099 ); 3100 ok( 3101 await runPython(` 3102 img = findUiaByDomId(doc, "img") 3103 tc = getUiaPattern(img, "TextChild") 3104 return uiaClient.CompareElements(tc.TextContainer, doc) 3105 `), 3106 "img TextContainer is doc" 3107 ); 3108 ok( 3109 await runPython(` 3110 global textbox 3111 textbox = findUiaByDomId(doc, "textbox") 3112 tc = getUiaPattern(textbox, "TextChild") 3113 return uiaClient.CompareElements(tc.TextContainer, doc) 3114 `), 3115 "textbox TextContainer is doc" 3116 ); 3117 // The IA2 -> UIA proxy doesn't support the TextChild pattern on text 3118 // leaves. 3119 if (gIsUiaEnabled) { 3120 ok( 3121 await runPython(` 3122 textboxLeaf = uiaClient.RawViewWalker.GetFirstChildElement(textbox) 3123 tc = getUiaPattern(textboxLeaf, "TextChild") 3124 return uiaClient.CompareElements(tc.TextContainer, textbox) 3125 `), 3126 "textbox leaf TextContainer is textbox" 3127 ); 3128 } 3129 ok( 3130 await runPython(` 3131 textboxP = findUiaByDomId(doc, "textboxP") 3132 tc = getUiaPattern(textboxP, "TextChild") 3133 return uiaClient.CompareElements(tc.TextContainer, textbox) 3134 `), 3135 "textboxP TextContainer is textbox" 3136 ); 3137 }); 3138 3139 /** 3140 * Test the TextChild pattern's TextRange property. 3141 */ 3142 addUiaTask(textChildSnippet, async function testTextChildTextRange() { 3143 is( 3144 await runPython(` 3145 global doc, p 3146 doc = getDocUia() 3147 p = findUiaByDomId(doc, "p") 3148 tc = getUiaPattern(p, "TextChild") 3149 return tc.TextRange.GetText(-1) 3150 `), 3151 "p", 3152 "p text correct" 3153 ); 3154 // The IA2 -> UIA proxy doesn't support the TextChild pattern on text 3155 // leaves. 3156 if (gIsUiaEnabled) { 3157 is( 3158 await runPython(` 3159 pLeaf = uiaClient.RawViewWalker.GetFirstChildElement(p) 3160 tc = getUiaPattern(pLeaf, "TextChild") 3161 return tc.TextRange.GetText(-1) 3162 `), 3163 "p", 3164 "p leaf text correct" 3165 ); 3166 } 3167 is( 3168 await runPython(` 3169 a = findUiaByDomId(doc, "a") 3170 tc = getUiaPattern(a, "TextChild") 3171 return tc.TextRange.GetText(-1) 3172 `), 3173 "a", 3174 "a text correct" 3175 ); 3176 if (gIsUiaEnabled) { 3177 // The IA2 -> UIA proxy doesn't expose an embedded object character for 3178 // images. 3179 is( 3180 await runPython(` 3181 img = findUiaByDomId(doc, "img") 3182 tc = getUiaPattern(img, "TextChild") 3183 return tc.TextRange.GetText(-1) 3184 `), 3185 kEmbedChar, 3186 "img text correct" 3187 ); 3188 // The IA2 -> UIA proxy adds spaces between elements that don't exist. 3189 is( 3190 await runPython(` 3191 global textbox 3192 textbox = findUiaByDomId(doc, "textbox") 3193 tc = getUiaPattern(textbox, "TextChild") 3194 return tc.TextRange.GetText(-1) 3195 `), 3196 "textboxLeaf textboxP", 3197 "textbox text correct" 3198 ); 3199 // The IA2 -> UIA proxy doesn't support the TextChild pattern on text 3200 // leaves. 3201 is( 3202 await runPython(` 3203 textboxLeaf = uiaClient.RawViewWalker.GetFirstChildElement(textbox) 3204 tc = getUiaPattern(textboxLeaf, "TextChild") 3205 return tc.TextRange.GetText(-1) 3206 `), 3207 "textboxLeaf ", 3208 "textbox leaf text correct" 3209 ); 3210 } 3211 is( 3212 await runPython(` 3213 textboxP = findUiaByDomId(doc, "textboxP") 3214 tc = getUiaPattern(textboxP, "TextChild") 3215 return tc.TextRange.GetText(-1) 3216 `), 3217 "textboxP", 3218 "textboxP text correct" 3219 ); 3220 });