testaro 14.2.6 → 14.4.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.
- package/README.md +53 -33
- package/actSpecs.js +1 -1
- package/call.js +1 -0
- package/package.json +1 -1
- package/run.js +35 -23
- package/standardize.js +133 -16
- package/testaro/allHidden.js +23 -3
- package/testaro/attVal.js +6 -0
- package/testaro/autocomplete.js +6 -2
- package/testaro/bulk.js +5 -1
- package/testaro/docType.js +2 -0
- package/testaro/dupAtt.js +10 -4
- package/testaro/embAc.js +7 -1
- package/testaro/filter.js +6 -1
- package/testaro/focAll.js +3 -0
- package/testaro/focInd.js +37 -13
- package/testaro/focOp.js +36 -15
- package/testaro/focVis.js +10 -2
- package/testaro/hover.js +8 -2
- package/testaro/labClash.js +36 -12
- package/testaro/linkTo.js +13 -5
- package/testaro/linkUl.js +21 -9
- package/testaro/menuNav.js +17 -6
- package/testaro/miniText.js +11 -2
- package/testaro/motion.js +13 -9
- package/testaro/nonTable.js +12 -4
- package/testaro/radioSet.js +15 -6
- package/testaro/role.js +19 -10
- package/testaro/styleDiff.js +14 -10
- package/testaro/tabNav.js +16 -4
- package/testaro/titledEl.js +7 -1
- package/testaro/zIndex.js +7 -4
- package/tests/ibm.js +1 -1
package/README.md
CHANGED
|
@@ -204,10 +204,13 @@ If the `STANDARD` environment variable has the value `also` (which it has by def
|
|
|
204
204
|
|
|
205
205
|
The standard format of each tool report has two properties:
|
|
206
206
|
- `totals`: an array of 4 integers, representing the counts of issue instances classified by the tool into 4 ordinal degrees of severity. For example, `[2, 13, 0, 5]` would mean that the tool reported 2 instances at the lowest severity, 13 at the next-lowest, none at the third-lowest, and 5 at the highest.
|
|
207
|
-
- `instances`: an array of objects describing facts about issue instances reported by the tool.
|
|
207
|
+
- `instances`: an array of objects describing facts about issue instances reported by the tool. This object has these properties, some of which have empty strings as values when the tool does not provide values:
|
|
208
208
|
- `issueID`: a code identifying the issue
|
|
209
209
|
- `what`: a description of the issue
|
|
210
|
+
- `count` (optional): the count of instances if this instance represents multiple instances
|
|
210
211
|
- `ordinalSeverity`: how the tool ranks the severity of the instance, on a 4-point ordinal scale
|
|
212
|
+
- `tagName`: upper-case tagName of the affected element
|
|
213
|
+
- `id`: value of the `id` property of that element
|
|
211
214
|
- `location`: an object with three properties:
|
|
212
215
|
- `doc`: whether the source (`source`) or the browser rendition (`dom`) was tested
|
|
213
216
|
- `type`: the type of location information provided by the tool (`line`, `selector`, or `xpath`)
|
|
@@ -218,12 +221,14 @@ The original result of a test act is recorded as the value of a `result` propert
|
|
|
218
221
|
|
|
219
222
|
``` javascript
|
|
220
223
|
standardResult: {
|
|
221
|
-
totals: [2, 0,
|
|
224
|
+
totals: [2, 0, 17, 0],
|
|
222
225
|
instances: [
|
|
223
226
|
{
|
|
224
227
|
issueID: 'rule01',
|
|
225
|
-
what: '
|
|
228
|
+
what: 'Button type invalid',
|
|
226
229
|
ordinalSeverity: 0,
|
|
230
|
+
tagName: 'BUTTON'
|
|
231
|
+
id: '',
|
|
227
232
|
location: {
|
|
228
233
|
doc: 'dom',
|
|
229
234
|
type: 'line',
|
|
@@ -233,8 +238,10 @@ standardResult: {
|
|
|
233
238
|
},
|
|
234
239
|
{
|
|
235
240
|
issueID: 'rule01',
|
|
236
|
-
what: '
|
|
241
|
+
what: 'Button type invalid',
|
|
237
242
|
ordinalSeverity: 1,
|
|
243
|
+
tagName: 'BUTTON',
|
|
244
|
+
id: 'submitbutton',
|
|
238
245
|
location: {
|
|
239
246
|
doc: 'dom',
|
|
240
247
|
type: 'line',
|
|
@@ -244,20 +251,23 @@ standardResult: {
|
|
|
244
251
|
},
|
|
245
252
|
{
|
|
246
253
|
issueID: 'rule02',
|
|
247
|
-
what: '
|
|
254
|
+
what: 'Links have empty href attributes',
|
|
255
|
+
count: 17,
|
|
248
256
|
ordinalSeverity: 3,
|
|
257
|
+
tagName: 'A',
|
|
258
|
+
id: '',
|
|
249
259
|
location: {
|
|
250
|
-
doc: '
|
|
251
|
-
type: '
|
|
252
|
-
spec: '
|
|
260
|
+
doc: '',
|
|
261
|
+
type: '',
|
|
262
|
+
spec: ''
|
|
253
263
|
},
|
|
254
|
-
excerpt: '
|
|
264
|
+
excerpt: ''
|
|
255
265
|
}
|
|
256
266
|
]
|
|
257
267
|
}
|
|
258
268
|
```
|
|
259
269
|
|
|
260
|
-
If a tool has the option to be used without itemization and is being so used, the `instances` array
|
|
270
|
+
If a tool has the option to be used without itemization and is being so used, the `instances` array may be empty.
|
|
261
271
|
|
|
262
272
|
### Acts
|
|
263
273
|
|
|
@@ -454,29 +464,6 @@ The `continuum` tests makes use of the files in the `continuum` directory. The t
|
|
|
454
464
|
|
|
455
465
|
Level Access on 22 August 2022 granted authorization for the copying of the `AccessEngine.community.js` file insofar as necessary for allowing Continuum community edition tests to be included in Testaro.
|
|
456
466
|
|
|
457
|
-
###### IBM Equal Access
|
|
458
|
-
|
|
459
|
-
The `ibm` tests require the `aceconfig.js` file.
|
|
460
|
-
|
|
461
|
-
As of 2 March 2023 (version 3.1.45 of `accessibility-checker`), the `ibm` tool threw errors when hosted under the Windows operating system. To prevent these errors, it was possible to edit two files in the `accessibility-checker` package as follows:
|
|
462
|
-
|
|
463
|
-
In `node_modules/accessibility-checker/lib/ACEngineManager.js`, remove or comment out these lines starting on line 169:
|
|
464
|
-
|
|
465
|
-
```javaScript
|
|
466
|
-
if (nodePath.charAt(0) !== '/') {
|
|
467
|
-
nodePath = "../../" + nodePath;
|
|
468
|
-
}
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
In `node_modules/accessibility-checker/lib/reporters/ACReporterJSON.js`, add these lines starting on line 106, immediately before the line `var resultsFileName = pathLib.join(resultDir, results.label + '.json');`:
|
|
472
|
-
|
|
473
|
-
```javaScript
|
|
474
|
-
// Replace the colons in the label with hyphen-minuses.
|
|
475
|
-
results.label = results.label.replace(/:/g, '-');
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
These changes were proposed as pull requests 1333 and 1334 (https://github.com/IBMa/equal-access/pulls).
|
|
479
|
-
|
|
480
467
|
###### HTML CodeSniffer
|
|
481
468
|
|
|
482
469
|
The `htmlcs` tool makes use of the `htmlcs/HTMLCS.js` file. That file was created, and can be recreated if necessary, as follows:
|
|
@@ -509,6 +496,31 @@ The changes in `htmlcs/HTMLCS.js` are:
|
|
|
509
496
|
> );
|
|
510
497
|
```
|
|
511
498
|
|
|
499
|
+
###### IBM Equal Access
|
|
500
|
+
|
|
501
|
+
The `ibm` tests require the `aceconfig.js` file.
|
|
502
|
+
|
|
503
|
+
As of 2 March 2023 (version 3.1.45 of `accessibility-checker`), the `ibm` tool threw errors when hosted under the Windows operating system. To prevent these errors, it was possible to edit two files in the `accessibility-checker` package as follows:
|
|
504
|
+
|
|
505
|
+
In `node_modules/accessibility-checker/lib/ACEngineManager.js`, remove or comment out these lines starting on line 169:
|
|
506
|
+
|
|
507
|
+
```javaScript
|
|
508
|
+
if (nodePath.charAt(0) !== '/') {
|
|
509
|
+
nodePath = "../../" + nodePath;
|
|
510
|
+
}
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
In `node_modules/accessibility-checker/lib/reporters/ACReporterJSON.js`, add these lines starting on line 106, immediately before the line `var resultsFileName = pathLib.join(resultDir, results.label + '.json');`:
|
|
514
|
+
|
|
515
|
+
```javaScript
|
|
516
|
+
// Replace the colons in the label with hyphen-minuses.
|
|
517
|
+
results.label = results.label.replace(/:/g, '-');
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
These changes were proposed as pull requests 1333 and 1334 (https://github.com/IBMa/equal-access/pulls).
|
|
521
|
+
|
|
522
|
+
The `ibm` tool is one of two tools (`testaro` is the other) with a `withItems` property. If you set `withItems` to `false`, the result includes the counts of “violations” and “recommendations”, but no information about the rules that gave rise to them.
|
|
523
|
+
|
|
512
524
|
###### QualWeb
|
|
513
525
|
|
|
514
526
|
The `qualWeb` tool performs the ACT rules, WCAG Techniques, and best-practices tests of QualWeb. Only failures and warnings are included in the report. The EARL report of QualWeb is not generated, because it is equivalent to the report of the ACT rules tests.
|
|
@@ -555,6 +567,14 @@ Tenon recommends giving it a public URL rather than giving it the content of a p
|
|
|
555
567
|
|
|
556
568
|
If a `tenon` test act is included in a job, environment variables named `TENON_USER` and `TENON_PASSWORD` must exist, with your Tenon username and password, respectively, as their values. These could be obtained from [Tenon](https://tenon.io/documentation/overview) until Tenon was closed to new subscribers in or about October 2022.
|
|
557
569
|
|
|
570
|
+
###### Testaro
|
|
571
|
+
|
|
572
|
+
If you do not specify rules when using the `testaro` tool, Testaro will test for the rules listed in the `evalRules` object of the `tests/testaro.js` file.
|
|
573
|
+
|
|
574
|
+
It has been found that the `motion` test of the `testaro` tool measures motion only when the `webkit` browser type is in use. If you want to use `testaro` with different browser types for different tests, you can include 2 or 3 `testaro` test acts in your job, specifying different browser types and different rules.
|
|
575
|
+
|
|
576
|
+
The `testaro` tool (like the `ibm` tool) has a `withItems` property. If you set it to `false`, the `standardResult` object of `testaro` will contain an `instances` property with summaries that identify issues and instance counts. If you set it to `true`, some of the instances will be itemized.
|
|
577
|
+
|
|
558
578
|
###### WAVE
|
|
559
579
|
|
|
560
580
|
If a `wave` test act is included in the job, an environment variable named `WAVE_KEY` must exist, with your WAVE API key as its value. You can get it from [WebAIM](https://wave.webaim.org/api/).
|
package/actSpecs.js
CHANGED
package/call.js
CHANGED
package/package.json
CHANGED
package/run.js
CHANGED
|
@@ -994,31 +994,43 @@ const doActs = async (report, actIndex, page) => {
|
|
|
994
994
|
}
|
|
995
995
|
// Conduct, report, and time the test.
|
|
996
996
|
const startTime = Date.now();
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
997
|
+
let testReport = {
|
|
998
|
+
result: {
|
|
999
|
+
success: false
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
1002
|
+
try {
|
|
1003
|
+
testReport = await require(`./tests/${act.which}`).reporter(...args);
|
|
1004
|
+
const expectations = act.expect;
|
|
1005
|
+
// If the test has expectations:
|
|
1006
|
+
if (expectations) {
|
|
1007
|
+
// Initialize whether they were fulfilled.
|
|
1008
|
+
testReport.result.expectations = [];
|
|
1009
|
+
let failureCount = 0;
|
|
1010
|
+
// For each expectation:
|
|
1011
|
+
expectations.forEach(spec => {
|
|
1012
|
+
const truth = isTrue(testReport, spec);
|
|
1013
|
+
testReport.result.expectations.push({
|
|
1014
|
+
property: spec[0],
|
|
1015
|
+
relation: spec[1],
|
|
1016
|
+
criterion: spec[2],
|
|
1017
|
+
actual: truth[0],
|
|
1018
|
+
passed: truth[1]
|
|
1019
|
+
});
|
|
1020
|
+
if (! truth[1]) {
|
|
1021
|
+
failureCount++;
|
|
1022
|
+
}
|
|
1013
1023
|
});
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
});
|
|
1018
|
-
testReport.result.failureCount = failureCount;
|
|
1024
|
+
testReport.result.failureCount = failureCount;
|
|
1025
|
+
}
|
|
1026
|
+
testReport.result.success = true;
|
|
1019
1027
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1028
|
+
catch(error) {
|
|
1029
|
+
console.log(`ERROR: Test act ${act.which} failed (${error.message.slice(0, 400)})`);
|
|
1030
|
+
}
|
|
1031
|
+
report.jobData.testTimes.push(
|
|
1032
|
+
[act.which, Math.round((Date.now() - startTime) / 1000)]
|
|
1033
|
+
);
|
|
1022
1034
|
report.jobData.testTimes.sort((a, b) => b[1] - a[1]);
|
|
1023
1035
|
// Add the result object (possibly an array) to the act.
|
|
1024
1036
|
const resultCount = Object.keys(testReport.result).length;
|
package/standardize.js
CHANGED
|
@@ -35,10 +35,23 @@ const doAxe = (result, standardResult, certainty) => {
|
|
|
35
35
|
critical: 1
|
|
36
36
|
};
|
|
37
37
|
const ordinalSeverity = severityWeights[node.impact] + (certainty === 'violations' ? 2 : 0);
|
|
38
|
+
const tagName = node.html && node.html.replace(/^<|[ >].*$/sg, '').toUpperCase();
|
|
39
|
+
let id = '';
|
|
40
|
+
if (node.target && node.target.length && node.target[0].startsWith('#')) {
|
|
41
|
+
id = node.target[0].slice(1);
|
|
42
|
+
}
|
|
43
|
+
else if (node.html) {
|
|
44
|
+
const idArray = node.html.match(/\sid="([^"]+)"/);
|
|
45
|
+
if (idArray && idArray.length === 2) {
|
|
46
|
+
id = idArray[1];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
38
49
|
const instance = {
|
|
39
50
|
issueID: rule.id,
|
|
40
51
|
what: Array.from(whatSet.values()).join('; '),
|
|
41
52
|
ordinalSeverity,
|
|
53
|
+
tagName,
|
|
54
|
+
id,
|
|
42
55
|
location: {
|
|
43
56
|
doc: 'dom',
|
|
44
57
|
type: 'selector',
|
|
@@ -58,17 +71,19 @@ const doHTMLCS = (result, standardResult, severity) => {
|
|
|
58
71
|
const ruleData = result[severity][ruleID];
|
|
59
72
|
Object.keys(ruleData).forEach(what => {
|
|
60
73
|
ruleData[what].forEach(item => {
|
|
61
|
-
const {tagName, code} = item;
|
|
74
|
+
const {tagName, id, code} = item;
|
|
62
75
|
const instance = {
|
|
63
76
|
issueID: ruleID,
|
|
64
77
|
what,
|
|
65
78
|
ordinalSeverity: ['Warning', '', '', 'Error'].indexOf(severity),
|
|
79
|
+
tagName: tagName.toUpperCase(),
|
|
80
|
+
id: id.slice(1),
|
|
66
81
|
location: {
|
|
67
82
|
doc: 'dom',
|
|
68
83
|
type: '',
|
|
69
84
|
spec: ''
|
|
70
85
|
},
|
|
71
|
-
excerpt: cap(
|
|
86
|
+
excerpt: cap(code)
|
|
72
87
|
};
|
|
73
88
|
standardResult.instances.push(instance);
|
|
74
89
|
});
|
|
@@ -81,10 +96,27 @@ const doNuVal = (result, standardResult, docType) => {
|
|
|
81
96
|
const items = result[docType] && result[docType].messages;
|
|
82
97
|
if (items && items.length) {
|
|
83
98
|
items.forEach(item => {
|
|
99
|
+
let tagName = '';
|
|
100
|
+
let id = '';
|
|
101
|
+
if (item.extract) {
|
|
102
|
+
const tagNameLCArray = item.extract.match(
|
|
103
|
+
/^Element ([^ ]+)|^An (img) element| (meta|script) element| element (script)| tag (script)/
|
|
104
|
+
);
|
|
105
|
+
if (tagNameLCArray && tagNameLCArray.length > 1) {
|
|
106
|
+
tagName = tagNameLCArray[1].toUpperCase();
|
|
107
|
+
}
|
|
108
|
+
const idArray = item.extract.match(/^.+\sid="([^"]+)"/);
|
|
109
|
+
if (idArray && idArray.length === 2) {
|
|
110
|
+
id = idArray[1];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Include the message twice, because in scoring it is likely to be replaced by a pattern.
|
|
84
114
|
const instance = {
|
|
85
115
|
issueID: item.message,
|
|
86
116
|
what: item.message,
|
|
87
117
|
ordinalSeverity: -1,
|
|
118
|
+
tagName,
|
|
119
|
+
id,
|
|
88
120
|
location: {
|
|
89
121
|
doc: docType === 'pageContent' ? 'dom' : 'source',
|
|
90
122
|
type: 'line',
|
|
@@ -125,16 +157,31 @@ const doQualWeb = (result, standardResult, ruleClassName) => {
|
|
|
125
157
|
const ruleResult = ruleClass.assertions[rule];
|
|
126
158
|
ruleResult.results.forEach(item => {
|
|
127
159
|
item.elements.forEach(element => {
|
|
160
|
+
const {htmlCode} = element;
|
|
161
|
+
let tagName = '';
|
|
162
|
+
let id = '';
|
|
163
|
+
if (htmlCode) {
|
|
164
|
+
const tagNameArray = htmlCode.match(/^<([^ >]+)/);
|
|
165
|
+
if (tagNameArray && tagNameArray.length === 2) {
|
|
166
|
+
tagName = tagNameArray[1].toUpperCase();
|
|
167
|
+
}
|
|
168
|
+
const idArray = htmlCode.match(/\sid="([^"]+)"/);
|
|
169
|
+
if (idArray && idArray.length === 2) {
|
|
170
|
+
id = idArray[1];
|
|
171
|
+
}
|
|
172
|
+
}
|
|
128
173
|
const instance = {
|
|
129
174
|
issueID: rule,
|
|
130
175
|
what: ruleResult.description,
|
|
131
176
|
ordinalSeverity: severities[ruleClassName][item.verdict],
|
|
177
|
+
tagName,
|
|
178
|
+
id,
|
|
132
179
|
location: {
|
|
133
180
|
doc: 'dom',
|
|
134
181
|
type: 'selector',
|
|
135
182
|
spec: element.pointer
|
|
136
183
|
},
|
|
137
|
-
excerpt: cap(
|
|
184
|
+
excerpt: cap(htmlCode)
|
|
138
185
|
};
|
|
139
186
|
standardResult.instances.push(instance);
|
|
140
187
|
standardResult.totals[instance.ordinalSeverity]++;
|
|
@@ -150,10 +197,25 @@ const doWAVE = (result, standardResult, categoryName) => {
|
|
|
150
197
|
const ordinalSeverity = categoryName === 'alert' ? 0 : 3;
|
|
151
198
|
Object.keys(category.items).forEach(rule => {
|
|
152
199
|
category.items[rule].selectors.forEach(selector => {
|
|
200
|
+
let tagName = '';
|
|
201
|
+
let id = '';
|
|
202
|
+
if (typeof selector === 'string') {
|
|
203
|
+
const finalTerm = selector.replace(/^.+\s/, '');
|
|
204
|
+
if (finalTerm.includes('#')) {
|
|
205
|
+
const finalArray = finalTerm.split('#');
|
|
206
|
+
tagName = finalArray[0].replace(/:.*/, '');
|
|
207
|
+
id = finalArray[1];
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
tagName = finalTerm.replace(/:.*/, '');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
153
213
|
const instance = {
|
|
154
214
|
issueID: rule,
|
|
155
215
|
what: category.items[rule].description,
|
|
156
216
|
ordinalSeverity,
|
|
217
|
+
tagName,
|
|
218
|
+
id,
|
|
157
219
|
location: {
|
|
158
220
|
doc: 'dom',
|
|
159
221
|
type: 'selector',
|
|
@@ -167,28 +229,39 @@ const doWAVE = (result, standardResult, categoryName) => {
|
|
|
167
229
|
}
|
|
168
230
|
};
|
|
169
231
|
// Converts a result.
|
|
170
|
-
const convert = (
|
|
232
|
+
const convert = (toolName, result, standardResult) => {
|
|
171
233
|
// alfa
|
|
172
|
-
if (
|
|
234
|
+
if (toolName === 'alfa' && result.totals) {
|
|
173
235
|
standardResult.totals = [result.totals.warnings, 0, 0, result.totals.failures];
|
|
174
236
|
result.items.forEach(item => {
|
|
237
|
+
const {codeLines} = item.target;
|
|
238
|
+
let id = '';
|
|
239
|
+
if (codeLines && codeLines.length) {
|
|
240
|
+
const code = codeLines[0];
|
|
241
|
+
const idMatchArray = code.match(/\sid="([^"]+)"/);
|
|
242
|
+
if (idMatchArray && idMatchArray.length === 2) {
|
|
243
|
+
id = idMatchArray[1];
|
|
244
|
+
}
|
|
245
|
+
}
|
|
175
246
|
const instance = {
|
|
176
247
|
issueID: item.rule.ruleID,
|
|
177
248
|
what: item.rule.ruleSummary,
|
|
178
249
|
ordinalSeverity: ['cantTell', '', '', 'failed'].indexOf(item.verdict),
|
|
250
|
+
tagName: item.target.tagName.toUpperCase(),
|
|
251
|
+
id,
|
|
179
252
|
location: {
|
|
180
253
|
doc: 'dom',
|
|
181
254
|
type: 'xpath',
|
|
182
255
|
spec: item.target.path
|
|
183
256
|
},
|
|
184
|
-
excerpt: cap(
|
|
257
|
+
excerpt: Array.isArray(codeLines) ? cap(codeLines.join(' ')) : ''
|
|
185
258
|
};
|
|
186
259
|
standardResult.instances.push(instance);
|
|
187
260
|
});
|
|
188
261
|
}
|
|
189
262
|
// axe
|
|
190
263
|
else if (
|
|
191
|
-
|
|
264
|
+
toolName === 'axe'
|
|
192
265
|
&& result.totals
|
|
193
266
|
&& (result.totals.rulesWarned || result.totals.rulesViolated)
|
|
194
267
|
) {
|
|
@@ -203,13 +276,25 @@ const convert = (testName, result, standardResult) => {
|
|
|
203
276
|
doAxe(result, standardResult, 'violations');
|
|
204
277
|
}
|
|
205
278
|
// continuum
|
|
206
|
-
else if (
|
|
279
|
+
else if (toolName === 'continuum' && Array.isArray(result) && result.length) {
|
|
207
280
|
standardResult.totals = [0, 0, 0, result.length];
|
|
208
281
|
result.forEach(item => {
|
|
282
|
+
let tagName = '';
|
|
283
|
+
let id = '';
|
|
284
|
+
if (item.fingerprint && item.fingerprint.css) {
|
|
285
|
+
const {css} = item.fingerprint;
|
|
286
|
+
tagName = css.replace(/[^a-z].*$/, '').toUpperCase();
|
|
287
|
+
const idArray = css.match(/\[id="([^"]+)"\]/);
|
|
288
|
+
if (idArray && idArray.length) {
|
|
289
|
+
id = idArray[1];
|
|
290
|
+
}
|
|
291
|
+
}
|
|
209
292
|
const instance = {
|
|
210
293
|
issueID: item.engineTestId.toString(),
|
|
211
294
|
what: item.attributeDetail,
|
|
212
|
-
ordinalSeverity:
|
|
295
|
+
ordinalSeverity: 3,
|
|
296
|
+
tagName,
|
|
297
|
+
id,
|
|
213
298
|
location: {
|
|
214
299
|
doc: 'dom',
|
|
215
300
|
type: 'selector',
|
|
@@ -221,7 +306,7 @@ const convert = (testName, result, standardResult) => {
|
|
|
221
306
|
});
|
|
222
307
|
}
|
|
223
308
|
// htmlcs
|
|
224
|
-
else if (
|
|
309
|
+
else if (toolName === 'htmlcs' && result) {
|
|
225
310
|
doHTMLCS(result, standardResult, 'Warning');
|
|
226
311
|
doHTMLCS(result, standardResult, 'Error');
|
|
227
312
|
const {instances} = standardResult;
|
|
@@ -233,13 +318,29 @@ const convert = (testName, result, standardResult) => {
|
|
|
233
318
|
];
|
|
234
319
|
}
|
|
235
320
|
// ibm
|
|
236
|
-
else if (
|
|
321
|
+
else if (toolName === 'ibm' && result.totals) {
|
|
237
322
|
standardResult.totals = [0, result.totals.recommendation, 0, result.totals.violation];
|
|
238
323
|
result.items.forEach(item => {
|
|
324
|
+
let tagName = '';
|
|
325
|
+
let id = '';
|
|
326
|
+
if (item.path && item.path.dom) {
|
|
327
|
+
const tagNameArray = item.path.dom.match(/^.+\/([^/[]+)/s);
|
|
328
|
+
if (tagNameArray && tagNameArray.length === 2) {
|
|
329
|
+
tagName = tagNameArray[1];
|
|
330
|
+
}
|
|
331
|
+
if (item.snippet) {
|
|
332
|
+
const idArray = item.snippet.match(/^.+\sid="([^"]+)"/s);
|
|
333
|
+
if (idArray && idArray.length === 2) {
|
|
334
|
+
id = idArray[1];
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
239
338
|
const instance = {
|
|
240
339
|
issueID: item.ruleId,
|
|
241
340
|
what: item.message,
|
|
242
341
|
ordinalSeverity: ['', 'recommendation', '', 'violation'].indexOf(item.level),
|
|
342
|
+
tagName,
|
|
343
|
+
id,
|
|
243
344
|
location: {
|
|
244
345
|
doc: 'dom',
|
|
245
346
|
type: 'xpath',
|
|
@@ -251,7 +352,7 @@ const convert = (testName, result, standardResult) => {
|
|
|
251
352
|
});
|
|
252
353
|
}
|
|
253
354
|
// nuVal
|
|
254
|
-
else if (
|
|
355
|
+
else if (toolName === 'nuVal' && (result.pageContent || result.rawPage)) {
|
|
255
356
|
if (result.pageContent) {
|
|
256
357
|
doNuVal(result, standardResult, 'pageContent');
|
|
257
358
|
}
|
|
@@ -268,7 +369,7 @@ const convert = (testName, result, standardResult) => {
|
|
|
268
369
|
}
|
|
269
370
|
// qualWeb
|
|
270
371
|
else if (
|
|
271
|
-
|
|
372
|
+
toolName === 'qualWeb'
|
|
272
373
|
&& result.modules
|
|
273
374
|
&& (
|
|
274
375
|
result.modules['act-rules']
|
|
@@ -288,14 +389,30 @@ const convert = (testName, result, standardResult) => {
|
|
|
288
389
|
}
|
|
289
390
|
}
|
|
290
391
|
// tenon
|
|
291
|
-
else if (
|
|
392
|
+
else if (toolName === 'tenon' && result.data && result.data.resultSet) {
|
|
292
393
|
result.data.resultSet.forEach(item => {
|
|
394
|
+
let tagName = '';
|
|
395
|
+
if (item.xpath) {
|
|
396
|
+
const tagNameArray = item.xpath.match(/^.+\/([^/[]+)/);
|
|
397
|
+
if (tagNameArray && tagNameArray.length === 2) {
|
|
398
|
+
tagName = tagNameArray[1].toUpperCase();
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
let id = '';
|
|
402
|
+
if (item.errorSnippet) {
|
|
403
|
+
const idArray = item.errorSnippet.match(/^.+\sid="([^"]+)"/);
|
|
404
|
+
if (idArray && idArray.length === 2) {
|
|
405
|
+
id = idArray[1];
|
|
406
|
+
}
|
|
407
|
+
}
|
|
293
408
|
const instance = {
|
|
294
409
|
issueID: item.tID ? item.tID.toString() : '',
|
|
295
410
|
what: item.errorTitle || '',
|
|
296
411
|
ordinalSeverity: Math.min(
|
|
297
412
|
3, Math.max(0, Math.round((item.certainty || 0) * (item.priority || 0) / 3333))
|
|
298
413
|
),
|
|
414
|
+
tagName,
|
|
415
|
+
id,
|
|
299
416
|
location: {
|
|
300
417
|
doc: 'dom',
|
|
301
418
|
type: 'xpath',
|
|
@@ -311,7 +428,7 @@ const convert = (testName, result, standardResult) => {
|
|
|
311
428
|
});
|
|
312
429
|
}
|
|
313
430
|
// testaro
|
|
314
|
-
else if (
|
|
431
|
+
else if (toolName === 'testaro') {
|
|
315
432
|
const rules = result.rules ? Object.keys(result.rules) : [];
|
|
316
433
|
standardResult.totals = [0, 0, 0, 0];
|
|
317
434
|
rules.forEach(rule => {
|
|
@@ -332,7 +449,7 @@ const convert = (testName, result, standardResult) => {
|
|
|
332
449
|
}
|
|
333
450
|
// wave
|
|
334
451
|
else if (
|
|
335
|
-
|
|
452
|
+
toolName === 'wave'
|
|
336
453
|
&& result.categories
|
|
337
454
|
&& (
|
|
338
455
|
result.categories.error
|
package/testaro/allHidden.js
CHANGED
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
This test reports a page that is entirely or mainly hidden.
|
|
4
4
|
*/
|
|
5
5
|
exports.reporter = async page => {
|
|
6
|
+
// Gets the hiddennesses of the document, body, and main region.
|
|
6
7
|
const data = await page.evaluate(() => {
|
|
8
|
+
// Identify the styles of the document, its body, and its main region.
|
|
7
9
|
const {body} = document;
|
|
8
|
-
const main = body && body.querySelector('main');
|
|
10
|
+
const main = body && body.querySelector('main, [role=main]');
|
|
9
11
|
const styles = {
|
|
10
12
|
doc: window.getComputedStyle(document.documentElement),
|
|
11
13
|
body: body && window.getComputedStyle(body),
|
|
12
14
|
main: main && window.getComputedStyle(main)
|
|
13
15
|
};
|
|
16
|
+
// Get the hiddennesses of the regions.
|
|
14
17
|
const data = {
|
|
15
18
|
hidden: {
|
|
16
19
|
document: document.documentElement.hidden,
|
|
@@ -36,8 +39,19 @@ exports.reporter = async page => {
|
|
|
36
39
|
document: document.documentElement.ariaHidden === 'true',
|
|
37
40
|
body: body ? body.ariaHidden === 'true' : false,
|
|
38
41
|
main: main ? main.ariaHidden === 'true' : false
|
|
42
|
+
},
|
|
43
|
+
tagName: {
|
|
44
|
+
document: 'HTML',
|
|
45
|
+
body: 'BODY',
|
|
46
|
+
main: main ? main.tagName : ''
|
|
47
|
+
},
|
|
48
|
+
id: {
|
|
49
|
+
document: document.id,
|
|
50
|
+
body: body.id,
|
|
51
|
+
main: main ? main.id : ''
|
|
39
52
|
}
|
|
40
53
|
};
|
|
54
|
+
// Identify whether each region is really hidden.
|
|
41
55
|
['document', 'body', 'main'].forEach(element => {
|
|
42
56
|
if (data.hidden[element] && ! ['block', 'flex'].includes(data.display[element])) {
|
|
43
57
|
data.reallyHidden[element] = true;
|
|
@@ -45,10 +59,11 @@ exports.reporter = async page => {
|
|
|
45
59
|
});
|
|
46
60
|
return data;
|
|
47
61
|
});
|
|
62
|
+
// For each combination of region and hiddenness:
|
|
48
63
|
const standardInstances = [];
|
|
49
64
|
const reportables = {
|
|
50
|
-
hidden: [
|
|
51
|
-
reallyHidden: [
|
|
65
|
+
hidden: [1, 'hidden'],
|
|
66
|
+
reallyHidden: [2, 'effectively hidden'],
|
|
52
67
|
visHidden: [0, 'visually hidden'],
|
|
53
68
|
ariaHidden: [1, 'hidden by ARIA'],
|
|
54
69
|
document: [1, 'Document', 'document.documentElement'],
|
|
@@ -57,11 +72,15 @@ exports.reporter = async page => {
|
|
|
57
72
|
};
|
|
58
73
|
['document', 'body', 'main'].forEach(region => {
|
|
59
74
|
['hidden', 'reallyHidden', 'visHidden', 'ariaHidden'].forEach(hider => {
|
|
75
|
+
// If the region has that hiddenness:
|
|
60
76
|
if (data[hider][region]) {
|
|
77
|
+
// Add a standard instance for that combination.
|
|
61
78
|
standardInstances.push({
|
|
62
79
|
issueID: `allHidden-${hider}-${region}`,
|
|
63
80
|
what: `${reportables[region][1]} ${reportables[hider][1]}`,
|
|
64
81
|
ordinalSeverity: reportables[region][0] + reportables[hider][0] || 0,
|
|
82
|
+
tagName: region.tagName,
|
|
83
|
+
id: region.id,
|
|
65
84
|
location: {
|
|
66
85
|
doc: 'dom',
|
|
67
86
|
type: 'selector',
|
|
@@ -72,6 +91,7 @@ exports.reporter = async page => {
|
|
|
72
91
|
}
|
|
73
92
|
});
|
|
74
93
|
});
|
|
94
|
+
// Get the severity totals.
|
|
75
95
|
const totals = [0, 0, 0, 0];
|
|
76
96
|
standardInstances.forEach(instance => {
|
|
77
97
|
totals[instance.ordinalSeverity]++;
|
package/testaro/attVal.js
CHANGED
|
@@ -32,6 +32,7 @@ exports.reporter = async (page, withItems, attributeName, areLicit, values) => {
|
|
|
32
32
|
});
|
|
33
33
|
const report = badElements.map(el => ({
|
|
34
34
|
tagName: el.tagName,
|
|
35
|
+
id: el.id,
|
|
35
36
|
textStart: textOf(el, 70),
|
|
36
37
|
attributeValue: el.getAttribute(attributeName)
|
|
37
38
|
}));
|
|
@@ -51,6 +52,8 @@ exports.reporter = async (page, withItems, attributeName, areLicit, values) => {
|
|
|
51
52
|
what:
|
|
52
53
|
`${item.tagName} element has attribute ${attributeName} with illicit value ${item.attributeValue}`,
|
|
53
54
|
ordinalSeverity: 2,
|
|
55
|
+
tagName: item.tagName,
|
|
56
|
+
id: item.id,
|
|
54
57
|
location: {
|
|
55
58
|
doc: '',
|
|
56
59
|
type: '',
|
|
@@ -64,7 +67,10 @@ exports.reporter = async (page, withItems, attributeName, areLicit, values) => {
|
|
|
64
67
|
standardInstances.push({
|
|
65
68
|
issueID: 'attVal',
|
|
66
69
|
what: 'Elements have attributes with illicit values',
|
|
70
|
+
count: data.total,
|
|
67
71
|
ordinalSeverity: 2,
|
|
72
|
+
tagName: '',
|
|
73
|
+
id: '',
|
|
68
74
|
location: {
|
|
69
75
|
doc: '',
|
|
70
76
|
type: '',
|