/* 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
World
`, 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( `
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( `
World
`, 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
`, 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( ` `, 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
World
World
World
`, 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
`, 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 } );