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
@@ -1,10 +0,0 @@
1
- Feature: Specify URL via the CLI
2
-
3
- Scenario: No config, just pass page URL on command-line
4
- Given a standards-compliant website running at http://localhost:54321
5
- When I run `a11y http://localhost:54321/perfect.html`
6
- Then it should pass with:
7
- """
8
- BBC Accesibility: http://localhost:54321/perfect.html
9
- -----------------------------------------------------
10
- """
@@ -1,16 +0,0 @@
1
- Feature: Specify URL via config
2
-
3
- Scenario: Specify a single page
4
- Given a standards-compliant website running at http://localhost:54321
5
- And a file named ".a11y.rb" with:
6
- """
7
- BBC::A11y.configure do
8
- page "http://localhost:54321/perfect.html"
9
- end
10
- """
11
- When I run `a11y`
12
- Then it should pass with:
13
- """
14
- BBC Accesibility: http://localhost:54321/perfect.html
15
- -----------------------------------------------------
16
- """
@@ -1,17 +0,0 @@
1
- module BBC
2
- module A11y
3
- TestsFailed = Class.new(StandardError)
4
-
5
- def self.current_version
6
- @current_version ||= File.read(File.dirname(__FILE__) + '/a11y/version')
7
- end
8
-
9
- def self.until_version(max_version)
10
- if current_version >= max_version
11
- raise "DEAD CODE: #{caller[0]}"
12
- end
13
- yield
14
- end
15
-
16
- end
17
- end
@@ -1,208 +0,0 @@
1
- require 'forwardable'
2
- require 'cucumber'
3
- require 'bbc/a11y/cucumber_support'
4
- require 'cucumber/core/filter'
5
- require 'colorize'
6
-
7
- module BBC
8
- module A11y
9
- module ConsoleWriter
10
- def underline(text, character="-")
11
- [text, character * text.length].join("\n")
12
- end
13
-
14
- def indent(spaces, text)
15
- text.split("\n").map { |line| (" " * spaces) + line }.join("\n")
16
- end
17
- end
18
-
19
- class CucumberFormatter
20
- include ConsoleWriter
21
-
22
- def initialize(*args)
23
- @current_feature = nil
24
- end
25
-
26
- def before_test_case(test_case)
27
- on_new_feature(test_case) do |feature|
28
- puts
29
- puts underline(feature.name)
30
- puts
31
- end
32
- print " - #{test_case.name}... "
33
- @step_results = []
34
- end
35
-
36
- def after_test_step(test_step, result)
37
- @step_results << [test_step, result]
38
- end
39
-
40
- def after_test_case(test_case, result)
41
- colour = ResultColour.new(result)
42
- print colour.apply_to(result.to_s)
43
- if !result.passed?
44
- puts
45
- puts
46
- print_scenario
47
- puts
48
- puts indent(4, colour.apply_to(result.exception.message.to_s))
49
- if result.failed?
50
- puts indent(4, colour.apply_to(result.exception.backtrace.join("\n")))
51
- end
52
- end
53
- puts
54
- if result.failed?
55
- CucumberRunner.test_case_failed
56
- end
57
- end
58
-
59
- private
60
-
61
- def print_scenario
62
- @step_results.each do |step, result|
63
- step.describe_source_to(StepsPrinter.new, result)
64
- end
65
- end
66
-
67
- def colour(result)
68
- ResultColour.new(result).apply_to(result.to_s)
69
- end
70
-
71
- def on_new_feature(test_case)
72
- feature = test_case.source.first
73
- if feature != @current_feature
74
- @current_feature = feature
75
- yield feature
76
- end
77
- end
78
-
79
- class StepsPrinter
80
- include ConsoleWriter
81
-
82
- def before_hook(*)
83
- end
84
-
85
- def scenario(*)
86
- end
87
-
88
- def feature(*)
89
- end
90
-
91
- def after_hook(*)
92
- end
93
-
94
- def step(step, result)
95
- colour = ResultColour.new(result)
96
- puts indent(6, colour.apply_to("#{step.keyword}#{step.name}"))
97
- end
98
- end
99
-
100
- class ResultColour
101
- def initialize(result)
102
- @color = :white
103
- result.describe_to(self)
104
- end
105
-
106
- def passed
107
- @color = :green
108
- end
109
-
110
- def skipped
111
- @color = :blue
112
- end
113
-
114
- def pending(*)
115
- @color = :yellow
116
- end
117
-
118
- def failed
119
- @color = :red
120
- end
121
-
122
- def undefined
123
- @color = :yellow
124
- end
125
-
126
- def duration(*)
127
- end
128
-
129
- def exception(*)
130
- end
131
-
132
- def apply_to(string)
133
- string.send(@color)
134
- end
135
- end
136
-
137
- end
138
-
139
- class CucumberRunner
140
- include ConsoleWriter
141
- FEATURES_PATH = File.expand_path(File.dirname(__FILE__) + "/../../../standards")
142
-
143
- class << self
144
- # need to use a global stash-point for the formatter to talk back to use
145
- # until Cucumber gives us a way to add formatter instances that we can
146
- # share.
147
- def failed_count
148
- @failed_count ||= 0
149
- end
150
-
151
- def test_case_failed
152
- @failed_count ||= 0
153
- @failed_count += 1
154
- end
155
- end
156
-
157
- def initialize(settings, cucumber_args)
158
- @settings = settings
159
- @cucumber_args = cucumber_args
160
- end
161
-
162
- def call
163
- runtime = Cucumber::Runtime.new(configuration)
164
- run_before_all_hooks
165
- @settings.pages.each do |page_settings|
166
- # stash the settings where the support code will find them
167
- BBC::A11y::CucumberSupport.current_page_settings = page_settings
168
- print_page_header page_settings
169
- runtime.run!
170
- end
171
- ensure
172
- run_after_all_hooks
173
- raise BBC::A11y::TestsFailed if self.class.failed_count > 0
174
- end
175
-
176
- private
177
-
178
- def configuration
179
- return @configuration if @configuration
180
- @configuration = Cucumber::Cli::Configuration.new
181
- if !@cucumber_args.any?
182
- @cucumber_args = [FEATURES_PATH, "--require", FEATURES_PATH]
183
- end
184
- # This is ugly, but until Cucumber offers a better API, we have to pass in our settings as though
185
- # they were CLI arguments
186
- @configuration.parse!(@cucumber_args +
187
- ["--format", "BBC::A11y::CucumberFormatter"])
188
- @configuration
189
- end
190
-
191
- def run_before_all_hooks
192
- @settings.before_all_hooks.each &:call
193
- end
194
-
195
- def run_after_all_hooks
196
- @settings.after_all_hooks.each &:call
197
- end
198
-
199
- def print_page_header(page_settings)
200
- puts
201
- puts
202
- puts underline("BBC Accesibility: #{page_settings.url}")
203
- end
204
-
205
- end
206
-
207
- end
208
- end
@@ -1,56 +0,0 @@
1
- require 'bbc/a11y/cucumber_support/disabled_w3c'
2
- require 'bbc/a11y/cucumber_support/language_detector'
3
- require 'bbc/a11y/cucumber_support/matchers'
4
- require 'bbc/a11y/cucumber_support/page'
5
- require 'bbc/a11y/cucumber_support/per_page_checks'
6
- require 'bbc/a11y/cucumber_support/w3c'
7
- require 'bbc/a11y/configuration'
8
-
9
- module BBC
10
- module A11y
11
-
12
- # These are the methods available to step definitions
13
- # that test the specifications.
14
- module CucumberSupport
15
- include PerPageChecks
16
-
17
- class << self
18
- attr_accessor :current_page_settings
19
- end
20
-
21
- # Returns an object that can validate URLs
22
- def w3c
23
- @w3c ||= DisabledW3C.new
24
- end
25
-
26
- # An object that represents the current page being viewed in the browser
27
- def page
28
- @page ||= Page.new(browser)
29
- end
30
-
31
- # An object to detect the natural lanugage of the page
32
- def language
33
- @language ||= LanguageDetector.new
34
- end
35
-
36
- # Settings specified for this test run
37
- def settings
38
- CucumberSupport.current_page_settings
39
- end
40
-
41
- # Ask for a manual check
42
- def confirm(question)
43
- formatted_question = "\n #{question} [Y/n]"
44
- answer = ask(formatted_question).strip
45
- fail unless ["Y", "y", ""].include?(answer)
46
- end
47
-
48
- end
49
-
50
- CucumberSupport.current_page_settings ||=
51
- Configuration::PageSettings.new(ENV['A11Y_URL'])
52
- end
53
-
54
- end
55
-
56
-
@@ -1,37 +0,0 @@
1
- module BBC
2
- module A11y
3
- module CucumberSupport
4
-
5
- class DisabledW3C
6
-
7
- def validate(url)
8
- raise Cucumber::Core::Test::Result::Skipped.new <<-MESSAGE
9
- W3C validation is disabled by default as it makes off-netowrk calls
10
- to the W3C web service and can be slow and unreliable.
11
-
12
- To enable these checks, include the following code in your .a11y.rb
13
- config file:
14
-
15
- BBC::A11y.configure do
16
- page "my_page.html" do
17
-
18
- customize_world do
19
- def w3c
20
- @w3c ||= BBC::A11y::CucumberSupport::W3C.new
21
- end
22
- end
23
-
24
- end
25
- end
26
- MESSAGE
27
- end
28
-
29
- def errors
30
- []
31
- end
32
-
33
- end
34
-
35
- end
36
- end
37
- end
@@ -1,94 +0,0 @@
1
- module BBC
2
- module A11y
3
- module CucumberSupport
4
-
5
- class HeadingHierarchy
6
- include RSpec::Matchers
7
-
8
- def initialize(page)
9
- @page = page
10
- end
11
-
12
- def validate
13
- return self unless headings.count > 1
14
- adjacent_pairs = headings.zip(headings[1..-1])[0..-2]
15
- errors = adjacent_pairs.reduce([]) { |errors, pair|
16
- previous, current = *pair
17
- if current > previous
18
- delta = current.number - previous.number
19
- if delta != 1
20
- errors << current
21
- end
22
- end
23
- errors
24
- }
25
- expect(errors).to be_empty, error_message(errors)
26
- self
27
- end
28
-
29
- def to_s
30
- headings.map { |h|
31
- indent = " " * (h.number - 1)
32
- indent + h.to_s
33
- }.join("\n")
34
- end
35
-
36
- private
37
-
38
- def error_message(errors)
39
- "Headings were not in order: " +
40
- headings.map { |h| errors.include?(h) ? "**#{h}**" : h }.
41
- join(", ")
42
- end
43
-
44
- def headings
45
- heading_elements.map { |h| Heading.new(h) }
46
- end
47
-
48
- def heading_elements
49
- all_heading_elements = page.all('h1,h2,h3,h4', visible: false)
50
- heading_elements_after_first_h1 = []
51
- all_heading_elements.each do |node|
52
- if node.tag_name == "h1" || heading_elements_after_first_h1.any?
53
- heading_elements_after_first_h1 << node
54
- end
55
- end
56
- heading_elements_after_first_h1
57
- end
58
-
59
- attr_reader :page
60
- private :page
61
-
62
- class Heading
63
- attr_reader :number
64
-
65
- def initialize(element)
66
- @element = element
67
- @tag_name = element.tag_name
68
- @number = @tag_name[1].to_i
69
- end
70
-
71
- def > (other)
72
- number > other.number
73
- end
74
-
75
- def == (other)
76
- begin
77
- other.element.path == @element.path
78
- rescue NotSupportedByDriverError
79
- other.element == @element
80
- end
81
- end
82
-
83
- def to_s
84
- @tag_name
85
- end
86
-
87
- attr_reader :element
88
- protected :element
89
- end
90
- end
91
-
92
- end
93
- end
94
- end
@@ -1,26 +0,0 @@
1
- module BBC
2
- module A11y
3
- module CucumberSupport
4
-
5
- module LanguageDetector
6
- # factory for language detector, allows us to use different mechanisms (e.g. a hard-coded language passed from settings)
7
- def self.new
8
- CLDLanguageDetector.new
9
- end
10
-
11
- require 'cld'
12
- class CLDLanguageDetector
13
- InsufficientConfidence = Class.new(StandardError)
14
-
15
- # returns the code of the language, or raises an error if insufficient confidence
16
- def detect(text)
17
- detected_language = CLD.detect_language(text.to_s)
18
- raise InsufficientConfidence unless detected_language[:reliable]
19
- detected_language[:code]
20
- end
21
- end
22
- end
23
-
24
- end
25
- end
26
- end