1 | import { registerAsyncHelper } from '@ember/test';
|
2 | import { assert } from '@ember/debug';
|
3 | import RSVP from 'rsvp';
|
4 | import config from 'ember-get-config';
|
5 | import formatViolation from 'ember-a11y-testing/utils/format-violation';
|
6 | import violationsHelper from 'ember-a11y-testing/utils/violations-helper';
|
7 | import { mark, markEndAndMeasure } from './utils';
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | function a11yAuditCallback(results) {
|
16 | let violations = results.violations;
|
17 |
|
18 | if (violations.length) {
|
19 | let allViolations = [];
|
20 |
|
21 | for (let i = 0, l = violations.length; i < l; i++) {
|
22 | let violation = violations[i];
|
23 | let violationNodes = violation.nodes.map(node => node.html);
|
24 |
|
25 | let violationMessage = formatViolation(violation, violationNodes);
|
26 | allViolations.push(violationMessage);
|
27 |
|
28 | console.error(violationMessage, violation);
|
29 | violationsHelper.push(violation);
|
30 | }
|
31 |
|
32 | let allViolationMessages = allViolations.join('\n');
|
33 | assert(`The page should have no accessibility violations. Violations:\n${allViolationMessages}`);
|
34 | }
|
35 | }
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 | function isPlainObj(obj) {
|
44 | return typeof obj == 'object' && obj.constructor == Object;
|
45 | }
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | function isNotSelectorObj(obj) {
|
56 | return !obj.hasOwnProperty('include') && !obj.hasOwnProperty('exclude');
|
57 | }
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 | function runA11yAudit(contextSelector = '#ember-testing-container', axeOptions) {
|
68 | mark('a11y_audit_start');
|
69 |
|
70 |
|
71 | if (arguments.length === 1 && isPlainObj(contextSelector) && isNotSelectorObj(contextSelector)) {
|
72 | axeOptions = contextSelector;
|
73 | contextSelector = '#ember-testing-container';
|
74 | }
|
75 |
|
76 | if (!axeOptions) {
|
77 |
|
78 | let a11yConfig = config['ember-a11y-testing'] || {};
|
79 | let componentOptions = a11yConfig['componentOptions'] || {};
|
80 | axeOptions = componentOptions['axeOptions'] || {};
|
81 | }
|
82 |
|
83 | document.body.classList.add('axe-running');
|
84 |
|
85 | let auditPromise = new RSVP.Promise((resolve, reject) => {
|
86 | axe.run(contextSelector, axeOptions, (error, result) => {
|
87 | if (!error) {
|
88 | return resolve(result);
|
89 | } else {
|
90 | return reject(error);
|
91 | }
|
92 | })
|
93 | });
|
94 |
|
95 | return auditPromise
|
96 | .then(a11yAuditCallback)
|
97 | .finally(() => {
|
98 | document.body.classList.remove('axe-running');
|
99 | markEndAndMeasure('a11y_audit', 'a11y_audit_start', 'a11y_audit_end');
|
100 | });
|
101 | }
|
102 |
|
103 |
|
104 | registerAsyncHelper('a11yAudit', function(app, ...args) {
|
105 | return runA11yAudit(...args);
|
106 | });
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 | export default function a11yAudit(...args) {
|
117 | if (window.a11yAudit) {
|
118 | return window.a11yAudit(...args);
|
119 | }
|
120 |
|
121 | return runA11yAudit(...args);
|
122 | }
|