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/testaro/miniText.js
CHANGED
|
@@ -30,7 +30,11 @@ exports.reporter = async (page, withItems) => {
|
|
|
30
30
|
if (pixels < 11) {
|
|
31
31
|
textParent.childNodes.forEach(node => {
|
|
32
32
|
if (node.nodeType === 3 && compact(node.textContent)) {
|
|
33
|
-
miniTexts.push(
|
|
33
|
+
miniTexts.push({
|
|
34
|
+
tagName: textParent.tagName,
|
|
35
|
+
id: textParent.id || '',
|
|
36
|
+
text: compact(node.textContent)
|
|
37
|
+
});
|
|
34
38
|
}
|
|
35
39
|
});
|
|
36
40
|
}
|
|
@@ -49,12 +53,14 @@ exports.reporter = async (page, withItems) => {
|
|
|
49
53
|
issueID: 'miniText',
|
|
50
54
|
what: 'Text font is smaller than 11 pixels',
|
|
51
55
|
ordinalSeverity: 2,
|
|
56
|
+
tagName: text.tagName,
|
|
57
|
+
id: text.id,
|
|
52
58
|
location: {
|
|
53
59
|
doc: '',
|
|
54
60
|
type: '',
|
|
55
61
|
spec: ''
|
|
56
62
|
},
|
|
57
|
-
excerpt: text
|
|
63
|
+
excerpt: text.text
|
|
58
64
|
});
|
|
59
65
|
});
|
|
60
66
|
}
|
|
@@ -62,7 +68,10 @@ exports.reporter = async (page, withItems) => {
|
|
|
62
68
|
standardInstances.push({
|
|
63
69
|
issueID: 'miniText',
|
|
64
70
|
what: 'Texts have fonts smaller than 11 pixels',
|
|
71
|
+
count: data.total,
|
|
65
72
|
ordinalSeverity: 2,
|
|
73
|
+
tagName: '',
|
|
74
|
+
id: '',
|
|
66
75
|
location: {
|
|
67
76
|
doc: '',
|
|
68
77
|
type: '',
|
package/testaro/motion.js
CHANGED
|
@@ -98,6 +98,13 @@ exports.reporter = async (page, withItems, delay = 2500, interval = 2500, count
|
|
|
98
98
|
pixelChanges.reduce((count, change) => count + (change ? 1 : 0), 0) / pixelChanges.length, 2
|
|
99
99
|
);
|
|
100
100
|
// Return the result.
|
|
101
|
+
const rawCount = 2 * (meanLocalRatio - 1)
|
|
102
|
+
+ maxLocalRatio - 1
|
|
103
|
+
+ globalRatio - 1
|
|
104
|
+
+ meanPixelChange / 10000
|
|
105
|
+
+ maxPixelChange / 25000
|
|
106
|
+
+ 3 * changeFrequency;
|
|
107
|
+
const count = rawCount ? Math.round(rawCount) : 0;
|
|
101
108
|
return {
|
|
102
109
|
data: {
|
|
103
110
|
bytes,
|
|
@@ -112,20 +119,17 @@ exports.reporter = async (page, withItems, delay = 2500, interval = 2500, count
|
|
|
112
119
|
},
|
|
113
120
|
totals: [
|
|
114
121
|
0,
|
|
115
|
-
0,
|
|
116
|
-
|
|
117
|
-
+ maxLocalRatio - 1
|
|
118
|
-
+ globalRatio - 1
|
|
119
|
-
+ meanPixelChange / 10000
|
|
120
|
-
+ maxPixelChange / 25000
|
|
121
|
-
+ 3 * changeFrequency
|
|
122
|
-
|| 0,
|
|
122
|
+
0,
|
|
123
|
+
count,
|
|
123
124
|
0
|
|
124
125
|
],
|
|
125
|
-
standardInstances:
|
|
126
|
+
standardInstances: count ? [{
|
|
126
127
|
issueID: 'motion',
|
|
127
128
|
what: 'Content moves or changes without user request',
|
|
129
|
+
count,
|
|
128
130
|
ordinalSeverity: 2,
|
|
131
|
+
tagName: '',
|
|
132
|
+
id: '',
|
|
129
133
|
location: {
|
|
130
134
|
doc: '',
|
|
131
135
|
type: '',
|
package/testaro/nonTable.js
CHANGED
|
@@ -13,7 +13,10 @@ exports.reporter = async (page, withItems) => {
|
|
|
13
13
|
const compact = string => string.replace(/[\t\n]/g, '').replace(/\s{2,}/g, ' ').trim();
|
|
14
14
|
// Adds the first 100 characters of the code of a pseudotable to the array of pseudotable texts.
|
|
15
15
|
const addBad = table => {
|
|
16
|
-
badTableTexts.push(
|
|
16
|
+
badTableTexts.push({
|
|
17
|
+
id: table.id,
|
|
18
|
+
text: compact(table.outerHTML).slice(0, 100)
|
|
19
|
+
});
|
|
17
20
|
};
|
|
18
21
|
// FUNCTION DEFINITIONS END
|
|
19
22
|
// For each table on the page:
|
|
@@ -63,17 +66,19 @@ exports.reporter = async (page, withItems) => {
|
|
|
63
66
|
const standardInstances = [];
|
|
64
67
|
if (withItems) {
|
|
65
68
|
data.items = badTableTexts;
|
|
66
|
-
data.items.forEach(
|
|
69
|
+
data.items.forEach(item => {
|
|
67
70
|
standardInstances.push({
|
|
68
71
|
issueID: 'nonTable',
|
|
69
72
|
what: 'Table is misused to arrange content',
|
|
70
73
|
ordinalSeverity: 0,
|
|
74
|
+
tagName: 'TABLE',
|
|
75
|
+
id: item.id,
|
|
71
76
|
location: {
|
|
72
77
|
doc: '',
|
|
73
78
|
type: '',
|
|
74
79
|
spec: ''
|
|
75
80
|
},
|
|
76
|
-
excerpt: text
|
|
81
|
+
excerpt: item.text
|
|
77
82
|
});
|
|
78
83
|
});
|
|
79
84
|
}
|
|
@@ -81,7 +86,10 @@ exports.reporter = async (page, withItems) => {
|
|
|
81
86
|
standardInstances.push({
|
|
82
87
|
issueID: 'nonTable',
|
|
83
88
|
what: 'Tables are misused to arrange content',
|
|
84
|
-
|
|
89
|
+
count: data.total,
|
|
90
|
+
ordinalSeverity: 0,
|
|
91
|
+
tagName: 'TABLE',
|
|
92
|
+
id: '',
|
|
85
93
|
location: {
|
|
86
94
|
doc: '',
|
|
87
95
|
type: '',
|
package/testaro/radioSet.js
CHANGED
|
@@ -74,6 +74,7 @@ exports.reporter = async (page, withItems) => {
|
|
|
74
74
|
totals.total = allRadios.length;
|
|
75
75
|
totals.inSet = setRadios.length;
|
|
76
76
|
totals.percent = totals.total ? Math.floor(100 * totals.inSet / totals.total) : 'N.A.';
|
|
77
|
+
const loneRadios = totals.total - totals.inSet;
|
|
77
78
|
// If itemization is required:
|
|
78
79
|
const standardInstances = [];
|
|
79
80
|
if (withItems) {
|
|
@@ -81,26 +82,34 @@ exports.reporter = async (page, withItems) => {
|
|
|
81
82
|
const nonSetRadios = allRadios.filter(radio => ! setRadios.includes(radio));
|
|
82
83
|
const items = data.items;
|
|
83
84
|
items.inSet = setRadios.map(radio => textOf(radio));
|
|
84
|
-
items.notInSet = nonSetRadios.map(radio =>
|
|
85
|
-
|
|
85
|
+
items.notInSet = nonSetRadios.map(radio => ({
|
|
86
|
+
id: radio.id,
|
|
87
|
+
text: textOf(radio)
|
|
88
|
+
}));
|
|
89
|
+
items.notInSet.forEach(item => {
|
|
86
90
|
standardInstances.push({
|
|
87
91
|
issueID: 'radioSet',
|
|
88
|
-
what: 'Radio button and
|
|
92
|
+
what: 'Radio button and its peers are not in a fieldset with a legend',
|
|
89
93
|
ordinalSeverity: 2,
|
|
94
|
+
tagName: 'INPUT',
|
|
95
|
+
id: item.id,
|
|
90
96
|
location: {
|
|
91
97
|
doc: '',
|
|
92
98
|
type: '',
|
|
93
99
|
spec: ''
|
|
94
100
|
},
|
|
95
|
-
excerpt: text
|
|
101
|
+
excerpt: item.text
|
|
96
102
|
});
|
|
97
103
|
});
|
|
98
104
|
}
|
|
99
|
-
else if (
|
|
105
|
+
else if (loneRadios > 0) {
|
|
100
106
|
standardInstances.push({
|
|
101
107
|
issueID: 'radioSet',
|
|
102
108
|
what: 'Radio buttons are not validly grouped in fieldsets with legends',
|
|
109
|
+
count: loneRadios,
|
|
103
110
|
ordinalSeverity: 2,
|
|
111
|
+
tagName: 'INPUT',
|
|
112
|
+
id: '',
|
|
104
113
|
location: {
|
|
105
114
|
doc: '',
|
|
106
115
|
type: '',
|
|
@@ -111,7 +120,7 @@ exports.reporter = async (page, withItems) => {
|
|
|
111
120
|
}
|
|
112
121
|
return {
|
|
113
122
|
data,
|
|
114
|
-
totals: [0, 0,
|
|
123
|
+
totals: [0, 0, loneRadios, 0],
|
|
115
124
|
standardInstances
|
|
116
125
|
};
|
|
117
126
|
}
|
package/testaro/role.js
CHANGED
|
@@ -15,6 +15,7 @@ exports.reporter = async page => await page.$eval('body', body => {
|
|
|
15
15
|
|
|
16
16
|
// CONSTANTS
|
|
17
17
|
|
|
18
|
+
// All roles implicit in HTML elements.
|
|
18
19
|
const badRoles = new Set([
|
|
19
20
|
'article',
|
|
20
21
|
'banner',
|
|
@@ -52,7 +53,7 @@ exports.reporter = async page => await page.$eval('body', body => {
|
|
|
52
53
|
'term',
|
|
53
54
|
'textbox'
|
|
54
55
|
]);
|
|
55
|
-
// All non-abstract roles
|
|
56
|
+
// All non-abstract roles.
|
|
56
57
|
const goodRoles = new Set([
|
|
57
58
|
'alert',
|
|
58
59
|
'alertdialog',
|
|
@@ -410,7 +411,7 @@ exports.reporter = async page => await page.$eval('body', body => {
|
|
|
410
411
|
|
|
411
412
|
// OPERATION
|
|
412
413
|
|
|
413
|
-
// Remove the
|
|
414
|
+
// Remove the element-implicit roles from the non-abstract roles.
|
|
414
415
|
goodRoles.forEach(role => {
|
|
415
416
|
if (badRoles.has(role)) {
|
|
416
417
|
goodRoles.delete(role);
|
|
@@ -481,12 +482,16 @@ exports.reporter = async page => await page.$eval('body', body => {
|
|
|
481
482
|
const standardInstances = [];
|
|
482
483
|
Object.keys(data.tagNames).forEach(tagName => {
|
|
483
484
|
Object.keys(data.tagNames[tagName]).forEach(role => {
|
|
484
|
-
|
|
485
|
-
|
|
485
|
+
const pairTotals = data.tagNames[tagName][role];
|
|
486
|
+
const redCount = pairTotals.redundant;
|
|
487
|
+
if (redCount) {
|
|
486
488
|
standardInstances.push({
|
|
487
|
-
issueID: 'role',
|
|
488
|
-
what:
|
|
489
|
+
issueID: 'role-redundant',
|
|
490
|
+
what: `${tagName} elements have redundant explicit role ${role} (count: ${redCount})`,
|
|
491
|
+
count: redCount,
|
|
489
492
|
ordinalSeverity: 1,
|
|
493
|
+
tagName,
|
|
494
|
+
id: '',
|
|
490
495
|
location: {
|
|
491
496
|
doc: '',
|
|
492
497
|
type: '',
|
|
@@ -495,12 +500,16 @@ exports.reporter = async page => await page.$eval('body', body => {
|
|
|
495
500
|
excerpt: ''
|
|
496
501
|
});
|
|
497
502
|
}
|
|
498
|
-
|
|
499
|
-
if (
|
|
503
|
+
const badCount = pairTotals.bad;
|
|
504
|
+
if (badCount) {
|
|
500
505
|
standardInstances.push({
|
|
501
|
-
issueID: 'role',
|
|
502
|
-
what:
|
|
506
|
+
issueID: 'role-bad',
|
|
507
|
+
what:
|
|
508
|
+
`${tagName} elements have invalid or native-replaceable explicit role ${role} (count: ${badCount})`,
|
|
509
|
+
count: badCount,
|
|
503
510
|
ordinalSeverity: 3,
|
|
511
|
+
tagName,
|
|
512
|
+
id: '',
|
|
504
513
|
location: {
|
|
505
514
|
doc: '',
|
|
506
515
|
type: '',
|
package/testaro/styleDiff.js
CHANGED
|
@@ -155,15 +155,15 @@ exports.reporter = async (page, withItems) => {
|
|
|
155
155
|
const totals = [0, 0, 0, 0];
|
|
156
156
|
const standardInstances = [];
|
|
157
157
|
const elementData = {
|
|
158
|
-
adjacentLink: [0, 'In-line links'],
|
|
159
|
-
listLink: [1, 'Links in columns'],
|
|
160
|
-
button: [2, 'Buttons'],
|
|
161
|
-
h1: [3, 'Level-1 headings'],
|
|
162
|
-
h2: [3, 'Level-2 headings'],
|
|
163
|
-
h3: [3, 'Level-3 headings'],
|
|
164
|
-
h4: [3, 'Level-4 headings'],
|
|
165
|
-
h5: [3, 'Level-5 headings'],
|
|
166
|
-
h6: [3, 'Level-6 headings'],
|
|
158
|
+
adjacentLink: [0, 'In-line links', 'A'],
|
|
159
|
+
listLink: [1, 'Links in columns', 'A'],
|
|
160
|
+
button: [2, 'Buttons', 'BUTTON'],
|
|
161
|
+
h1: [3, 'Level-1 headings', 'H1'],
|
|
162
|
+
h2: [3, 'Level-2 headings', 'H2'],
|
|
163
|
+
h3: [3, 'Level-3 headings', 'H3'],
|
|
164
|
+
h4: [3, 'Level-4 headings', 'H4'],
|
|
165
|
+
h5: [3, 'Level-5 headings', 'H5'],
|
|
166
|
+
h6: [3, 'Level-6 headings', 'H6'],
|
|
167
167
|
};
|
|
168
168
|
Object.keys(elementData).forEach(elementName => {
|
|
169
169
|
const elementTotal = data.totals[elementName];
|
|
@@ -171,11 +171,15 @@ exports.reporter = async (page, withItems) => {
|
|
|
171
171
|
const currentData = elementData[elementName];
|
|
172
172
|
const severity = currentData[0];
|
|
173
173
|
const elementSubtotals = elementTotal.subtotals;
|
|
174
|
-
|
|
174
|
+
const extraCount = elementSubtotals.length - 1;
|
|
175
|
+
totals[severity] += extraCount;
|
|
175
176
|
standardInstances.push({
|
|
176
177
|
issueID: 'styleDiff',
|
|
177
178
|
what: `${currentData[1]} have ${elementSubtotals.length} different styles`,
|
|
179
|
+
count: extraCount,
|
|
178
180
|
ordinalSeverity: severity,
|
|
181
|
+
tagName: currentData[2],
|
|
182
|
+
id: '',
|
|
179
183
|
location: {
|
|
180
184
|
doc: '',
|
|
181
185
|
type: '',
|
package/testaro/tabNav.js
CHANGED
|
@@ -220,7 +220,10 @@ exports.reporter = async (page, withItems) => {
|
|
|
220
220
|
if (withItems) {
|
|
221
221
|
let found = true;
|
|
222
222
|
// Initialize a report on the element.
|
|
223
|
-
|
|
223
|
+
const moreItemData = await page.evaluate(element => ({
|
|
224
|
+
tagName: element.tagName,
|
|
225
|
+
id: element.id
|
|
226
|
+
}), currentTab)
|
|
224
227
|
.catch(error => {
|
|
225
228
|
console.log(`ERROR: could not get tag name (${error.message})`);
|
|
226
229
|
found = false;
|
|
@@ -228,6 +231,8 @@ exports.reporter = async (page, withItems) => {
|
|
|
228
231
|
return 'ERROR: not found';
|
|
229
232
|
});
|
|
230
233
|
if (found) {
|
|
234
|
+
itemData.tagName = moreItemData.tagName;
|
|
235
|
+
itemData.id = moreItemData.id;
|
|
231
236
|
itemData.text = await allText(page, currentTab);
|
|
232
237
|
itemData.navigationErrors = [];
|
|
233
238
|
}
|
|
@@ -335,14 +340,18 @@ exports.reporter = async (page, withItems) => {
|
|
|
335
340
|
data.tabElements.incorrect.forEach(item => {
|
|
336
341
|
standardInstances.push({
|
|
337
342
|
issueID: 'tabNav',
|
|
338
|
-
what:
|
|
343
|
+
what:
|
|
344
|
+
`${item.tagName} element responds nonstandardly to ${item.navigationErrors.join(', ')}`,
|
|
345
|
+
count: item.navigationErrors.length,
|
|
339
346
|
ordinalSeverity: 1,
|
|
347
|
+
tagName: item.tagName,
|
|
348
|
+
id: item.id,
|
|
340
349
|
location: {
|
|
341
350
|
doc: '',
|
|
342
351
|
type: '',
|
|
343
352
|
spec: ''
|
|
344
353
|
},
|
|
345
|
-
excerpt:
|
|
354
|
+
excerpt: item.text
|
|
346
355
|
});
|
|
347
356
|
});
|
|
348
357
|
}
|
|
@@ -350,7 +359,10 @@ exports.reporter = async (page, withItems) => {
|
|
|
350
359
|
standardInstances.push({
|
|
351
360
|
issueID: 'tabNav',
|
|
352
361
|
what: 'Tablists have nonstandard navigation',
|
|
353
|
-
|
|
362
|
+
count: data.totals.navigations.all.incorrect,
|
|
363
|
+
ordinalSeverity: 1,
|
|
364
|
+
tagName: '',
|
|
365
|
+
id: '',
|
|
354
366
|
location: {
|
|
355
367
|
doc: '',
|
|
356
368
|
type: '',
|
package/testaro/titledEl.js
CHANGED
|
@@ -16,6 +16,7 @@ exports.reporter = async (page, withItems) => {
|
|
|
16
16
|
// FUNCTION DEFINITION END
|
|
17
17
|
return badTitleElements.map(element => ({
|
|
18
18
|
tagName: element.tagName,
|
|
19
|
+
id: element.id,
|
|
19
20
|
text: compact(element.textContent),
|
|
20
21
|
title: compact(element.title)
|
|
21
22
|
}));
|
|
@@ -30,8 +31,10 @@ exports.reporter = async (page, withItems) => {
|
|
|
30
31
|
badTitleElements.forEach(element => {
|
|
31
32
|
standardInstances.push({
|
|
32
33
|
issueID: 'titledEl',
|
|
33
|
-
what:
|
|
34
|
+
what: `${element.tagName} element has a title attribute`,
|
|
34
35
|
ordinalSeverity: 2,
|
|
36
|
+
tagName: element.tagName,
|
|
37
|
+
id: element.id,
|
|
35
38
|
location: {
|
|
36
39
|
doc: '',
|
|
37
40
|
type: '',
|
|
@@ -45,7 +48,10 @@ exports.reporter = async (page, withItems) => {
|
|
|
45
48
|
standardInstances.push({
|
|
46
49
|
issueID: 'titledEl',
|
|
47
50
|
what: 'Ineligible elements have title attributes',
|
|
51
|
+
count: data.total,
|
|
48
52
|
ordinalSeverity: 2,
|
|
53
|
+
tagName: '',
|
|
54
|
+
id: '',
|
|
49
55
|
location: {
|
|
50
56
|
doc: '',
|
|
51
57
|
type: '',
|
package/testaro/zIndex.js
CHANGED
|
@@ -51,18 +51,18 @@ exports.reporter = async (page, withItems) => {
|
|
|
51
51
|
const standardInstances = [];
|
|
52
52
|
if (data.items) {
|
|
53
53
|
data.items.forEach(item => {
|
|
54
|
-
const itemID = item.id ? ` (ID ${item.id})` : '';
|
|
55
|
-
const which = `${item.tagName}${itemID}`;
|
|
56
54
|
standardInstances.push({
|
|
57
55
|
issueID: 'zIndex',
|
|
58
|
-
what:
|
|
56
|
+
what: `${item.tagName} element has a non-default Z index`,
|
|
59
57
|
ordinalSeverity: 0,
|
|
58
|
+
tagName: item.tagName,
|
|
59
|
+
id: item.id,
|
|
60
60
|
location: {
|
|
61
61
|
doc: '',
|
|
62
62
|
type: '',
|
|
63
63
|
spec: ''
|
|
64
64
|
},
|
|
65
|
-
excerpt:
|
|
65
|
+
excerpt: item.text
|
|
66
66
|
});
|
|
67
67
|
});
|
|
68
68
|
}
|
|
@@ -70,7 +70,10 @@ exports.reporter = async (page, withItems) => {
|
|
|
70
70
|
standardInstances.push({
|
|
71
71
|
issueID: 'zIndex',
|
|
72
72
|
what: 'Elements have non-default Z indexes',
|
|
73
|
+
count: data.totals.total,
|
|
73
74
|
ordinalSeverity: 0,
|
|
75
|
+
tagName: '',
|
|
76
|
+
id: '',
|
|
74
77
|
location: {
|
|
75
78
|
doc: '',
|
|
76
79
|
type: '',
|
package/tests/ibm.js
CHANGED
|
@@ -87,7 +87,7 @@ const trimReport = (report, withItems, rules) => {
|
|
|
87
87
|
}
|
|
88
88
|
return data;
|
|
89
89
|
};
|
|
90
|
-
// Performs
|
|
90
|
+
// Performs the IBM tests and returns the result.
|
|
91
91
|
const doTest = async (content, withItems, timeLimit, rules) => {
|
|
92
92
|
// Conduct the test and get the result.
|
|
93
93
|
let report;
|