/* 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/. */
/**
* Test tables for both local and remote Accessibles. There is more extensive
* coverage in ../../mochitest/table. These tests are primarily to ensure that
* the cache works as expected and that there is consistency between local and
* remote.
*/
"use strict" ;
/* import-globals-from ../../mochitest/table.js */
/* import-globals-from ../../mochitest/attributes.js */
loadScripts(
{ name:
"table.js" , dir: MOCHITESTS_DIR },
{ name:
"attributes.js" , dir: MOCHITESTS_DIR }
);
/**
* Test table counts, indexes, extents and implicit headers.
*/
addAccessibleTask(
`
<table id=
"table" >
<thead>
<tr><th id=
"a" >a</th><th id=
"bc" colspan=
"2" >bc</th><th id=
"d" >d</th></tr>
</thead>
<tbody>
<tr><th id=
"ei" rowspan=
"2" >ei</th><td id=
"fj" rowspan=
"0" >fj</td><td id=
"g" >g</td><td id=
"h" >h</td></tr>
<tr><td id=
"k" >k</td></tr>
</tbody>
</table>
`,
async
function (browser, docAcc) {
const table = findAccessibleChildByID(docAcc,
"table" , [
nsIAccessibleTable,
]);
is(table.rowCount, 3,
"table rowCount correct" );
is(table.columnCount, 4,
"table columnCount correct" );
testTableIndexes(table, [
[0, 1, 1, 2],
[3, 4, 5, 6],
[3, 4, 7, -1],
]);
const cells = {};
for (
const id of [
"a" ,
"bc" ,
"d" ,
"ei" ,
"fj" ,
"g" ,
"h" ,
"k" ]) {
cells[id] = findAccessibleChildByID(docAcc, id, [nsIAccessibleTableCell]);
}
is(cells.a.rowExtent, 1,
"a rowExtent correct" );
is(cells.a.columnExtent, 1,
"a columnExtent correct" );
is(cells.bc.rowExtent, 1,
"bc rowExtent correct" );
is(cells.bc.columnExtent, 2,
"bc columnExtent correct" );
is(cells.ei.rowExtent, 2,
"ei rowExtent correct" );
is(cells.fj.rowExtent, 2,
"fj rowExtent correct" );
testHeaderCells([
{
cell: cells.ei,
rowHeaderCells: [],
columnHeaderCells: [cells.a],
},
{
cell: cells.g,
rowHeaderCells: [cells.ei],
columnHeaderCells: [cells.bc],
},
{
cell: cells.k,
rowHeaderCells: [cells.ei],
columnHeaderCells: [cells.bc],
},
]);
},
{
chrome:
true ,
topLevel:
true ,
iframe:
true ,
remoteIframe:
true ,
}
);
/**
* Test table explicit headers.
*/
addAccessibleTask(
`
<table id=
"table" >
<tr><th id=
"a" >a</th><th id=
"b" >b</th></tr>
<tr><td id=
"c" headers=
"b d" >c</td><th scope=
"row" id=
"d" >d</th></tr>
<tr><td id=
"e" headers=
"c f" >e</td><td id=
"f" >f</td></tr>
</table>
`,
async
function (browser, docAcc) {
const cells = {};
for (
const id of [
"a" ,
"b" ,
"c" ,
"d" ,
"e" ,
"f" ]) {
cells[id] = findAccessibleChildByID(docAcc, id, [nsIAccessibleTableCell]);
}
testHeaderCells([
{
cell: cells.c,
rowHeaderCells: [cells.d],
columnHeaderCells: [cells.b],
},
{
cell: cells.e,
rowHeaderCells: [cells.f],
columnHeaderCells: [cells.c],
},
]);
},
{
chrome:
true ,
topLevel:
true ,
iframe:
true ,
remoteIframe:
true ,
}
);
/**
* Test that an inner table doesn't impact an outer table.
*/
addAccessibleTask(
`
<table id=
"outerTable" >
<tr><th id=
"outerCell" >outerCell<table id=
"innerTable" >
<tr><th id=
"innerCell" >a</th></tr></table>
</table></th></tr>
</table>
`,
async
function (browser, docAcc) {
const outerTable = findAccessibleChildByID(docAcc,
"outerTable" , [
nsIAccessibleTable,
]);
is(outerTable.rowCount, 1,
"outerTable rowCount correct" );
is(outerTable.columnCount, 1,
"outerTable columnCount correct" );
const outerCell = findAccessibleChildByID(docAcc,
"outerCell" );
is(
outerTable.getCellAt(0, 0),
outerCell,
"outerTable returns correct cell"
);
const innerTable = findAccessibleChildByID(docAcc,
"innerTable" , [
nsIAccessibleTable,
]);
is(innerTable.rowCount, 1,
"innerTable rowCount correct" );
is(innerTable.columnCount, 1,
"innerTable columnCount correct" );
const innerCell = findAccessibleChildByID(docAcc,
"innerCell" );
is(
innerTable.getCellAt(0, 0),
innerCell,
"innerTable returns correct cell"
);
},
{
chrome:
true ,
topLevel:
true ,
iframe:
true ,
remoteIframe:
true ,
}
);
/**
* Test table caption and summary.
*/
addAccessibleTask(
`
<table id=
"t1" >
<caption id=
"c1" >c1</caption>
<tr><th>a</th></tr>
</table>
<table id=
"t2" summary=
"s2" >
<tr><th>a</th></tr>
</table>
<table id=
"t3" summary=
"s3" >
<caption id=
"c3" >c3</caption>
<tr><th>a</th></tr>
</table>
`,
async
function (browser, docAcc) {
const t1 = findAccessibleChildByID(docAcc,
"t1" , [nsIAccessibleTable]);
const c1 = findAccessibleChildByID(docAcc,
"c1" );
is(t1.caption, c1,
"t1 caption correct" );
ok(!t1.summary,
"t1 no summary" );
const t2 = findAccessibleChildByID(docAcc,
"t2" , [nsIAccessibleTable]);
ok(!t2.caption,
"t2 caption is null" );
is(t2.summary,
"s2" ,
"t2 summary correct" );
const t3 = findAccessibleChildByID(docAcc,
"t3" , [nsIAccessibleTable]);
const c3 = findAccessibleChildByID(docAcc,
"c3" );
is(t3.caption, c3,
"t3 caption correct" );
is(t3.summary,
"s3" ,
"t3 summary correct" );
},
{
chrome:
true ,
topLevel:
true ,
iframe:
true ,
remoteIframe:
true ,
}
);
/**
* Test table layout guess.
*/
addAccessibleTask(
`
<table id=
"layout" ><tr><td>a</td></tr></table>
<table id=
"data" ><tr><th>a</th></tr></table>
<table id=
"mutate" ><tr><td>a</td><td>b</td></tr></table>
<div id=
"newTableContainer" ></div>
`,
async
function (browser, docAcc) {
const layout = findAccessibleChildByID(docAcc,
"layout" );
testAttrs(layout, {
"layout-guess" :
"true" },
true );
const data = findAccessibleChildByID(docAcc,
"data" );
testAbsentAttrs(data, {
"layout-guess" :
"true" });
const mutate = findAccessibleChildByID(docAcc,
"mutate" );
testAttrs(mutate, {
"layout-guess" :
"true" },
true );
info(
"mutate: Adding 5 rows" );
let reordered = waitForEvent(EVENT_REORDER, mutate);
await invokeContentTask(browser, [], () => {
const frag = content.document.createDocumentFragment();
for (let r = 0; r < 6; ++r) {
const tr = content.document.createElement(
"tr" );
tr.innerHTML =
" a b ";
frag.append(tr);
}
content.document.getElementById(
"mutate" ).tBodies[0].append(frag);
});
await reordered;
testAbsentAttrs(mutate, {
"layout-guess" :
"true" });
info(
"mutate: Removing 5 rows" );
reordered = waitForEvent(EVENT_REORDER, mutate);
await invokeContentTask(browser, [], () => {
// Pause refresh driver so all the children removals below will
// be collated into the same tick and only one 'reorder' event will
// be dispatched.
content.windowUtils.advanceTimeAndRefresh(100);
let tBody = content.document.getElementById(
"mutate" ).tBodies[0];
for (let r = 0; r < 6; ++r) {
tBody.lastChild.remove();
}
// Resume refresh driver
content.windowUtils.restoreNormalRefresh();
});
await reordered;
testAttrs(mutate, {
"layout-guess" :
"true" },
true );
info(
"mutate: Adding new table" );
let shown = waitForEvent(EVENT_SHOW,
"newTable" );
await invokeContentTask(browser, [], () => {
content.document.getElementById(
"newTableContainer" ).innerHTML =
`<table id=
"newTable" ><tr><th>a</th></tr></table>`;
});
let newTable = (await shown).accessible;
testAbsentAttrs(newTable, {
"layout-guess" :
"true" });
},
{
chrome:
true ,
topLevel:
true ,
iframe:
true ,
remoteIframe:
true ,
}
);
/**
* Test table layout guess with border styling changes.
*/
addAccessibleTask(
`
<table id=
"layout" ><tr><td id=
"cell" >a</td><td>b</td></tr>
<tr><td>c</td><td>d</td></tr><tr><td>c</td><td>d</td></tr></table>
`,
async
function (browser, docAcc) {
const layout = findAccessibleChildByID(docAcc,
"layout" );
testAttrs(layout, {
"layout-guess" :
"true" },
true );
info(
"changing border style on table cell" );
await invokeContentTask(browser, [], () => {
content.document.getElementById(
"cell" ).style.border =
"1px solid black" ;
content.document.body.offsetTop;
// Flush layout.
});
await untilCacheOk(() => {
// manually verify the attribute doesn't exist, since `testAbsentAttrs`
// has internal calls to ok() which fail if the cache hasn't yet updated
for (let prop of layout.attributes.enumerate()) {
if (prop.key ==
"layout-guess" ) {
return false ;
}
}
return true ;
},
"Table is a data table" );
},
{
chrome:
true ,
topLevel:
true ,
iframe:
true ,
remoteIframe:
true ,
}
);
/**
* Test ARIA grid.
*/
addAccessibleTask(
`
<div id=
"grid" role=
"grid" >
<div role=
"rowgroup" >
<div role=
"row" ><div id=
"a" role=
"columnheader" >a</div><div id=
"b" role=
"columnheader" >b</div></
div>
</div>
<div tabindex="-1" >
<div role="row" ><div id="c" role="rowheader" >c</div><div id="d" role="gridcell" >d</div></div>
</div>
</div>
`,
async function (browser, docAcc) {
const grid = findAccessibleChildByID(docAcc, "grid" , [nsIAccessibleTable]);
is(grid.rowCount, 2, "grid rowCount correct" );
is(grid.columnCount, 2, "grid columnCount correct" );
testTableIndexes(grid, [
[0, 1],
[2, 3],
]);
const cells = {};
for (const id of ["a" , "b" , "c" , "d" ]) {
cells[id] = findAccessibleChildByID(docAcc, id, [nsIAccessibleTableCell]);
}
is(cells.a.rowExtent, 1, "a rowExtent correct" );
is(cells.a.columnExtent, 1, "a columnExtent correct" );
testHeaderCells([
{
cell: cells.c,
rowHeaderCells: [],
columnHeaderCells: [cells.a],
},
{
cell: cells.d,
rowHeaderCells: [cells.c],
columnHeaderCells: [cells.b],
},
]);
},
{
chrome: true ,
topLevel: true ,
iframe: true ,
remoteIframe: true ,
}
);
function setNodeHidden(browser, id, hidden) {
return invokeContentTask(browser, [id, hidden], (cId, cHidden) => {
content.document.getElementById(cId).hidden = cHidden;
});
}
/**
* Test that the table is updated correctly when it is mutated.
*/
addAccessibleTask(
`
<table id="table" >
<tr id="r1" ><td>a</td><td id="b" >b</td></tr>
<tr id="r2" hidden><td>c</td><td>d</td></tr>
</table>
<div id="owner" ></div>
`,
async function (browser, docAcc) {
const table = findAccessibleChildByID(docAcc, "table" , [
nsIAccessibleTable,
]);
is(table.rowCount, 1, "table rowCount correct" );
is(table.columnCount, 2, "table columnCount correct" );
testTableIndexes(table, [[0, 1]]);
info("Showing r2" );
let reordered = waitForEvent(EVENT_REORDER, table);
await setNodeHidden(browser, "r2" , false );
await reordered;
is(table.rowCount, 2, "table rowCount correct" );
testTableIndexes(table, [
[0, 1],
[2, 3],
]);
info("Hiding r2" );
reordered = waitForEvent(EVENT_REORDER, table);
await setNodeHidden(browser, "r2" , true );
await reordered;
is(table.rowCount, 1, "table rowCount correct" );
testTableIndexes(table, [[0, 1]]);
info("Hiding b" );
reordered = waitForEvent(EVENT_REORDER, "r1" );
await setNodeHidden(browser, "b" , true );
await reordered;
is(table.columnCount, 1, "table columnCount correct" );
testTableIndexes(table, [[0]]);
info("Showing b" );
reordered = waitForEvent(EVENT_REORDER, "r1" );
await setNodeHidden(browser, "b" , false );
await reordered;
is(table.columnCount, 2, "table columnCount correct" );
info("Moving b out of table using aria-owns" );
reordered = waitForEvent(EVENT_REORDER, "r1" );
await invokeContentTask(browser, [], () => {
content.document.getElementById("owner" ).setAttribute("aria-owns" , "b" );
});
await reordered;
is(table.columnCount, 1, "table columnCount correct" );
},
{
chrome: true ,
topLevel: true ,
iframe: true ,
remoteIframe: true ,
}
);
/**
* Test the handling of ARIA tables with display: contents.
*/
addAccessibleTask(
`
<div id="table" role="table" style="display: contents;" >
<div role="row" ><div role="cell" >a</div></div>
</div>
`,
async function (browser, docAcc) {
const table = findAccessibleChildByID(docAcc, "table" , [
nsIAccessibleTable,
]);
is(table.rowCount, 1, "table rowCount correct" );
is(table.columnCount, 1, "table columnCount correct" );
},
{
chrome: true ,
topLevel: true ,
iframe: true ,
remoteIframe: true ,
}
);
/**
* Test a broken ARIA table with an invalid cell.
*/
addAccessibleTask(
`
<div id="table" role="table" >
<div role="main" >
<div role="row" >
<div id="cell" role="cell" >a</div>
</div>
</div>
</div>
`,
async function (browser, docAcc) {
const table = findAccessibleChildByID(docAcc, "table" , [
nsIAccessibleTable,
]);
is(table.rowCount, 0, "table rowCount correct" );
is(table.columnCount, 0, "table columnCount correct" );
const cell = findAccessibleChildByID(docAcc, "cell" );
let queryOk = false ;
try {
cell.QueryInterface(nsIAccessibleTableCell);
queryOk = true ;
} catch (e) {}
ok(!queryOk, "Got nsIAccessibleTableCell on an invalid cell" );
},
{
chrome: true ,
topLevel: true ,
iframe: true ,
remoteIframe: true ,
}
);
/**
* Test that building the cache for a malformed table with an iframe inside a
* row doesn't crash (bug 1800780).
*/
addAccessibleTask(
`<table><tr id="tr" ></tr></table>`,
async function (browser) {
let reordered = waitForEvent(EVENT_REORDER, "tr" );
await invokeContentTask(browser, [], () => {
const iframe = content.document.createElement("iframe" );
content.document.getElementById("tr" ).append(iframe);
});
await reordered;
},
{ topLevel: true }
);
/**
* Verify that table row and column information is correct when there are
* intervening generics between the table and a rowgroup.
*/
addAccessibleTask(
`
<div id="table" role="grid" >
<div role="rowgroup" >
<div role="row" >
<div role="columnheader" >a</div>
</div>
</div>
<div tabindex="-1" style="height: 1px; overflow: auto;" >
<div role="rowgroup" >
<div role="row" >
<div id="cell" role="gridcell" >b</div>
</div>
</div>
</div>
</div>
`,
async function (browser, docAcc) {
const table = findAccessibleChildByID(docAcc, "table" , [
nsIAccessibleTable,
]);
info("Verifying that the table row and column counts are correct." );
is(table.rowCount, 2, "table rowCount correct" );
is(table.columnCount, 1, "table columnCount correct" );
info("Verifying that the cell row and column extents are correct." );
const cell = findAccessibleChildByID(docAcc, "cell" , [
nsIAccessibleTableCell,
]);
is(cell.rowExtent, 1, "cell rowExtent correct" );
is(cell.columnExtent, 1, "cell colExtent correct" );
is(cell.rowIndex, 1, "cell rowIndex correct" );
is(cell.columnIndex, 0, "cell columnIndex correct" );
},
{ chrome: true , topLevel: true , iframe: true , remoteIframe: true }
);
/**
* Verify that table row and column information is correct when there are
* intervening generics between rows and cells.
*/
addAccessibleTask(
`
<div id="table" role="grid" >
<div role="rowgroup" >
<div role="row" >
<div role="columnheader" >a</div>
</div>
</div>
<div role="rowgroup" >
<div role="row" >
<div tabindex="-1" style="height: 1px; overflow: auto;" >
<div id="cell" role="gridcell" >b</div>
</div>
</div>
</div>
</div>
`,
async function (browser, docAcc) {
const table = findAccessibleChildByID(docAcc, "table" , [
nsIAccessibleTable,
]);
info("Verifying that the table row and column counts are correct." );
is(table.rowCount, 2, "table rowCount correct" );
is(table.columnCount, 1, "table columnCount correct" );
info("Verifying that the cell row and column extents are correct." );
const cell = findAccessibleChildByID(docAcc, "cell" , [
nsIAccessibleTableCell,
]);
is(cell.rowExtent, 1, "cell rowExtent correct" );
is(cell.columnExtent, 1, "cell colExtent correct" );
is(cell.rowIndex, 1, "cell rowIndex correct" );
is(cell.columnIndex, 0, "cell columnIndex correct" );
},
{ chrome: true , topLevel: true , iframe: true , remoteIframe: true }
);
/**
* Verify that we don't crash for authoring error like <table role="gridcell">.
*/
addAccessibleTask(
`<table id="table" role="gridcell" >`,
async function (browser, docAcc) {
const table = findAccessibleChildByID(docAcc, "table" );
ok(table, "Retrieved table Accessible" );
},
{ chrome: true , topLevel: true }
);
/**
* Test ARIA tables in SVG.
*/
addAccessibleTask(
`
<svg id="table" role="table" >
<text id="caption" role="caption" >caption</text>
<g role="row" >
<text id="a" role="columnheader" >a</text>
<text id="b" role="columnheader" >b</text>
</g>
<g role="row" >
<text id="c" role="cell" >c</text>
<text id="d" role="cell" >d</text>
</g>
</svg>
`,
async function (browser, docAcc) {
const table = findAccessibleChildByID(docAcc, "table" , [
nsIAccessibleTable,
]);
is(table.rowCount, 2, "table rowCount correct" );
is(table.columnCount, 2, "table columnCount correct" );
const caption = findAccessibleChildByID(docAcc, "caption" );
is(table.caption, caption, "table caption correct" );
testTableIndexes(table, [
[0, 1],
[2, 3],
]);
const cells = {};
for (const id of ["a" , "b" , "c" , "d" ]) {
cells[id] = findAccessibleChildByID(docAcc, id, [nsIAccessibleTableCell]);
}
testHeaderCells([
{
cell: cells.c,
rowHeaderCells: [],
columnHeaderCells: [cells.a],
},
{
cell: cells.d,
rowHeaderCells: [],
columnHeaderCells: [cells.b],
},
]);
},
{ chrome: true , topLevel: true , remoteIframe: true }
);
/**
* Verify that we don't crash for authoring error like <tr role="grid">.
*/
addAccessibleTask(
`
<table id="table" >
<tr><th>a</th></tr>
<tr role="grid" ><td id="b" >b</td></tr>
</table>
`,
async function (browser, docAcc) {
const table = findAccessibleChildByID(docAcc, "table" , [
nsIAccessibleTable,
]);
is(table.rowCount, 1, "table rowCount correct" );
is(table.columnCount, 1, "table columnCount correct" );
const b = findAccessibleChildByID(docAcc, "b" );
let queryOk = false ;
try {
b.QueryInterface(nsIAccessibleTableCell);
queryOk = true ;
} catch (e) {}
ok(!queryOk, "No nsIAccessibleTableCell on invalid cell b" );
}
);
Messung V0.5 C=94 H=97 G=95
¤ Dauer der Verarbeitung: 0.7 Sekunden
¤
*© Formatika GbR, Deutschland