capybara_accessibility_audit 0.1.1 → 0.3.0
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.
- checksums.yaml +4 -4
- data/README.md +107 -2
- data/lib/capybara_accessibility_audit/{auditor.rb → adapter.rb} +8 -2
- data/lib/capybara_accessibility_audit/audit_system_test_extensions.rb +7 -10
- data/lib/capybara_accessibility_audit/axe_auditor.rb +131 -0
- data/lib/capybara_accessibility_audit/engine.rb +35 -14
- data/lib/capybara_accessibility_audit/log_subscriber.rb +17 -0
- data/lib/capybara_accessibility_audit/notification_reporter.rb +24 -0
- data/lib/capybara_accessibility_audit/raise_reporter.rb +11 -0
- data/lib/capybara_accessibility_audit/version.rb +1 -1
- data/lib/capybara_accessibility_audit.rb +14 -1
- metadata +55 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 152ffd3d124d45c7cc7cec829bcd30c18a2f97dbc988c23cb7629cfe0e8eaa09
|
|
4
|
+
data.tar.gz: c174479db34168f55e3526e011e833d8fb6d7282392ab1f706d56be2786f1ca4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fa0be00cf21080048e5fec94d3cabb82dbe61aca8a5d04ea341d8aef776aefe5fae2936e958e66de86d0c064cea2d61a2c4f22ac764808c9f6d28c09059f385b
|
|
7
|
+
data.tar.gz: 31d70ffeab59611501a8bbf3933137526273b2e871a716d636cf157168b299b0fa5145925b87be58aeebd314bd7937801fc184cff6d257a1979003893ec1a0d9
|
data/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# CapybaraAccessibilityAudit
|
|
2
2
|
|
|
3
3
|
Extend your Capybara-powered System Tests to automatically audit the page for
|
|
4
|
-
WCAG
|
|
4
|
+
[WCAG Standards-based accessibility violations](https://www.w3.org/WAI/standards-guidelines/wcag/).
|
|
5
5
|
|
|
6
6
|
## Usage
|
|
7
7
|
|
|
@@ -60,9 +60,59 @@ end
|
|
|
60
60
|
[aXe]: https://www.deque.com/axe/
|
|
61
61
|
[axe-core-rspec]: https://github.com/dequelabs/axe-core-gems/blob/develop/packages/axe-core-rspec/README.md#matcher
|
|
62
62
|
|
|
63
|
+
## Active Support instrumentation
|
|
64
|
+
|
|
65
|
+
Capybara Accessibility Audit integrates with [Active Support's
|
|
66
|
+
instrumentation][] through publishing [ActiveSupport::Notifications][].
|
|
67
|
+
|
|
68
|
+
### `audit.capybara_accessibility_audit` notification
|
|
69
|
+
|
|
70
|
+
Subscribe to `audit.capybara_accessibility_audit` notifications emitted when an
|
|
71
|
+
accessibility audit is automatically conducted. In addition to the
|
|
72
|
+
metadata provided by default (like `name`, `duration`, and `allocations`, etc.),
|
|
73
|
+
the `payload` includes additional information:
|
|
74
|
+
|
|
75
|
+
| Payload | Type | Description |
|
|
76
|
+
| ------------- | ---------------------------------- | ----------- |
|
|
77
|
+
| method | Symbol | The Capybara method that triggered the audit
|
|
78
|
+
| options | [ActiveSupport::OrderedOptions][] | The audit's configuration
|
|
79
|
+
| test | [ActionDispatch::SystemTestCase][] | The test case that triggered the audit
|
|
80
|
+
|
|
81
|
+
> [!NOTE]
|
|
82
|
+
> The `audit.capybara_accessibility_audit` notifications are only published when
|
|
83
|
+
> an audit is conducted automatically. No `audit.capybara_accessibility_audit`
|
|
84
|
+
> notifications will be published when `assert_no_accessibility_violations` is
|
|
85
|
+
> invoked directly.
|
|
86
|
+
|
|
87
|
+
[Active Support's instrumentation]: https://guides.rubyonrails.org/active_support_instrumentation.html
|
|
88
|
+
[ActiveSupport::Notifications]: https://api.rubyonrails.org/classes/ActiveSupport/Notifications.html
|
|
89
|
+
[ActiveSupport::OrderedOptions]: https://api.rubyonrails.org/classes/ActiveSupport/OrderedOptions.html
|
|
90
|
+
[ActionDispatch::SystemTestCase]: https://api.rubyonrails.org/classes/ActionDispatch/SystemTestCase.html
|
|
91
|
+
|
|
92
|
+
### `report.capybara_accessibility_audit` notification
|
|
93
|
+
|
|
94
|
+
Subscribe to `report.capybara_accessibility_audit` notifications emitted when an
|
|
95
|
+
accessibility audit detects violations. The `payload` includes:
|
|
96
|
+
|
|
97
|
+
| Payload | Type | Description |
|
|
98
|
+
| ------------- | ---------------------------------- | ----------- |
|
|
99
|
+
| report | [Axe::API::Results][] | The underlying axe.js [Results][] object
|
|
100
|
+
| options | [ActiveSupport::OrderedOptions][] | The audit's configuration
|
|
101
|
+
| test | [ActionDispatch::SystemTestCase][] | The test case that triggered the audit
|
|
102
|
+
|
|
103
|
+
[ActiveSupport::OrderedOptions]: https://api.rubyonrails.org/classes/ActiveSupport/OrderedOptions.html
|
|
104
|
+
[ActionDispatch::SystemTestCase]: https://api.rubyonrails.org/classes/ActionDispatch/SystemTestCase.html
|
|
105
|
+
[Axe::API::Results]: https://github.com/dequelabs/axe-core-gems/blob/v4.11.0/packages/axe-core-api/lib/axe/api/results.rb
|
|
106
|
+
[Results]: https://www.deque.com/axe/core-documentation/api-documentation/#results-object
|
|
107
|
+
|
|
108
|
+
> [!NOTE]
|
|
109
|
+
> The `report.capybara_accessibility_audit` notifications are only published when
|
|
110
|
+
> `config.capybara_accessibility_audit.reporter` is configured with
|
|
111
|
+
> `:notification` or `:log`.
|
|
112
|
+
|
|
63
113
|
## Frequently Asked Questions
|
|
64
114
|
|
|
65
|
-
My application already exists,
|
|
115
|
+
My application already exists, automated accessibility audits are uncovering violations left and right. Do I have to fix them all at once?
|
|
66
116
|
---
|
|
67
117
|
|
|
68
118
|
Your suite has control over which rules are skipped and which rules are
|
|
@@ -114,6 +164,28 @@ end
|
|
|
114
164
|
As you resolve the violations, you can remove entries from the list of skipped
|
|
115
165
|
rules.
|
|
116
166
|
|
|
167
|
+
How many I conduct a preliminary audit that comprehensively exercises my system test suite without failing tests that result in violations?
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
You can configure the audit's reporting mechanism. By default, the
|
|
171
|
+
`config.capybara_accessibility_audit.reporter` value is set to `:raise`, which
|
|
172
|
+
will raise violation errors that will fail the test suite.
|
|
173
|
+
|
|
174
|
+
To log violations, rather than raise them, you can configure
|
|
175
|
+
`config.capybara_accessibility_audit.reporter` to `:log`:
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
class MySystemTest < ApplicationSystemTestCase
|
|
180
|
+
self.accessibility_audit_reporter = :log
|
|
181
|
+
|
|
182
|
+
test "with overridden accessibility :log reporter" do
|
|
183
|
+
visit examples_path
|
|
184
|
+
# ...
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
```
|
|
188
|
+
|
|
117
189
|
I've implemented a custom Capybara action to toggle a disclosure element. How can I automatically audit for violations after it's called?
|
|
118
190
|
---
|
|
119
191
|
|
|
@@ -204,6 +276,22 @@ class MySystemTest < ApplicationSystemTestCase
|
|
|
204
276
|
end
|
|
205
277
|
```
|
|
206
278
|
|
|
279
|
+
My pages render on the client. How long does the audit wait for them?
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
Capybara returns from an action as soon as the driver is done with it, and a
|
|
283
|
+
page that renders on the client keeps changing after that point. The auditor
|
|
284
|
+
therefore waits for the DOM to stay unchanged before it runs `axe`. It waits
|
|
285
|
+
for 100 milliseconds of quiet, and it audits the page as it is after 2000
|
|
286
|
+
milliseconds, so a page that never settles cannot block the suite.
|
|
287
|
+
|
|
288
|
+
To change those values, override them on the auditor:
|
|
289
|
+
|
|
290
|
+
```ruby
|
|
291
|
+
CapybaraAccessibilityAudit::AxeAuditor.quiet_period_ms = 250
|
|
292
|
+
CapybaraAccessibilityAudit::AxeAuditor.quiet_period_timeout_ms = 5000
|
|
293
|
+
```
|
|
294
|
+
|
|
207
295
|
## Installation
|
|
208
296
|
Add this line to your application's Gemfile:
|
|
209
297
|
|
|
@@ -222,3 +310,20 @@ Please read [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
|
222
310
|
|
|
223
311
|
## License
|
|
224
312
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
313
|
+
|
|
314
|
+
<!-- START /templates/footer.md -->
|
|
315
|
+
## About thoughtbot
|
|
316
|
+
|
|
317
|
+

|
|
318
|
+
|
|
319
|
+
This repo is maintained and funded by thoughtbot, inc.
|
|
320
|
+
The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
|
321
|
+
|
|
322
|
+
We love open source software!
|
|
323
|
+
See [our other projects][community].
|
|
324
|
+
We are [available for hire][hire].
|
|
325
|
+
|
|
326
|
+
[community]: https://thoughtbot.com/community?utm_source=github
|
|
327
|
+
[hire]: https://thoughtbot.com/hire-us?utm_source=github
|
|
328
|
+
|
|
329
|
+
<!-- END /templates/footer.md -->
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module CapybaraAccessibilityAudit
|
|
2
|
-
class
|
|
2
|
+
class Adapter
|
|
3
3
|
delegate_missing_to :@test
|
|
4
4
|
|
|
5
5
|
def initialize(test)
|
|
@@ -8,7 +8,13 @@ module CapybaraAccessibilityAudit
|
|
|
8
8
|
|
|
9
9
|
def audit!(method)
|
|
10
10
|
if accessibility_audit_enabled && method.in?(accessibility_audit_after_methods) && javascript_enabled?
|
|
11
|
-
|
|
11
|
+
ActiveSupport::Notifications.instrument "audit.capybara_accessibility_audit" do |payload|
|
|
12
|
+
payload[:method] = method
|
|
13
|
+
payload[:options] = accessibility_audit_options
|
|
14
|
+
payload[:test] = @test
|
|
15
|
+
|
|
16
|
+
assert_no_accessibility_violations(**accessibility_audit_options)
|
|
17
|
+
end
|
|
12
18
|
end
|
|
13
19
|
end
|
|
14
20
|
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
require "axe-capybara"
|
|
2
|
-
require "axe/matchers/be_axe_clean"
|
|
3
|
-
|
|
4
1
|
module CapybaraAccessibilityAudit
|
|
5
2
|
module AuditSystemTestExtensions
|
|
6
3
|
extend ActiveSupport::Concern
|
|
@@ -16,11 +13,14 @@ module CapybaraAccessibilityAudit
|
|
|
16
13
|
class_attribute :accessibility_audit_after_methods, default: Set.new
|
|
17
14
|
class_attribute :accessibility_audit_enabled, default: true
|
|
18
15
|
class_attribute :accessibility_audit_options, default: ActiveSupport::OrderedOptions.new
|
|
16
|
+
class_attribute :accessibility_audit_reporter, default: :raise
|
|
17
|
+
|
|
18
|
+
attr_accessor :accessibility_audit_auditor
|
|
19
19
|
|
|
20
20
|
MODAL_METHODS.each do |method|
|
|
21
21
|
define_method method do |*arguments, **options, &block|
|
|
22
22
|
result = super(*arguments, **options) { skip_accessibility_audits(&block) }
|
|
23
|
-
result.tap {
|
|
23
|
+
result.tap { Adapter.new(self).audit!(method) }
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
end
|
|
@@ -36,7 +36,7 @@ module CapybaraAccessibilityAudit
|
|
|
36
36
|
def accessibility_audit_after(*methods)
|
|
37
37
|
(methods.flatten.to_set - accessibility_audit_after_methods).each do |method|
|
|
38
38
|
define_method method do |*arguments, **options, &block|
|
|
39
|
-
super(*arguments, **options, &block).tap {
|
|
39
|
+
super(*arguments, **options, &block).tap { Adapter.new(self).audit!(method) }
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
accessibility_audit_after_methods << method
|
|
@@ -90,7 +90,7 @@ module CapybaraAccessibilityAudit
|
|
|
90
90
|
accessibility_audit_options.skipping = skipping
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
-
def assert_no_accessibility_violations(**options)
|
|
93
|
+
def assert_no_accessibility_violations(auditor: accessibility_audit_auditor, **options)
|
|
94
94
|
options.assert_valid_keys(
|
|
95
95
|
:according_to,
|
|
96
96
|
:checking,
|
|
@@ -101,10 +101,7 @@ module CapybaraAccessibilityAudit
|
|
|
101
101
|
)
|
|
102
102
|
options.compact_blank!
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
axe_matcher = options.inject(axe_matcher) { |matcher, option| matcher.public_send(*option) }
|
|
106
|
-
|
|
107
|
-
assert axe_matcher.matches?(page), axe_matcher.failure_message
|
|
104
|
+
auditor.audit(**options)
|
|
108
105
|
end
|
|
109
106
|
end
|
|
110
107
|
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
require "axe/api/context"
|
|
2
|
+
require "axe/api/options"
|
|
3
|
+
require "axe/api/results"
|
|
4
|
+
require "axe/configuration"
|
|
5
|
+
|
|
6
|
+
module CapybaraAccessibilityAudit
|
|
7
|
+
class AxeAuditor
|
|
8
|
+
Error = Class.new(StandardError)
|
|
9
|
+
|
|
10
|
+
ERROR_KEY = "capybara_accessibility_audit_error"
|
|
11
|
+
|
|
12
|
+
class_attribute :source, instance_accessor: false, default: Axe::Configuration.instance.jslib
|
|
13
|
+
|
|
14
|
+
class_attribute :quiet_period_ms, instance_accessor: false, default: 100
|
|
15
|
+
class_attribute :quiet_period_timeout_ms, instance_accessor: false, default: 2000
|
|
16
|
+
|
|
17
|
+
def initialize(test, reporter)
|
|
18
|
+
@test = test
|
|
19
|
+
@reporter = reporter
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def audit(**options)
|
|
23
|
+
settle
|
|
24
|
+
install
|
|
25
|
+
|
|
26
|
+
results = run(options)
|
|
27
|
+
|
|
28
|
+
@reporter.report Axe::API::Results.new(results)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def page
|
|
34
|
+
@test.page
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def settle
|
|
38
|
+
quiet_period_ms = self.class.quiet_period_ms
|
|
39
|
+
earliest = monotonic_time + quiet_period_ms
|
|
40
|
+
deadline = monotonic_time + self.class.quiet_period_timeout_ms
|
|
41
|
+
|
|
42
|
+
observe_mutations
|
|
43
|
+
|
|
44
|
+
until monotonic_time >= deadline
|
|
45
|
+
if (duration = unchanged_for).nil?
|
|
46
|
+
observe_mutations
|
|
47
|
+
elsif monotonic_time >= earliest && duration >= quiet_period_ms
|
|
48
|
+
break
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
sleep 0.01
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def monotonic_time
|
|
56
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Records the time of the last change to the DOM. The document keeps the
|
|
60
|
+
# observer that is already there.
|
|
61
|
+
def observe_mutations
|
|
62
|
+
page.execute_script <<~JS
|
|
63
|
+
if (!window.capybaraAccessibilityAudit) {
|
|
64
|
+
window.capybaraAccessibilityAudit = {changedAt: Date.now()}
|
|
65
|
+
|
|
66
|
+
new MutationObserver(() => {
|
|
67
|
+
window.capybaraAccessibilityAudit.changedAt = Date.now()
|
|
68
|
+
}).observe(document, {attributes: true, characterData: true, childList: true, subtree: true})
|
|
69
|
+
}
|
|
70
|
+
JS
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Answers how long the DOM has been unchanged, in milliseconds. Answers
|
|
74
|
+
# nil when a page load replaced the document that has the observer. Each
|
|
75
|
+
# call is a short round trip. A single long-lived script would lose its
|
|
76
|
+
# callback when a page load discards the document it runs in.
|
|
77
|
+
def unchanged_for
|
|
78
|
+
duration = page.evaluate_script <<~JS
|
|
79
|
+
window.capybaraAccessibilityAudit ? Date.now() - window.capybaraAccessibilityAudit.changedAt : null
|
|
80
|
+
JS
|
|
81
|
+
|
|
82
|
+
duration if duration.is_a?(Numeric) # :playwright returns null as {}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def run(config)
|
|
86
|
+
context, options = split(config)
|
|
87
|
+
|
|
88
|
+
json = page.evaluate_async_script <<~JS, context.as_json, options.as_json, ERROR_KEY
|
|
89
|
+
const [ context, options, errorKey, callback ] = arguments
|
|
90
|
+
|
|
91
|
+
axe.run(context, options)
|
|
92
|
+
.then(JSON.stringify)
|
|
93
|
+
.catch(error => JSON.stringify({ [errorKey]: error.message }))
|
|
94
|
+
.then(callback)
|
|
95
|
+
JS
|
|
96
|
+
|
|
97
|
+
case JSON.parse(json, symbolize_names: true)
|
|
98
|
+
in {capybara_accessibility_audit_error:}
|
|
99
|
+
raise Error, capybara_accessibility_audit_error
|
|
100
|
+
in Hash => report
|
|
101
|
+
report
|
|
102
|
+
else
|
|
103
|
+
raise Error, "Unexpected report structure"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def split(config)
|
|
108
|
+
context = Axe::API::Context.new
|
|
109
|
+
options = Axe::API::Options.new
|
|
110
|
+
|
|
111
|
+
config.each do |name, value|
|
|
112
|
+
case name
|
|
113
|
+
when :within, :excluding then context.public_send(name, value)
|
|
114
|
+
else options.public_send(name, value)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
[context, options]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def install
|
|
122
|
+
page.execute_script(self.class.source) unless installed?
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def installed?
|
|
126
|
+
page.evaluate_script <<~JS
|
|
127
|
+
"axe" in window && typeof axe.run === "function"
|
|
128
|
+
JS
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module CapybaraAccessibilityAudit
|
|
2
2
|
class Engine < ::Rails::Engine
|
|
3
3
|
config.capybara_accessibility_audit = ActiveSupport::OrderedOptions.new
|
|
4
|
+
config.capybara_accessibility_audit.auditor = AxeAuditor
|
|
4
5
|
config.capybara_accessibility_audit.audit_after = %i[
|
|
5
6
|
visit
|
|
6
7
|
click_button
|
|
@@ -9,28 +10,48 @@ module CapybaraAccessibilityAudit
|
|
|
9
10
|
click_on
|
|
10
11
|
]
|
|
11
12
|
config.capybara_accessibility_audit.audit_enabled = true
|
|
13
|
+
config.capybara_accessibility_audit.reporter = :raise
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
initializer "capybara_accessibility_audit.minitest" do |app|
|
|
16
|
+
ActiveSupport.on_load :action_dispatch_system_test_case do
|
|
17
|
+
include CapybaraAccessibilityAudit::AuditSystemTestExtensions
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
self.accessibility_audit_enabled = app.config.capybara_accessibility_audit.audit_enabled
|
|
20
|
+
self.accessibility_audit_reporter = app.config.capybara_accessibility_audit.reporter
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
accessibility_audit_after app.config.capybara_accessibility_audit.audit_after
|
|
23
|
+
|
|
24
|
+
setup do
|
|
25
|
+
auditor_class = app.config.capybara_accessibility_audit.auditor
|
|
26
|
+
reporter_class = CapybaraAccessibilityAudit.reporter_class(accessibility_audit_reporter)
|
|
27
|
+
|
|
28
|
+
self.accessibility_audit_auditor = auditor_class.new(self, reporter_class.new(self))
|
|
29
|
+
end
|
|
30
|
+
end
|
|
19
31
|
end
|
|
20
32
|
|
|
21
|
-
|
|
22
|
-
RSpec
|
|
23
|
-
|
|
24
|
-
config.include CapybaraAccessibilityAudit::AuditSystemTestExtensions, type: :feature
|
|
33
|
+
initializer "capybara_accessibility_audit.rspec" do |app|
|
|
34
|
+
if defined?(RSpec)
|
|
35
|
+
require "rspec/core"
|
|
25
36
|
|
|
26
|
-
configure
|
|
27
|
-
|
|
37
|
+
RSpec.configure do |config|
|
|
38
|
+
config.include CapybaraAccessibilityAudit::AuditSystemTestExtensions, type: :system
|
|
39
|
+
config.include CapybaraAccessibilityAudit::AuditSystemTestExtensions, type: :feature
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
configure = proc do
|
|
42
|
+
self.accessibility_audit_enabled = app.config.capybara_accessibility_audit.audit_enabled
|
|
31
43
|
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
accessibility_audit_after app.config.capybara_accessibility_audit.audit_after
|
|
45
|
+
|
|
46
|
+
auditor_class = app.config.capybara_accessibility_audit.auditor
|
|
47
|
+
reporter_class = CapybaraAccessibilityAudit.reporter_class(accessibility_audit_reporter)
|
|
48
|
+
|
|
49
|
+
self.accessibility_audit_auditor = auditor_class.new(self, reporter_class.new(self))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
config.before(type: :system, &configure)
|
|
53
|
+
config.before(type: :feature, &configure)
|
|
54
|
+
end
|
|
34
55
|
end
|
|
35
56
|
end
|
|
36
57
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module CapybaraAccessibilityAudit
|
|
2
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
|
3
|
+
def report(event)
|
|
4
|
+
report = event.payload[:report]
|
|
5
|
+
test = event.payload[:test]
|
|
6
|
+
|
|
7
|
+
if test.accessibility_audit_reporter == :log
|
|
8
|
+
error color(<<~ERROR, :red)
|
|
9
|
+
[capybara_accessibility_audit] Accessibility audit detected violations in "#{test.class.name}##{test.name}":
|
|
10
|
+
#{report.failure_message}
|
|
11
|
+
ERROR
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attach_to :capybara_accessibility_audit
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module CapybaraAccessibilityAudit
|
|
2
|
+
class NotificationReporter
|
|
3
|
+
def initialize(test)
|
|
4
|
+
@test = test
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def report(results)
|
|
8
|
+
if results.violations.present?
|
|
9
|
+
publish(results)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def publish(report)
|
|
16
|
+
ActiveSupport::Notifications.instrument "report.capybara_accessibility_audit", {
|
|
17
|
+
auditor: @test.accessibility_audit_auditor,
|
|
18
|
+
options: @test.accessibility_audit_options,
|
|
19
|
+
report: report,
|
|
20
|
+
test: @test
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -3,7 +3,20 @@ loader = Zeitwerk::Loader.for_gem
|
|
|
3
3
|
loader.setup
|
|
4
4
|
|
|
5
5
|
module CapybaraAccessibilityAudit
|
|
6
|
-
|
|
6
|
+
extend self
|
|
7
|
+
|
|
8
|
+
def reporter_class(name)
|
|
9
|
+
case name
|
|
10
|
+
when :notification, :log
|
|
11
|
+
NotificationReporter
|
|
12
|
+
when :raise
|
|
13
|
+
RaiseReporter
|
|
14
|
+
when ::Class
|
|
15
|
+
name
|
|
16
|
+
else
|
|
17
|
+
raise ArgumentError.new("unsupported reporter: #{name}")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
7
20
|
end
|
|
8
21
|
|
|
9
22
|
loader.eager_load
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: capybara_accessibility_audit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sean Doyle
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rails
|
|
@@ -16,14 +15,14 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
18
|
+
version: '6.1'
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
25
|
+
version: '6.1'
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
27
|
name: capybara
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -39,7 +38,7 @@ dependencies:
|
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
39
|
version: '0'
|
|
41
40
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name: axe-core-
|
|
41
|
+
name: axe-core-api
|
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
|
44
43
|
requirements:
|
|
45
44
|
- - ">="
|
|
@@ -66,6 +65,48 @@ dependencies:
|
|
|
66
65
|
- - ">="
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
67
|
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: bigdecimal
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: drb
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
type: :runtime
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: mutex_m
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
type: :runtime
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
69
110
|
description: Accessibility tooling for Capybara
|
|
70
111
|
email:
|
|
71
112
|
- sean.p.doyle24@gmail.com
|
|
@@ -77,9 +118,13 @@ files:
|
|
|
77
118
|
- README.md
|
|
78
119
|
- Rakefile
|
|
79
120
|
- lib/capybara_accessibility_audit.rb
|
|
121
|
+
- lib/capybara_accessibility_audit/adapter.rb
|
|
80
122
|
- lib/capybara_accessibility_audit/audit_system_test_extensions.rb
|
|
81
|
-
- lib/capybara_accessibility_audit/
|
|
123
|
+
- lib/capybara_accessibility_audit/axe_auditor.rb
|
|
82
124
|
- lib/capybara_accessibility_audit/engine.rb
|
|
125
|
+
- lib/capybara_accessibility_audit/log_subscriber.rb
|
|
126
|
+
- lib/capybara_accessibility_audit/notification_reporter.rb
|
|
127
|
+
- lib/capybara_accessibility_audit/raise_reporter.rb
|
|
83
128
|
- lib/capybara_accessibility_audit/version.rb
|
|
84
129
|
- lib/tasks/capybara_accessibility_audit.rake
|
|
85
130
|
homepage: https://github.com/thoughtbot/capybara_accessibility_audit
|
|
@@ -89,7 +134,7 @@ metadata:
|
|
|
89
134
|
homepage_uri: https://github.com/thoughtbot/capybara_accessibility_audit
|
|
90
135
|
source_code_uri: https://github.com/thoughtbot/capybara_accessibility_audit
|
|
91
136
|
changelog_uri: https://github.com/thoughtbot/capybara_accessibility_audit/blob/main/CHANGELOG.md
|
|
92
|
-
|
|
137
|
+
rubygems_mfa_required: 'true'
|
|
93
138
|
rdoc_options: []
|
|
94
139
|
require_paths:
|
|
95
140
|
- lib
|
|
@@ -97,15 +142,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
97
142
|
requirements:
|
|
98
143
|
- - ">="
|
|
99
144
|
- !ruby/object:Gem::Version
|
|
100
|
-
version: '0'
|
|
145
|
+
version: '3.0'
|
|
101
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
147
|
requirements:
|
|
103
148
|
- - ">="
|
|
104
149
|
- !ruby/object:Gem::Version
|
|
105
150
|
version: '0'
|
|
106
151
|
requirements: []
|
|
107
|
-
rubygems_version:
|
|
108
|
-
signing_key:
|
|
152
|
+
rubygems_version: 4.0.17
|
|
109
153
|
specification_version: 4
|
|
110
154
|
summary: Accessibility tooling for Capybara
|
|
111
155
|
test_files: []
|