/* 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";
let NO_MOVE = { unexpected: [[EVENT_REORDER,
"container"]] };
let MOVE = { expected: [[EVENT_REORDER,
"container"]] };
// Set last ordinal child as aria-owned, should produce no reorder.
addAccessibleTask(
`<ul id=
"container"><li id=
"a">Test</li></ul>`,
async
function (browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc,
"container");
testChildrenIds(containerAcc, [
"a"]);
await contentSpawnMutation(browser, NO_MOVE,
function () {
// aria-own ordinal child in place, should be a no-op.
content.document
.getElementById(
"container")
.setAttribute(
"aria-owns",
"a");
});
testChildrenIds(containerAcc, [
"a"]);
}
);
// Add a new ordinal child to a container with an aria-owned child.
// Order should respect aria-owns.
addAccessibleTask(
`<ul id=
"container"><li id=
"a">Test</li></ul>`,
async
function (browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc,
"container");
testChildrenIds(containerAcc, [
"a"]);
await contentSpawnMutation(browser, MOVE,
function () {
let container = content.document.getElementById(
"container");
container.setAttribute(
"aria-owns",
"a");
let aa = content.document.createElement(
"li");
aa.id =
"aa";
container.appendChild(aa);
});
testChildrenIds(containerAcc, [
"aa",
"a"]);
await contentSpawnMutation(browser, MOVE,
function () {
content.document.getElementById(
"container").removeAttribute(
"aria-owns");
});
testChildrenIds(containerAcc, [
"a",
"aa"]);
}
);
// Remove a no-move aria-owns attribute, should result in a no-move.
addAccessibleTask(
`<ul id=
"container" aria-owns=
"a"><li id=
"a">Test</li></ul>`,
async
function (browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc,
"container");
testChildrenIds(containerAcc, [
"a"]);
await contentSpawnMutation(browser, NO_MOVE,
function () {
// remove aria-owned child that is already ordinal, should be no-op.
content.document.getElementById(
"container").removeAttribute(
"aria-owns");
});
testChildrenIds(containerAcc, [
"a"]);
}
);
// Attempt to steal an aria-owned child. The attempt should fail.
addAccessibleTask(
`
<ul>
<li id=
"a">Test</li>
</ul>
<ul aria-owns=
"a"></ul>
<ul id=
"container"></ul>`,
async
function (browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc,
"container");
testChildrenIds(containerAcc, []);
await contentSpawnMutation(browser, NO_MOVE,
function () {
content.document
.getElementById(
"container")
.setAttribute(
"aria-owns",
"a");
});
testChildrenIds(containerAcc, []);
}
);
// Don't aria-own children of <select>
addAccessibleTask(
`
<div id=
"container" role=
"group" aria-owns=
"b"></div>
<select id=
"select">
<option id=
"a"></option>
<option id=
"b"></option>
</select>`,
async
function (browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc,
"container");
let selectAcc = findAccessibleChildByID(accDoc,
"select");
testChildrenIds(containerAcc, []);
testChildrenIds(selectAcc.firstChild, [
"a",
"b"]);
}
);
// Don't allow <select> to aria-own
addAccessibleTask(
`
<div id=
"container" role=
"group">
<div id=
"a"></div>
<div id=
"b"></div>
</div>
<select id=
"select" aria-owns=
"a">
<option id=
"c"></option>
</select>`,
async
function (browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc,
"container");
let selectAcc = findAccessibleChildByID(accDoc,
"select");
testChildrenIds(containerAcc, [
"a",
"b"]);
testChildrenIds(selectAcc.firstChild, [
"c"]);
}
);
// Don't allow one <select> to aria-own an <option> from another <select>.
addAccessibleTask(
`
<select id=
"select1" aria-owns=
"c">
<option id=
"a"></option>
<option id=
"b"></option>
</select>
<select id=
"select2">
<option id=
"c"></option>
</select>`,
async
function (browser, accDoc) {
let selectAcc1 = findAccessibleChildByID(accDoc,
"select1");
let selectAcc2 = findAccessibleChildByID(accDoc,
"select2");
testChildrenIds(selectAcc1.firstChild, [
"a",
"b"]);
testChildrenIds(selectAcc2.firstChild, [
"c"]);
}
);
// Don't allow a <select> to reorder its children with aria-owns.
addAccessibleTask(
`
<select id=
"container" aria-owns=
"c b a">
<option id=
"a"></option>
<option id=
"b"></option>
<option id=
"c"></option>
</select>`,
async
function (browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc,
"container");
testChildrenIds(containerAcc.firstChild, [
"a",
"b",
"c"]);
await contentSpawnMutation(browser, NO_MOVE,
function () {
content.document
.getElementById(
"container")
.setAttribute(
"aria-owns",
"a c b");
});
testChildrenIds(containerAcc.firstChild, [
"a",
"b",
"c"]);
}
);
// Don't crash if ID in aria-owns does not exist
addAccessibleTask(
`
<select id=
"container" aria-owns=
"boom" multiple></select>`,
async
function () {
ok(
true,
"Did not crash");
}
);
addAccessibleTask(
`
<ul id=
"one">
<li id=
"a">Test</li>
<li id=
"b">Test 2</li>
<li id=
"c">Test 3</li>
</ul>
<ul id=
"two"></ul>`,
async
function (browser, accDoc) {
let one = findAccessibleChildByID(accDoc,
"one");
let two = findAccessibleChildByID(accDoc,
"two");
let waitfor = {
expected: [
[EVENT_REORDER,
"one"],
[EVENT_REORDER,
"two"],
],
};
await contentSpawnMutation(browser, waitfor,
function () {
// Put same id twice in aria-owns
content.document.getElementById(
"two").setAttribute(
"aria-owns",
"a a");
});
testChildrenIds(one, [
"b",
"c"]);
testChildrenIds(two, [
"a"]);
await contentSpawnMutation(browser, waitfor,
function () {
// If the previous double-id aria-owns worked correctly, we should
// be in a good state and all is fine..
content.document.getElementById(
"two").setAttribute(
"aria-owns",
"a b");
});
testChildrenIds(one, [
"c"]);
testChildrenIds(two, [
"a",
"b"]);
}
);
addAccessibleTask(
`<div id=
"a"></div><div id=
"b"></div>`,
async
function (browser, accDoc) {
testChildrenIds(accDoc, [
"a",
"b"]);
let waitFor = {
expected: [[EVENT_REORDER, e => e.accessible == accDoc]],
};
await contentSpawnMutation(browser, waitFor,
function () {
content.document.documentElement.style.display =
"none";
content.document.documentElement.getBoundingClientRect();
content.document.body.setAttribute(
"aria-owns",
"b a");
content.document.documentElement.remove();
});
testChildrenIds(accDoc, []);
}
);
// Don't allow ordinal child to be placed after aria-owned child (bug 1405796)
addAccessibleTask(
`<div id=
"container"><div id=
"a">Hello</div></div>
<div><div id=
"c">There</div><div id=
"d">There</div></div>`,
async
function (browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc,
"container");
testChildrenIds(containerAcc, [
"a"]);
await contentSpawnMutation(browser, MOVE,
function () {
content.document
.getElementById(
"container")
.setAttribute(
"aria-owns",
"c");
});
testChildrenIds(containerAcc, [
"a",
"c"]);
await contentSpawnMutation(browser, MOVE,
function () {
let span = content.document.createElement(
"span");
content.document.getElementById(
"container").appendChild(span);
let b = content.document.createElement(
"div");
b.id =
"b";
content.document.getElementById(
"container").appendChild(b);
});
testChildrenIds(containerAcc, [
"a",
"b",
"c"]);
await contentSpawnMutation(browser, MOVE,
function () {
content.document
.getElementById(
"container")
.setAttribute(
"aria-owns",
"c d");
});
testChildrenIds(containerAcc, [
"a",
"b",
"c",
"d"]);
}
);