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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d8df36f88dadb635f0d2de52661d26fcce169ecf
4
- data.tar.gz: 9260e8f08cf9846a400900516cf63c8fe789920b
3
+ metadata.gz: 10a369a2db0ae8f7e5b16e92a0f57e12ac3343be
4
+ data.tar.gz: 1b733f1a53afad2c0d200f801ec95ff6ed2ed7c1
5
5
  SHA512:
6
- metadata.gz: b580f97a7dc87d151d4693e259d62b050b4d5c087ff6d485a390daad502f04ef82aabfc648a95c2b941774c2a0dc35348ca89c0759ec578114fe64838b68c800
7
- data.tar.gz: 39ee8ec689f4bae55ab38261388f2a0e672ffe1f78815eb6cddd0a4acc792240a1783db15dd93a97732105f1446cdb579c39940b93958cf67bb0b863f3505e01
6
+ metadata.gz: 79571febea89695f33ae26639f47567dec98e73bed577c5ade2559db0b3235db15c3ec6245c5a6878598eda8f5ef163dd67b8c0df61603fb15c3ffe6779bd8db
7
+ data.tar.gz: de1ff17432e5fe20a0e67572fdbb0b973ff835d86620a12b7f3e63abe28ecb557ec7e7e824c488832c5cad9f19ea45cc962d23e4f084cc5dcc55c48ddff9c1d7
@@ -0,0 +1 @@
1
+ 2.2.3
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Circle CI](https://circleci.com/gh/cucumber-ltd/bbc-a11y.svg?style=svg&circle-token=00d656fd091643ad692c78ca60e30ad95df9563a)](https://circleci.com/gh/cucumber-ltd/bbc-a11y)
2
+
1
3
  # WARNING - PROTOTYPE SOFTWARE
2
4
 
3
5
  This project is still at an experimental / proof-of-concept stage. Please set your expectations appropriately, but *do* [give us as much feedback](https://github.com/cucumber-ltd/bbc-a11y/issues) as you can.
@@ -32,24 +34,20 @@ Now install the gem:
32
34
  You'll need to configure a11y with a set of URLs to run the checks against. Create a file `a11y.rb` in the root of your project that looks something like this:
33
35
 
34
36
  ```
35
- BBC::A11y.configure do
36
- page "http://bbc.co.uk"
37
- page "http://bbc.co.uk/news"
38
- end
37
+ page "http://bbc.co.uk"
38
+ page "http://bbc.co.uk/news"
39
39
  ```
40
40
 
41
41
  ### Skipping scenarios
42
42
 
43
- Nobody's perfect. Use `skip_scenario` in the configuration to opt-out of certain checks.
43
+ Nobody's perfect. Use `skip_standard` in the configuration to opt-out of certain checks.
44
44
 
45
45
  ```
46
- BBC::A11y.configure do
47
- page "http://bbc.co.uk" do
48
- skip_scenario /W3C/
49
- end
50
-
51
- page "http://bbc.co.uk/news"
46
+ page "http://bbc.co.uk" do
47
+ skip_standard /W3C/
52
48
  end
49
+
50
+ page "http://bbc.co.uk/news"
53
51
  ```
54
52
 
55
53
  A11y will skip any scenarios from the specifications whose name contains that string.
data/Rakefile CHANGED
@@ -4,9 +4,9 @@ Bundler::GemHelper.install_tasks
4
4
  task default: [:unit, :acceptance]
5
5
 
6
6
  task :unit do
7
- sh "rspec"
7
+ sh "bundle exec rspec"
8
8
  end
9
9
 
10
10
  task :acceptance do
11
- sh "cucumber"
11
+ sh "bundle exec cucumber"
12
12
  end
data/a11y.rb ADDED
@@ -0,0 +1,5 @@
1
+ page "https://bbc.co.uk/news" do
2
+ skip_standard /W3C/
3
+ skip_standard /JavaScript/
4
+ skip_standard /title/
5
+ end
@@ -13,16 +13,14 @@ Gem::Specification.new do |s|
13
13
  s.license = "MIT"
14
14
  s.required_ruby_version = ">= 1.9.3"
15
15
 
16
- s.add_dependency 'cucumber', '~> 2.0.0.rc'
17
- s.add_dependency 'rspec', '~> 3.0'
18
16
  s.add_dependency 'capybara'
19
- s.add_dependency 'poltergeist'
20
- s.add_dependency 'w3c_validators'
21
- s.add_dependency 'cld'
22
17
  s.add_dependency 'colorize'
18
+
19
+ s.add_development_dependency 'rspec', '~> 3.0'
23
20
  s.add_development_dependency 'aruba'
24
21
  s.add_development_dependency 'pry'
25
22
  s.add_development_dependency 'rake'
23
+ s.add_development_dependency 'cucumber'
26
24
 
27
25
  s.rubygems_version = ">= 1.6.1"
28
26
  s.files = `git ls-files`.split("\n").reject {|path| path =~ /\.gitignore$/ }
data/bin/a11y CHANGED
@@ -2,5 +2,5 @@
2
2
  $:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
3
3
 
4
4
  require 'bbc/a11y/cli'
5
- require 'bbc/a11y/cucumber_runner'
6
- BBC::A11y::CLI.new($stdin, $stdout, $stderr, ARGV.dup).call(BBC::A11y::CucumberRunner)
5
+
6
+ BBC::A11y::CLI.new($stdin, $stdout, $stderr, ARGV.dup).call
@@ -1,6 +1,2 @@
1
- BBC::A11y.configure do
2
-
3
- page "http://bbc.co.uk/news"
4
- page "http://bbc.co.uk/mundo"
5
-
6
- end
1
+ page "http://bbc.co.uk/news"
2
+ page "http://bbc.co.uk/mundo"
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'rack'
4
- gem 'bbc-a11y', path: '..'
4
+ gem 'bbc-a11y', path: '../..'
@@ -36,29 +36,17 @@ class Server
36
36
  end
37
37
 
38
38
  server = Server.new
39
+ server.start
39
40
 
40
- BBC::A11y.configure do
41
-
42
- before_all do
43
- server.start
44
- end
45
-
46
- after_all do
47
- server.stop
48
- end
49
-
50
- page "http://localhost:#{server.port}/perfect.html" do
51
- skip_scenario "W3C"
52
- end
41
+ at_exit do
42
+ server.stop
43
+ end
53
44
 
54
- page "http://localhost:#{server.port}/missing_header.html" do
55
- skip_scenario "W3C"
56
- skip_scenario "Check headings"
45
+ page "http://localhost:#{server.port}/perfect.html" do
46
+ skip_standard "W3C"
47
+ end
57
48
 
58
- customize_world do
59
- def Xassert_title_describes_primary_content_of_document(title, doc)
60
- puts "TODO"
61
- end
62
- end
63
- end
49
+ page "http://localhost:#{server.port}/missing_header.html" do
50
+ skip_standard "W3C"
51
+ skip_standard "Check headings"
64
52
  end
@@ -0,0 +1,62 @@
1
+ Feature: Focusable Controls
2
+
3
+ Controls for JavaScript enhanced interactions **must** be `<a>`, `<button>`,
4
+ or `<input>` elements if that is the only mechanism for controlling them.
5
+
6
+ `<a>` elements used for controls **must** have an `href` attribute.
7
+
8
+ Controls that have no purpose without JavaScript **must not** be added to the
9
+ page before the associated code is available capable of running.
10
+
11
+ Rationale
12
+ =========
13
+
14
+ When creating controls for user interaction with JavaScript enhanced features,
15
+ for example a carousel with previous and next controls, the controls must be
16
+ implemented with elements that provide natively focusable elements with click,
17
+ keydown, and focus events so they are accessible to keyboard as well as
18
+ pointing device users. If there is an alternative method of controlling the
19
+ feature, for example a carousel that automatically displays new content when
20
+ it receives content then controls that are only available to pointing device
21
+ users can be used.
22
+
23
+ In general, use `<a>` elements when there is a URL associated with the
24
+ interaction when JavaScript is not enabled, and `<button>` elements for
25
+ interactions that don't have an associated URL.
26
+
27
+ `<a>` elements without a `href` attribute are not keyboard accessible, and
28
+ therefore must not be used for controls.
29
+
30
+ When there is no core (non-JavaScript) interaction then the control must not
31
+ be added to the document before the associated JavaScript is capable of
32
+ running as this would lead to controls that apparently do nothing, potentially
33
+ causing confusion to users.
34
+
35
+ Scenario: All anchor tags have href attributes
36
+ Given a page with the HTML:
37
+ """
38
+ <button type="button">Open panel</button>
39
+ <ul>
40
+ <li><a href="/news">News</a></li>
41
+ <li><a href="#sporttab">Sport</a></li>
42
+ <li><a href="#entertainmenttab">Entertainment</a></li>
43
+ </ul>
44
+ """
45
+ When I validate the anchor hrefs standards
46
+ Then it passes
47
+
48
+ Scenario: Some anchor tags do not have href attributes
49
+ Given a page with the HTML:
50
+ """
51
+ <ul>
52
+ <li><a>News</a></li>
53
+ <li><a href="#sport">Sport</a></li>
54
+ <li><a>Entertainment</a></li>
55
+ </ul>
56
+ """
57
+ When I validate the anchor hrefs standards
58
+ Then it fails with the message:
59
+ """
60
+ Anchor has no href attribute: /html/body/ul/li[1]/a
61
+ Anchor has no href attribute: /html/body/ul/li[3]/a
62
+ """
@@ -0,0 +1,45 @@
1
+ Feature: Form Interactions
2
+
3
+ Forms must have a submit button and forms must not update the location of the
4
+ page on change, focus, or blur events.
5
+
6
+ All `<form>` elements that take user input (i.e. do not consist only of
7
+ `input[type=hidden]` elements to store state) **must** have a submit button in
8
+ the form of a `<input>[type=submit,image]` or `<button>[type=submit]` element.
9
+
10
+ Changes to the page **must** location must only take place on explicit user
11
+ action i.e. when a submit button is activated. They must not take place when
12
+ change (particularly for `select` elements), focus, or blur events are fired.
13
+
14
+ Rationale
15
+ =========
16
+
17
+ All forms should have a submit button to provide a clear call to action. This
18
+ is particularly important to users with cognitive disabilities, but is also
19
+ beneficial to low vision users as an indication of the end of the form.
20
+
21
+ Scenario: Form with a submit button
22
+ Given a page with the HTML:
23
+ """
24
+ <form action="/search">
25
+ <label for="q">Search term:</label>
26
+ <input type="text" name="q" id="q">
27
+ <input type="submit" value="Search">
28
+ </form>
29
+ """
30
+ When I validate the form submit buttons standards
31
+ Then it passes
32
+
33
+ Scenario: Form with no submit button
34
+ Given a page with the HTML:
35
+ """
36
+ <form action="/search">
37
+ <label for="q">Search term:</label>
38
+ <input type="text" name="q" id="q">
39
+ </form>
40
+ """
41
+ When I validate the form submit buttons standards
42
+ Then it fails with the message:
43
+ """
44
+ Form has no submit button: /html/body/form
45
+ """
@@ -0,0 +1,55 @@
1
+ Feature: Correctly use form labels
2
+
3
+ Form fields that allow input (`select`, and `textarea` elements, and all
4
+ `input` element types other than image, submit, reset, button, or hidden)
5
+ **must** have an associated label, either in the form of a `<label>` element
6
+ or, for simple forms when no visible label is required, a `title` attribute.
7
+
8
+ Rationale
9
+ ---------
10
+
11
+ Form labels are important for all users in order to understand what the form
12
+ field is however they are essential for speech output users who cannot easily
13
+ infer what the form element is by looking at the surrounding content.
14
+
15
+ While there are WAI-ARIA attributes that allow for labelling of forms it is
16
+ not supported in all versions of assistive technologies that BBC users could
17
+ reasonably expect to be able to use.
18
+
19
+ Scenario: All fields have labels or title attributes
20
+ Given a page with the HTML:
21
+ """
22
+ <label for="search">Search the BBC</label>
23
+ <input type="text" id="search" name="q" />
24
+
25
+ <label for="search2">
26
+ Search the BBC
27
+ <input id="search2" type="text" name="q" />
28
+ </label>
29
+
30
+ <input type="text" name="q" title="Search the BBC" />
31
+ """
32
+ When I validate the form labels standards
33
+ Then it passes
34
+
35
+ Scenario: Some fields without labels or title attributes
36
+ Given a page with the HTML:
37
+ """
38
+ <input type="text" name="name" title="Name" />
39
+ <input type="email" name="email" title="Email" />
40
+
41
+ <textarea name="notes"></textarea>
42
+ <select name="preference"></select>
43
+ <input type="text" name="q" value="Search the BBC" />
44
+ <input type="text" name="q" aria-label="Search the BBC" />
45
+ <input type="text" name="q" placeholder="Search the BBC" />
46
+ """
47
+ When I validate the form labels standards
48
+ Then it fails with the message:
49
+ """
50
+ Field has no label or title attribute: /html/body/textarea
51
+ Field has no label or title attribute: /html/body/select
52
+ Field has no label or title attribute: /html/body/input[3]
53
+ Field has no label or title attribute: /html/body/input[4]
54
+ Field has no label or title attribute: /html/body/input[5]
55
+ """
@@ -0,0 +1,154 @@
1
+ Feature: Headings
2
+
3
+ A document **must** have exactly one `<h1>` element.
4
+
5
+ Heading levels after the document `<h1>` element **must** be sequential and **must not** skip heading levels.
6
+
7
+ Heading elements **must** be followed by content.
8
+
9
+ Rationale
10
+ =========
11
+
12
+ A logical heading structure is invaluable for users of screen readers and similar assistive technologies to help navigate content.
13
+
14
+ Users should be able to use the document's `<h1>` identify its main content. Documents should have one main subject.
15
+
16
+ Heading levels should not be skipped as a predictable document outline is an important factor for understandability.
17
+
18
+ Headings should not be used for non-heading purposes, i.e. to identify blocks of content. A heading should always
19
+ be followed either by non-heading content or by a heading of one level deeper.
20
+
21
+ Scenario: No main heading
22
+ Given a page with the HTML:
23
+ """
24
+ <h2>Heading 2</h2>
25
+ """
26
+ When I validate the heading standards
27
+ Then it fails with the message:
28
+ """
29
+ A document must have exactly one heading. Found 0 h1 elements.
30
+ """
31
+
32
+ Scenario: More than one main heading
33
+ Given a page with the HTML:
34
+ """
35
+ <h1>Heading 1</h1>
36
+ <h2>Heading 2</h2>
37
+ <h1>Heading 1</h1>
38
+ """
39
+ When I validate the heading standards
40
+ Then it fails with the message:
41
+ """
42
+ A document must have exactly one heading. Found 2 h1 elements:
43
+ /html/body/h1[1]
44
+ /html/body/h1[2]
45
+ """
46
+
47
+ Scenario: Headings in ascending order
48
+ Given a page with the HTML:
49
+ """
50
+ <h1>Heading 1</h1>
51
+ <h2>Heading 2</h2>
52
+ <h3>Heading 3</h3>
53
+ <h4>Heading 4</h4>
54
+ <h5>Heading 5</h5>
55
+ <h6>Heading 6</h6>
56
+ """
57
+ When I validate the heading standards
58
+ Then it passes
59
+
60
+ Scenario: Headings in invalid order
61
+ Given a page with the HTML:
62
+ """
63
+ <h1>Heading 1</h1>
64
+ <h3>Heading 3</h3>
65
+ <h2>Heading 2</h2>
66
+ """
67
+ When I validate the heading standards
68
+ Then it fails with the message:
69
+ """
70
+ Headings are not in order: h1 is followed by h3
71
+ """
72
+
73
+ Scenario: Headings jump back up more than one level
74
+ Given a page with the HTML:
75
+ """
76
+ <h1>Heading 1</h1>
77
+ <h2>Heading 2</h2>
78
+ <h3>Heading 3</h3>
79
+ <h4>Heading 4</h4>
80
+ <h2>Heading 2b</h2>
81
+ <h3>Heading 3b</h3>
82
+ """
83
+ When I validate the heading standards
84
+ Then it passes
85
+
86
+ Scenario: Heading is hidden
87
+ Given a page with the HTML:
88
+ """
89
+ <h1>Heading 1</h1>
90
+ <h3 style="display:none">Heading 3</h3>
91
+ <h2>Heading 2</h2>
92
+ """
93
+ When I validate the heading standards
94
+ Then it fails with the message:
95
+ """
96
+ Headings are not in order: h1 is followed by h3
97
+ """
98
+
99
+ Scenario: Heading in a script tag
100
+ Given a page with the HTML:
101
+ """
102
+ <h1>Heading 1</h1>
103
+ <script>
104
+ var stuff = "<h3>Heading 3</h3>";
105
+ </script>
106
+ <h2>Heading 2</h2>
107
+ """
108
+ When I validate the heading standards
109
+ Then it passes
110
+
111
+ Scenario: Subheading before the first main heading
112
+ Given a page with the HTML:
113
+ """
114
+ <h3>Ignore me</h3>
115
+ <h1>Heading 1</h1>
116
+ <h2>Heading 2</h2>
117
+ """
118
+ When I validate the heading standards
119
+ Then it passes
120
+
121
+ Scenario: Content between headings
122
+ Given a page with the HTML:
123
+ """
124
+ <div role="main">
125
+ <h1>Main heading</h1>
126
+ <p>non-heading content</p>
127
+ <h2>Another heading</h2>
128
+ <p>non-heading content</p>
129
+ <h3>Main content</h3>
130
+ <h2>Secondary content</h2>
131
+ <p>non-heading content</p>
132
+ <h2>Tertiary content</h2>
133
+ <p>Lorem ipsum…</p>
134
+ </div>
135
+ """
136
+ When I validate the heading standards
137
+ Then it passes
138
+
139
+ Scenario: No content between headings
140
+ Given a page with the HTML:
141
+ """
142
+ <div role="main">
143
+ <h1>Main heading</h1>
144
+ <p>non-heading content</p>
145
+ <h2>Secondary content</h2>
146
+ <h2>Tertiary content</h2>
147
+ <p>non-heading content</p>
148
+ </div>
149
+ """
150
+ When I validate the heading standards
151
+ Then it fails with the message:
152
+ """
153
+ Heading elements must be followed by content. No content follows a h2.
154
+ """