testaro 14.3.0 → 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 +9 -1
- 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 +12 -0
- package/testaro/attVal.js +6 -0
- package/testaro/autocomplete.js +6 -2
- package/testaro/bulk.js +2 -0
- package/testaro/docType.js +2 -0
- package/testaro/dupAtt.js +10 -4
- package/testaro/embAc.js +6 -1
- package/testaro/filter.js +6 -1
- package/testaro/focAll.js +2 -0
- package/testaro/focInd.js +8 -1
- package/testaro/focOp.js +7 -3
- package/testaro/focVis.js +9 -2
- package/testaro/hover.js +6 -2
- package/testaro/labClash.js +7 -0
- package/testaro/linkTo.js +12 -5
- package/testaro/linkUl.js +20 -9
- package/testaro/menuNav.js +12 -4
- package/testaro/miniText.js +10 -2
- package/testaro/motion.js +5 -3
- package/testaro/nonTable.js +10 -3
- package/testaro/radioSet.js +10 -3
- package/testaro/role.js +8 -3
- package/testaro/styleDiff.js +11 -9
- package/testaro/tabNav.js +11 -2
- package/testaro/titledEl.js +6 -1
- package/testaro/zIndex.js +5 -3
package/README.md
CHANGED
|
@@ -204,11 +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
210
|
- `count` (optional): the count of instances if this instance represents multiple instances
|
|
211
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
|
|
212
214
|
- `location`: an object with three properties:
|
|
213
215
|
- `doc`: whether the source (`source`) or the browser rendition (`dom`) was tested
|
|
214
216
|
- `type`: the type of location information provided by the tool (`line`, `selector`, or `xpath`)
|
|
@@ -225,6 +227,8 @@ standardResult: {
|
|
|
225
227
|
issueID: 'rule01',
|
|
226
228
|
what: 'Button type invalid',
|
|
227
229
|
ordinalSeverity: 0,
|
|
230
|
+
tagName: 'BUTTON'
|
|
231
|
+
id: '',
|
|
228
232
|
location: {
|
|
229
233
|
doc: 'dom',
|
|
230
234
|
type: 'line',
|
|
@@ -236,6 +240,8 @@ standardResult: {
|
|
|
236
240
|
issueID: 'rule01',
|
|
237
241
|
what: 'Button type invalid',
|
|
238
242
|
ordinalSeverity: 1,
|
|
243
|
+
tagName: 'BUTTON',
|
|
244
|
+
id: 'submitbutton',
|
|
239
245
|
location: {
|
|
240
246
|
doc: 'dom',
|
|
241
247
|
type: 'line',
|
|
@@ -248,6 +254,8 @@ standardResult: {
|
|
|
248
254
|
what: 'Links have empty href attributes',
|
|
249
255
|
count: 17,
|
|
250
256
|
ordinalSeverity: 3,
|
|
257
|
+
tagName: 'A',
|
|
258
|
+
id: '',
|
|
251
259
|
location: {
|
|
252
260
|
doc: '',
|
|
253
261
|
type: '',
|
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
|
@@ -39,6 +39,16 @@ exports.reporter = async page => {
|
|
|
39
39
|
document: document.documentElement.ariaHidden === 'true',
|
|
40
40
|
body: body ? body.ariaHidden === 'true' : false,
|
|
41
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 : ''
|
|
42
52
|
}
|
|
43
53
|
};
|
|
44
54
|
// Identify whether each region is really hidden.
|
|
@@ -69,6 +79,8 @@ exports.reporter = async page => {
|
|
|
69
79
|
issueID: `allHidden-${hider}-${region}`,
|
|
70
80
|
what: `${reportables[region][1]} ${reportables[hider][1]}`,
|
|
71
81
|
ordinalSeverity: reportables[region][0] + reportables[hider][0] || 0,
|
|
82
|
+
tagName: region.tagName,
|
|
83
|
+
id: region.id,
|
|
72
84
|
location: {
|
|
73
85
|
doc: 'dom',
|
|
74
86
|
type: 'selector',
|
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: '',
|
package/testaro/autocomplete.js
CHANGED
|
@@ -20,7 +20,7 @@ const addFailure = async (withItems, input, inputText, autocomplete, data) => {
|
|
|
20
20
|
// If itemization is required:
|
|
21
21
|
if (withItems) {
|
|
22
22
|
// Add the item to the data.
|
|
23
|
-
data.items.push([autocomplete, inputText.slice(0, 100)]);
|
|
23
|
+
data.items.push([autocomplete, input.id || '', inputText.slice(0, 100)]);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
};
|
|
@@ -77,12 +77,14 @@ exports.reporter = async (page, withItems) => {
|
|
|
77
77
|
issueID: `autocomplete-${item[0]}`,
|
|
78
78
|
what: `Input is missing the required autocomplete attribute with value ${item[0]}`,
|
|
79
79
|
ordinalSeverity: 2,
|
|
80
|
+
tagName: 'INPUT',
|
|
81
|
+
id: item[1] || '',
|
|
80
82
|
location: {
|
|
81
83
|
doc: '',
|
|
82
84
|
type: '',
|
|
83
85
|
spec: ''
|
|
84
86
|
},
|
|
85
|
-
excerpt: item[
|
|
87
|
+
excerpt: item[2]
|
|
86
88
|
});
|
|
87
89
|
});
|
|
88
90
|
}
|
|
@@ -91,6 +93,8 @@ exports.reporter = async (page, withItems) => {
|
|
|
91
93
|
issueID: 'autocomplete',
|
|
92
94
|
what: 'Inputs are missing required autocomplete attributes',
|
|
93
95
|
ordinalSeverity: 2,
|
|
96
|
+
tagName: '',
|
|
97
|
+
id: '',
|
|
94
98
|
location: {
|
|
95
99
|
doc: '',
|
|
96
100
|
type: '',
|
package/testaro/bulk.js
CHANGED
package/testaro/docType.js
CHANGED
package/testaro/dupAtt.js
CHANGED
|
@@ -53,11 +53,12 @@ exports.reporter = async (page, withItems) => {
|
|
|
53
53
|
// Extract the opening tags of its elements.
|
|
54
54
|
let elements = rawPage.match(/<[a-zA-Z][^<>]+>/g);
|
|
55
55
|
// Delete their enclosing angle brackets and the values of any attributes in them.
|
|
56
|
-
|
|
56
|
+
const elementsWithVals = elements.map(el => el.replace(/^< *| *>$/g, ''));
|
|
57
|
+
const elementsWithoutVals = elementsWithVals.map(el => el.replace(/^ *|=[^ ]*$/g, ''));
|
|
57
58
|
// For each element:
|
|
58
|
-
|
|
59
|
+
elementsWithoutVals.forEach((elementWithoutVals, index) => {
|
|
59
60
|
// Identify its tag name and attributes.
|
|
60
|
-
const terms =
|
|
61
|
+
const terms = elementWithoutVals.split(' ');
|
|
61
62
|
// If it has 2 or more attributes:
|
|
62
63
|
if (terms.length > 2) {
|
|
63
64
|
// If any is duplicated:
|
|
@@ -65,11 +66,14 @@ exports.reporter = async (page, withItems) => {
|
|
|
65
66
|
const attributes = terms.slice(1);
|
|
66
67
|
const attSet = new Set(attributes);
|
|
67
68
|
if (attSet.size < attributes.length) {
|
|
68
|
-
// Add
|
|
69
|
+
// Add it to the data.
|
|
69
70
|
data.total++;
|
|
70
71
|
if (withItems) {
|
|
71
72
|
data.items.push({
|
|
72
73
|
tagName,
|
|
74
|
+
id: terms.includes('id')
|
|
75
|
+
? elementsWithVals[index].replace(/^.+id=/, '').replace(/ .*$/, '')
|
|
76
|
+
: '',
|
|
73
77
|
attributes
|
|
74
78
|
});
|
|
75
79
|
}
|
|
@@ -83,6 +87,8 @@ exports.reporter = async (page, withItems) => {
|
|
|
83
87
|
issueID: 'dupAtt',
|
|
84
88
|
what: `Element ${item.tagName} has 2 attributes with the same name`,
|
|
85
89
|
ordinalSeverity: 2,
|
|
90
|
+
tagName: item.tagName,
|
|
91
|
+
id: item.id,
|
|
86
92
|
location: {
|
|
87
93
|
doc: '',
|
|
88
94
|
type: '',
|
package/testaro/embAc.js
CHANGED
|
@@ -32,6 +32,7 @@ exports.reporter = async (page, withItems) => await page.$$eval(
|
|
|
32
32
|
}
|
|
33
33
|
items.push({
|
|
34
34
|
embeddedElement: bad.tagName,
|
|
35
|
+
embeddedID: bad.id,
|
|
35
36
|
excerpt: compact(container.outerHTML)
|
|
36
37
|
});
|
|
37
38
|
}
|
|
@@ -45,8 +46,10 @@ exports.reporter = async (page, withItems) => await page.$$eval(
|
|
|
45
46
|
items.forEach(item => {
|
|
46
47
|
standardInstances.push({
|
|
47
48
|
issueID: `embAc-${item.embeddedElement}`,
|
|
48
|
-
what:
|
|
49
|
+
what: `${item.embeddedElement} element is embedded in a link or button`,
|
|
49
50
|
ordinalSeverity: 2,
|
|
51
|
+
tagName: item.embeddedElement,
|
|
52
|
+
id: item.id,
|
|
50
53
|
location: {
|
|
51
54
|
doc: '',
|
|
52
55
|
type: '',
|
|
@@ -62,6 +65,8 @@ exports.reporter = async (page, withItems) => await page.$$eval(
|
|
|
62
65
|
what: 'Interactive elements are contained by links or buttons',
|
|
63
66
|
count: total,
|
|
64
67
|
ordinalSeverity: 2,
|
|
68
|
+
tagName: '',
|
|
69
|
+
id: '',
|
|
65
70
|
location: {
|
|
66
71
|
doc: '',
|
|
67
72
|
type: '',
|
package/testaro/filter.js
CHANGED
|
@@ -40,6 +40,7 @@ exports.reporter = async (page, withItems) => {
|
|
|
40
40
|
filterData.forEach(filterDatum => {
|
|
41
41
|
data.items.push({
|
|
42
42
|
tagName: filterDatum.element.tagName,
|
|
43
|
+
id: filterDatum.element.id,
|
|
43
44
|
text: compact(filterDatum.element.textContent) || compact(filterDatum.element.outerHTML),
|
|
44
45
|
impact: filterDatum.impact
|
|
45
46
|
});
|
|
@@ -53,8 +54,10 @@ exports.reporter = async (page, withItems) => {
|
|
|
53
54
|
data.items.forEach(item => {
|
|
54
55
|
standardInstances.push({
|
|
55
56
|
issueID: 'filterStyle',
|
|
56
|
-
what:
|
|
57
|
+
what: `${item.tagName} element has a filter style that impacts ${item.impact} elements`,
|
|
57
58
|
ordinalSeverity: 2,
|
|
59
|
+
tagName: item.toUpperCase(),
|
|
60
|
+
id: item.id,
|
|
58
61
|
location: {
|
|
59
62
|
doc: '',
|
|
60
63
|
type: '',
|
|
@@ -69,6 +72,8 @@ exports.reporter = async (page, withItems) => {
|
|
|
69
72
|
issueID: 'filterStyle',
|
|
70
73
|
what: 'Elements have filter styles impacting other elements',
|
|
71
74
|
ordinalSeverity: 2,
|
|
75
|
+
tagName: '',
|
|
76
|
+
id: '',
|
|
72
77
|
location: {
|
|
73
78
|
doc: '',
|
|
74
79
|
type: '',
|
package/testaro/focAll.js
CHANGED