From 8c2cca932017bfccf7411d8e17971e1950827b5a Mon Sep 17 00:00:00 2001 From: James Teh Date: Sat, 26 Feb 2022 23:01:56 +0000 Subject: [PATCH] Bug 1741793 part 6: Add tests to exercise RemoteAccessible text selection retrieval. r=eeejay Differential Revision: https://phabricator.services.mozilla.com/D139345 --- .../browser/e10s/browser_caching_text.js | 230 ++++++++++++++++++ 1 file changed, 230 insertions(+) diff --git a/accessible/tests/browser/e10s/browser_caching_text.js b/accessible/tests/browser/e10s/browser_caching_text.js index 101fd8231887..5c462438be17 100644 --- a/accessible/tests/browser/e10s/browser_caching_text.js +++ b/accessible/tests/browser/e10s/browser_caching_text.js @@ -677,3 +677,233 @@ addAccessibleTask( }, { chrome: true, topLevel: true, iframe: true, remoteIframe: true } ); + +function waitForSelectionChange(selectionAcc, caretAcc) { + if (!caretAcc) { + caretAcc = selectionAcc; + } + return waitForEvents( + [ + [EVENT_TEXT_SELECTION_CHANGED, selectionAcc], + // We must swallow the caret events as well to avoid confusion with later, + // unrelated caret events. + [EVENT_TEXT_CARET_MOVED, caretAcc], + ], + true + ); +} + +function changeDomSelection( + browser, + anchorId, + anchorOffset, + focusId, + focusOffset +) { + return invokeContentTask( + browser, + [anchorId, anchorOffset, focusId, focusOffset], + ( + contentAnchorId, + contentAnchorOffset, + contentFocusId, + contentFocusOffset + ) => { + // We want the text node, so we use firstChild. + content.window + .getSelection() + .setBaseAndExtent( + content.document.getElementById(contentAnchorId).firstChild, + contentAnchorOffset, + content.document.getElementById(contentFocusId).firstChild, + contentFocusOffset + ); + } + ); +} + +function testSelectionRange( + browser, + root, + startContainer, + startOffset, + endContainer, + endOffset +) { + if (browser.isRemoteBrowser && !isCacheEnabled) { + todo( + false, + "selectionRanges not implemented for non-cached RemoteAccessible" + ); + return; + } + let selRange = root.selectionRanges.queryElementAt(0, nsIAccessibleTextRange); + testTextRange( + selRange, + getAccessibleDOMNodeID(root), + startContainer, + startOffset, + endContainer, + endOffset + ); +} + +/** + * Test text selection. + */ +addAccessibleTask( + ` + +
+

a

+

bc

+ +
+ `, + async function(browser, docAcc) { + const textarea = findAccessibleChildByID(docAcc, "textarea", [ + nsIAccessibleText, + ]); + info("Focusing textarea"); + let caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); + textarea.takeFocus(); + await caretMoved; + testSelectionRange(browser, textarea, textarea, 0, textarea, 0); + is(textarea.selectionCount, 0, "textarea selectionCount is 0"); + + info("Selecting a in textarea"); + let selChanged = waitForSelectionChange(textarea); + EventUtils.synthesizeKey("KEY_ArrowRight", { shiftKey: true }); + await selChanged; + testSelectionRange(browser, textarea, textarea, 0, textarea, 1); + testTextGetSelection(textarea, 0, 1, 0); + + info("Selecting b in textarea"); + selChanged = waitForSelectionChange(textarea); + EventUtils.synthesizeKey("KEY_ArrowRight", { shiftKey: true }); + await selChanged; + testSelectionRange(browser, textarea, textarea, 0, textarea, 2); + testTextGetSelection(textarea, 0, 2, 0); + + info("Unselecting b in textarea"); + selChanged = waitForSelectionChange(textarea); + EventUtils.synthesizeKey("KEY_ArrowLeft", { shiftKey: true }); + await selChanged; + testSelectionRange(browser, textarea, textarea, 0, textarea, 1); + testTextGetSelection(textarea, 0, 1, 0); + + info("Unselecting a in textarea"); + // We don't fire selection changed when the selection collapses. + caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea); + EventUtils.synthesizeKey("KEY_ArrowLeft", { shiftKey: true }); + await caretMoved; + testSelectionRange(browser, textarea, textarea, 0, textarea, 0); + is(textarea.selectionCount, 0, "textarea selectionCount is 0"); + + const editable = findAccessibleChildByID(docAcc, "editable", [ + nsIAccessibleText, + ]); + const p1 = findAccessibleChildByID(docAcc, "p1", [nsIAccessibleText]); + info("Focusing editable, caret to start"); + caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, p1); + await changeDomSelection(browser, "p1", 0, "p1", 0); + await caretMoved; + testSelectionRange(browser, editable, p1, 0, p1, 0); + is(editable.selectionCount, 0, "editable selectionCount is 0"); + is(p1.selectionCount, 0, "p1 selectionCount is 0"); + + info("Selecting a in editable"); + selChanged = waitForSelectionChange(p1); + await changeDomSelection(browser, "p1", 0, "p1", 1); + await selChanged; + testSelectionRange(browser, editable, p1, 0, p1, 1); + testTextGetSelection(editable, 0, 1, 0); + testTextGetSelection(p1, 0, 1, 0); + + const p2 = findAccessibleChildByID(docAcc, "p2", [nsIAccessibleText]); + // Selecting across two Accessibles with only a partial selection in the + // second. + info("Selecting ab in editable"); + selChanged = waitForSelectionChange(editable, p2); + await changeDomSelection(browser, "p1", 0, "p2", 1); + await selChanged; + testSelectionRange(browser, editable, p1, 0, p2, 1); + testTextGetSelection(editable, 0, 2, 0); + testTextGetSelection(p1, 0, 1, 0); + testTextGetSelection(p2, 0, 1, 0); + + const pWithLink = findAccessibleChildByID(docAcc, "pWithLink", [ + nsIAccessibleText, + ]); + const link = findAccessibleChildByID(docAcc, "link", [nsIAccessibleText]); + // Selecting both text and a link. + info("Selecting de in editable"); + selChanged = waitForSelectionChange(pWithLink, link); + await changeDomSelection(browser, "pWithLink", 0, "link", 1); + await selChanged; + testSelectionRange(browser, editable, pWithLink, 0, link, 1); + testTextGetSelection(editable, 2, 3, 0); + testTextGetSelection(pWithLink, 0, 2, 0); + testTextGetSelection(link, 0, 1, 0); + + // Selecting a link and text on either side. + info("Selecting def in editable"); + selChanged = waitForSelectionChange(pWithLink, pWithLink); + await changeDomSelection(browser, "pWithLink", 0, "textAfterLink", 1); + await selChanged; + testSelectionRange(browser, editable, pWithLink, 0, pWithLink, 3); + testTextGetSelection(editable, 2, 3, 0); + testTextGetSelection(pWithLink, 0, 3, 0); + testTextGetSelection(link, 0, 1, 0); + + // Noncontiguous selection. + info("Selecting a in editable"); + selChanged = waitForSelectionChange(p1); + await changeDomSelection(browser, "p1", 0, "p1", 1); + await selChanged; + info("Adding c to selection in editable"); + selChanged = waitForSelectionChange(p2); + await invokeContentTask(browser, [], () => { + const r = content.document.createRange(); + const p2text = content.document.getElementById("p2").firstChild; + r.setStart(p2text, 0); + r.setEnd(p2text, 1); + content.window.getSelection().addRange(r); + }); + await selChanged; + if (browser.isRemoteBrowser && !isCacheEnabled) { + todo( + false, + "selectionRanges not implemented for non-cached RemoteAccessible" + ); + } else { + let selRanges = editable.selectionRanges; + is(selRanges.length, 2, "2 selection ranges"); + testTextRange( + selRanges.queryElementAt(0, nsIAccessibleTextRange), + "range 0", + p1, + 0, + p1, + 1 + ); + testTextRange( + selRanges.queryElementAt(1, nsIAccessibleTextRange), + "range 1", + p2, + 0, + p2, + 1 + ); + } + is(editable.selectionCount, 2, "editable selectionCount is 2"); + testTextGetSelection(editable, 0, 1, 0); + testTextGetSelection(editable, 1, 2, 1); + }, + { + chrome: true, + topLevel: !isWinNoCache, + iframe: !isWinNoCache, + remoteIframe: !isWinNoCache, + } +);