Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test that EditContext handles eSetSelection correctly.</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div></div>
<script>
'use strict';
const host = document.querySelector('div');
const editContext = new EditContext({text: 'cạ̀́b'});
host.editContext = editContext;
editContext.addEventListener('characterboundsupdate', e => {
// Provide fake character bounds so that we don't suppress IME notifications
const bounds = new Array(e.rangeEnd - e.rangeStart).fill(new DOMRect(1,1,1,1));
editContext.updateCharacterBounds(e.rangeStart, bounds);
});
const utils = SpecialPowers.getDOMWindowUtils(window);
async function doTest(test) {
const {selectionStart, selectionEnd, description} = test;
const expectStart = test.expectStart ?? selectionStart;
const expectEnd = test.expectEnd ?? selectionEnd;
const expectRange = `${expectStart}-${expectEnd}`;
let firedTextUpdate = false;
editContext.addEventListener('textupdate', e => {
firedTextUpdate = true;
is(e.updateRangeStart, e.updateRangeEnd,
`${description}: TextUpdateEvent should not delete any text.`);
is(e.text, '',
`${description}: TextUpdateEvent should not insert any text.`);
is(`${e.selectionStart}-${e.selectionEnd}`, expectRange,
`${description}: TextUpdateEvent.selectionStart/End should be set appropriately.`);
is(`${editContext.selectionStart}-${editContext.selectionEnd}`, expectRange,
`${description}: EditContext.selectionStart/End should be updated.`);
}, {once: true});
const flags = test.expandToClusterBoundary
? utils.SELECTION_EXPAND_TO_CLUSTER_BOUNDARY
: 0;
const reverse = selectionStart > selectionEnd;
const offset = Math.min(selectionStart, selectionEnd);
const length = Math.abs(selectionStart - selectionEnd);
const success = await synthesizeSelectionSet(offset, length, reverse, window, flags);
ok(firedTextUpdate, `${description}: Should fire textupdate.`);
ok(success, `${description}: sendSelectionSetEvent should succeed.`);
}
const tests = [
{
description: 'Forwards selection',
selectionStart: 2,
selectionEnd: 4,
},
{
description: 'Backwards selection',
selectionStart: 4,
selectionEnd: 2,
},
{
description: 'Collapsed selection',
selectionStart: 3,
selectionEnd: 3,
},
{
description: 'Forwards selection expanding to grapheme cluster boundary',
selectionStart: 2,
selectionEnd: 4,
expectStart: 1,
expectEnd: 5,
expandToClusterBoundary: true,
},
{
description: 'Backwards selection expanding to grapheme cluster boundary',
selectionStart: 4,
selectionEnd: 2,
expectStart: 5,
expectEnd: 1,
expandToClusterBoundary: true,
},
{
description: 'Collapsed selection expanding to grapheme cluster boundary',
selectionStart: 3,
selectionEnd: 3,
expectStart: 1,
expectEnd: 5,
expandToClusterBoundary: true,
},
];
add_task(async () => {
await SimpleTest.promiseFocus();
host.focus();
for (let test of tests) {
await doTest(test);
}
});
add_task(async () => {
host.focus();
editContext.updateSelection(1, 4);
// Test that this eSetSelection event updates the IMEContentObserver's cached selection,
// so it doesn't skip sending the second eSetSelection
await synthesizeSelectionSet(3, 0);
is(`${editContext.selectionStart}-${editContext.selectionEnd}`, '3-3',
'EditContext selection should be updated when eSetSelection is dispatched.');
await synthesizeSelectionSet(1, 4);
is(`${editContext.selectionStart}-${editContext.selectionEnd}`, '1-5',
'EditContext selection should be updated again when eSetSelection is dispatched with original selection.');
});
</script>
</body>
</html>