Skip to content

Commit

Permalink
chore(rules): add missing heading identifers
Browse files Browse the repository at this point in the history
  • Loading branch information
j-mendez committed Oct 12, 2023
1 parent 6332e10 commit 4798dcf
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 27 deletions.
1 change: 1 addition & 0 deletions RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ List of techniques we want to have and whether we have it handled or not for WCA
| [H32](https://www.w3.org/TR/WCAG20-TECHS/H32.html) | missing form submit button | error ||
| [H36](https://www.w3.org/TR/WCAG20-TECHS/H36.html) | missing form img alt | error ||
| [H37](https://www.w3.org/TR/WCAG20-TECHS/H37.html) | missing img alt | error ||
| [H42](https://www.w3.org/TR/WCAG20-TECHS/H42.html) | heading found with no content | error ||
| [H57](https://www.w3.org/TR/WCAG20-TECHS/H57.html) | html contains valid lang | error ||
| [H64](https://www.w3.org/TR/WCAG20-TECHS/H64.html) | iframe missing title | error ||
| [F40](https://www.w3.org/TR/WCAG20-TECHS/F40.html) | meta redirect used with a time limit | error ||
Expand Down
3 changes: 3 additions & 0 deletions accessibility-rs/src/engine/rules/techniques.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub enum Techniques {
H36,
/// <https://www.w3.org/TR/WCAG20-TECHS/H37>
H37,
/// <https://www.w3.org/TR/WCAG20-TECHS/H42>
H42,
/// <https://www.w3.org/TR/WCAG20-TECHS/H57>
H57,
/// <https://www.w3.org/TR/WCAG20-TECHS/H64>
Expand All @@ -39,6 +41,7 @@ impl Techniques {
Techniques::H32 => vec!["H32.2"],
Techniques::H36 => vec!["H36"],
Techniques::H37 => vec!["H37"],
Techniques::H42 => vec!["H42.2"],
Techniques::H57 => vec!["H57.2", "H57.3.Lang", "H57.3.XmlLang"],
Techniques::H64 => vec!["H64.1", "H64.2"],
Techniques::F40 => vec!["F40.2"],
Expand Down
4 changes: 4 additions & 0 deletions accessibility-rs/src/engine/rules/wcag_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,16 @@ pub enum Guideline {
Predictable,
/// Provide users enough time to read and use content.
EnoughTime,
/// Create content that can be presented in different ways (for example simpler layout) without losing information or structure.
Adaptable,
}

impl Guideline {
/// the guideline to string code
pub fn as_str(&self) -> &'static str {
match self {
Guideline::TextAlternatives => "Guideline1_1",
Guideline::Adaptable => "Guideline1_3",
Guideline::EnoughTime => "Guideline2_2",
Guideline::Navigable => "Guideline2_4",
Guideline::Readable => "Guideline3_1",
Expand All @@ -84,6 +87,7 @@ impl Guideline {
pub fn as_index(&self) -> &'static str {
match self {
Guideline::TextAlternatives => "1_1",
Guideline::Adaptable => "1_3",
Guideline::EnoughTime => "2_2",
Guideline::Navigable => "2_4",
Guideline::Readable => "3_1",
Expand Down
71 changes: 44 additions & 27 deletions accessibility-rs/src/engine/rules/wcag_rule_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::engine::rules::techniques::Techniques;
use crate::engine::rules::wcag_base::{Criteria, Guideline, Principle};
use crate::ElementRef;
use accessibility_scraper::Selector;
use slotmap::DefaultKey;
use std::collections::BTreeMap;

/// a valid alt attribute for image
Expand All @@ -23,6 +24,16 @@ fn has_alt(ele: ElementRef<'_>) -> bool {
valid
}

/// elements empty
fn is_empty(nodes: &Vec<(ElementRef<'_>, Option<DefaultKey>)>) -> bool {
let mut empty = false;
for ele in nodes {
let ele = ele.0;
empty = ele.inner_html().trim().is_empty();
}
empty
}

// todo: validate each element and add a shape that can prevent repitiion
lazy_static! {
/// a list of rules that should be applied for WCAG1
Expand Down Expand Up @@ -129,30 +140,17 @@ lazy_static! {
])),
("a", Vec::from([
Rule::new(Techniques::H30, Criteria::Error, Principle::Perceivable, Guideline::TextAlternatives, |_rule, nodes| {
// todo: use tree to see if img exist to skip
let mut valid = true;
let selector = unsafe { Selector::parse("img").unwrap_unchecked() };
// todo: use tree to see if img exist to skip

for ele in nodes {
let ele = ele.0;
let mut elements = ele.select(&selector);

while let Some(el) = elements.next() {
// allow checking for role presentation not supported as wide as empty alt
match el.attr("role") {
Some(role) => {
if role == "presentation" {
continue;
}
}
_ => ()
};
match el.attr("alt") {
Some(_) => (),
_ => valid = false
}
valid = has_alt(el);
}

}

Validation::new_issue(valid, "2")
Expand All @@ -164,22 +162,41 @@ lazy_static! {

for ele in nodes {
let ele = ele.0;
match ele.attr("role") {
Some(role) => {
if role == "presentation" {
continue;
}
}
_ => ()
};
match ele.attr("alt") {
Some(_) => (),
_ => valid = false
}
valid = has_alt(ele);
}

Validation::new_issue(valid, Techniques::H37.pairs()[0])
}),
])),
("h1", Vec::from([
Rule::new(Techniques::H42, Criteria::Error, Principle::Perceivable, Guideline::Adaptable, |_rule, nodes| {
Validation::new_issue(!is_empty(nodes), Techniques::H42.pairs()[0])
}),
])),
("h2", Vec::from([
Rule::new(Techniques::H42, Criteria::Error, Principle::Perceivable, Guideline::Adaptable, |_rule, nodes| {
Validation::new_issue(!is_empty(nodes), Techniques::H42.pairs()[0])
}),
])),
("h3", Vec::from([
Rule::new(Techniques::H42, Criteria::Error, Principle::Perceivable, Guideline::Adaptable, |_rule, nodes| {
Validation::new_issue(!is_empty(nodes), Techniques::H42.pairs()[0])
}),
])),
("h4", Vec::from([
Rule::new(Techniques::H42, Criteria::Error, Principle::Perceivable, Guideline::Adaptable, |_rule, nodes| {
Validation::new_issue(!is_empty(nodes), Techniques::H42.pairs()[0])
}),
])),
("h5", Vec::from([
Rule::new(Techniques::H42, Criteria::Error, Principle::Perceivable, Guideline::Adaptable, |_rule, nodes| {
Validation::new_issue(!is_empty(nodes), Techniques::H42.pairs()[0])
}),
])),
("h6", Vec::from([
Rule::new(Techniques::H42, Criteria::Error, Principle::Perceivable, Guideline::Adaptable, |_rule, nodes| {
Validation::new_issue(!is_empty(nodes), Techniques::H42.pairs()[0])
}),
]))
]
.into_iter()
Expand Down
94 changes: 94 additions & 0 deletions accessibility-rs/tests/unit/heading.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! Test for headings.
use accessibility_rs::AuditConfig;

#[test]
/// empty headings
fn _audit_headings_empty() {
let audit = accessibility_rs::audit(AuditConfig::basic(
r###"<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>Valid headings</title>
</head>
<body>
<h1>Plant Foods that Humans Eat</h1>
<p>There are an abundant number of plants that humans eat...</p>
<h2>Fruit</h2>
<p> A fruit is a structure of a plant that contains its
seeds...</p>
<h3>Apple</h3>
<p>The apple is the pomaceous fruit of the apple tree...</p>
<h3>Orange</h3>
<p>The orange is a hybrid of ancient cultivated origin...</p>
<h3>Banana</h3>
<p>Banana is the common name for herbaceous plants ...</p>
<h2>Vegetables</h2>
<p>A vegetable is an edible plant or part of a plant other than a
sweet fruit ...</p>
<h3>Broccoli</h3>
<p>Broccoli is a plant of the mustard/cabbage family ... </p>
<h3>Brussels sprouts</h3>
<p>The Brussels sprout of the Brassicaceae family, is a Cultivar
group of wild cabbage ...</p>
<h3>Green beans</h3>
<p>Green beans have been bred for the fleshiness, flavor, or
sweetness of their pods...</p>
</body>
</html>"###,
));
let mut valid = true;

for x in &audit {
if x.code == "WCAGAAA.Principle1.Guideline1_3.H42" {
valid = false;
break;
}
}

assert_eq!(valid, true);

let audit = accessibility_rs::audit(AuditConfig::basic(
r###"<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>Do not use missing Headings.</title>
</head>
<body>
<h1> </h1>
<p>There are an abundant number of plants that humans eat...</p>
<h2> </h2>
<p> A fruit is a structure of a plant that contains its
seeds...</p>
<h3> </h3>
<p>The apple is the pomaceous fruit of the apple tree...</p>
<h3></h3>
<p>The orange is a hybrid of ancient cultivated origin...</p>
<h3> </h3>
<p>Banana is the common name for herbaceous plants ...</p>
<h2> </h2>
<p>A vegetable is an edible plant or part of a plant other than a
sweet fruit ...</p>
<h3> </h3>
<p>Broccoli is a plant of the mustard/cabbage family ... </p>
<h3></h3>
<p>The Brussels sprout of the Brassicaceae family, is a Cultivar
group of wild cabbage ...</p>
<h3> </h3>
<p>Green beans have been bred for the fleshiness, flavor, or
sweetness of their pods...</p>
<h4> </h4>
<h5> </h5>
<h6> </h6>
</body>
</html>"###,
));
let mut valid = true;

for x in &audit {
if x.code == "WCAGAAA.Principle1.Guideline1_3.H42" {
valid = false;
break;
}
}

assert_eq!(valid, false)
}
1 change: 1 addition & 0 deletions accessibility-rs/tests/unit/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod anchor;
pub mod heading;
pub mod img;
pub mod meta;

0 comments on commit 4798dcf

Please sign in to comment.