Skip to content
Snippets Groups Projects
Commit 4f3b04f8 authored by David Sveningsson's avatar David Sveningsson
Browse files

feat: new rule `aria-hidden-body`

parent 8ed7c007
No related branches found
No related tags found
Loading
Pipeline #457204214 passed
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs/rules/aria-hidden-body.md inline validation: correct 1`] = `Array []`;
exports[`docs/rules/aria-hidden-body.md inline validation: incorrect 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 7,
"context": undefined,
"line": 1,
"message": "aria-hidden must not be used on <body>",
"offset": 6,
"ruleId": "aria-hidden-body",
"ruleUrl": "https://html-validate.org/rules/aria-hidden-body.html",
"selector": "body",
"severity": 2,
"size": 11,
},
],
"source": "<body aria-hidden=\\"true\\"></body>",
"warningCount": 0,
},
]
`;
import HtmlValidate from "../../../src/htmlvalidate";
const markup: { [key: string]: string } = {};
markup["incorrect"] = `<body aria-hidden="true"></body>`;
markup["correct"] = `<body></body>`;
describe("docs/rules/aria-hidden-body.md", () => {
it("inline validation: incorrect", () => {
expect.assertions(1);
const htmlvalidate = new HtmlValidate({"rules":{"aria-hidden-body":"error"}});
const report = htmlvalidate.validateString(markup["incorrect"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: correct", () => {
expect.assertions(1);
const htmlvalidate = new HtmlValidate({"rules":{"aria-hidden-body":"error"}});
const report = htmlvalidate.validateString(markup["correct"]);
expect(report.results).toMatchSnapshot();
});
});
---
docType: rule
name: aria-hidden-body
category: a17y
summary: requires `aria-hidden` not to be used on `<body>`
---
# Attribute name case (`aria-hidden-body`)
Requires `aria-hidden` is not used on the `<body>` element.
## Rule details
Examples of **incorrect** code for this rule:
<validate name="incorrect" rules="aria-hidden-body">
<body aria-hidden="true"></body>
</validate>
Examples of **correct** code for this rule:
<validate name="correct" rules="aria-hidden-body">
<body></body>
</validate>
## Options
This rule takes no options.
## Version history
-- %version% - Rule added.
......@@ -2,6 +2,7 @@ import { ConfigData } from "../config-data";
const config: ConfigData = {
rules: {
"aria-hidden-body": "error",
"aria-label-misuse": "error",
"deprecated-rule": "warn",
"empty-heading": "error",
......
......@@ -2,6 +2,7 @@ import { ConfigData } from "../config-data";
const config: ConfigData = {
rules: {
"aria-hidden-body": "error",
"aria-label-misuse": "error",
"attr-case": "error",
"attr-delimiter": "error",
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`rule attr-case should contain documentation 1`] = `
Object {
"description": "\`aria-hidden\` must not be used on the \`<body>\` element as it makes the page inaccessible to assistive technology such as screenreaders",
"url": "https://html-validate.org/rules/aria-hidden-body.html",
}
`;
import HtmlValidate from "../htmlvalidate";
import "../jest";
import { processAttribute } from "../transform/mocks/attribute";
describe("rule attr-case", () => {
let htmlvalidate: HtmlValidate;
beforeAll(() => {
htmlvalidate = new HtmlValidate({
root: true,
rules: { "aria-hidden-body": "error" },
});
});
it("should not report error for other elements", () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<div aria-hidden="true"></div>');
expect(report).toBeValid();
});
it("should not report error when body is missing aria-hidden attribute", () => {
expect.assertions(1);
const report = htmlvalidate.validateString("<body></body>");
expect(report).toBeValid();
});
it("should not report error when body is missing aria-hidden value", () => {
expect.assertions(1);
const report = htmlvalidate.validateString("<body aria-hidden></div>");
expect(report).toBeValid();
});
it("should not report error when body has invalid aria-hidden value", () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<body aria-hidden="foobar">');
expect(report).toBeValid();
});
it('should not report error when body has aria-hidden="false"', () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<body aria-hidden="false"></body>');
expect(report).toBeValid();
});
it('should report error when body has aria-hidden="true"', () => {
expect.assertions(2);
const report = htmlvalidate.validateString('<body aria-hidden="true"></body>');
expect(report).toBeInvalid();
expect(report).toHaveError("aria-hidden-body", "aria-hidden must not be used on <body>");
});
it("should report error when body has dynamic aria-hidden value", () => {
expect.assertions(2);
const report = htmlvalidate.validateString('<body dynamic-aria-hidden="foo"></body>', {
processAttribute,
});
expect(report).toBeInvalid();
expect(report).toHaveError("aria-hidden-body", "aria-hidden must not be used on <body>");
});
it("should contain documentation", () => {
expect.assertions(1);
expect(htmlvalidate.getRuleDocumentation("aria-hidden-body")).toMatchSnapshot();
});
});
import { TagReadyEvent } from "../event";
import { Rule, RuleDocumentation, ruleDocumentationUrl } from "../rule";
export default class AriaHiddenBody extends Rule {
public documentation(): RuleDocumentation {
return {
description:
"`aria-hidden` must not be used on the `<body>` element as it makes the page inaccessible to assistive technology such as screenreaders",
url: ruleDocumentationUrl(__filename),
};
}
public setup(): void {
this.on("tag:ready", this.isRelevant, (event: TagReadyEvent) => {
const { target } = event;
const attr = target.getAttribute("aria-hidden");
if (!attr || !attr.valueMatches("true", true)) {
return;
}
this.report(target, "aria-hidden must not be used on <body>", attr.keyLocation);
});
}
protected isRelevant(event: TagReadyEvent): boolean {
return event.target.is("body");
}
}
import { RuleConstructor } from "../rule";
import AllowedLinks from "./allowed-links";
import AriaHiddenBody from "./aria-hidden-body";
import AriaLabelMisuse from "./aria-label-misuse";
import AttrCase from "./attr-case";
import AttrDelimiter from "./attr-delimiter";
......@@ -67,6 +68,7 @@ import WCAG from "./wcag";
const bundledRules: Record<string, RuleConstructor<any, any>> = {
"allowed-links": AllowedLinks,
"aria-hidden-body": AriaHiddenBody,
"aria-label-misuse": AriaLabelMisuse,
"attr-case": AttrCase,
"attr-delimiter": AttrDelimiter,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment