/* 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";
async function testDetailsRelations(anchor, target) {
await testCachedRelation(anchor, RELATION_DETAILS, target);
await testCachedRelation(target, RELATION_DETAILS_FOR, anchor);
}
async function testNoDetailsRelations(anchor, target) {
await testCachedRelation(anchor, RELATION_DETAILS, []);
await testCachedRelation(target, RELATION_DETAILS_FOR, []);
}
async function invokeContentTaskAndTick(browser, args, task) {
await invokeContentTask(browser, args, task);
await invokeContentTask(browser, [], () => {
content.windowUtils.advanceTimeAndRefresh(100);
content.windowUtils.restoreNormalRefresh();
});
}
async function invokeSetAttributeAndTick(browser, id, attr, attrValue) {
await invokeSetAttribute(browser, id, attr, attrValue);
await invokeContentTask(browser, [], () => {
content.windowUtils.advanceTimeAndRefresh(100);
content.windowUtils.restoreNormalRefresh();
});
}
/**
* Test details relations for CSS explicit and implicit Anchor Positioning
*/
addAccessibleTask(
`
World
Hello
World
Hello
No Target
`,
async function testSimplePositionAnchors(browser, docAcc) {
info("Implicit anchor");
const btn1 = findAccessibleChildByID(docAcc, "btn1");
const target1 = findAccessibleChildByID(docAcc, "target1");
await testDetailsRelations(btn1, target1);
info("Make anchor invalid");
await invokeContentTaskAndTick(browser, [], () => {
Object.assign(content.document.getElementById("btn1").style, {
"anchor-name": "--invalid",
});
});
await testNoDetailsRelations(btn1, target1);
info("Make anchor valid again");
await invokeContentTaskAndTick(browser, [], () => {
Object.assign(content.document.getElementById("btn1").style, {
"anchor-name": "--btn1",
});
});
await testDetailsRelations(btn1, target1);
info("Assign target to different anchor");
await invokeContentTaskAndTick(browser, [], () => {
Object.assign(content.document.getElementById("target1").style, {
"position-anchor": "--btn3",
});
});
const btn3 = findAccessibleChildByID(docAcc, "btn3");
await testDetailsRelations(btn3, target1);
await testCachedRelation(btn1, RELATION_DETAILS, []);
info("Assign target to invalid anchor");
await invokeContentTaskAndTick(browser, [], () => {
Object.assign(content.document.getElementById("target1").style, {
"position-anchor": "--invalid",
});
});
await testNoDetailsRelations(btn3, target1);
info("Explicit anchor");
const btn2 = findAccessibleChildByID(docAcc, "btn2");
const target2 = findAccessibleChildByID(docAcc, "target2");
await testDetailsRelations(btn2, target2);
await invokeContentTaskAndTick(browser, [], () => {
Object.assign(content.document.getElementById("target2").style, {
left: "0px",
});
});
await testNoDetailsRelations(btn2, target2);
},
{ chrome: true, topLevel: true }
);
/**
* Test no details relations for sibling target
*/
addAccessibleTask(
`
Hello
Cruel
World
`,
async function testSiblingPositionAnchor(browser, docAcc) {
info("Target is sibling after anchor, no relation");
const siblingBtn = findAccessibleChildByID(docAcc, "sibling-btn");
const siblingTarget = findAccessibleChildByID(docAcc, "sibling-target");
await testNoDetailsRelations(siblingBtn, siblingTarget);
await invokeSetAttributeAndTick(browser, "intermediate-button", "hidden");
await testDetailsRelations(siblingBtn, siblingTarget);
},
{ chrome: true, topLevel: true }
);
/**
* Test no details relations parent anchor with child target
*/
addAccessibleTask(
`
Hello
World
Hello
`,
async function testSiblingPositionAnchor(browser, docAcc) {
info("Target is child of anchor, no relation");
const parentBtn = findAccessibleChildByID(docAcc, "parent-btn");
const childTarget = findAccessibleChildByID(docAcc, "child-target");
await testNoDetailsRelations(parentBtn, childTarget);
if (!browser.isRemoteBrowser) {
// Bug 1989629: This doesn't work in e10s yet.
info("Target is owned by anchor, no relation");
const ownerBtn = findAccessibleChildByID(docAcc, "owner-btn");
const ownedTarget = findAccessibleChildByID(docAcc, "owned-target");
await testNoDetailsRelations(ownerBtn, ownedTarget);
info("Remove aria owns, relation should be restored");
await invokeSetAttributeAndTick(browser, "owner-btn", "aria-owns");
await testDetailsRelations(ownerBtn, ownedTarget);
}
},
{ chrome: true, topLevel: true }
);
/**
* Test no details relations for CSS anchor with multiple targets or targets with multiple anchors
*/
addAccessibleTask(
`
Cruel
World
Hello
Hello
Cruel
World
`,
async function testMultiplePositionAnchors(browser, docAcc) {
info("Multiple targets for one anchor");
const multiTargetBtn = findAccessibleChildByID(docAcc, "multiTarget-btn");
const multiTargetTarget1 = findAccessibleChildByID(
docAcc,
"multiTarget-target1"
);
const multiTargetTarget2 = findAccessibleChildByID(
docAcc,
"multiTarget-target2"
);
await testNoDetailsRelations(multiTargetBtn, multiTargetTarget1);
await testNoDetailsRelations(multiTargetBtn, multiTargetTarget2);
info("Remove one target from anchor via styling");
await invokeSetAttributeAndTick(
browser,
"multiTarget-target2",
"class",
"unanchored"
);
await testDetailsRelations(multiTargetBtn, multiTargetTarget1);
info("Restore target styling");
await invokeSetAttributeAndTick(browser, "multiTarget-target2", "class");
await testNoDetailsRelations(multiTargetBtn, multiTargetTarget2);
info("Remove one target node completely");
await invokeSetAttributeAndTick(
browser,
"multiTarget-target2",
"hidden",
"true"
);
await testDetailsRelations(multiTargetBtn, multiTargetTarget1);
info("Add back target node");
await invokeSetAttributeAndTick(browser, "multiTarget-target2", "hidden");
await testNoDetailsRelations(multiTargetBtn, multiTargetTarget1);
info("Multiple anchors for one target");
const multiAnchorBtn1 = findAccessibleChildByID(docAcc, "multiAnchor-btn1");
const multiAnchorBtn2 = findAccessibleChildByID(docAcc, "multiAnchor-btn2");
const multiAnchorTarget = findAccessibleChildByID(
docAcc,
"multiAnchor-target"
);
await testNoDetailsRelations(multiAnchorBtn1, multiAnchorTarget);
await testNoDetailsRelations(multiAnchorBtn2, multiAnchorTarget);
info("Remove one anchor via styling");
await invokeSetAttributeAndTick(
browser,
"multiAnchor-target",
"class",
"unanchored"
);
await testDetailsRelations(multiAnchorBtn2, multiAnchorTarget);
info("Add back one anchor via styling");
await invokeSetAttributeAndTick(browser, "multiAnchor-target", "class");
await testNoDetailsRelations(multiAnchorBtn2, multiAnchorTarget);
info("Remove one anchor node");
await invokeSetAttributeAndTick(
browser,
"multiAnchor-btn1",
"hidden",
"true"
);
await testDetailsRelations(multiAnchorBtn2, multiAnchorTarget);
info("Add back anchor node");
await invokeSetAttributeAndTick(browser, "multiAnchor-btn1", "hidden");
await testNoDetailsRelations(multiAnchorBtn2, multiAnchorTarget);
},
{ chrome: true, topLevel: true }
);
/**
* Test no details relations for tooltip target
*/
addAccessibleTask(
`
World
Hello
`,
async function testTooltipPositionAnchor(browser, docAcc) {
info("Target is tooltip, no relation");
const btn = findAccessibleChildByID(docAcc, "btn");
const tooltipTarget = findAccessibleChildByID(docAcc, "tooltip-target");
await testNoDetailsRelations(btn, tooltipTarget);
},
{ chrome: true, topLevel: true }
);
/**
* Test no details relations for when explicit relations are set.
*/
addAccessibleTask(
`
World
Hello
World
Hello
World
Hello
World
Hello
`,
async function testTooltipPositionAnchor(browser, docAcc) {
info("Test no details relations when explicit relations are set");
const btnDescribedby = findAccessibleChildByID(docAcc, "btn-describedby");
const targetDescribedby = findAccessibleChildByID(
docAcc,
"target-describedby"
);
const btnLabelledby = findAccessibleChildByID(docAcc, "btn-labelledby");
const targetLabelledby = findAccessibleChildByID(
docAcc,
"target-labelledby"
);
const btnAnchorsetdetails = findAccessibleChildByID(
docAcc,
"btn-anchorsetdetails"
);
const targetAnchorsetdetails = findAccessibleChildByID(
docAcc,
"target-anchorsetdetails"
);
const btnTargetsetdetails = findAccessibleChildByID(
docAcc,
"btn-targetsetdetails"
);
const targetTargetsetdetails = findAccessibleChildByID(
docAcc,
"target-targetsetdetails"
);
await testNoDetailsRelations(btnDescribedby, targetDescribedby);
await invokeSetAttributeAndTick(
browser,
"btn-describedby",
"aria-describedby"
);
await testDetailsRelations(btnDescribedby, targetDescribedby);
await testNoDetailsRelations(btnLabelledby, targetLabelledby);
await invokeSetAttributeAndTick(
browser,
"btn-labelledby",
"aria-labelledby"
);
await testDetailsRelations(btnLabelledby, targetLabelledby);
await testNoDetailsRelations(btnAnchorsetdetails, targetAnchorsetdetails);
await invokeSetAttributeAndTick(
browser,
"btn-anchorsetdetails",
"aria-details"
);
await testDetailsRelations(btnAnchorsetdetails, targetAnchorsetdetails);
await testNoDetailsRelations(btnTargetsetdetails, targetTargetsetdetails);
await invokeSetAttributeAndTick(
browser,
"target-targetsetdetails",
"aria-details"
);
await testDetailsRelations(btnTargetsetdetails, targetTargetsetdetails);
},
{ chrome: true, topLevel: true }
);
/**
* Test no details when anchor is used for sizing target only
*/
addAccessibleTask(
`
World
Hello
Cruel
`,
async function testTooltipPositionAnchor(browser, docAcc) {
info("Target is tooltip, no relation");
const anchor1 = findAccessibleChildByID(docAcc, "anchor1");
const target = findAccessibleChildByID(docAcc, "target");
await testNoDetailsRelations(anchor1, target);
info("Use anchor for positioning as well");
await invokeSetAttributeAndTick(browser, "target", "class", "positioned");
await testDetailsRelations(anchor1, target);
info("Use second anchor for sizing");
await invokeSetAttributeAndTick(
browser,
"target",
"class",
"positioned anchor-height"
);
await testNoDetailsRelations(anchor1, target);
},
{ chrome: true, topLevel: true }
);
/**
* Test multi columns colspan
*/
addAccessibleTask(
`
`,
async function testTooltipPositionAnchor(browser, docAcc) {
const anchor = findAccessibleChildByID(docAcc, "anchor");
const target = findAccessibleChildByID(docAcc, "target");
await testDetailsRelations(anchor, target);
},
{ chrome: true, topLevel: true }
);