diff --git a/accessibility-checker-engine/help/group_withInputs_hasName.mdx b/accessibility-checker-engine/help/group_withInputs_hasName.mdx new file mode 100644 index 000000000..bb7412cc9 --- /dev/null +++ b/accessibility-checker-engine/help/group_withInputs_hasName.mdx @@ -0,0 +1,80 @@ +--- +title: "group_withInputs_hasName - Accessibility Checker Rule Help" +--- +import "../../../styles/ToolHelp.scss" +import { CodeSnippet, Tag } from "carbon-components-react"; + +
+ + + +### A `role="group"` or `
` element does not have an accessible name or has a duplicate name + + + + +
+ + + + +Multiple `
` or `role="group"` elements with similar nested `` elements must have unique labels + + + + + + + + + + + + + +### Why is this important? + +A label associated with a group of related input elements also serves as a common label for individual inputs in the group. +Assistive technologies (AT) can indicate the start and end of the group and the group’s label as the user navigates into and out of the group. +AT needs to be able to present the group label with each input control to remind users with which group they are part. +When there are multiple groups with the same input elements then the label of the group needs to be unique so it can be distinguished. + +For example, in a retail scenario where two groups of input elements represent _Name, Address, City, and Zip_, +the groups need to be distinguished from one another by labelling one group "_Mailing address_" and the other "_Shipping address_".    + +
+ + +### What to do + +* Provide a unique label for a group of form controls using `
` and `` elements +* **Or**, distinguish multiple `role="group"` elements with a unique `aria-labelledby` or `aria-label` +* **Or**, for a group of radio buttons, use `role="radiogroup"` instead of `role="group"` + + + + +### About this requirement + + + +* [IBM 1.3.1 Info and relationships](https://www.ibm.com/able/requirements/requirements/#1_3_1) +* [IBM 3.3.2 Labels or Instructions](https://www.ibm.com/able/requirements/requirements/#3_3_2) +* [WCAG technique ARIA 17](https://www.w3.org/WAI/WCAG21/Techniques/aria/ARIA17.html)  +* [WCAG technique H71](https://www.w3.org/TR/WCAG20-TECHS/H71.html) +* [WCAG technique F82](https://www.w3.org/TR/2016/NOTE-WCAG20-TECHS-20161007/F82) +* [ARIA specification - Group Role]( https://www.w3.org/TR/wai-aria-1.2/#group) +* [Carbon design system - Form accessibility](https://www.carbondesignsystem.com/components/form/accessibility/) + + +### Who does this affect? + +* People using a screen reader, including blind, low vision and neurodivergent people +* People with low vision using screen magnification +* People using other assistive technologies that expose accessibility information + + + +
+ +export default ({ children, _frontmatter }) => ({children}) diff --git a/accessibility-checker-engine/src/v2/aria/ARIAMapper.ts b/accessibility-checker-engine/src/v2/aria/ARIAMapper.ts index e756c2c80..11b2f6b65 100644 --- a/accessibility-checker-engine/src/v2/aria/ARIAMapper.ts +++ b/accessibility-checker-engine/src/v2/aria/ARIAMapper.ts @@ -409,9 +409,23 @@ export class ARIAMapper extends CommonMapper { if (cur.nodeName.toLowerCase() === "input" && elem.hasAttribute("id") && elem.getAttribute("id").length > 0) { let label = elem.ownerDocument.querySelector("label[for='"+elem.getAttribute("id")+"']"); if (label) { - return this.computeNameHelp(walkId, label, false, false); + if (label.hasAttribute("aria-label") || label.hasAttribute("aria-labelledby")) { + return this.computeNameHelp(walkId, label, false, false); + } else { + return label.textContent; + } + } + } + if (cur.nodeName.toLowerCase() === "fieldset") { + if( (cur).querySelector("legend")){ + let legend = (cur).querySelector("legend"); + return legend.innerText; + }else{ + return this.computeNameHelp(walkId, cur, false, false); } + } + } // 2e. diff --git a/accessibility-checker-engine/src/v2/checker/accessibility/help/index.ts b/accessibility-checker-engine/src/v2/checker/accessibility/help/index.ts index 827437a1a..820105492 100644 --- a/accessibility-checker-engine/src/v2/checker/accessibility/help/index.ts +++ b/accessibility-checker-engine/src/v2/checker/accessibility/help/index.ts @@ -862,6 +862,13 @@ let a11yHelp = { "Pass_0": `${Config.helpRoot}/Rpt_Aria_ArticleRoleLabel_Implicit`, "Fail_1": `${Config.helpRoot}/Rpt_Aria_ArticleRoleLabel_Implicit` }, + // ALI - DONE + "group_withInputs_hasName": { + 0: `${Config.helpRoot}/group_withInputs_hasName`, + "Pass_1": `${Config.helpRoot}/group_withInputs_hasName`, + "Fail_1": `${Config.helpRoot}/group_withInputs_hasName`, + "Fail_2": `${Config.helpRoot}/group_withInputs_hasName` + }, // JCH - DONE // "Rpt_Aria_MultipleGroupRoles_Implicit": { // 0: `${Config.helpRoot}/Rpt_Aria_MultipleGroupRoles_Implicit`, diff --git a/accessibility-checker-engine/src/v2/checker/accessibility/nls/index.ts b/accessibility-checker-engine/src/v2/checker/accessibility/nls/index.ts index 7a0fbac23..d7a0cbd52 100644 --- a/accessibility-checker-engine/src/v2/checker/accessibility/nls/index.ts +++ b/accessibility-checker-engine/src/v2/checker/accessibility/nls/index.ts @@ -855,6 +855,14 @@ let a11yNls = { "Pass_0": "Rule Passed", "Fail_1": "The element with \"article\" role does not have a label" }, + + // ALI - DONE + "group_withInputs_hasName": { + 0: "Groups with nested inputs must have unique accessible name", + "Pass_1": "Group/Fieldset \"{0}\" with an input has a unique name", + "Fail_1": "Group/Fieldset does not have an accessible name", + "Fail_2": "Group/Fieldset \"{0}\" has a duplicate name to another group" + }, // JCH - DONE // "Rpt_Aria_MultipleGroupRoles_Implicit": { // 0: "Each element with \"group\" role must have a unique label that describes its purpose", diff --git a/accessibility-checker-engine/src/v2/checker/accessibility/rules/rpt-ariaLabeling-rules.ts b/accessibility-checker-engine/src/v2/checker/accessibility/rules/rpt-ariaLabeling-rules.ts index 8aebcaf74..9cc998a2e 100644 --- a/accessibility-checker-engine/src/v2/checker/accessibility/rules/rpt-ariaLabeling-rules.ts +++ b/accessibility-checker-engine/src/v2/checker/accessibility/rules/rpt-ariaLabeling-rules.ts @@ -14,7 +14,15 @@ limitations under the License. *****************************************************************************/ -import { Rule, RuleResult, RuleFail, RuleContext, RulePotential, RuleManual, RulePass } from "../../../api/IEngine"; +import { + Rule, + RuleResult, + RuleFail, + RuleContext, + RulePotential, + RuleManual, + RulePass, +} from "../../../api/IEngine"; import { RPTUtil } from "../util/legacy"; import { ARIADefinitions } from "../../../aria/ARIADefinitions"; import { FragmentUtil } from "../util/fragment"; @@ -25,24 +33,32 @@ import { DOMWalker } from "../../../dom/DOMWalker"; let a11yRulesLabeling: Rule[] = [ { /** - * Description: Triggers if a landmark element has the same parent-landmark, - * AND the same role as another landmark, - * AND is not differentiated by aria-label or aria-labelledby. + * Description: Triggers if a landmark element has the same parent-landmark, + * AND the same role as another landmark, + * AND is not differentiated by aria-label or aria-labelledby. * This causes it to be difficult for a keyboard user to know the difference between two landmarks * Origin: https://www.w3.org/WAI/WCAG21/Techniques/aria/ARIA13 this is not directly part of the ARIA spec so this is only in the IBM rules as a Violation - * - * NOTE: When we have two landmarks at the root level of the document this rule will not check for that. - * For example if we have
we do not fail this rule. + * + * NOTE: When we have two landmarks at the root level of the document this rule will not check for that. + * For example if we have
we do not fail this rule. * Althought this might be an accessibility error anyway. See: * https://stackoverflow.com/questions/34896476/can-i-use-more-than-one-main-html-tag-in-the-same-page/34906037 */ id: "landmark_name_unique", - context: "aria:complementary, aria:banner, aria:contentinfo, aria:main, aria:navigation, aria:region, aria:search, aria:form", - run: (context: RuleContext, options?: {}): RuleResult | RuleResult[] => { + context: + "aria:complementary, aria:banner, aria:contentinfo, aria:main, aria:navigation, aria:region, aria:search, aria:form", + run: ( + context: RuleContext, + options?: {} + ): RuleResult | RuleResult[] => { // TODO do I need to fiter out bad contentinfo nodes: The footer element is not a contentinfo landmark when it is a descendant of the following HTML5 sectioning elements: https://www.w3.org/TR/2017/NOTE-wai-aria-practices-1.1-20171214/examples/landmarks/HTML5.html const ruleContext = context["dom"].node as Element; let ownerDocument = FragmentUtil.getOwnerFragment(ruleContext); - let formCache = RPTUtil.getCache(ruleContext.ownerDocument, "landmark_name_unique", null); + let formCache = RPTUtil.getCache( + ruleContext.ownerDocument, + "landmark_name_unique", + null + ); if (!formCache) { // console.log("---------ENTERING FORM CACHE") @@ -50,94 +66,143 @@ let a11yRulesLabeling: Rule[] = [ navigationNodes: [], navigationNodesComputedLabels: [], navigationNodesParents: [], - navigationNodesMatchFound: [] - } - let navigationNodesTemp = ownerDocument.querySelectorAll('aside,[role="complementary"], footer,[role="contentinfo"], header,[role="banner"], main,[role="main"], nav,[role="navigation"], form,[role="form"], section,[role="region"],[role="search"]'); + navigationNodesMatchFound: [], + }; + let navigationNodesTemp = ownerDocument.querySelectorAll( + 'aside,[role="complementary"], footer,[role="contentinfo"], header,[role="banner"], main,[role="main"], nav,[role="navigation"], form,[role="form"], section,[role="region"],[role="search"]' + ); let navigationNodes = Array.from(navigationNodesTemp); let navigationNodesParents = []; let navigationNodesMatchFound = []; - for (let i = 0; i < navigationNodes.length; i++) { // Loop over all the landmark nodes + for (let i = 0; i < navigationNodes.length; i++) { + // Loop over all the landmark nodes let els = []; - let a = navigationNodes[i].parentElement + let a = navigationNodes[i].parentElement; while (a) { els.push(a); a = a.parentElement; } - for (let j = 0; j < els.length; j++) { // Loop over all the parents of the landmark nodes - // Find nearest landmark parent based on the tagName or the role attribute - let tagNameTrigger = ["ASIDE", "FOOTER", "FORM", "HEADER", "MAIN", "NAV", "SECTION"].includes(els[j].tagName) + for (let j = 0; j < els.length; j++) { + // Loop over all the parents of the landmark nodes + // Find nearest landmark parent based on the tagName or the role attribute + let tagNameTrigger = [ + "ASIDE", + "FOOTER", + "FORM", + "HEADER", + "MAIN", + "NAV", + "SECTION", + ].includes(els[j].tagName); let roleNameTrigger = false; if (els[j].hasAttribute("role")) { - roleNameTrigger = ["complementary", "contentinfo", "form", "banner", "main", "navigation", "region", "search"].includes(els[j].getAttribute("role")) // TODO we are not covering the case where a elemenent with multiple roles. E.g. role = "form banner". This is a improvment we might want to add in the future. + roleNameTrigger = [ + "complementary", + "contentinfo", + "form", + "banner", + "main", + "navigation", + "region", + "search", + ].includes(els[j].getAttribute("role")); // TODO we are not covering the case where a elemenent with multiple roles. E.g. role = "form banner". This is a improvment we might want to add in the future. } if (tagNameTrigger || roleNameTrigger) { // Nearest parent-landmark found - navigationNodesParents.push(els[j]) - break + navigationNodesParents.push(els[j]); + break; } - if (j === els.length - 1) { // This node is at the head of the file so it does not have a parent - navigationNodesParents.push(null) // TODO might want to change to NULL - break + if (j === els.length - 1) { + // This node is at the head of the file so it does not have a parent + navigationNodesParents.push(null); // TODO might want to change to NULL + break; } } } let navigationNodesComputedLabels = []; - for (let i = 0; i < navigationNodes.length; i++) { // Loop over all the landmark nodes - navigationNodesComputedLabels.push(ARIAMapper.computeName(navigationNodes[i])) + for (let i = 0; i < navigationNodes.length; i++) { + // Loop over all the landmark nodes + navigationNodesComputedLabels.push( + ARIAMapper.computeName(navigationNodes[i]) + ); } - for (let i = 0; i < navigationNodesParents.length; i++) { // Loop over all the parents of the landmark nodes to find duplicates + for (let i = 0; i < navigationNodesParents.length; i++) { + // Loop over all the parents of the landmark nodes to find duplicates let matchFound = false; let pass_0_flag = false; for (let j = 0; j < navigationNodesParents.length; j++) { if (j === i) { // We do not want to compare against ourselfs - continue + continue; } - + // This if statement focus on the case where the parent landmark is null - if ((navigationNodesParents[i] === null) && (navigationNodesParents[j] === null)) { + if ( + navigationNodesParents[i] === null && + navigationNodesParents[j] === null + ) { // We are looking at two root nodes, so we should compare them. - if (ARIAMapper.nodeToRole(navigationNodes[i]) === ARIAMapper.nodeToRole(navigationNodes[j])) { + if ( + ARIAMapper.nodeToRole(navigationNodes[i]) === + ARIAMapper.nodeToRole(navigationNodes[j]) + ) { // Both nodes have the same role AND - if ((navigationNodesComputedLabels[i] === navigationNodesComputedLabels[j])) { + if ( + navigationNodesComputedLabels[i] === + navigationNodesComputedLabels[j] + ) { // both have the same (computed) aria-label/aria-labelledby // if (navigationNodesComputedLabels[i] === "") { - navigationNodesMatchFound.push("Fail_0"); // Fail 0 - matchFound = true - break + navigationNodesMatchFound.push("Fail_0"); // Fail 0 + matchFound = true; + break; // } } else { - // Same parents && same node roles BUT different computed aria-label/aria-labelledby + // Same parents && same node roles BUT different computed aria-label/aria-labelledby // We have at least a Pass_0. But we need to check all nodes to see if another one fails. So set a flag. - pass_0_flag = true + pass_0_flag = true; } } else { // Same parents but different node roles // Not applicable } - }else if ((navigationNodesParents[i] === null) || (navigationNodesParents[j] === null)) { + } else if ( + navigationNodesParents[i] === null || + navigationNodesParents[j] === null + ) { // We are looking at a single root node - continue + continue; } // This if statement focus on the case where the parent landmark is NOT null - if (DOMUtil.sameNode(navigationNodesParents[i], navigationNodesParents[j])) { - // We have the same parent-landmark AND - if (ARIAMapper.nodeToRole(navigationNodes[i]) === ARIAMapper.nodeToRole(navigationNodes[j])) { + if ( + DOMUtil.sameNode( + navigationNodesParents[i], + navigationNodesParents[j] + ) + ) { + // We have the same parent-landmark AND + if ( + ARIAMapper.nodeToRole(navigationNodes[i]) === + ARIAMapper.nodeToRole(navigationNodes[j]) + ) { // Both nodes have the same role AND - if ((navigationNodesComputedLabels[i] === navigationNodesComputedLabels[j])) { + if ( + navigationNodesComputedLabels[i] === + navigationNodesComputedLabels[j] + ) { // both have the same (computed) aria-label/aria-labelledby // if (navigationNodesComputedLabels[i] === "") { - navigationNodesMatchFound.push("Fail_0"); // Fail 0 - matchFound = true - break + navigationNodesMatchFound.push("Fail_0"); // Fail 0 + matchFound = true; + break; // } } else { - // Same parents && same node roles BUT different computed aria-label/aria-labelledby + // Same parents && same node roles BUT different computed aria-label/aria-labelledby // We have at least a Pass_0. But we need to check all nodes to see if another one fails. So set a flag. - pass_0_flag = true + pass_0_flag = true; } } else { // Same parents but different node roles // Not applicable @@ -154,20 +219,23 @@ let a11yRulesLabeling: Rule[] = [ } } } - formCache.navigationNodesComputedLabels = navigationNodesComputedLabels; + formCache.navigationNodesComputedLabels = + navigationNodesComputedLabels; formCache.navigationNodes = navigationNodes; formCache.navigationNodesParents = navigationNodesParents; formCache.navigationNodesMatchFound = navigationNodesMatchFound; - RPTUtil.setCache(ruleContext.ownerDocument, "landmark_name_unique", formCache); + RPTUtil.setCache( + ruleContext.ownerDocument, + "landmark_name_unique", + formCache + ); // TODO Add validation that all 3 arrays are the same length // console.log("-------------End formCache") - } // End formCache let indexToCheck = -1; for (let i = 0; i < formCache.navigationNodes.length; i++) { - if (ruleContext.isSameNode(formCache.navigationNodes[i])) { indexToCheck = i; } @@ -175,15 +243,37 @@ let a11yRulesLabeling: Rule[] = [ if (indexToCheck === -1) { return null; } - if (formCache.navigationNodesMatchFound[indexToCheck].includes("Pass_0")) { - return RulePass(formCache.navigationNodesMatchFound[indexToCheck], [ARIAMapper.nodeToRole(formCache.navigationNodes[indexToCheck])]); - } else if (formCache.navigationNodesMatchFound[indexToCheck].includes("Fail_0")) { - return RuleFail(formCache.navigationNodesMatchFound[indexToCheck], [ARIAMapper.nodeToRole(formCache.navigationNodes[indexToCheck]), formCache.navigationNodesComputedLabels[indexToCheck]]); + if ( + formCache.navigationNodesMatchFound[indexToCheck].includes( + "Pass_0" + ) + ) { + return RulePass( + formCache.navigationNodesMatchFound[indexToCheck], + [ + ARIAMapper.nodeToRole( + formCache.navigationNodes[indexToCheck] + ), + ] + ); + } else if ( + formCache.navigationNodesMatchFound[indexToCheck].includes( + "Fail_0" + ) + ) { + return RuleFail( + formCache.navigationNodesMatchFound[indexToCheck], + [ + ARIAMapper.nodeToRole( + formCache.navigationNodes[indexToCheck] + ), + formCache.navigationNodesComputedLabels[indexToCheck], + ] + ); } else { return null; } - - } + }, }, { /** @@ -193,14 +283,23 @@ let a11yRulesLabeling: Rule[] = [ */ id: "Rpt_Aria_RegionLabel_Implicit", context: "dom:*[role], dom:section", - run: (context: RuleContext, options?: {}): RuleResult | RuleResult[] => { + run: ( + context: RuleContext, + options?: {} + ): RuleResult | RuleResult[] => { const ruleContext = context["dom"].node as Element; let tagName = ruleContext.tagName.toLowerCase(); - if (tagName === "section" && !RPTUtil.hasRole(ruleContext, "region", false)) { + if ( + tagName === "section" && + !RPTUtil.hasRole(ruleContext, "region", false) + ) { return null; } - if (tagName !== "section" && !RPTUtil.hasRoleInSemantics(ruleContext, "region")) { + if ( + tagName !== "section" && + !RPTUtil.hasRoleInSemantics(ruleContext, "region") + ) { return null; } @@ -208,10 +307,9 @@ let a11yRulesLabeling: Rule[] = [ if (passed) { return RulePass("Pass_0"); } else { - return RuleFail(tagName === "section" ? "Fail_1" : "Fail_2"); } - } + }, }, { /** @@ -221,17 +319,33 @@ let a11yRulesLabeling: Rule[] = [ */ id: "Rpt_Aria_MultipleMainsRequireLabel_Implicit_2", context: "aria:main", - run: (context: RuleContext, options?: {}): RuleResult | RuleResult[] => { + run: ( + context: RuleContext, + options?: {} + ): RuleResult | RuleResult[] => { const ruleContext = context["dom"].node as Element; let contextLabel = RPTUtil.getAriaLabel(ruleContext); - let parentDocRole = RPTUtil.getAncestorWithRole(ruleContext, "document", true); - let mains = RPTUtil.getElementsByRoleHidden(ruleContext.ownerDocument, "main", true, true); + let parentDocRole = RPTUtil.getAncestorWithRole( + ruleContext, + "document", + true + ); + let mains = RPTUtil.getElementsByRoleHidden( + ruleContext.ownerDocument, + "main", + true, + true + ); let result = null; for (let i = 0; i < mains.length; ++i) { if (mains[i] === ruleContext) continue; result = RulePass("Pass_0"); - let thisParentDocRole = RPTUtil.getAncestorWithRole(mains[i], "document", true); + let thisParentDocRole = RPTUtil.getAncestorWithRole( + mains[i], + "document", + true + ); if (thisParentDocRole === parentDocRole) { if (RPTUtil.getAriaLabel(mains[i]) === contextLabel) { result = RuleFail("Fail_1"); @@ -240,7 +354,7 @@ let a11yRulesLabeling: Rule[] = [ } } return result; - } + }, }, { /** @@ -250,13 +364,21 @@ let a11yRulesLabeling: Rule[] = [ */ id: "Rpt_Aria_MultipleMainsVisibleLabel_Implicit", context: "dom:body", - run: (context: RuleContext, options?: {}): RuleResult | RuleResult[] => { + run: ( + context: RuleContext, + options?: {} + ): RuleResult | RuleResult[] => { const ruleContext = context["dom"].node as Element; // Consider the Check Hidden Content setting that is set by the rules - //call getElementsByRoleHidden with considerImplicit flag as true - //so that the method returs
elements - let landmarks = RPTUtil.getElementsByRoleHidden(ruleContext.ownerDocument, "main", true, true); + //call getElementsByRoleHidden with considerImplicit flag as true + //so that the method returs
elements + let landmarks = RPTUtil.getElementsByRoleHidden( + ruleContext.ownerDocument, + "main", + true, + true + ); if (landmarks.length === 0 || landmarks.length === 1) { return null; } @@ -268,7 +390,7 @@ let a11yRulesLabeling: Rule[] = [ } else { return RulePass("Pass_0"); } - } + }, }, { /** @@ -277,22 +399,39 @@ let a11yRulesLabeling: Rule[] = [ */ id: "Rpt_Aria_MultipleBannerLandmarks_Implicit", context: "aria:banner", - run: (context: RuleContext, options?: {}): RuleResult | RuleResult[] => { + run: ( + context: RuleContext, + options?: {} + ): RuleResult | RuleResult[] => { const ruleContext = context["dom"].node as Element; // Consider the Check Hidden Content setting that is set by the rules - // Also, consider Implicit role checking. - let landmarks = RPTUtil.getElementsByRoleHidden(ruleContext.ownerDocument, "banner", true, true); + // Also, consider Implicit role checking. + let landmarks = RPTUtil.getElementsByRoleHidden( + ruleContext.ownerDocument, + "banner", + true, + true + ); if (landmarks.length === 0 || landmarks.length === 1) { return null; } - let dupes = RPTUtil.getCache(ruleContext.ownerDocument, "Rpt_Aria_MultipleBannerLandmarks_Implicit", null); + let dupes = RPTUtil.getCache( + ruleContext.ownerDocument, + "Rpt_Aria_MultipleBannerLandmarks_Implicit", + null + ); if (!dupes) { dupes = RPTUtil.findAriaLabelDupes(landmarks); - RPTUtil.setCache(ruleContext.ownerDocument, "Rpt_Aria_MultipleBannerLandmarks_Implicit", dupes); + RPTUtil.setCache( + ruleContext.ownerDocument, + "Rpt_Aria_MultipleBannerLandmarks_Implicit", + dupes + ); } let myLabel = RPTUtil.getAriaLabel(ruleContext); - let passed = myLabel !== "" && (!(myLabel in dupes) || dupes[myLabel] <= 1); + let passed = + myLabel !== "" && (!(myLabel in dupes) || dupes[myLabel] <= 1); //return new ValidationResult(passed, ruleContext, '', '', [ myLabel ]); if (!passed) { @@ -300,7 +439,7 @@ let a11yRulesLabeling: Rule[] = [ } else { return RulePass("Pass_0"); } - } + }, }, { /** @@ -309,30 +448,42 @@ let a11yRulesLabeling: Rule[] = [ */ id: "Rpt_Aria_OneBannerInSiblingSet_Implicit", context: "dom:*[role], dom:header", - run: (context: RuleContext, options?: {}): RuleResult | RuleResult[] => { + run: ( + context: RuleContext, + options?: {} + ): RuleResult | RuleResult[] => { const ruleContext = context["dom"].node as Element; if (!RPTUtil.hasRoleInSemantics(ruleContext, "banner")) { return null; } - let passed = RPTUtil.getSiblingWithRoleHidden(ruleContext, "banner", true, true) === null; + let passed = + RPTUtil.getSiblingWithRoleHidden( + ruleContext, + "banner", + true, + true + ) === null; //return new ValidationResult(passed, [ruleContext], 'role', '', []); if (passed) { return RulePass("Pass_0"); } else { return RuleFail("Fail_1"); } - } + }, }, { /** - * Description: Triggers if a complementary role is not labeled with an aria-label or aria-labelledby + * Description: Triggers if a complementary role is not labeled with an aria-label or aria-labelledby * also, consider