Skip to content

Commit

Permalink
feat: axe-core-rspec gem (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeeyyy committed Jul 9, 2020
1 parent aad434d commit 6acf37c
Show file tree
Hide file tree
Showing 31 changed files with 1,510 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -28,4 +28,4 @@ mkmf.log
bin/
node_modules/
spec/examples.txt
results/
./results
1 change: 1 addition & 0 deletions src/common/Gemfile
Expand Up @@ -7,6 +7,7 @@ group :test,
gem "selenium-webdriver"
gem "watir"
gem "capybara"
gem "virtus"

gem "rake"
gem "rspec"
Expand Down
69 changes: 69 additions & 0 deletions src/common/axe/api/a11y_check.rb
@@ -0,0 +1,69 @@
require "forwardable"
require "json"
require_relative "../../chain_mail/chainable"
require_relative "../core"
require_relative "./audit"
require_relative "./context"
require_relative "./options"
require_relative "./results"

module Axe
module API
class A11yCheck
JS_NAME = "run"
METHOD_NAME = "#{Core::JS_NAME}.#{JS_NAME}"

extend Forwardable
def_delegators :@context,
:within,
:excluding
def_delegators :@options,
:according_to,
:checking,
:checking_only,
:skipping,
:with_options

extend ChainMail::Chainable
chainable :within,
:excluding,
:according_to,
:checking,
:checking_only,
:skipping,
:with_options

def initialize
@context = Context.new
@options = Options.new
end

def call(page)
audit page do |results|
Audit.new to_js, Results.new(results)
end
end

extend Gem::Deprecate
deprecate :initialize, "3.0"
deprecate :call, "3.0"

private

def audit(page)
yield page.execute_async_script "#{METHOD_NAME}.apply(#{Core::JS_NAME}, arguments)", *js_args
end

def js_args
[@context, @options]
.reject(&:empty?)
.map(&:to_json)
end

def to_js
str_args = (js_args + ["callback"]).join(", ")
"#{METHOD_NAME}(#{str_args});"
end
end
end
end
24 changes: 24 additions & 0 deletions src/common/axe/api/audit.rb
@@ -0,0 +1,24 @@
module Axe
module API
class Audit
attr_reader :invocation, :results

def initialize(invocation, results)
@invocation = invocation
@results = results
end

def passed?
results.violations.count == 0
end

def failure_message
"#{results.failure_message}\nInvocation: #{invocation}"
end

def failure_message_when_negated
"Expected to find accessibility violations. None were detected.\n\nInvocation: #{invocation}"
end
end
end
end
35 changes: 35 additions & 0 deletions src/common/axe/api/context.rb
@@ -0,0 +1,35 @@
require_relative "./selector"

module Axe
module API
class Context
def initialize
@inclusion = []
@exclusion = []
end

def within(*selectors)
@inclusion.concat selectors.map { |s| Array(Selector.new s) }
end

def excluding(*selectors)
@exclusion.concat selectors.map { |s| Array(Selector.new s) }
end

def to_hash
{ include: @inclusion, exclude: @exclusion }
.reject { |k, v| v.empty? }
end

def to_json
to_hash.to_json
end

def empty?
to_hash.empty?
end

alias :to_s :to_json
end
end
end
32 changes: 32 additions & 0 deletions src/common/axe/api/options.rb
@@ -0,0 +1,32 @@
require "forwardable"
require_relative "./rules"

module Axe
module API
class Options
extend Forwardable

def_delegators :@rules, :according_to, :checking, :checking_only, :skipping
def_delegator :@custom, :merge!, :with_options

def initialize
@rules = Rules.new
@custom = {}
end

def to_hash
@rules.to_hash.merge(@custom)
end

def to_json
to_hash.to_json
end

def empty?
to_hash.empty?
end

alias :to_s :to_json
end
end
end
48 changes: 48 additions & 0 deletions src/common/axe/api/results.rb
@@ -0,0 +1,48 @@
require_relative "./value_object"

module Axe
module API
class Results < ValueObject
require_relative "./results/rule"

values do
attribute :inapplicable, ::Array[Rule]
attribute :incomplete, ::Array[Rule]
attribute :passes, ::Array[Rule]
attribute :timestamp
attribute :url, ::String
attribute :violations, ::Array[Rule]
end

def failure_message
[
"",
violation_count_message,
"",
violations_failure_messages,
].flatten.join("\n")
end

def to_h
{
inapplicable: inapplicable.map(&:to_h),
incomplete: incomplete.map(&:to_h),
passes: passes.map(&:to_h),
timestamp: timestamp,
url: url,
violations: violations.map(&:to_h),
}
end

private

def violation_count_message
"Found #{violations.count} accessibility #{violations.count == 1 ? "violation" : "violations"}:"
end

def violations_failure_messages
violations.each_with_index.map(&:failure_messages)
end
end
end
end
32 changes: 32 additions & 0 deletions src/common/axe/api/results/check.rb
@@ -0,0 +1,32 @@
require_relative "../value_object"
require_relative "../results/node"

module Axe
module API
class Results
class Check < ValueObject
values do
attribute :data, ::String
attribute :id, ::Symbol
attribute :impact, ::Symbol
attribute :message, ::String
attribute :relatedNodes, ::Array[Node]
end

def failure_message
message
end

def to_h
{
data: data,
id: id,
impact: impact,
message: message,
relatedNodes: relatedNodes.map(&:to_h),
}
end
end
end
end
end
51 changes: 51 additions & 0 deletions src/common/axe/api/results/checked_node.rb
@@ -0,0 +1,51 @@
require_relative "./node"
require_relative "./check"

module Axe
module API
class Results
class CheckedNode < Node
values do
attribute :impact, ::Symbol
attribute :any, ::Array[Check]
attribute :all, ::Array[Check]
attribute :none, ::Array[Check]
attribute :failureSummary, ::Symbol
attribute :html, ::String
attribute :target
end

def failure_messages
[
super,
fix(all, "Fix all of the following:"),
fix(none, "Fix all of the following:"),
fix(any, "Fix any of the following:"),
]
end

def to_h
{
all: all.map(&:to_h),
any: any.map(&:to_h),
failureSummary: failureSummary,
html: html,
impact: impact,
none: none.map(&:to_h),
target: target,
}
end

private

def fix(checks, message)
valid_checks = checks.reject { |c| c.nil? }
[
(message unless valid_checks.empty?),
valid_checks.map(&:failure_message).map { |line| line.prepend("- ") },
].compact
end
end
end
end
end
35 changes: 35 additions & 0 deletions src/common/axe/api/results/node.rb
@@ -0,0 +1,35 @@
require_relative "../value_object"

module Axe
module API
class Results
class Node < ValueObject
values do
attribute :html, ::String
attribute :target # String or Array[String]
end

def failure_messages
[selector_message, node_html]
end

def to_h
{
html: html,
target: target,
}
end

private

def selector_message
"Selector: #{Array(target).join(", ")}"
end

def node_html
"HTML: #{html.gsub(/^\s*|\n*/, "")}" unless html.nil?
end
end
end
end
end

0 comments on commit 6acf37c

Please sign in to comment.