-
Notifications
You must be signed in to change notification settings - Fork 53
Expand file tree
/
Copy pathaxe.py
More file actions
executable file
·114 lines (98 loc) · 3.8 KB
/
axe.py
File metadata and controls
executable file
·114 lines (98 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import json
import os
_DEFAULT_SCRIPT = os.path.join(
os.path.dirname(__file__), "node_modules", "axe-core", "axe.min.js"
)
class Axe:
def __init__(self, selenium, script_url=_DEFAULT_SCRIPT):
self.script_url = script_url
self.selenium = selenium
def inject(self):
"""
Recursively inject aXe into all iframes and the top level document.
:param script_url: location of the axe-core script.
:type script_url: string
"""
with open(self.script_url, encoding="utf8") as f:
self.selenium.execute_script(f.read())
def run(self, context=None, options=None):
"""
Run axe against the current page.
:param context: which page part(s) to analyze and/or what to exclude.
:param options: dictionary of aXe options.
"""
template = (
"var callback = arguments[arguments.length - 1];"
+ "axe.run(%s).then(results => callback(results))"
)
args = ""
# If context parameter is passed, add to args
if context is not None:
args += "%r" % context
# Add comma delimiter only if both parameters are passed
if context is not None and options is not None:
args += ","
# If options parameter is passed, add to args
if options is not None:
args += "%s" % options
command = template % args
response = self.selenium.execute_async_script(command)
return response
def report(self, violations):
"""
Return readable report of accessibility violations found.
:param violations: Dictionary of violations.
:type violations: dict
:return report: Readable report of violations.
:rtype: string
"""
string = ""
string += "Found " + str(len(violations)) + " accessibility violations:"
for violation in violations:
string += (
"\n\n\nRule Violated:\n"
+ violation["id"]
+ " - "
+ violation["description"]
+ "\n\tURL: "
+ violation["helpUrl"]
+ "\n\tImpact Level: "
+ violation["impact"]
+ "\n\tTags:"
)
for tag in violation["tags"]:
string += " " + tag
string += "\n\tElements Affected:"
i = 1
for node in violation["nodes"]:
for target in node["target"]:
string += "\n\t" + str(i) + ") Target: " + target
i += 1
for item in node["all"]:
string += "\n\t\t" + item["message"]
for item in node["any"]:
string += "\n\t\t" + item["message"]
for item in node["none"]:
string += "\n\t\t" + item["message"]
string += "\n\n\n"
return string
def write_results(self, data, name=None):
"""
Write JSON to file with the specified name.
:param name: Path to the file to be written to. If no path is passed
a new JSON file "results.json" will be created in the
current working directory.
:param output: JSON object.
"""
if name:
filepath = os.path.abspath(name)
else:
filepath = os.path.abspath("results.json")
with open(filepath, "w", encoding="utf8") as f:
try:
f.write(json.dumps(data, indent=4))
except NameError:
f.write(json.dumps(data, indent=4))