axe-core-api 2.6.1.pre.78a535c
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +362 -0
- data/README.md +5 -0
- data/lib/axe/api/a11y_check.rb +69 -0
- data/lib/axe/api/audit.rb +24 -0
- data/lib/axe/api/context.rb +35 -0
- data/lib/axe/api/options.rb +32 -0
- data/lib/axe/api/results.rb +48 -0
- data/lib/axe/api/results/check.rb +32 -0
- data/lib/axe/api/results/checked_node.rb +51 -0
- data/lib/axe/api/results/node.rb +35 -0
- data/lib/axe/api/results/rule.rb +58 -0
- data/lib/axe/api/rules.rb +37 -0
- data/lib/axe/api/run.rb +53 -0
- data/lib/axe/api/selector.rb +18 -0
- data/lib/axe/api/value_object.rb +9 -0
- data/lib/axe/configuration.rb +44 -0
- data/lib/axe/core.rb +45 -0
- data/lib/axe/dsl.rb +15 -0
- data/lib/axe/expectation.rb +33 -0
- data/lib/axe/finds_page.rb +55 -0
- data/lib/axe/matchers/be_accessible.rb +36 -0
- data/lib/chain_mail/chainable.rb +19 -0
- data/lib/hooks.rb +31 -0
- data/lib/loader.rb +25 -0
- data/lib/webdriver_script_adapter/exec_eval_script_adapter.rb +27 -0
- data/lib/webdriver_script_adapter/execute_async_script_adapter.rb +94 -0
- data/lib/webdriver_script_adapter/frame_adapter.rb +84 -0
- data/lib/webdriver_script_adapter/query_selector_adapter.rb +17 -0
- data/node_modules/axe-core/axe.min.js +12 -0
- metadata +200 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative "./selector"
|
2
|
+
|
3
|
+
module Axe
|
4
|
+
module API
|
5
|
+
class Context
|
6
|
+
def initialize
|
7
|
+
@inclusion = []
|
8
|
+
@exclusion = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def within(*selectors)
|
12
|
+
@inclusion.concat selectors.map { |s| Array(Selector.new s) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def excluding(*selectors)
|
16
|
+
@exclusion.concat selectors.map { |s| Array(Selector.new s) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_hash
|
20
|
+
{ include: @inclusion, exclude: @exclusion }
|
21
|
+
.reject { |k, v| v.empty? }
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_json
|
25
|
+
to_hash.to_json
|
26
|
+
end
|
27
|
+
|
28
|
+
def empty?
|
29
|
+
to_hash.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
alias :to_s :to_json
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require_relative "./rules"
|
3
|
+
|
4
|
+
module Axe
|
5
|
+
module API
|
6
|
+
class Options
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :@rules, :according_to, :checking, :checking_only, :skipping
|
10
|
+
def_delegator :@custom, :merge!, :with_options
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@rules = Rules.new
|
14
|
+
@custom = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_hash
|
18
|
+
@rules.to_hash.merge(@custom)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_json
|
22
|
+
to_hash.to_json
|
23
|
+
end
|
24
|
+
|
25
|
+
def empty?
|
26
|
+
to_hash.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
alias :to_s :to_json
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative "./value_object"
|
2
|
+
|
3
|
+
module Axe
|
4
|
+
module API
|
5
|
+
class Results < ValueObject
|
6
|
+
require_relative "./results/rule"
|
7
|
+
|
8
|
+
values do
|
9
|
+
attribute :inapplicable, ::Array[Rule]
|
10
|
+
attribute :incomplete, ::Array[Rule]
|
11
|
+
attribute :passes, ::Array[Rule]
|
12
|
+
attribute :timestamp
|
13
|
+
attribute :url, ::String
|
14
|
+
attribute :violations, ::Array[Rule]
|
15
|
+
end
|
16
|
+
|
17
|
+
def failure_message
|
18
|
+
[
|
19
|
+
"",
|
20
|
+
violation_count_message,
|
21
|
+
"",
|
22
|
+
violations_failure_messages,
|
23
|
+
].flatten.join("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_h
|
27
|
+
{
|
28
|
+
inapplicable: inapplicable.map(&:to_h),
|
29
|
+
incomplete: incomplete.map(&:to_h),
|
30
|
+
passes: passes.map(&:to_h),
|
31
|
+
timestamp: timestamp,
|
32
|
+
url: url,
|
33
|
+
violations: violations.map(&:to_h),
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def violation_count_message
|
40
|
+
"Found #{violations.count} accessibility #{violations.count == 1 ? "violation" : "violations"}:"
|
41
|
+
end
|
42
|
+
|
43
|
+
def violations_failure_messages
|
44
|
+
violations.each_with_index.map(&:failure_messages)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative "../value_object"
|
2
|
+
require_relative "../results/node"
|
3
|
+
|
4
|
+
module Axe
|
5
|
+
module API
|
6
|
+
class Results
|
7
|
+
class Check < ValueObject
|
8
|
+
values do
|
9
|
+
attribute :data, ::String
|
10
|
+
attribute :id, ::Symbol
|
11
|
+
attribute :impact, ::Symbol
|
12
|
+
attribute :message, ::String
|
13
|
+
attribute :relatedNodes, ::Array[Node]
|
14
|
+
end
|
15
|
+
|
16
|
+
def failure_message
|
17
|
+
message
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_h
|
21
|
+
{
|
22
|
+
data: data,
|
23
|
+
id: id,
|
24
|
+
impact: impact,
|
25
|
+
message: message,
|
26
|
+
relatedNodes: relatedNodes.map(&:to_h),
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require_relative "./node"
|
2
|
+
require_relative "./check"
|
3
|
+
|
4
|
+
module Axe
|
5
|
+
module API
|
6
|
+
class Results
|
7
|
+
class CheckedNode < Node
|
8
|
+
values do
|
9
|
+
attribute :impact, ::Symbol
|
10
|
+
attribute :any, ::Array[Check]
|
11
|
+
attribute :all, ::Array[Check]
|
12
|
+
attribute :none, ::Array[Check]
|
13
|
+
attribute :failureSummary, ::Symbol
|
14
|
+
attribute :html, ::String
|
15
|
+
attribute :target
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure_messages
|
19
|
+
[
|
20
|
+
super,
|
21
|
+
fix(all, "Fix all of the following:"),
|
22
|
+
fix(none, "Fix all of the following:"),
|
23
|
+
fix(any, "Fix any of the following:"),
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_h
|
28
|
+
{
|
29
|
+
all: all.map(&:to_h),
|
30
|
+
any: any.map(&:to_h),
|
31
|
+
failureSummary: failureSummary,
|
32
|
+
html: html,
|
33
|
+
impact: impact,
|
34
|
+
none: none.map(&:to_h),
|
35
|
+
target: target,
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def fix(checks, message)
|
42
|
+
valid_checks = checks.reject { |c| c.nil? }
|
43
|
+
[
|
44
|
+
(message unless valid_checks.empty?),
|
45
|
+
valid_checks.map(&:failure_message).map { |line| line.prepend("- ") },
|
46
|
+
].compact
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative "../value_object"
|
2
|
+
|
3
|
+
module Axe
|
4
|
+
module API
|
5
|
+
class Results
|
6
|
+
class Node < ValueObject
|
7
|
+
values do
|
8
|
+
attribute :html, ::String
|
9
|
+
attribute :target # String or Array[String]
|
10
|
+
end
|
11
|
+
|
12
|
+
def failure_messages
|
13
|
+
[selector_message, node_html]
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_h
|
17
|
+
{
|
18
|
+
html: html,
|
19
|
+
target: target,
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def selector_message
|
26
|
+
"Selector: #{Array(target).join(", ")}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def node_html
|
30
|
+
"HTML: #{html.gsub(/^\s*|\n*/, "")}" unless html.nil?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative "../value_object"
|
2
|
+
require_relative "./checked_node"
|
3
|
+
|
4
|
+
module Axe
|
5
|
+
module API
|
6
|
+
class Results
|
7
|
+
class Rule < ValueObject
|
8
|
+
values do
|
9
|
+
attribute :id, ::Symbol
|
10
|
+
attribute :description, ::String
|
11
|
+
attribute :help, ::String
|
12
|
+
attribute :helpUrl, ::String
|
13
|
+
attribute :impact, ::Symbol
|
14
|
+
attribute :tags, ::Array[::Symbol]
|
15
|
+
attribute :nodes, ::Array[CheckedNode]
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure_messages(index)
|
19
|
+
[
|
20
|
+
title_message(index + 1),
|
21
|
+
*[
|
22
|
+
helpUrl,
|
23
|
+
node_count_message,
|
24
|
+
"",
|
25
|
+
nodes.reject { |n| n.nil? }.map(&:failure_messages).map { |n| n.push("") }.flatten.map(&indent),
|
26
|
+
].flatten.map(&indent),
|
27
|
+
]
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_h
|
31
|
+
{
|
32
|
+
description: description,
|
33
|
+
help: help,
|
34
|
+
helpUrl: helpUrl,
|
35
|
+
id: id,
|
36
|
+
impact: impact,
|
37
|
+
nodes: nodes.map(&:to_h),
|
38
|
+
tags: tags,
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def indent
|
45
|
+
->(line) { line.prepend(" " * 4) unless line.nil? }
|
46
|
+
end
|
47
|
+
|
48
|
+
def title_message(count)
|
49
|
+
"#{count}) #{id}: #{help} (#{impact})"
|
50
|
+
end
|
51
|
+
|
52
|
+
def node_count_message
|
53
|
+
"The following #{nodes.length} #{nodes.length == 1 ? "node" : "nodes"} violate this rule:"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Axe
|
2
|
+
module API
|
3
|
+
class Rules
|
4
|
+
def initialize
|
5
|
+
@tags = []
|
6
|
+
@included = []
|
7
|
+
@excluded = []
|
8
|
+
@exclusive = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def according_to(*tags)
|
12
|
+
@tags.concat tags.flatten
|
13
|
+
end
|
14
|
+
|
15
|
+
def checking(*rules)
|
16
|
+
@included.concat rules.flatten
|
17
|
+
end
|
18
|
+
|
19
|
+
def checking_only(*rules)
|
20
|
+
@exclusive.concat rules.flatten
|
21
|
+
end
|
22
|
+
|
23
|
+
def skipping(*rules)
|
24
|
+
@excluded.concat rules.flatten
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_hash
|
28
|
+
{}.tap do |options|
|
29
|
+
# TODO warn that tags + exclusive-rules are incompatible
|
30
|
+
options.merge! runOnly: { type: :tag, values: @tags } unless @tags.empty?
|
31
|
+
options.merge! runOnly: { type: :rule, values: @exclusive } unless @exclusive.empty?
|
32
|
+
options.merge! rules: Hash[@included.product([enabled: true]) + @excluded.product([enabled: false])] unless @included.empty? && @excluded.empty?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/axe/api/run.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
require_relative "../../chain_mail/chainable"
|
5
|
+
require_relative "./audit"
|
6
|
+
require_relative "./context"
|
7
|
+
require_relative "./options"
|
8
|
+
require_relative "./results"
|
9
|
+
require_relative "../core"
|
10
|
+
|
11
|
+
module Axe
|
12
|
+
module API
|
13
|
+
class Run
|
14
|
+
JS_NAME = "run"
|
15
|
+
METHOD_NAME = "#{Core::JS_NAME}.#{JS_NAME}"
|
16
|
+
|
17
|
+
extend Forwardable
|
18
|
+
def_delegators :@context, :within, :excluding
|
19
|
+
def_delegators :@options, :according_to, :checking, :checking_only, :skipping, :with_options
|
20
|
+
|
21
|
+
extend ChainMail::Chainable
|
22
|
+
chainable :within, :excluding, :according_to, :checking, :checking_only, :skipping, :with_options
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@context = Context.new
|
26
|
+
@options = Options.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def call(page)
|
30
|
+
audit page do |results|
|
31
|
+
Audit.new to_js, Results.new(results)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def audit(page)
|
38
|
+
yield page.execute_async_script "#{METHOD_NAME}.apply(#{Core::JS_NAME}, arguments)", *js_args
|
39
|
+
end
|
40
|
+
|
41
|
+
def js_args
|
42
|
+
[@context, @options]
|
43
|
+
.reject(&:empty?)
|
44
|
+
.map(&:to_json)
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_js
|
48
|
+
str_args = (js_args + ["callback"]).join(", ")
|
49
|
+
"#{METHOD_NAME}(#{str_args});"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Axe
|
2
|
+
module API
|
3
|
+
class Selector
|
4
|
+
def initialize(s)
|
5
|
+
@selector = case s
|
6
|
+
when Array then s
|
7
|
+
when String, Symbol then [String(s)]
|
8
|
+
when Hash then Selector.new(s[:selector]).to_a.unshift s[:iframe]
|
9
|
+
else Selector.new(s.selector).to_a.unshift s.iframe
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_a
|
14
|
+
@selector
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "singleton"
|
2
|
+
require "forwardable"
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
require_relative "../hooks"
|
6
|
+
require_relative "../webdriver_script_adapter/execute_async_script_adapter"
|
7
|
+
|
8
|
+
module Axe
|
9
|
+
class Configuration
|
10
|
+
include Singleton
|
11
|
+
include Common::Hooks
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
attr_writer :jslib
|
15
|
+
attr_accessor :page,
|
16
|
+
:jslib_path,
|
17
|
+
:skip_iframes
|
18
|
+
def_delegators ::WebDriverScriptAdapter,
|
19
|
+
:async_results_identifier,
|
20
|
+
:async_results_identifier=,
|
21
|
+
:max_wait_time,
|
22
|
+
:max_wait_time=,
|
23
|
+
:wait_interval,
|
24
|
+
:wait_interval=
|
25
|
+
|
26
|
+
# init
|
27
|
+
def initialize
|
28
|
+
@page = :page
|
29
|
+
@skip_iframes = :skip_iframes
|
30
|
+
@jslib_path = get_root + "/node_modules/axe-core/axe.min.js"
|
31
|
+
end
|
32
|
+
|
33
|
+
# jslib
|
34
|
+
def jslib
|
35
|
+
@jslib ||= Pathname.new(@jslib_path).read
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def get_root
|
41
|
+
Gem::Specification.find_by_name('axe-core-api').gem_dir
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|