/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict" ;
/* import-globals-from ../../mochitest/attributes.js */
/* import-globals-from ../../mochitest/text.js */
loadScripts({ name:
"attributes.js" , dir: MOCHITESTS_DIR });
/**
* Test line and word offsets for various cases for both local and remote
* Accessibles. There is more extensive coverage in ../../mochitest/text. These
* tests don't need to duplicate all of that, since much of the underlying code
* is unified. They should ensure that the cache works as expected and that
* there is consistency between local and remote.
*/
addAccessibleTask(
`
<p id=
"br" >ab cd<br>ef gh</p>
<pre id=
"pre" >ab cd
ef gh</pre>
<p id=
"linksStartEnd" ><a href=
"https://example.com/ ">abc
<p id=
"linksBreaking" >a<a href=
"https://example.com/ ">b cd
<p id=
"p" >a<br role=
"presentation" >b</p>
<p id=
"leafThenWrap" style=
"font-family: monospace; width: 2ch; word-break: break-word;" ><span>a</span>bc</p>
<p id=
"bidi" style=
"font-family: monospace; width: 3ch; word-break: break-word" >אb גד eו זח טj</
p>
`,
async function (browser, docAcc) {
for (const id of ["br" , "pre" ]) {
const acc = findAccessibleChildByID(docAcc, id);
testCharacterCount([acc], 11);
testTextAtOffset(acc, BOUNDARY_LINE_START, [
[0, 5, "ab cd\n" , 0, 6],
[6, 11, "ef gh" , 6, 11],
]);
testTextBeforeOffset(acc, BOUNDARY_LINE_START, [
[0, 5, "" , 0, 0],
[6, 11, "ab cd\n" , 0, 6],
]);
testTextAfterOffset(acc, BOUNDARY_LINE_START, [
[0, 5, "ef gh" , 6, 11],
[6, 11, "" , 11, 11],
]);
testTextAtOffset(acc, BOUNDARY_LINE_END, [
[0, 5, "ab cd" , 0, 5],
[6, 11, "\nef gh" , 5, 11],
]);
testTextBeforeOffset(acc, BOUNDARY_LINE_END, [
[0, 5, "" , 0, 0],
[6, 11, "ab cd" , 0, 5],
]);
testTextAfterOffset(acc, BOUNDARY_LINE_END, [
[0, 5, "\nef gh" , 5, 11],
[6, 11, "" , 11, 11],
]);
testTextAtOffset(acc, BOUNDARY_WORD_START, [
[0, 2, "ab " , 0, 3],
[3, 5, "cd\n" , 3, 6],
[6, 8, "ef " , 6, 9],
[9, 11, "gh" , 9, 11],
]);
testTextBeforeOffset(acc, BOUNDARY_WORD_START, [
[0, 2, "" , 0, 0],
[3, 5, "ab " , 0, 3],
[6, 8, "cd\n" , 3, 6],
[9, 11, "ef " , 6, 9],
]);
testTextAfterOffset(acc, BOUNDARY_WORD_START, [
[0, 2, "cd\n" , 3, 6],
[3, 5, "ef " , 6, 9],
[6, 8, "gh" , 9, 11],
[9, 11, "" , 11, 11],
]);
testTextAtOffset(acc, BOUNDARY_WORD_END, [
[0, 1, "ab" , 0, 2],
[2, 4, " cd" , 2, 5],
[5, 7, "\nef" , 5, 8],
[8, 11, " gh" , 8, 11],
]);
testTextBeforeOffset(acc, BOUNDARY_WORD_END, [
[0, 2, "" , 0, 0],
[3, 5, "ab" , 0, 2],
// See below for offset 6.
[7, 8, " cd" , 2, 5],
[9, 11, "\nef" , 5, 8],
]);
testTextBeforeOffset(acc, BOUNDARY_WORD_END, [[6, 6, " cd" , 2, 5]]);
testTextAfterOffset(acc, BOUNDARY_WORD_END, [
[0, 2, " cd" , 2, 5],
[3, 5, "\nef" , 5, 8],
[6, 8, " gh" , 8, 11],
[9, 11, "" , 11, 11],
]);
testTextAtOffset(acc, BOUNDARY_PARAGRAPH, [
[0, 5, "ab cd\n" , 0, 6],
[6, 11, "ef gh" , 6, 11],
]);
}
const linksStartEnd = findAccessibleChildByID(docAcc, "linksStartEnd" );
testTextAtOffset(linksStartEnd, BOUNDARY_LINE_START, [
[0, 3, `${kEmbedChar}b${kEmbedChar}`, 0, 3],
]);
testTextAtOffset(linksStartEnd, BOUNDARY_WORD_START, [
[0, 3, `${kEmbedChar}b${kEmbedChar}`, 0, 3],
]);
const linksBreaking = findAccessibleChildByID(docAcc, "linksBreaking" );
testTextAtOffset(linksBreaking, BOUNDARY_LINE_START, [
[0, 0, `a${kEmbedChar}`, 0, 2],
[1, 1, `a${kEmbedChar}d`, 0, 3],
[2, 3, `${kEmbedChar}d`, 1, 3],
]);
const p = findAccessibleChildByID(docAcc, "p" );
testTextAtOffset(p, BOUNDARY_LINE_START, [
[0, 0, "a" , 0, 1],
[1, 2, "b" , 1, 2],
]);
testTextAtOffset(p, BOUNDARY_PARAGRAPH, [[0, 2, "ab" , 0, 2]]);
const leafThenWrap = findAccessibleChildByID(docAcc, "leafThenWrap" );
testTextAtOffset(leafThenWrap, BOUNDARY_LINE_START, [
[0, 1, "ab" , 0, 2],
[2, 3, "c" , 2, 3],
]);
const bidi = findAccessibleChildByID(docAcc, "bidi" );
testTextAtOffset(bidi, BOUNDARY_LINE_START, [
[0, 2, "אb " , 0, 3],
[3, 5, "גד " , 3, 6],
[6, 8, "eו " , 6, 9],
[9, 11, "זח " , 9, 12],
[12, 14, "טj" , 12, 14],
]);
},
{ chrome: true , topLevel: true , iframe: true , remoteIframe: true }
);
/**
* Test line offsets after text mutation.
*/
addAccessibleTask(
`
<p id="initBr" ><br></p>
<p id="rewrap" style="font-family: monospace; width: 2ch; word-break: break-word;" ><span id="rewrap1" >ac</span>def</p>
`,
async function (browser, docAcc) {
const initBr = findAccessibleChildByID(docAcc, "initBr" );
testTextAtOffset(initBr, BOUNDARY_LINE_START, [
[0, 0, "\n" , 0, 1],
[1, 1, "" , 1, 1],
]);
info("initBr: Inserting text before br" );
let reordered = waitForEvent(EVENT_REORDER, initBr);
await invokeContentTask(browser, [], () => {
const initBrNode = content.document.getElementById("initBr" );
initBrNode.insertBefore(
content.document.createTextNode("a" ),
initBrNode.firstElementChild
);
});
await reordered;
testTextAtOffset(initBr, BOUNDARY_LINE_START, [
[0, 1, "a\n" , 0, 2],
[2, 2, "" , 2, 2],
]);
const rewrap = findAccessibleChildByID(docAcc, "rewrap" );
testTextAtOffset(rewrap, BOUNDARY_LINE_START, [
[0, 1, "ac" , 0, 2],
[2, 3, "de" , 2, 4],
[4, 5, "f" , 4, 5],
]);
info("rewrap: Changing ac to abc" );
reordered = waitForEvent(EVENT_REORDER, rewrap);
await invokeContentTask(browser, [], () => {
const rewrap1 = content.document.getElementById("rewrap1" );
rewrap1.textContent = "abc" ;
});
await reordered;
testTextAtOffset(rewrap, BOUNDARY_LINE_START, [
[0, 1, "ab" , 0, 2],
[2, 3, "cd" , 2, 4],
[4, 6, "ef" , 4, 6],
]);
},
{ chrome: true , topLevel: true , iframe: true , remoteIframe: true }
);
/**
* Test retrieval of text offsets when an invalid offset is given.
*/
addAccessibleTask(
`<p id="p" >test</p>`,
async function (browser, docAcc) {
const p = findAccessibleChildByID(docAcc, "p" );
testTextAtOffset(p, BOUNDARY_LINE_START, [[5, 5, "" , 0, 0]]);
testTextBeforeOffset(p, BOUNDARY_LINE_START, [[5, 5, "" , 0, 0]]);
testTextAfterOffset(p, BOUNDARY_LINE_START, [[5, 5, "" , 0, 0]]);
},
{
// The old HyperTextAccessible implementation doesn't crash, but it returns
// different offsets. This doesn't matter because they're invalid either
// way. Since the new HyperTextAccessibleBase implementation is all we will
// have soon, just test that.
chrome: true ,
topLevel: true ,
iframe: true ,
remoteIframe: true ,
}
);
/**
* Test HyperText embedded object methods.
*/
addAccessibleTask(
`<div id="container" >a<a id="link" href="https://example.com/ ">bc `,
async
function (browser, docAcc) {
const container = findAccessibleChildByID(docAcc,
"container" , [
nsIAccessibleHyperText,
]);
is(container.linkCount, 1,
"container linkCount is 1" );
let link = container.getLinkAt(0);
queryInterfaces(link, [nsIAccessible, nsIAccessibleHyperText]);
is(getAccessibleDOMNodeID(link),
"link" ,
"LinkAt 0 is the link" );
is(container.getLinkIndex(link), 0,
"getLinkIndex for link is 0" );
is(link.startIndex, 1,
"link's startIndex is 1" );
is(link.endIndex, 2,
"link's endIndex is 2" );
is(container.getLinkIndexAtOffset(1), 0,
"getLinkIndexAtOffset(1) is 0" );
is(container.getLinkIndexAtOffset(0), -1,
"getLinkIndexAtOffset(0) is -1" );
is(link.linkCount, 0,
"link linkCount is 0" );
},
{
chrome:
true ,
topLevel:
true ,
iframe:
true ,
remoteIframe:
true ,
}
);
/**
* Test HyperText embedded object methods near a list bullet.
*/
addAccessibleTask(
`<ul><li id=
"li" ><a id=
"link" href=
"https://example.com/ ">a`,
async
function (browser, docAcc) {
const li = findAccessibleChildByID(docAcc,
"li" , [nsIAccessibleHyperText]);
let link = li.getLinkAt(0);
queryInterfaces(link, [nsIAccessible]);
is(getAccessibleDOMNodeID(link),
"link" ,
"LinkAt 0 is the link" );
is(li.getLinkIndex(link), 0,
"getLinkIndex for link is 0" );
is(link.startIndex, 2,
"link's startIndex is 2" );
is(li.getLinkIndexAtOffset(2), 0,
"getLinkIndexAtOffset(2) is 0" );
is(li.getLinkIndexAtOffset(0), -1,
"getLinkIndexAtOffset(0) is -1" );
},
{
chrome:
true ,
topLevel:
true ,
iframe:
true ,
remoteIframe:
true ,
}
);
const boldAttrs = {
"font-weight" :
"700" };
/**
* Test text attribute methods.
*/
addAccessibleTask(
`
<p id=
"plain" >ab</p>
<p id=
"bold" style=
"font-weight: bold;" >ab</p>
<p id=
"partialBold" >ab<b>cd</b>ef</p>
<p id=
"consecutiveBold" >ab<b>cd</b><b>ef</b>gh</p>
<p id=
"embeddedObjs" >ab<a href=
"https://example.com/ ">cdef gh ij
<p id=
"empty" ></p>
<p id=
"fontFamilies" style=
"font-family: sans-serif;" >ab<span style=
"font-family: monospace;" >cd</span><span style=
"font-family: monospace;" >ef</span>gh</p>
`,
async
function (browser, docAcc) {
let defAttrs = {
"text-position" :
"baseline" ,
"font-style" :
"normal" ,
"font-weight" :
"400" ,
};
const plain = findAccessibleChildByID(docAcc,
"plain" );
testDefaultTextAttrs(plain, defAttrs,
true );
for (let offset = 0; offset <= 2; ++offset) {
testTextAttrs(plain, offset, {}, defAttrs, 0, 2,
true );
}
const bold = findAccessibleChildByID(docAcc,
"bold" );
defAttrs[
"font-weight" ] =
"700" ;
testDefaultTextAttrs(bold, defAttrs,
true );
testTextAttrs(bold, 0, {}, defAttrs, 0, 2,
true );
const partialBold = findAccessibleChildByID(docAcc,
"partialBold" );
defAttrs[
"font-weight" ] =
"400" ;
testDefaultTextAttrs(partialBold, defAttrs,
true );
testTextAttrs(partialBold, 0, {}, defAttrs, 0, 2,
true );
testTextAttrs(partialBold, 2, boldAttrs, defAttrs, 2, 4,
true );
testTextAttrs(partialBold, 4, {}, defAttrs, 4, 6,
true );
const consecutiveBold = findAccessibleChildByID(docAcc,
"consecutiveBold" );
testDefaultTextAttrs(consecutiveBold, defAttrs,
true );
testTextAttrs(consecutiveBold, 0, {}, defAttrs, 0, 2,
true );
testTextAttrs(consecutiveBold, 2, boldAttrs, defAttrs, 2, 6,
true );
testTextAttrs(consecutiveBold, 6, {}, defAttrs, 6, 8,
true );
const embeddedObjs = findAccessibleChildByID(docAcc,
"embeddedObjs" );
testDefaultTextAttrs(embeddedObjs, defAttrs,
true );
testTextAttrs(embeddedObjs, 0, {}, defAttrs, 0, 2,
true );
for (let offset = 2; offset <= 4; ++offset) {
// attrs and defAttrs should be completely empty, so we pass
// false for aSkipUnexpectedAttrs.
testTextAttrs(embeddedObjs, offset, {}, {}, 2, 5,
false );
}
testTextAttrs(embeddedObjs, 5, {}, defAttrs, 5, 7,
true );
const empty = findAccessibleChildByID(docAcc,
"empty" );
testDefaultTextAttrs(empty, defAttrs,
true );
testTextAttrs(empty, 0, {}, defAttrs, 0, 0,
true );
const fontFamilies = findAccessibleChildByID(docAcc,
"fontFamilies" , [
nsIAccessibleHyperText,
]);
testDefaultTextAttrs(fontFamilies, defAttrs,
true );
testTextAttrs(fontFamilies, 0, {}, defAttrs, 0, 2,
true );
testTextAttrs(fontFamilies, 2, {}, defAttrs, 2, 6,
true );
testTextAttrs(fontFamilies, 6, {}, defAttrs, 6, 8,
true );
},
{
chrome:
true ,
topLevel:
true ,
iframe:
true ,
remoteIframe:
true ,
}
);
/**
* Test cluster offsets.
*/
addAccessibleTask(
`<p id=
"clusters" >À2♂️♂️5x͇͕̦̍͂͒7È</p>`,
async
function testCluster(browser, docAcc) {
const clusters = findAccessibleChildByID(docAcc,
"clusters" );
testCharacterCount(clusters, 26);
testTextAtOffset(clusters, BOUNDARY_CLUSTER, [
[0, 1,
"À" , 0, 2],
[2, 2,
"2" , 2, 3],
[3, 7,
"🤦♂️" , 3, 8],
[8, 14,
"🤦🏼♂️" , 8, 15],
[15, 15,
"5" , 15, 16],
[16, 22,
"x͇͕̦̍͂͒" , 16, 23],
[23, 23,
"7" , 23, 24],
[24, 25,
"È" , 24, 26],
[26, 26,
"" , 26, 26],
]);
// Ensure that BOUNDARY_CHAR returns single Unicode characters.
testTextAtOffset(clusters, BOUNDARY_CHAR, [
[0, 0,
"A" , 0, 1],
[1, 1,
"̀" , 1, 2],
]);
},
{ chrome:
true , topLevel:
true }
);
Messung V0.5 C=91 H=92 G=91
¤ Dauer der Verarbeitung: 0.30 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland