stormbreaker 0.0.8 → 1.0.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/Rakefile +4 -5
- data/lib/stormbreaker/axe_helper.rb +3 -3
- data/lib/stormbreaker/axe_matcher_auditor.rb +1 -1
- data/lib/stormbreaker/axe_results_serializer.rb +4 -6
- data/lib/stormbreaker/axe_rspec_auditor.rb +2 -2
- data/lib/stormbreaker/axe_violation.rb +1 -1
- data/lib/stormbreaker/axe_violation_manager.rb +16 -11
- data/lib/stormbreaker/configuration.rb +15 -9
- data/lib/stormbreaker/erb_formatter.rb +3 -5
- data/lib/stormbreaker/tasks/results.rake +2 -2
- data/lib/stormbreaker/version.rb +1 -1
- data/lib/stormbreaker.rb +14 -14
- metadata +58 -21
- data/.gitignore +0 -6
- data/Gemfile +0 -5
- data/LICENSE.txt +0 -21
- data/README.md +0 -76
- data/stormbreaker.gemspec +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67edbad3ec4bb16f236684110d0eeb2aa67886f76687ee642a34070b4ba70739
|
4
|
+
data.tar.gz: 5b090b5f745e66af0791943f36a70bcdf24834313714e2e18908867a1cf7ebd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf4fc4c0e961a065dccf6e8abf29b03e6b867eb6d6e683838f9af0e8bf9dbfada29c91a12ff887fbeadcf8806819a1320ca4220eafe979395be78507d81e9851
|
7
|
+
data.tar.gz: 2cf560c7fe36c6ac6fa71e51b0f66bc22be41931cf5f002c2a975326bd828c96bd6bb7aba60b0f29175ec8e8784fbc6991700f1f312573361ce9e63712b5c018
|
data/Rakefile
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "bundler/gem_tasks"
|
4
4
|
|
5
5
|
CLOBBER.include(
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
'Gemfile.lock'
|
6
|
+
"coverage/",
|
7
|
+
"pkg/",
|
8
|
+
"stormbreaker-*.gem"
|
10
9
|
)
|
11
10
|
|
12
11
|
path = File.expand_path(__dir__)
|
@@ -5,7 +5,7 @@ module Stormbreaker
|
|
5
5
|
class AxeHelper
|
6
6
|
def self.assert_axe
|
7
7
|
@driver ||= Stormbreaker.configured_driver
|
8
|
-
raise
|
8
|
+
raise "Driver is not configured" unless @driver
|
9
9
|
|
10
10
|
axe_matcher = Axe::Matchers::BeAxeClean.new
|
11
11
|
axe_matcher.according_to configuration.rules
|
@@ -13,14 +13,14 @@ module Stormbreaker
|
|
13
13
|
|
14
14
|
# Always assert that driver's current page _is_ axe compliant
|
15
15
|
RSpec::Expectations::PositiveExpectationHandler.handle_matcher(@driver, axe_matcher)
|
16
|
-
call_stack = caller.
|
16
|
+
call_stack = caller.grep(/selenium.*_spec\.rb/).first(5)
|
17
17
|
# only get /path/to/spec:line_number from call stack
|
18
18
|
call_stack.map! { |c| c.scan(%r{^[A-Za-z0-9/_-]*\.rb:\d*}) }
|
19
19
|
|
20
20
|
violations = axe_matcher.audit([]).results.violations
|
21
21
|
violations.each do |v|
|
22
22
|
v.nodes.each do |node|
|
23
|
-
manager.add_failure(called_by: call_stack, violation: v, node:
|
23
|
+
manager.add_failure(called_by: call_stack, violation: v, node:)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "yaml"
|
4
4
|
|
5
5
|
module Stormbreaker
|
6
6
|
class AxeResultsSerializer
|
@@ -9,10 +9,8 @@ module Stormbreaker
|
|
9
9
|
def self.serialize_results(total_violations)
|
10
10
|
dump = YAML.dump(total_violations)
|
11
11
|
prefix = Stormbreaker.configuration.serialize_prefix
|
12
|
-
filename = "#{prefix}_#{Time.now.utc.strftime(
|
13
|
-
File.
|
14
|
-
f.write(dump)
|
15
|
-
end
|
12
|
+
filename = "#{prefix}_#{Time.now.utc.strftime("%Y%m%d%H%M%S")}_#{Digest::SHA2.hexdigest(dump)}"
|
13
|
+
File.write(filename, dump)
|
16
14
|
puts "Serialized results written to #{filename}"
|
17
15
|
end
|
18
16
|
|
@@ -24,7 +22,7 @@ module Stormbreaker
|
|
24
22
|
combined_manager = Stormbreaker::AxeViolationManager.new
|
25
23
|
results_files.each do |file|
|
26
24
|
puts "Loading #{file}"
|
27
|
-
total_violations = YAML.
|
25
|
+
total_violations = YAML.safe_load_file(file, permitted_classes: ALLOWED_CLASSES, aliases: true)
|
28
26
|
total_violations.each do |violation|
|
29
27
|
combined_manager.add_failure_to_total(violation)
|
30
28
|
end
|
@@ -4,12 +4,12 @@
|
|
4
4
|
module Stormbreaker
|
5
5
|
module AxeRSpecAuditor
|
6
6
|
# Fire Axe assertion before normal Rspec assertion in case RSpec assertion fails and prevents Axe from running
|
7
|
-
def to(matcher = nil, message = nil
|
7
|
+
def to(matcher = nil, message = nil)
|
8
8
|
Stormbreaker::AxeHelper.assert_axe
|
9
9
|
super
|
10
10
|
end
|
11
11
|
|
12
|
-
def not_to(matcher = nil, message = nil
|
12
|
+
def not_to(matcher = nil, message = nil)
|
13
13
|
Stormbreaker::AxeHelper.assert_axe
|
14
14
|
super
|
15
15
|
end
|
@@ -4,7 +4,7 @@ module Stormbreaker
|
|
4
4
|
class AxeViolation
|
5
5
|
attr_accessor :called_by, :severity, :element, :violation, :complete_summary
|
6
6
|
|
7
|
-
def initialize(called_by: Set.new, severity:
|
7
|
+
def initialize(called_by: Set.new, severity: "", element: "", violation: "", complete_summary: "")
|
8
8
|
self.called_by = Set.new.merge(called_by)
|
9
9
|
self.severity = severity
|
10
10
|
self.violation = violation
|
@@ -10,21 +10,24 @@ module Stormbreaker
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def add_failure(called_by: Set.new, violation: nil, node: nil)
|
13
|
-
axe_violation = get_violation(called_by
|
13
|
+
axe_violation = get_violation(called_by:, violation:, node:)
|
14
14
|
add_failure_to_test(axe_violation)
|
15
15
|
add_failure_to_total(axe_violation)
|
16
16
|
end
|
17
17
|
|
18
18
|
def get_violation(called_by: Set.new, violation: nil, node: nil)
|
19
|
-
raise
|
19
|
+
raise "No violation found" unless violation && node
|
20
20
|
|
21
21
|
severity = violation.impact
|
22
22
|
element = node.html
|
23
23
|
rule = violation.description
|
24
24
|
complete_summary = node.failure_messages.flatten.join("\n")
|
25
25
|
|
26
|
-
AxeViolation.new(called_by
|
27
|
-
|
26
|
+
AxeViolation.new(called_by:,
|
27
|
+
severity:,
|
28
|
+
element:,
|
29
|
+
violation: rule,
|
30
|
+
complete_summary:)
|
28
31
|
end
|
29
32
|
|
30
33
|
def add_failure_to_test(axe_violation)
|
@@ -32,7 +35,9 @@ module Stormbreaker
|
|
32
35
|
end
|
33
36
|
|
34
37
|
def add_failure_to_total(axe_violation)
|
35
|
-
match = @total_violations.select
|
38
|
+
match = @total_violations.select do |v|
|
39
|
+
(v.violation == axe_violation.violation && v.element == axe_violation.element)
|
40
|
+
end
|
36
41
|
raise "Multiple total_violations Found for #{v.description}" if match.count > 1
|
37
42
|
|
38
43
|
if match.any?
|
@@ -67,23 +72,23 @@ module Stormbreaker
|
|
67
72
|
end
|
68
73
|
|
69
74
|
def list_test_results
|
70
|
-
summary =
|
71
|
-
prev_violation =
|
75
|
+
summary = ""
|
76
|
+
prev_violation = ""
|
72
77
|
sort_test_violations.each do |violation|
|
73
|
-
summary += <<~
|
74
|
-
#{prev_violation
|
78
|
+
summary += <<~TEXT
|
79
|
+
#{(prev_violation == violation.violation) ? "" : "\n#{violation.violation} - Severity: #{violation.severity}\n"}
|
75
80
|
#{violation.complete_summary.gsub("\n", "\n ")}
|
76
81
|
|
77
82
|
Violations Found In:
|
78
83
|
#{violation.called_by.to_a.join("\n")}
|
79
|
-
|
84
|
+
TEXT
|
80
85
|
prev_violation = violation.violation
|
81
86
|
end
|
82
87
|
summary
|
83
88
|
end
|
84
89
|
|
85
90
|
def summarize_total_results_by_severity
|
86
|
-
summary =
|
91
|
+
summary = ""
|
87
92
|
error_categories = Stormbreaker.configuration.enabled_severity_categories
|
88
93
|
unique_violations = 0
|
89
94
|
|
@@ -16,27 +16,33 @@ module Stormbreaker
|
|
16
16
|
end
|
17
17
|
|
18
18
|
class Configuration
|
19
|
-
attr_accessor :rules,
|
20
|
-
|
19
|
+
attr_accessor :rules,
|
20
|
+
:skip,
|
21
|
+
:driver,
|
22
|
+
:enabled_severity_categories,
|
23
|
+
:results_path,
|
24
|
+
:serialize_output,
|
25
|
+
:serialized_input_path,
|
26
|
+
:serialize_prefix
|
21
27
|
|
22
28
|
def initialize
|
23
29
|
@rules = %i[wcag2a wcag2aa section508]
|
24
30
|
@skip = %i[color-contrast duplicate-id]
|
25
31
|
@enabled_severity_categories = ALL_SEVERITY_CATEGORIES
|
26
32
|
@driver = nil
|
27
|
-
@results_path =
|
33
|
+
@results_path = "results.html"
|
28
34
|
@serialize_output = false
|
29
|
-
@serialized_input_path =
|
30
|
-
@serialize_prefix =
|
35
|
+
@serialized_input_path = "."
|
36
|
+
@serialize_prefix = "stormbreaker_results"
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
34
40
|
def self.configured_driver
|
35
41
|
# Driver may be a lambda
|
36
42
|
@configured_driver ||= if configuration.driver.respond_to?(:call)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
43
|
+
configuration.driver.call
|
44
|
+
else
|
45
|
+
configuration.driver
|
46
|
+
end
|
41
47
|
end
|
42
48
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "erb"
|
4
4
|
|
5
5
|
module Stormbreaker
|
6
6
|
class ErbFormatter
|
@@ -22,9 +22,7 @@ module Stormbreaker
|
|
22
22
|
|
23
23
|
def write_to_erb
|
24
24
|
erb = ERB.new(template)
|
25
|
-
File.
|
26
|
-
f.write erb.result(binding)
|
27
|
-
end
|
25
|
+
File.write(Stormbreaker.configuration.results_path, erb.result(binding))
|
28
26
|
puts "Results written to #{Stormbreaker.configuration.results_path}"
|
29
27
|
end
|
30
28
|
|
@@ -39,7 +37,7 @@ module Stormbreaker
|
|
39
37
|
end
|
40
38
|
|
41
39
|
def template
|
42
|
-
File.read(File.join(File.dirname(__FILE__),
|
40
|
+
File.read(File.join(File.dirname(__FILE__), "../templates/results.erb"))
|
43
41
|
end
|
44
42
|
end
|
45
43
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
namespace :stormbreaker do
|
4
|
-
desc
|
4
|
+
desc "Combines results that were created from isolated test runs"
|
5
5
|
task :combine_results, %i[path prefix] do |_t, args|
|
6
|
-
require_relative
|
6
|
+
require_relative "../../stormbreaker"
|
7
7
|
manager = Stormbreaker::AxeResultsSerializer.combine_results(args[:path], args[:prefix])
|
8
8
|
erb_writer = Stormbreaker::ErbFormatter.new(manager.total_violations)
|
9
9
|
erb_writer.write_to_erb
|
data/lib/stormbreaker/version.rb
CHANGED
data/lib/stormbreaker.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
3
|
+
require "axe-selenium"
|
4
|
+
require "axe-rspec"
|
5
|
+
require "rspec/core/formatters/base_text_formatter"
|
6
|
+
|
7
|
+
require "stormbreaker/configuration"
|
8
|
+
require "stormbreaker/axe_helper"
|
9
|
+
require "stormbreaker/axe_matcher_auditor"
|
10
|
+
require "stormbreaker/axe_results_reporter"
|
11
|
+
require "stormbreaker/axe_rspec_auditor"
|
12
|
+
require "stormbreaker/axe_violation_manager"
|
13
|
+
require "stormbreaker/axe_violation"
|
14
|
+
require "stormbreaker/erb_formatter"
|
15
|
+
require "stormbreaker/axe_results_serializer"
|
16
16
|
|
17
17
|
module Stormbreaker
|
18
|
-
autoload :VERSION,
|
18
|
+
autoload :VERSION, "stormbreaker/version"
|
19
19
|
|
20
20
|
def self.install!
|
21
21
|
::RSpec::Expectations::ExpectationTarget.prepend AxeRSpecAuditor
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stormbreaker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Watson
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-08-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: axe-core-api
|
@@ -17,42 +17,42 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: 4.1
|
20
|
+
version: '4.1'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 4.1
|
27
|
+
version: '4.1'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: axe-core-rspec
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
32
|
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 4.1
|
34
|
+
version: '4.1'
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 4.1
|
41
|
+
version: '4.1'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: axe-core-selenium
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
46
|
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: 4.1
|
48
|
+
version: '4.1'
|
49
49
|
type: :runtime
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: 4.1
|
55
|
+
version: '4.1'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: rspec
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,33 +82,33 @@ dependencies:
|
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '2.2'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
|
-
name:
|
85
|
+
name: byebug
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
88
|
- - "~>"
|
89
89
|
- !ruby/object:Gem::Version
|
90
|
-
version:
|
90
|
+
version: '11.1'
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
95
|
- - "~>"
|
96
96
|
- !ruby/object:Gem::Version
|
97
|
-
version:
|
97
|
+
version: '11.1'
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
|
-
name:
|
99
|
+
name: nokogiri
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|
101
101
|
requirements:
|
102
102
|
- - "~>"
|
103
103
|
- !ruby/object:Gem::Version
|
104
|
-
version:
|
104
|
+
version: '1.11'
|
105
105
|
type: :development
|
106
106
|
prerelease: false
|
107
107
|
version_requirements: !ruby/object:Gem::Requirement
|
108
108
|
requirements:
|
109
109
|
- - "~>"
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version:
|
111
|
+
version: '1.11'
|
112
112
|
- !ruby/object:Gem::Dependency
|
113
113
|
name: rake
|
114
114
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,6 +123,48 @@ dependencies:
|
|
123
123
|
- - "~>"
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '12.3'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: rubocop-inst
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - "~>"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '1.0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '1.0'
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: rubocop-rake
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - "~>"
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0.6'
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0.6'
|
154
|
+
- !ruby/object:Gem::Dependency
|
155
|
+
name: selenium-webdriver
|
156
|
+
requirement: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - "~>"
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '4.11'
|
161
|
+
type: :development
|
162
|
+
prerelease: false
|
163
|
+
version_requirements: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - "~>"
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '4.11'
|
126
168
|
- !ruby/object:Gem::Dependency
|
127
169
|
name: simplecov
|
128
170
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,10 +187,6 @@ executables: []
|
|
145
187
|
extensions: []
|
146
188
|
extra_rdoc_files: []
|
147
189
|
files:
|
148
|
-
- ".gitignore"
|
149
|
-
- Gemfile
|
150
|
-
- LICENSE.txt
|
151
|
-
- README.md
|
152
190
|
- Rakefile
|
153
191
|
- lib/stormbreaker.rb
|
154
192
|
- lib/stormbreaker/axe_helper.rb
|
@@ -163,7 +201,6 @@ files:
|
|
163
201
|
- lib/stormbreaker/tasks/results.rake
|
164
202
|
- lib/stormbreaker/version.rb
|
165
203
|
- lib/templates/results.erb
|
166
|
-
- stormbreaker.gemspec
|
167
204
|
homepage:
|
168
205
|
licenses:
|
169
206
|
- MIT
|
@@ -178,14 +215,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
178
215
|
requirements:
|
179
216
|
- - ">="
|
180
217
|
- !ruby/object:Gem::Version
|
181
|
-
version: '
|
218
|
+
version: '3.1'
|
182
219
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
220
|
requirements:
|
184
221
|
- - ">="
|
185
222
|
- !ruby/object:Gem::Version
|
186
223
|
version: '0'
|
187
224
|
requirements: []
|
188
|
-
rubygems_version: 3.
|
225
|
+
rubygems_version: 3.3.26
|
189
226
|
signing_key:
|
190
227
|
specification_version: 4
|
191
228
|
summary: Add axe assertions to expect statements by default in Ruby Selenium
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/LICENSE.txt
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
MIT License
|
2
|
-
|
3
|
-
Copyright (c) 2021 Instructure, Inc.
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
13
|
-
copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
SOFTWARE.
|
data/README.md
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
# Stormbreaker
|
2
|
-
|
3
|
-
Stormbreaker automatically adds axe assertions to your ruby selenium tests on top of rspec assertions
|
4
|
-
while providing some additional functionality to sort, group, and display accessibility violations.
|
5
|
-
While it would be fairly easy to add the axe-rspec matchers to an existing suite, stormbreaker adds
|
6
|
-
simple on/off functionality so that you don't have to bloat your testing suite with a huge number of
|
7
|
-
axe assertions. Various configuration options exist to allow certain accessibility rules or severity
|
8
|
-
types (critical / serious / moderate / minor) to be enabled/disabled.
|
9
|
-
|
10
|
-
Rules can be found at https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md
|
11
|
-
|
12
|
-
Stormbreaker provides extra value for mature testing suites where selenium tests exercise a majority
|
13
|
-
of an application's views.
|
14
|
-
|
15
|
-
### What does adding assertions on top of RSpec assertions mean?
|
16
|
-
|
17
|
-
```
|
18
|
-
expect(page.find_element('#important_title').text).to eq('Important Title')
|
19
|
-
```
|
20
|
-
|
21
|
-
*__Without Stormbreaker__*:
|
22
|
-
|
23
|
-
In the above example, selenium would retrieve the text of an element on a page and then check
|
24
|
-
its contents with RSpec.
|
25
|
-
|
26
|
-
*__With Stormbreaker__*:
|
27
|
-
|
28
|
-
In the above example, selenium will still retrieve the text of an element on a page and then check
|
29
|
-
its contents with RSpec, but it will first check to see if page is accessible according to the
|
30
|
-
configured rules.
|
31
|
-
|
32
|
-
An accessibility violation will not immediately cause a test to fail. Instead, a test will run either
|
33
|
-
until completion, or until a failed non-axe assertion. Any axe violations will be collected along the
|
34
|
-
way, ensuring that each test provides as much accessibility coverage as possible. Accessibility
|
35
|
-
violations will be reported on a detailed per-test basis and will be summarized for each suite.
|
36
|
-
|
37
|
-
In addition to violations being reported in the standard RSpec output, an html file utilizing client-side
|
38
|
-
javascript will also be produced to help sort violations by severity and violation type.
|
39
|
-
|
40
|
-
### Configuring Stormbreaker
|
41
|
-
|
42
|
-
In your spec_helper.rb add:
|
43
|
-
|
44
|
-
```
|
45
|
-
require 'stormbreaker'
|
46
|
-
Stormbreaker.install!
|
47
|
-
Stormbreaker.configure do |config|
|
48
|
-
# Driver configuration -- can be a lambda or an object. May need to be a lambda if your driver isnt
|
49
|
-
# available in your spec_helper.rb. This wont be referenced until an assertion is first run
|
50
|
-
config.driver = lambda { Driver.new }
|
51
|
-
|
52
|
-
# Axe config
|
53
|
-
config.rules = %i[wcag2a wcag2aa section508]
|
54
|
-
config.skip = %i[color-contrast duplicate-id]
|
55
|
-
config.enabled_severity_categories = %i[critical serious moderate minor]
|
56
|
-
|
57
|
-
# Standard results output
|
58
|
-
config.results_path = 'results.html'
|
59
|
-
|
60
|
-
# Serialization configuration
|
61
|
-
config.serialize_output = true
|
62
|
-
config.serialized_input_path = '.'
|
63
|
-
config.serialize_prefix = 'stormbreaker_results'
|
64
|
-
end
|
65
|
-
```
|
66
|
-
|
67
|
-
After adding stormbreaker to your Gemfile and installing it, then run `bundle exec rspec`
|
68
|
-
|
69
|
-
### Running tests in parallel
|
70
|
-
|
71
|
-
Stormbreaker's code is largely prepended onto RSpec's code, so it should not affect any parallelization.
|
72
|
-
However, if you'd like to generate an html that includes all of the different runs, stormbreaker provides
|
73
|
-
an option to dump each run's serialized results and then combine them into a single html file using a
|
74
|
-
rake task.
|
75
|
-
|
76
|
-
`bundle exec rake stormbreaker:combine_results['<path/to/#{serialize_prefix}*>']`
|
data/stormbreaker.gemspec
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# rubocop:disable Layout/ExtraSpacing, Layout/SpaceAroundOperators, Metrics/BlockLength
|
4
|
-
require './lib/stormbreaker/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |gem|
|
7
|
-
gem.name = 'stormbreaker'
|
8
|
-
gem.version = Stormbreaker::VERSION
|
9
|
-
gem.license = 'MIT'
|
10
|
-
gem.authors = [
|
11
|
-
'Brian Watson',
|
12
|
-
'Mikey Hargiss'
|
13
|
-
]
|
14
|
-
gem.email = [
|
15
|
-
'bwatson@instructure.com',
|
16
|
-
'mhargiss@instructure.com'
|
17
|
-
]
|
18
|
-
gem.summary = 'Add axe assertions to expect statements by default in Ruby Selenium'
|
19
|
-
|
20
|
-
gem.files = `git ls-files -z`
|
21
|
-
.split("\x0")
|
22
|
-
.reject { |f| f.match(%r{^(test|spec|features|bin)/}) }
|
23
|
-
.reject { |f| f.match(/^(Jenkinsfile|Dockerfile|.dockerignore|.rspec|.rubocop)/) }
|
24
|
-
gem.bindir = 'bin'
|
25
|
-
gem.require_paths = ['lib']
|
26
|
-
|
27
|
-
gem.metadata = {
|
28
|
-
'allowed_push_host' => 'https://rubygems.org',
|
29
|
-
'rubygems_mfa_required' => 'true'
|
30
|
-
}
|
31
|
-
|
32
|
-
gem.required_ruby_version = '>= 2.6'
|
33
|
-
|
34
|
-
gem.add_dependency 'axe-core-api', '~> 4.1.0'
|
35
|
-
gem.add_dependency 'axe-core-rspec', '~> 4.1.0'
|
36
|
-
gem.add_dependency 'axe-core-selenium', '~> 4.1.0'
|
37
|
-
gem.add_dependency 'rspec', '~> 3.8'
|
38
|
-
gem.add_development_dependency 'bundler', '~> 2.2'
|
39
|
-
gem.add_development_dependency 'nokogiri', '~> 1.11.7'
|
40
|
-
gem.add_development_dependency 'pry', '~> 0.14.1'
|
41
|
-
gem.add_development_dependency 'rake', '~> 12.3'
|
42
|
-
gem.add_development_dependency 'simplecov', '~> 0.17'
|
43
|
-
end
|
44
|
-
# rubocop:enable Layout/ExtraSpacing, Layout/SpaceAroundOperators, Metrics/BlockLength
|