bbc-a11y 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/README.md +9 -11
  4. data/Rakefile +2 -2
  5. data/a11y.rb +5 -0
  6. data/bbc-a11y.gemspec +3 -5
  7. data/bin/a11y +2 -2
  8. data/examples/bbc-pages/a11y.rb +2 -6
  9. data/examples/local-web-app/Gemfile +1 -1
  10. data/examples/local-web-app/a11y.rb +10 -22
  11. data/features/check_standards/focusable_controls.feature +62 -0
  12. data/features/check_standards/form_interactions.feature +45 -0
  13. data/features/check_standards/form_labels.feature +55 -0
  14. data/features/check_standards/headings.feature +154 -0
  15. data/features/check_standards/image_alt.feature +39 -0
  16. data/features/check_standards/language.feature +46 -0
  17. data/features/check_standards/main_landmark.feature +39 -0
  18. data/features/check_standards/tab_index.feature +54 -0
  19. data/features/cli/display_failing_result.feature +10 -0
  20. data/features/{exit_status.feature → cli/exit_status.feature} +1 -2
  21. data/features/cli/provide_muting_tips.feature +25 -0
  22. data/features/cli/report_configuration_errors.feature +43 -0
  23. data/features/cli/skipping_standards.feature +15 -0
  24. data/features/cli/specify_url.feature +9 -0
  25. data/features/cli/specify_url_via_config.feature +13 -0
  26. data/features/mute_errors.feature +118 -0
  27. data/features/step_definitions/steps.rb +25 -1
  28. data/lib/bbc/a11y/cli.rb +32 -44
  29. data/lib/bbc/a11y/configuration.rb +56 -22
  30. data/lib/bbc/a11y/linter.rb +42 -0
  31. data/lib/bbc/a11y/standards.rb +43 -0
  32. data/lib/bbc/a11y/standards/anchor_hrefs.rb +18 -0
  33. data/lib/bbc/a11y/standards/content_follows_headings.rb +22 -0
  34. data/lib/bbc/a11y/standards/exactly_one_main_heading.rb +20 -0
  35. data/lib/bbc/a11y/standards/exactly_one_main_landmark.rb +20 -0
  36. data/lib/bbc/a11y/standards/form_labels.rb +39 -0
  37. data/lib/bbc/a11y/standards/form_submit_buttons.rb +21 -0
  38. data/lib/bbc/a11y/standards/heading_hierarchy.rb +34 -0
  39. data/lib/bbc/a11y/standards/image_alt.rb +18 -0
  40. data/lib/bbc/a11y/standards/language_attribute.rb +19 -0
  41. data/lib/bbc/a11y/standards/tab_index.rb +22 -0
  42. data/lib/bbc/a11y/version +1 -1
  43. data/spec/bbc/a11y/cli_spec.rb +22 -15
  44. data/spec/bbc/a11y/configuration_spec.rb +15 -40
  45. data/standards/support/capybara.rb +1 -2
  46. metadata +62 -81
  47. data/features/specify_url_via_cli.feature +0 -10
  48. data/features/specify_url_via_config.feature +0 -16
  49. data/lib/bbc/a11y.rb +0 -17
  50. data/lib/bbc/a11y/cucumber_runner.rb +0 -208
  51. data/lib/bbc/a11y/cucumber_support.rb +0 -56
  52. data/lib/bbc/a11y/cucumber_support/disabled_w3c.rb +0 -37
  53. data/lib/bbc/a11y/cucumber_support/heading_hierarchy.rb +0 -94
  54. data/lib/bbc/a11y/cucumber_support/language_detector.rb +0 -26
  55. data/lib/bbc/a11y/cucumber_support/matchers.rb +0 -21
  56. data/lib/bbc/a11y/cucumber_support/page.rb +0 -94
  57. data/lib/bbc/a11y/cucumber_support/per_page_checks.rb +0 -28
  58. data/lib/bbc/a11y/cucumber_support/w3c.rb +0 -36
  59. data/spec/bbc/a11y/cucumber_support/heading_hierarchy_spec.rb +0 -162
  60. data/spec/bbc/a11y/cucumber_support/matchers_spec.rb +0 -52
  61. data/spec/bbc/a11y/cucumber_support/page_spec.rb +0 -197
@@ -0,0 +1,39 @@
1
+ Feature: Image alternative content
2
+
3
+ All images **must** have an alt attribute.
4
+
5
+ All editorial significant images **must** have a non-null alt attribute value,
6
+ or a text alternative in the preceding or following content.
7
+
8
+ Rationale
9
+ =========
10
+
11
+ Assistive technologies such as screen readers will provide a text alternative
12
+ for images that do not have alt attributes based on the image file name. For
13
+ images that do not have editorial significance or are described in the
14
+ surrounding text content it is appropriate to use a null (alt="") value for
15
+ the image alt attribute to avoid this.
16
+
17
+ All editorially significantly images must have a text alternative either as
18
+ the value of the alt attribute or in the immediately surrounding text content.
19
+
20
+ Scenario: Images with alt attributes
21
+ Given a page with the HTML:
22
+ """
23
+ <img src="a.jpeg" alt="A picture of something" />
24
+ <img src="b.jpeg" alt="" />
25
+ """
26
+ When I validate the image alt standards
27
+ Then it passes
28
+
29
+ Scenario: Images without alt attributes
30
+ Given a page with the HTML:
31
+ """
32
+ <img src="a.jpeg" alt="A picture of something" />
33
+ <img src="b.jpeg" />
34
+ """
35
+ When I validate the image alt standards
36
+ Then it fails with the message:
37
+ """
38
+ Image has no alt attribute (src="b.jpeg")
39
+ """
@@ -0,0 +1,46 @@
1
+ Feature: Specify content language
2
+
3
+ The main language of the page **must** be specified.
4
+
5
+ Changes to language within the page **must** be indicated.
6
+
7
+ Rationale
8
+ =========
9
+
10
+ Assistive technologies such as screen readers have support for different languages,
11
+ allowing for appropriate pronunciation.
12
+
13
+ Scenario: lang attribute on html element
14
+ Given a page with the HTML:
15
+ """
16
+ <!DOCTYPE html>
17
+ <html lang="en-GB">
18
+ <head>
19
+ <title>Language specified</title>
20
+ </head>
21
+ <body>
22
+ <h1>The language is specified</h1>
23
+ </body>
24
+ </html>
25
+ """
26
+ When I validate the language attribute standards
27
+ Then it passes
28
+
29
+ Scenario: Missing lang attribute on html element
30
+ Given a page with the HTML:
31
+ """
32
+ <!DOCTYPE html>
33
+ <html>
34
+ <head>
35
+ <title>Language missing</title>
36
+ </head>
37
+ <body>
38
+ <h1>The language is missing</h1>
39
+ </body>
40
+ </html>
41
+ """
42
+ When I validate the language attribute standards
43
+ Then it fails with the message:
44
+ """
45
+ The main language must be specified. <html> tag has no lang attribute.
46
+ """
@@ -0,0 +1,39 @@
1
+ Feature: Main landmark
2
+
3
+ A page **must** have exactly one element with `role="main"`
4
+
5
+ Rationale
6
+ =========
7
+
8
+ The WAI-ARIA `main` landmark role can be help keyboard users with assistive technologies such as screen readers (and in the future as native browser functionality) to skip directly to the main content of a page, bypassing navigation and other contents that might be before it.
9
+
10
+ Scenario: Page has a single main element
11
+ Given a page with the HTML:
12
+ """
13
+ <div role="main">Main element</div>
14
+ """
15
+ When I validate the landmark standards
16
+ Then it passes
17
+
18
+ Scenario: Page has two main elements
19
+ Given a page with the HTML:
20
+ """
21
+ <div role="main">Main one</div>
22
+ <div role="main">Main two</div>
23
+ """
24
+ When I validate the landmark standards
25
+ Then it fails with the message:
26
+ """
27
+ A document must have exactly one main landmark. Found 2 elements with role="main".
28
+ """
29
+
30
+ Scenario: Page has zero main elements
31
+ Given a page with the HTML:
32
+ """
33
+ <div role="not-main">Main one</div>
34
+ """
35
+ When I validate the landmark standards
36
+ Then it fails with the message:
37
+ """
38
+ A document must have exactly one main landmark. Found 0 elements with role="main".
39
+ """
@@ -0,0 +1,54 @@
1
+ Feature: Correctly use `tabindex` attributes
2
+
3
+ Positive `tabindex` attribute values **must not** be used to create a logical tab order.
4
+
5
+ `tabindex` values of `0` **must not** be used on elements that are not focusable by default.
6
+
7
+ Rationale
8
+ =========
9
+
10
+ Typical BBC pages are made up of several shared components (Global navigation, page content, share tools,
11
+ location service widgets, etc.) so no one piece of code has complete awareness of the content of the page
12
+ or when the content updates. Positive `tabindex` values results in unpredictable tab order that do not occur
13
+ if the natural order of content is relied upon.
14
+
15
+ Using `tabindex="0"` on an element adds it to the document tab order, however it does not change the element
16
+ type to allow it to be discovered by navigating by link or form element, nor does it bind click and key press
17
+ handlers to the element. There are no circumstances in which it is not better to use a natively focusable
18
+ control such as a `<a>` or `<button>`.
19
+
20
+ Scenario: Element with negative tab index
21
+ Given a page with the HTML:
22
+ """
23
+ <a href="/news">News</a>
24
+ <button type="submit">Search</button>
25
+ <div tabindex="-1"></div>
26
+ """
27
+ When I validate the tab index standards
28
+ Then it passes
29
+
30
+ Scenario: Focusable elements with zero tab index
31
+ Given a page with the HTML:
32
+ """
33
+ <a href="/news" tabindex="0">News</a>
34
+ <button tabindex="0">Search</button>
35
+ <input type="submit" tabindex="0" value="Submit" />
36
+ <select tabindex="0"></select>
37
+ <textarea tabindex="0"></textarea>
38
+ """
39
+ When I validate the tab index standards
40
+ Then it passes
41
+
42
+ Scenario: Unfocusable element with zero tab index
43
+ Given a page with the HTML:
44
+ """
45
+ <a href="/news" tabindex="1">News</a>
46
+ <button type="submit" tabindex="2">Search</button>
47
+ <div tabindex="3"></div>
48
+ <div tabindex="0"></div>
49
+ """
50
+ When I validate the tab index standards
51
+ Then it fails with the message:
52
+ """
53
+ tabindex="0" must not be used on <div> elements (not focusable by default)
54
+ """
@@ -0,0 +1,10 @@
1
+ Feature: Display failing result
2
+
3
+ Scenario: One standard fails
4
+ Given a website running at http://localhost:54321
5
+ When I run `a11y http://localhost:54321/missing_header.html`
6
+ Then it should fail with exactly:
7
+ """
8
+ ✗ http://localhost:54321/missing_header.html
9
+ - A document must have exactly one heading. Found 0 h1 elements.
10
+ """
@@ -1,4 +1,3 @@
1
- @wip
2
1
  Feature: Exit status
3
2
 
4
3
  For CI, we need to make sure the process exits with a non-zero
@@ -9,6 +8,6 @@ Feature: Exit status
9
8
  Then the exit status should be 0
10
9
 
11
10
  Scenario: Failing test
12
- Given a standards-compliant website running at http://localhost:54321
11
+ Given a website running at http://localhost:54321
13
12
  When I run `a11y http://localhost:54321/missing_header.html`
14
13
  Then the exit status should be 1
@@ -0,0 +1,25 @@
1
+ Feature: Provide muting tips
2
+
3
+ To make it easy to configure mute rules, when you see failures, you'll also
4
+ see some JSON snippets that suggest how to add configuration to mute the
5
+ warning.
6
+
7
+ Scenario: Generate a warning where there are several bad elements
8
+ Given a page with the HTML:
9
+ """
10
+ <div id="my-amazing-code">
11
+ <h1>I am wonderfull</h1>
12
+ </div>
13
+ <h1>Bad stuff here. Ignore me.</h1>
14
+ """
15
+ When I validate the exactly one main heading standard, with muting hints enabled
16
+ Then it fails with the message:
17
+ """
18
+ To mute these errors, add the following configuration:
19
+
20
+ {
21
+ "mute": [
22
+ "exactly-one-main-heading"
23
+ ]
24
+ }
25
+ """
@@ -0,0 +1,43 @@
1
+ Feature: Report configuration errors
2
+
3
+ Scenario: Call an unknown keyword in the configuration file
4
+ Given a file named "a11y.rb" with:
5
+ """
6
+ page "one"
7
+ page "two"
8
+ paage "http://bad.com"
9
+ page "three"
10
+ page "four"
11
+ """
12
+ When I run `a11y`
13
+ Then it should fail with exactly:
14
+ """
15
+ There was an error reading your configuration file at line 3 of 'a11y.rb'
16
+
17
+ page "two"
18
+ => paage "http://bad.com"
19
+ page "three"
20
+
21
+ `paage` is not part of the configuration language
22
+
23
+ For help learning the configuration DSL, please visit https://github.com/cucumber-ltd/bbc-a11y
24
+
25
+ """
26
+
27
+ Scenario: Compilation error in configuration file
28
+ Given a file named "a11y.rb" with:
29
+ """
30
+ 1/0
31
+ """
32
+ When I run `a11y`
33
+ Then it should fail with exactly:
34
+ """
35
+ There was an error reading your configuration file at line 1 of 'a11y.rb'
36
+
37
+ => 1/0
38
+
39
+ divided by 0
40
+
41
+ For help learning the configuration DSL, please visit https://github.com/cucumber-ltd/bbc-a11y
42
+
43
+ """
@@ -0,0 +1,15 @@
1
+ Feature: Skipping Standards
2
+
3
+ Scenario: One standard is skipped
4
+ Given a website running at http://localhost:54321
5
+ And a file named "a11y.rb" with:
6
+ """
7
+ page "http://localhost:54321/missing_header.html" do
8
+ skip_standard /head/i
9
+ end
10
+ """
11
+ When I run `a11y`
12
+ Then it should pass with:
13
+ """
14
+ ✓ http://localhost:54321/missing_header.html
15
+ """
@@ -0,0 +1,9 @@
1
+ Feature: Specify URL
2
+
3
+ Scenario: No config, just pass page URL on command-line
4
+ Given a website running at http://localhost:54321
5
+ When I run `a11y http://localhost:54321/perfect.html`
6
+ Then it should pass with exactly:
7
+ """
8
+ ✓ http://localhost:54321/perfect.html
9
+ """
@@ -0,0 +1,13 @@
1
+ Feature: Specify URL via config
2
+
3
+ Scenario: Specify a single page
4
+ Given a website running at http://localhost:54321
5
+ And a file named "a11y.rb" with:
6
+ """
7
+ page "http://localhost:54321/perfect.html"
8
+ """
9
+ When I run `a11y`
10
+ Then it should pass with:
11
+ """
12
+ ✓ http://localhost:54321/perfect.html
13
+ """
@@ -0,0 +1,118 @@
1
+ Feature: Mute errors
2
+
3
+ Things like ORB and Barlesque that we don't control will clutter up our pages
4
+ with violations.
5
+
6
+ We need a way to ignore the errors generated by these areas of the page so
7
+ we can focus on the problems that we can actually fix.
8
+
9
+ Rules:
10
+
11
+ - exclude any errors that match the filtering rules
12
+
13
+ Scenario: Mute an error with no specific elements in it
14
+
15
+ Where the standard (e.g. exactly one main heading standard) applies to the
16
+ whole page, we still report an error even when we have an ignore rule.
17
+
18
+ Given a page with no h1s
19
+ And an ignore rule for a region of the page
20
+ When I validate the exactly one main heading standard
21
+ Then it fails with the message:
22
+ """
23
+ A document must have exactly one heading. Found 0 h1 elements.
24
+ """
25
+
26
+ Scenario: Mute an error that mentions just one HTML element
27
+
28
+ Scenario: Mute an error that mentions one or more elements
29
+ Given a page with the HTML:
30
+ """
31
+ <div id="dodgy-legacy-banner">
32
+ <h1>I am a legacy</h1>
33
+ </div>
34
+ <h1>The real heading</h1>
35
+ """
36
+ When I validate the exactly one main heading standard
37
+ Then it fails with the message:
38
+ """
39
+ A document must have exactly one heading. Found 2 h1 elements:
40
+ /html/body/div/h1
41
+ /html/body/h1
42
+ """
43
+ When I add a configuration with:
44
+ """
45
+ mute: [
46
+ {
47
+ standard: "exactly-one-main-heading",
48
+ css: "#dodgy-legacy-banner h1"
49
+ }
50
+ ]
51
+ """
52
+ And I validate the exactly one main heading standard
53
+ Then it passes
54
+
55
+ Scenario: Mute an error about one bad element, but still see other similar problems on the page
56
+ Given a page with the HTML:
57
+ """
58
+ <div id="dodgy-legacy-banner">
59
+ <h1>I am a legacy</h1>
60
+ </div>
61
+ <h1>The real heading</h1>
62
+ <h1>Team, fix me</h1>
63
+ """
64
+ When I validate the exactly one main heading standard
65
+ Then it fails with the message:
66
+ """
67
+ A document must have exactly one heading. Found 3 h1 elements:
68
+ /html/body/div/h1
69
+ /html/body/h1[1]
70
+ /html/body/h1[2]
71
+ """
72
+ When I add a configuration with:
73
+ """
74
+ mute: [
75
+ {
76
+ standard: "exactly-one-main-heading",
77
+ css: "#dodgy-legacy-banner h1"
78
+ }
79
+ ]
80
+ """
81
+ When I validate the exactly one main heading standard
82
+ Then it fails with the message:
83
+ """
84
+ A document must have exactly one heading. Found 2 h1 elements:
85
+ /html/body/h1[1]
86
+ /html/body/h1[2]
87
+ """
88
+
89
+ Scenario: Mute an error about one bad element, but still see other similar problems on the page
90
+ Given a page with the HTML:
91
+ """
92
+ <div id="legacy">
93
+ <input type="text" name="txtName"/>
94
+ </div>
95
+ <input type="text" name="name"/>
96
+ """
97
+ When I validate the form labels standards
98
+ Then it fails with the message:
99
+ """
100
+ Field has no label or title attribute:
101
+ /html/body/div/input
102
+ /html/body/input
103
+ """
104
+ When I add a configuration with:
105
+ """
106
+ mute: [
107
+ {
108
+ standard: "form-labels",
109
+ css: "#legacy input"
110
+ }
111
+ ]
112
+ """
113
+ When I validate the form labels standard
114
+ Then it fails with the message:
115
+ """
116
+ Field has no label or title attribute:
117
+ /html/body/input
118
+ """
@@ -1,4 +1,8 @@
1
- Given(/^a standards-compliant website running at http:\/\/localhost:(\d+)$/) do |port|
1
+ require 'capybara'
2
+ require 'bbc/a11y/linter'
3
+ require 'bbc/a11y/standards'
4
+
5
+ Given(/^a website running at http:\/\/localhost:(\d+)$/) do |port|
2
6
  WebServer.ensure_running_on(port)
3
7
  end
4
8
 
@@ -11,3 +15,23 @@ Given(/^one test fails$/) do
11
15
  WebServer.ensure_running_on(54321)
12
16
  step "I run `a11y http://localhost:54321/missing_header.html`"
13
17
  end
18
+
19
+ Given(/^a page with the HTML:$/) do |string|
20
+ @page = Capybara.string(string.to_s)
21
+ end
22
+
23
+ When(/^I validate the (.+) standards$/) do |pattern|
24
+ regexp = Regexp.new(pattern.gsub(' ', ''), Regexp::IGNORECASE)
25
+ standards = BBC::A11y::Standards.matching regexp
26
+ raise "No standards match '#{pattern}'" unless standards.any?
27
+ @result = BBC::A11y::Linter.new(@page, standards).run
28
+ end
29
+
30
+ Then(/^it passes$/) do
31
+ expect(@result).to be_passed
32
+ end
33
+
34
+ Then(/^it fails with the message:$/) do |message|
35
+ expect(@result).to be_failed
36
+ expect(@result.to_s).to eq message.to_s
37
+ end