Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<html>
<head>
<title>Text selection testing</title>
<link rel="stylesheet" type="text/css"
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../promisified-events.js"></script>
<script type="application/javascript">
/**
* Helper function to test selection bounds.
* @param {string} aID The ID to test.
* @param {nsIAccessibleText} acc The accessible to test.
* @param {int} index The selection's index to test.
* @param {array} offsets The start and end offset to test against.
* @param {string} msgStart The start of the message to return in test
* messages.
*/
function testSelectionBounds(aID, acc, index, offsets, msgStart) {
const [expectedStart, expectedEnd] = offsets;
const startOffset = {}, endOffset = {};
acc.getSelectionBounds(index, startOffset, endOffset);
is(startOffset.value, Math.min(expectedStart, expectedEnd),
msgStart + ": Wrong start offset for " + aID);
is(endOffset.value, Math.max(expectedStart, expectedEnd),
msgStart + ": Wrong end offset for " + aID);
}
/**
* Test adding selections to accessibles.
* @param {string} aID The ID of the element to test.
* @param {array} aSelections Array of selection start and end indices.
*/
async function addSelections(aID, aSelections) {
info("Test adding selections to " + aID);
const hyperText = getAccessible(aID, [ nsIAccessibleText ]);
const initialSelectionCount = hyperText.selectionCount;
// Multiple selection changes will be coalesced, so just listen for one.
const selectionChange = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, aID);
for (let [startOffset, endOffset] of aSelections) {
hyperText.addSelection(startOffset, endOffset);
}
await selectionChange;
is(hyperText.selectionCount,
aSelections.length + initialSelectionCount,
"addSelection: Wrong selection count for " + aID);
for (let i in aSelections) {
testSelectionBounds(aID, hyperText, initialSelectionCount + i,
aSelections[i], "addSelection");
}
is(hyperText.caretOffset, aSelections[hyperText.selectionCount -1][1],
"addSelection: caretOffset not at selection end for " + aID);
}
/**
* Test changing selections in accessibles.
* @param {string} aID The ID of the element to test.
* @param {int} aIndex The index of the selection to change.
* @param {array} aSelection Array of the selection's new start and end
* indices.
*/
async function changeSelection(aID, aIndex, aSelection) {
info("Test changing the selection of " + aID + " at index " + aIndex);
const [startOffset, endOffset] = aSelection;
const hyperText = getAccessible(aID, [ nsIAccessibleText ]);
const selectionChanged = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, aID);
hyperText.setSelectionBounds(aIndex, startOffset, endOffset);
await selectionChanged;
testSelectionBounds(aID, hyperText, aIndex,
aSelection, "setSelectionBounds");
is(hyperText.caretOffset, endOffset,
"setSelectionBounds: caretOffset not at selection end for " + aID);
}
/**
* Test removing all selections from accessibles.
* @param {string} aID The ID of the element to test.
*/
async function removeSelections(aID) {
info("Testing removal of all selections from " + aID);
const hyperText = getAccessible(aID, [ nsIAccessibleText ]);
let selectionsRemoved = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, document);
const selectionCount = hyperText.selectionCount;
for (let i = 0; i < selectionCount; i++) {
hyperText.removeSelection(0);
}
await selectionsRemoved;
is(hyperText.selectionCount, 0,
"removeSelection: Wrong selection count for " + aID);
}
/**
* Test that changing the DOM selection is reflected in the accessibles.
* @param {string} aID The container ID to test in
* @param {string} aNodeID1 The start node of the selection
* @param {int} aNodeOffset1 The offset where the selection should start
* @param {string} aNodeID2 The node in which the selection should end
* @param {int} aNodeOffset2 The index at which the selection should end
* @param {array} aTests An array of accessibles and their start and end
* offsets to test.
*/
async function changeDOMSelection(aID, aNodeID1, aNodeOffset1,
aNodeID2, aNodeOffset2,
aTests) {
info("Test that DOM selection changes are reflected in the accessibles");
let selectionChanged = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, aID);
// HyperTextAccessible::GetSelectionDOMRanges ignores hidden selections.
// Here we may be focusing an editable element (and thus hiding the
// main document selection), so blur it so that we test what we want to
// test.
document.activeElement.blur();
const sel = window.getSelection();
const range = document.createRange();
range.setStart(getNode(aNodeID1), aNodeOffset1);
range.setEnd(getNode(aNodeID2), aNodeOffset2);
sel.addRange(range);
await selectionChanged;
for (let i = 0; i < aTests.length; i++) {
const text = getAccessible(aTests[i][0], nsIAccessibleText);
is(text.selectionCount, 1,
"setSelectionBounds: Wrong selection count for " + aID);
testSelectionBounds(aID, text, 0, [aTests[i][1], aTests[i][2]],
"setSelectionBounds");
}
}
/**
* Test expected and unexpected events for selecting
* all text and focusing both an input and text area. We expect a caret
* move, but not a text selection change.
* @param {string} aID The ID of the element to test.
*/
async function eventsForSelectingAllTextAndFocus(aID) {
info("Test expected caretMove and unexpected textSelection events for " +aID);
let events = waitForEvents({
expected: [[EVENT_TEXT_CARET_MOVED, aID]],
unexpected: [[EVENT_TEXT_SELECTION_CHANGED, aID]]}, aID);
selectAllTextAndFocus(aID);
await events;
}
/**
* Do tests
*/
async function doTests() {
await addSelections("paragraph", [[1, 3], [6, 10]]);
await changeSelection("paragraph", 0, [2, 4]);
await removeSelections("paragraph");
// reverse selection
await addSelections("paragraph", [[1, 3], [10, 6]]);
await removeSelections("paragraph");
await eventsForSelectingAllTextAndFocus("textbox");
await changeSelection("textbox", 0, [1, 3]);
// reverse selection
await changeSelection("textbox", 0, [3, 1]);
await eventsForSelectingAllTextAndFocus("textarea");
await changeSelection("textarea", 0, [1, 3]);
await changeDOMSelection("c1", "c1_span1", 0, "c1_span2", 0,
[["c1", 2, 2]]);
await changeDOMSelection("c2", "c2", 0, "c2_div2", 1,
[["c2", 0, 3], ["c2_div2", 0, 2]]);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<a target="_blank"
title="nsIAccessibleText::setSelectionBounds doesn't fire text selection changed events in some cases">
</a>
<a target="_blank"
title="no text selection changed event when selection is removed">
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<p id="paragraph">hello world</p>
<input id="textbox" value="hello"/>
<textarea id="textarea">hello</textarea>
<div id="c1">hi<span id="c1_span1"></span><span id="c1_span2"></span>hi</div>
<div id="c2">hi<div id="c2_div2">hi</div></div>
</body>
</html>