diff --git a/accessibility-checker-engine/src/v4/rules/element_tabbable_unobscured.ts b/accessibility-checker-engine/src/v4/rules/element_tabbable_unobscured.ts index a39d44040..9d298c22a 100644 --- a/accessibility-checker-engine/src/v4/rules/element_tabbable_unobscured.ts +++ b/accessibility-checker-engine/src/v4/rules/element_tabbable_unobscured.ts @@ -45,7 +45,9 @@ export let element_tabbable_unobscured: Rule = { act: [], run: (context: RuleContext, options?: {}, contextHierarchies?: RuleContextHierarchy): RuleResult | RuleResult[] => { const ruleContext = context["dom"].node as HTMLElement; - if (!VisUtil.isNodeVisible(ruleContext) || (!RPTUtil.isTabbable(ruleContext) && (!ruleContext .hasAttribute("tabindex")|| parseInt(ruleContext.getAttribute("tabindex")) < 0))) + + if (!VisUtil.isNodeVisible(ruleContext) || !RPTUtil.isTabbable(ruleContext)) + return null; const nodeName = ruleContext.nodeName.toLocaleLowerCase(); @@ -64,16 +66,18 @@ export let element_tabbable_unobscured: Rule = { if (bounds['height'] === 0 || bounds['width'] === 0 ) return null; - var doc = ruleContext.ownerDocument; + const doc = ruleContext.ownerDocument; if (!doc) { return null; } - var win = doc.defaultView; + const win = doc.defaultView; + if (!win) { return null; } - var cStyle = win.getComputedStyle(ruleContext); + const cStyle = win.getComputedStyle(ruleContext); + if (cStyle === null) return null; @@ -81,7 +85,8 @@ export let element_tabbable_unobscured: Rule = { if (!zindex || zindex === 'auto') zindex = "0"; - var elems = doc.querySelectorAll('body *:not(script)'); + const elems = doc.querySelectorAll('body *:not(script)'); + if (!elems || elems.length == 0) return; @@ -96,27 +101,28 @@ export let element_tabbable_unobscured: Rule = { if (ruleContext.contains(elem)) { //the next node in elems will be after the target node (ruleContext). before = false; - } else { - if (VisUtil.isNodeVisible(elem) && !elem.contains(ruleContext)) { - const bnds = mapper.getBounds(elem); - var zStyle = win.getComputedStyle(elem); - let z_index = '0'; - if (zStyle) { - z_index = zStyle.zIndex; - if (!z_index || isNaN(Number(z_index))) - z_index = "0"; - } - if (bnds.height !== 0 && bnds.width !== 0 - && bnds.top <= bounds.top && bnds.left <= bounds.left && bnds.top + bnds.height >= bounds.top + bounds.height - && bnds.left + bnds.height >= bounds.left + bounds.width - && (before ? parseInt(zindex) < parseInt(z_index): parseInt(zindex) <= parseInt(z_index))) - violations.push(elem); + } else if (VisUtil.isNodeVisible(elem) && !elem.contains(ruleContext)) { + const bnds = mapper.getBounds(elem); + const zStyle = win.getComputedStyle(elem); + let z_index = '0'; + if (zStyle) { + z_index = zStyle.zIndex; + if (!z_index || isNaN(Number(z_index))) + z_index = "0"; + } + if (bnds.height !== 0 && bnds.width !== 0 + && bnds.top <= bounds.top && bnds.left <= bounds.left && bnds.top + bnds.height >= bounds.top + bounds.height + && bnds.left + bnds.height >= bounds.left + bounds.width + && (before ? parseInt(zindex) < parseInt(z_index): parseInt(zindex) <= parseInt(z_index))) + { + violations.push(elem); } } }); - if (violations.length > 0) + if (violations.length > 0) { return RulePotential("potential_obscured", []); + } return RulePass("pass"); } diff --git a/accessibility-checker-engine/src/v4/rulesets.ts b/accessibility-checker-engine/src/v4/rulesets.ts index dd0c6d062..f5a4eea58 100644 --- a/accessibility-checker-engine/src/v4/rulesets.ts +++ b/accessibility-checker-engine/src/v4/rulesets.ts @@ -71,10 +71,11 @@ const summaries = { "3.3.2": "Labels or instructions are provided when content requires user input.", "3.3.3": "If an input error is automatically detected and suggestions for correction are known, then the suggestions are provided to the user, unless it would jeopardize the security or purpose of the content.", "3.3.4": "For content that cause legal commitments or financial transactions for the user to occur, that modify or delete user-controllable data in data storage systems, or that submit user test responses, the user can reverse, correct, or confirm the action.", + "4.1.1": "(Obsolete and removed) This requirement was originally adopted to address problems that assistive technology (AT) had directly parsing HTML. AT no longer has any need to directly parse HTML. Consequently, these problems either no longer exist or are addressed by other requirements.", "4.1.2": "For all user interface components (including, but not limited to: form elements, links and components generated by scripts), the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to user agents, including assistive technologies.", "4.1.3": "In content implemented using markup languages, status messages can be programmatically determined through role or properties such that they can be presented to the user by assistive technologies without receiving focus.", - "HTML": "The HTML specification issues that cause accessibility issues may be covered by other rules and will be reported under those accessibility requirements. However, some non-conforming HTML specification issues are reported.", - "ARIA": "The ARIA specification issues that cause accessibility issues may be covered by other rules and will be reported under those accessibility requirements. However, some non-conforming ARIA specification issues are reported.", + "HTML": "The HTML specification issues that cause accessibility issues may be covered by other rules and will be reported under those accessibility requirements. However, some non-conforming HTML specification issues are still reported.", + "ARIA": "The ARIA specification issues that cause accessibility issues may be covered by other rules and will be reported under those accessibility requirements. However, some non-conforming ARIA specification issues are still reported.", } export let a11yRulesets: Guideline[] = [ @@ -107,7 +108,7 @@ export let a11yRulesets: Guideline[] = [ id: "IBM_Accessibility", name: "IBM Accessibility 7.2", category: eGuidelineCategory.ACCESSIBILITY, - description: "Rules for WCAG 2.1 AA plus additional IBM checklist supplemental requirements.", + description: "Rules for WCAG 2.0 & 2.1 A and AA plus additional IBM supplemental requirements.", // This ruleset has all 2.0 and 2.1 checkpoints that are A or AA checkpoints: SCs .filter(sc => (sc.level === "A" || sc.level === "AA" || sc.level === "NA") && (sc.wcagType === "2.0" || sc.wcagType === "2.1" || sc.wcagType === "2.2" || sc.wcagType === "NA")) @@ -123,7 +124,7 @@ export let a11yRulesets: Guideline[] = [ id: "WCAG_2_2", name: "WCAG 2.2 (A, AA)", category: eGuidelineCategory.ACCESSIBILITY, - description: "Rules for WCAG 2.2 AA. This is the current W3C recommendation. Content that conforms to WCAG 2.2 also conforms to WCAG 2.1.", + description: "Rules for WCAG 2.2 A & AA. This is the current W3C recommendation (specification). Content that conforms to WCAG 2.2 also conforms to WCAG 2.1.", // This ruleset has all 2.0 and 2.1 checkpoints that are A or AA checkpoints: SCs .filter(sc => (sc.level === "A" || sc.level === "AA") && (sc.wcagType === "2.0" || sc.wcagType === "2.1" || sc.wcagType === "2.2")) @@ -139,7 +140,7 @@ export let a11yRulesets: Guideline[] = [ id: "WCAG_2_1", name: "WCAG 2.1 (A, AA)", category: eGuidelineCategory.ACCESSIBILITY, - description: "Rules for WCAG 2.1 AA. This is the current W3C recommendation. Content that conforms to WCAG 2.1 also conforms to WCAG 2.0.", + description: "Rules for WCAG 2.1 A & AA. This is the current W3C recommendation. Content that conforms to WCAG 2.1 also conforms to WCAG 2.0.", // This ruleset has all 2.0 and 2.1 checkpoints that are A or AA checkpoints: SCs .filter(sc => (sc.level === "A" || sc.level === "AA") && (sc.wcagType === "2.0" || sc.wcagType === "2.1")) @@ -155,7 +156,7 @@ export let a11yRulesets: Guideline[] = [ id: "WCAG_2_0", name: "WCAG 2.0 (A, AA)", category: eGuidelineCategory.ACCESSIBILITY, - description: "Rules for WCAG 2.0 AA. Referenced by US Section 508, but not the latest W3C recommendation.", + description: "Rules for WCAG 2.0 A & AA. Referenced by US Section 508, but not the latest W3C recommendation.", // This ruleset has all 2.0 checkpoints that are A or AA checkpoints: SCs .filter(sc => (sc.level === "A" || sc.level === "AA") && (sc.wcagType === "2.0")) diff --git a/accessibility-checker-engine/src/v4/sc-urls.json b/accessibility-checker-engine/src/v4/sc-urls.json index bd7be2f9d..a84f4603c 100644 --- a/accessibility-checker-engine/src/v4/sc-urls.json +++ b/accessibility-checker-engine/src/v4/sc-urls.json @@ -630,7 +630,7 @@ "scAltId": ["focus-not-obscured-minimum"], "test": "WCAG2:focus-not-obscured-minimum", "howToMeetUrl": "https://www.w3.org/TR/WCAG22/#focus-not-obscured-minimum", - "understandingUrl": "https://www.w3.org/TR/WCAG22/#focus-not-obscured-minimum", + "understandingUrl": "https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum.html", "handle": "Focus Not Obscured (Minimum)", "level": "AA", "wcagType": "2.2" @@ -955,7 +955,7 @@ "test": "", "howToMeetUrl": "https://html.spec.whatwg.org/multipage/", "understandingUrl": "https://html.spec.whatwg.org/multipage/", - "handle": "HTML Messages", + "handle": "specification", "level": "NA", "wcagType": "NA" }, @@ -967,8 +967,8 @@ "test": "", "howToMeetUrl": "https://w3c.github.io/aria/", "understandingUrl": "https://w3c.github.io/aria/", - "handle": "ARIA Messages", + "handle": "specification", "level": "NA", "wcagType": "NA" } - } \ No newline at end of file + } diff --git a/accessibility-checker/src-ts/lib/ACHelper.ts b/accessibility-checker/src-ts/lib/ACHelper.ts index ed57977be..ab1cd9ce3 100644 --- a/accessibility-checker/src-ts/lib/ACHelper.ts +++ b/accessibility-checker/src-ts/lib/ACHelper.ts @@ -287,7 +287,7 @@ cb(e); async function getComplianceHelperWebDriverIO(label, parsed, curPol) : Promise { - try { + try { const startScan = Date.now(); // NOTE: Engine should already be loaded const page = parsed; diff --git a/accessibility-checker/test/webdriverio/.achecker.yml b/accessibility-checker/test/webdriverio/.achecker.yml index 2d2a8c666..c4af7e443 100644 --- a/accessibility-checker/test/webdriverio/.achecker.yml +++ b/accessibility-checker/test/webdriverio/.achecker.yml @@ -13,6 +13,7 @@ ignoreHTTPSErrors: true # We are setting no policies because we want the unit test to run for all policies policies: - IBM_Accessibility + - WCAG_2_2 # optional - Specify one or many violation levels on which to fail the test # i.e. If specified violation then the testcase will only fail if diff --git a/accessibility-checker/test/webdriverio/test/specs/example.e2e.ts b/accessibility-checker/test/webdriverio/test/specs/example.e2e.ts index 25bc94fe9..0f317c2d8 100644 --- a/accessibility-checker/test/webdriverio/test/specs/example.e2e.ts +++ b/accessibility-checker/test/webdriverio/test/specs/example.e2e.ts @@ -134,10 +134,11 @@ describe("Rule Unit Tests from WebdriverIO", function () { legacyExpectedInfo: (typeof ((window as any).OpenAjax) !== 'undefined' && (window as any).OpenAjax && (window as any).OpenAjax.a11y && (window as any).OpenAjax.a11y.ruleCoverage), expectedInfo: (typeof ((window as any).UnitTest) !== 'undefined' && (window as any).UnitTest) })); - + // Extract the ruleCoverage object from the unit testcases that is loaded on to the iframe. let expectedInfo = unitTestInfo.expectedInfo; let legacyExpectedInfo = unitTestInfo.legacyExpectedInfo; + if (expectedInfo && expectedInfo.ruleIds) { let filtReport = []; for (const issue of report.results) { @@ -164,7 +165,7 @@ describe("Rule Unit Tests from WebdriverIO", function () { if (pc !== 0) return pc; return b.ruleId.localeCompare(a.ruleId); }) - // console.log(expectedInfo.results); + expect(filtReport).toEqual(expectedInfo.results); } else if (legacyExpectedInfo) { let expectedInfo = {}