testaro 13.0.2 → 14.1.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 +190 -94
- package/actSpecs.js +17 -158
- package/package.json +1 -1
- package/run.js +31 -31
- package/standardize.js +338 -0
- package/{tests → testaro}/allHidden.js +36 -1
- package/{tests → testaro}/attVal.js +36 -2
- package/{tests → testaro}/autocomplete.js +34 -1
- package/{tests → testaro}/bulk.js +15 -1
- package/{tests → testaro}/docType.js +15 -1
- package/{tests → testaro}/dupAtt.js +34 -1
- package/{tests → testaro}/elements.js +9 -3
- package/testaro/embAc.js +78 -0
- package/{tests → testaro}/filter.js +35 -1
- package/{tests → testaro}/focAll.js +20 -3
- package/{tests → testaro}/focInd.js +45 -3
- package/{tests → testaro}/focOp.js +61 -2
- package/{tests → testaro}/focVis.js +35 -1
- package/{tests → testaro}/hover.js +67 -5
- package/{tests → testaro}/labClash.js +54 -4
- package/{tests → testaro}/linkTo.js +33 -1
- package/{tests → testaro}/linkUl.js +43 -5
- package/{tests → testaro}/menuNav.js +42 -1
- package/{tests → testaro}/miniText.js +32 -1
- package/{tests → testaro}/motion.js +27 -4
- package/{tests → testaro}/nonTable.js +32 -1
- package/{tests → testaro}/radioSet.js +33 -2
- package/{tests → testaro}/role.js +38 -1
- package/{tests → testaro}/styleDiff.js +43 -2
- package/{tests → testaro}/tabNav.js +42 -1
- package/{tests → testaro}/textNodes.js +6 -2
- package/{tests → testaro}/title.js +8 -4
- package/{tests → testaro}/titledEl.js +32 -1
- package/{tests → testaro}/zIndex.js +40 -2
- package/tests/alfa.js +72 -75
- package/tests/continuum.js +6 -2
- package/tests/ibm.js +14 -42
- package/tests/testaro.js +73 -0
- package/validation/tests/jobs/allHidden.json +877 -174
- package/validation/tests/jobs/attVal.json +57 -19
- package/validation/tests/jobs/autocomplete.json +34 -8
- package/validation/tests/jobs/bulk.json +33 -7
- package/validation/tests/jobs/docType.json +23 -5
- package/validation/tests/jobs/dupAtt.json +47 -8
- package/validation/tests/jobs/elements.json +231 -70
- package/validation/tests/jobs/embAc.json +70 -15
- package/validation/tests/jobs/filter.json +56 -12
- package/validation/tests/jobs/focAll.json +64 -16
- package/validation/tests/jobs/focInd.json +107 -23
- package/validation/tests/jobs/focOp.json +93 -21
- package/validation/tests/jobs/focVis.json +16 -4
- package/validation/tests/jobs/hover.json +246 -56
- package/validation/tests/jobs/labClash.json +43 -11
- package/validation/tests/jobs/linkTo.json +16 -4
- package/validation/tests/jobs/linkUl.json +79 -19
- package/validation/tests/jobs/menuNav.json +313 -65
- package/validation/tests/jobs/miniText.json +21 -5
- package/validation/tests/jobs/motion.json +81 -23
- package/validation/tests/jobs/nonTable.json +26 -6
- package/validation/tests/jobs/radioSet.json +43 -11
- package/validation/tests/jobs/role.json +93 -19
- package/validation/tests/jobs/styleDiff.json +124 -28
- package/validation/tests/jobs/tabNav.json +313 -65
- package/validation/tests/jobs/textNodes.json +190 -49
- package/validation/tests/jobs/title.json +23 -5
- package/validation/tests/jobs/titledEl.json +26 -6
- package/validation/tests/jobs/zIndex.json +28 -8
- package/validation/tests/old/allHidden.json +314 -0
- package/validation/tests/old/attVal.json +60 -0
- package/validation/tests/old/autocomplete.json +51 -0
- package/validation/tests/old/bulk.json +48 -0
- package/validation/tests/old/docType.json +46 -0
- package/validation/tests/old/dupAtt.json +51 -0
- package/validation/tests/old/elements.json +140 -0
- package/validation/tests/old/embAc.json +54 -0
- package/validation/tests/old/filter.json +55 -0
- package/validation/tests/old/focAll.json +68 -0
- package/validation/tests/old/focInd.json +69 -0
- package/validation/tests/old/focOp.json +62 -0
- package/validation/tests/old/focVis.json +35 -0
- package/validation/tests/old/hover.json +118 -0
- package/validation/tests/old/labClash.json +52 -0
- package/validation/tests/old/linkTo.json +35 -0
- package/validation/tests/old/linkUl.json +71 -0
- package/validation/tests/old/menuNav.json +106 -0
- package/validation/tests/old/miniText.json +36 -0
- package/validation/tests/old/motion.json +62 -0
- package/validation/tests/old/nonTable.json +37 -0
- package/validation/tests/old/radioSet.json +52 -0
- package/validation/tests/old/role.json +60 -0
- package/validation/tests/old/styleDiff.json +71 -0
- package/validation/tests/old/tabNav.json +106 -0
- package/validation/tests/old/temp.js +28 -0
- package/validation/tests/old/textNodes.json +98 -0
- package/validation/tests/old/title.json +46 -0
- package/validation/tests/old/titledEl.json +37 -0
- package/validation/tests/old/zIndex.json +49 -0
- package/validation/tests/targets/attVal/good.html +1 -1
- package/validation/tests/targets/elements/index.html +1 -0
- package/tests/embAc.js +0 -36
|
@@ -43,5 +43,39 @@ exports.reporter = async (page, withItems) => {
|
|
|
43
43
|
}
|
|
44
44
|
return data;
|
|
45
45
|
}, withItems);
|
|
46
|
-
|
|
46
|
+
const totals = [0, data.totals.impactedElements, data.totals.styledElements, 0, 0];
|
|
47
|
+
const standardInstances = [];
|
|
48
|
+
if (data.items) {
|
|
49
|
+
data.items.forEach(item => {
|
|
50
|
+
standardInstances.push({
|
|
51
|
+
issueID: 'filterStyle',
|
|
52
|
+
what: `Element ${item.tagName} has a filter style that impacts ${item.impact} elements`,
|
|
53
|
+
ordinalSeverity: 2,
|
|
54
|
+
location: {
|
|
55
|
+
doc: '',
|
|
56
|
+
type: '',
|
|
57
|
+
spec: ''
|
|
58
|
+
},
|
|
59
|
+
excerpt: `${item.tagName}: ${item.text}`
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else if (data.totals.styledElements) {
|
|
64
|
+
standardInstances.push({
|
|
65
|
+
issueID: 'filterStyle',
|
|
66
|
+
what: 'Elements have filter styles impacting other elements',
|
|
67
|
+
ordinalSeverity: 2,
|
|
68
|
+
location: {
|
|
69
|
+
doc: '',
|
|
70
|
+
type: '',
|
|
71
|
+
spec: ''
|
|
72
|
+
},
|
|
73
|
+
excerpt: ''
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
data,
|
|
78
|
+
totals,
|
|
79
|
+
standardInstances
|
|
80
|
+
};
|
|
47
81
|
};
|
|
@@ -48,10 +48,27 @@ exports.reporter = async page => {
|
|
|
48
48
|
refocused++;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
return {result: {
|
|
51
|
+
const data = {
|
|
53
52
|
tabFocusables,
|
|
54
53
|
tabFocused,
|
|
55
54
|
discrepancy: tabFocused - tabFocusables
|
|
56
|
-
}
|
|
55
|
+
};
|
|
56
|
+
// Reload the page.
|
|
57
|
+
await page.reload({timeout: 15000});
|
|
58
|
+
// Return the result.
|
|
59
|
+
return {
|
|
60
|
+
data,
|
|
61
|
+
totals: [0, 0, Math.abs(data.discrepancy), 0],
|
|
62
|
+
standardInstances: data.discrepancy ? [{
|
|
63
|
+
issueID: 'focAll',
|
|
64
|
+
what: 'Some focusable elements are not Tab-focusable or vice versa',
|
|
65
|
+
ordinalSeverity: 2,
|
|
66
|
+
location: {
|
|
67
|
+
doc: '',
|
|
68
|
+
type: '',
|
|
69
|
+
spec: ''
|
|
70
|
+
},
|
|
71
|
+
excerpt: ''
|
|
72
|
+
}] : []
|
|
73
|
+
};
|
|
57
74
|
};
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
WARNING: This test fails to recognize outlines when run with firefox.
|
|
15
15
|
*/
|
|
16
|
-
exports.reporter = async (page, revealAll, allowedDelay
|
|
16
|
+
exports.reporter = async (page, withItems, revealAll = false, allowedDelay = 250) => {
|
|
17
17
|
// If required, make all elements visible.
|
|
18
18
|
if (revealAll) {
|
|
19
19
|
await require('../procs/allVis').allVis(page);
|
|
@@ -67,7 +67,8 @@ exports.reporter = async (page, revealAll, allowedDelay, withItems) => {
|
|
|
67
67
|
if (withItems) {
|
|
68
68
|
const elementData = {
|
|
69
69
|
tagName,
|
|
70
|
-
text: element.textContent.trim().replace(/\s
|
|
70
|
+
text: (element.textContent.trim() || element.outerHTML.trim()).replace(/\s+/g, ' ')
|
|
71
|
+
.slice(0, 100)
|
|
71
72
|
};
|
|
72
73
|
if (status === 'outlinePresent') {
|
|
73
74
|
elementData.delay = delay;
|
|
@@ -163,5 +164,46 @@ exports.reporter = async (page, revealAll, allowedDelay, withItems) => {
|
|
|
163
164
|
}
|
|
164
165
|
return data;
|
|
165
166
|
}, [allowedDelay, withItems]);
|
|
166
|
-
|
|
167
|
+
const {types} = data.totals;
|
|
168
|
+
const totals = [0, 0, types.nonOutlinePresent.total, types.indicatorMissing.total];
|
|
169
|
+
const standardInstances = [];
|
|
170
|
+
if (data.items) {
|
|
171
|
+
const issueNames = ['nonOutlinePresent', 'indicatorMissing'];
|
|
172
|
+
issueNames.forEach(issueName => {
|
|
173
|
+
data.items[issueName].forEach(item => {
|
|
174
|
+
const qualifier = issueName === 'nonOutlinePresent' ? 'a non-outline' : 'no';
|
|
175
|
+
standardInstances.push({
|
|
176
|
+
issueID: `focInd-${issueName}`,
|
|
177
|
+
what: `Element ${item.tagName} has ${qualifier} focus indicator`,
|
|
178
|
+
ordinalSeverity: issueName === 'nonOutlinePresent' ? 2 : 3,
|
|
179
|
+
location: {
|
|
180
|
+
doc: '',
|
|
181
|
+
type: '',
|
|
182
|
+
spec: ''
|
|
183
|
+
},
|
|
184
|
+
excerpt: item.text
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
else if (types.nonOutlinePresent.total || types.indicatorMissing.total) {
|
|
190
|
+
standardInstances.push({
|
|
191
|
+
issueID: 'focInd',
|
|
192
|
+
what: 'Elements have missing or non-outline focus indicators',
|
|
193
|
+
ordinalSeverity: types.indicatorMissing.total ? 3 : 2,
|
|
194
|
+
location: {
|
|
195
|
+
doc: '',
|
|
196
|
+
type: '',
|
|
197
|
+
spec: ''
|
|
198
|
+
},
|
|
199
|
+
excerpt: ''
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
// Reload the page.
|
|
203
|
+
await page.reload({timeout: 15000});
|
|
204
|
+
return {
|
|
205
|
+
data,
|
|
206
|
+
totals,
|
|
207
|
+
standardInstances
|
|
208
|
+
};
|
|
167
209
|
};
|
|
@@ -85,7 +85,7 @@ exports.reporter = async (page, withItems) => {
|
|
|
85
85
|
id: id || '',
|
|
86
86
|
text: (element.textContent.trim() || element.outerHTML.trim())
|
|
87
87
|
.replace(/\s{2,}/sg, ' ')
|
|
88
|
-
.slice(0,
|
|
88
|
+
.slice(0, 100)
|
|
89
89
|
};
|
|
90
90
|
if (status !== 'f') {
|
|
91
91
|
elementData.byTag = byTag;
|
|
@@ -134,5 +134,64 @@ exports.reporter = async (page, withItems) => {
|
|
|
134
134
|
console.log(`ERROR getting focOp data (${error.message})`);
|
|
135
135
|
data.prevented = true;
|
|
136
136
|
});
|
|
137
|
-
|
|
137
|
+
// Derive the standard data.
|
|
138
|
+
const totals = [0, 0, 0, 0];
|
|
139
|
+
if (
|
|
140
|
+
data.totals
|
|
141
|
+
&& data.totals.types
|
|
142
|
+
&& data.totals.types.onlyFocusable
|
|
143
|
+
&& data.totals.types.onlyOperable
|
|
144
|
+
&& typeof data.totals.types.onlyFocusable.total === 'number'
|
|
145
|
+
&& typeof data.totals.types.onlyOperable.total === 'number'
|
|
146
|
+
) {
|
|
147
|
+
totals[2] = data.totals.types.onlyFocusable.total;
|
|
148
|
+
totals[3] = data.totals.types.onlyOperable.total;
|
|
149
|
+
}
|
|
150
|
+
const standardInstances = [];
|
|
151
|
+
if (data.items && data.items.onlyFocusable && data.items.onlyOperable) {
|
|
152
|
+
['onlyFocusable', 'onlyOperable'].forEach(issue => {
|
|
153
|
+
const issueID = issue === 'onlyFocusable'
|
|
154
|
+
? 'focOp-focusable-inoperable'
|
|
155
|
+
: 'focOp-operable-nonfocusable';
|
|
156
|
+
const gripe = issue === 'onlyFocusable'
|
|
157
|
+
? 'is focusable but not operable'
|
|
158
|
+
: 'is operable but not focusable';
|
|
159
|
+
const ordinalSeverity = issue === 'onlyFocusable' ? 2 : 3;
|
|
160
|
+
data.items[issue].forEach(item => {
|
|
161
|
+
const itemID = item.id ? ` (ID ${item.id})` : '';
|
|
162
|
+
const which = `${item.tagName}${itemID}`;
|
|
163
|
+
standardInstances.push({
|
|
164
|
+
issueID,
|
|
165
|
+
what: `Element ${which} ${gripe}`,
|
|
166
|
+
ordinalSeverity,
|
|
167
|
+
location: {
|
|
168
|
+
doc: '',
|
|
169
|
+
type: '',
|
|
170
|
+
spec: ''
|
|
171
|
+
},
|
|
172
|
+
excerpt: item.text
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
else if (totals[2] || totals[3]) {
|
|
178
|
+
standardInstances.push({
|
|
179
|
+
issueID: 'focOp',
|
|
180
|
+
what: 'Focusable elements are inoperable or vice versa',
|
|
181
|
+
ordinalSeverity: totals[3] ? 3 : 2,
|
|
182
|
+
location: {
|
|
183
|
+
doc: '',
|
|
184
|
+
type: '',
|
|
185
|
+
spec: ''
|
|
186
|
+
},
|
|
187
|
+
excerpt: ''
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
// Reload the page.
|
|
191
|
+
await page.reload({timeout: 15000});
|
|
192
|
+
return {
|
|
193
|
+
data,
|
|
194
|
+
totals,
|
|
195
|
+
standardInstances
|
|
196
|
+
};
|
|
138
197
|
};
|
|
@@ -25,5 +25,39 @@ exports.reporter = async (page, withItems) => {
|
|
|
25
25
|
if (withItems) {
|
|
26
26
|
data.items = badLinks;
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
const totals = [0, 0, data.total, 0];
|
|
29
|
+
const standardInstances = [];
|
|
30
|
+
if (data.items) {
|
|
31
|
+
data.items.forEach(item => {
|
|
32
|
+
standardInstances.push({
|
|
33
|
+
issueID: 'focVis',
|
|
34
|
+
what: 'Visible link is above or to the left of the display',
|
|
35
|
+
ordinalSeverity: 2,
|
|
36
|
+
location: {
|
|
37
|
+
doc: '',
|
|
38
|
+
type: '',
|
|
39
|
+
spec: ''
|
|
40
|
+
},
|
|
41
|
+
excerpt: item
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else if (data.total) {
|
|
46
|
+
standardInstances.push({
|
|
47
|
+
issueID: 'focVis',
|
|
48
|
+
what: 'Visible links are above or to the left of the display',
|
|
49
|
+
ordinalSeverity: 2,
|
|
50
|
+
location: {
|
|
51
|
+
doc: '',
|
|
52
|
+
type: '',
|
|
53
|
+
spec: ''
|
|
54
|
+
},
|
|
55
|
+
excerpt: ''
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
data,
|
|
60
|
+
totals,
|
|
61
|
+
standardInstances
|
|
62
|
+
};
|
|
29
63
|
};
|
|
@@ -43,7 +43,7 @@ const samProb = (index, popSize, sampleRatio) =>
|
|
|
43
43
|
const getSample = (population, sampleSize) => {
|
|
44
44
|
const popSize = population.length;
|
|
45
45
|
// If the sample is at least as large as the population:
|
|
46
|
-
if (sampleSize >= popSize) {
|
|
46
|
+
if (sampleSize >= popSize || sampleSize < 0) {
|
|
47
47
|
// Return the population as the sample.
|
|
48
48
|
return population.map(trigger => [trigger, 1]);
|
|
49
49
|
}
|
|
@@ -181,7 +181,7 @@ const find = async (data, withItems, page, sample) => {
|
|
|
181
181
|
const itemData = {
|
|
182
182
|
tagName,
|
|
183
183
|
id: (await firstTrigger[0].getAttribute('id')) || '',
|
|
184
|
-
text: await textOf(firstTrigger[0],
|
|
184
|
+
text: await textOf(firstTrigger[0], 100)
|
|
185
185
|
};
|
|
186
186
|
try {
|
|
187
187
|
// Hover over the trigger.
|
|
@@ -269,7 +269,7 @@ const find = async (data, withItems, page, sample) => {
|
|
|
269
269
|
// Add them to the data.
|
|
270
270
|
data.items.impactTriggers.push({
|
|
271
271
|
tagName,
|
|
272
|
-
text: await textOf(firstTrigger[0],
|
|
272
|
+
text: await textOf(firstTrigger[0], 100),
|
|
273
273
|
additions,
|
|
274
274
|
removals,
|
|
275
275
|
opacityChanges,
|
|
@@ -309,7 +309,7 @@ const find = async (data, withItems, page, sample) => {
|
|
|
309
309
|
}
|
|
310
310
|
};
|
|
311
311
|
// Performs the hover test and reports results.
|
|
312
|
-
exports.reporter = async (page, sampleSize = -1
|
|
312
|
+
exports.reporter = async (page, withItems, sampleSize = -1) => {
|
|
313
313
|
// Initialize the result.
|
|
314
314
|
let data = {
|
|
315
315
|
totals: {
|
|
@@ -376,6 +376,68 @@ exports.reporter = async (page, sampleSize = -1, withItems) => {
|
|
|
376
376
|
data.totals[key] = Math.round(data.totals[key]);
|
|
377
377
|
});
|
|
378
378
|
}
|
|
379
|
+
const severity = {
|
|
380
|
+
impactTriggers: 3,
|
|
381
|
+
additions: 1,
|
|
382
|
+
removals: 2,
|
|
383
|
+
opacityChanges: 1,
|
|
384
|
+
opacityImpact: 0,
|
|
385
|
+
unhoverables: 3,
|
|
386
|
+
noCursors: 3,
|
|
387
|
+
badCursors: 2,
|
|
388
|
+
noIndicators: 3,
|
|
389
|
+
badIndicators: 2
|
|
390
|
+
};
|
|
391
|
+
const what = {
|
|
392
|
+
impactTriggers: 'Hovering over element has unexpected effects',
|
|
393
|
+
unhoverables: 'Operable element cannot be hovered over',
|
|
394
|
+
noCursors: 'Hoverable element hides the mouse cursor',
|
|
395
|
+
badCursors: 'Link or button makes the hovering mouse cursor nonstandard',
|
|
396
|
+
noIndicators: 'Button shows no indication of being hovered over',
|
|
397
|
+
badIndicators: 'List item changes when hovered over'
|
|
398
|
+
};
|
|
399
|
+
const totals = [0, 0, 0, 0];
|
|
400
|
+
Object.keys(data.totals).forEach(issue => {
|
|
401
|
+
totals[severity[issue]] += data.totals[issue];
|
|
402
|
+
});
|
|
403
|
+
const standardInstances = [];
|
|
404
|
+
if (data.items) {
|
|
405
|
+
Object.keys(data.items).forEach(issue => {
|
|
406
|
+
data.items[issue].forEach(item => {
|
|
407
|
+
const itemID = item.id ? ` (ID ${item.id})` : '';
|
|
408
|
+
standardInstances.push({
|
|
409
|
+
issueID: `hover-${issue}`,
|
|
410
|
+
what: what[issue],
|
|
411
|
+
ordinalSeverity: severity[issue],
|
|
412
|
+
location: {
|
|
413
|
+
doc: '',
|
|
414
|
+
type: '',
|
|
415
|
+
spec: ''
|
|
416
|
+
},
|
|
417
|
+
excerpt: `${itemID}: ${item.text}`
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
else if (totals.some(total => total)) {
|
|
423
|
+
standardInstances.push({
|
|
424
|
+
issueID: 'hover',
|
|
425
|
+
what: 'Hovering has unexpected impacts',
|
|
426
|
+
ordinalSeverity: totals.reduce((max, current, index) => current ? index : max, 0),
|
|
427
|
+
location: {
|
|
428
|
+
doc: '',
|
|
429
|
+
type: '',
|
|
430
|
+
spec: ''
|
|
431
|
+
},
|
|
432
|
+
excerpt: ''
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
// Reload the page.
|
|
436
|
+
await page.reload({timeout: 15000});
|
|
379
437
|
// Return the result.
|
|
380
|
-
return {
|
|
438
|
+
return {
|
|
439
|
+
data,
|
|
440
|
+
totals,
|
|
441
|
+
standardInstances
|
|
442
|
+
};
|
|
381
443
|
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
exports.reporter = async (page, withItems) => {
|
|
9
9
|
return await page.$eval('body', (body, withItems) => {
|
|
10
10
|
// FUNCTION DEFINITION START
|
|
11
|
-
const debloat = text => text.replace(/\s+/g, ' ').trim();
|
|
11
|
+
const debloat = text => text ? text.replace(/\s+/g, ' ').trim().slice(0, 100) : '';
|
|
12
12
|
// FUNCTION DEFINITION END
|
|
13
13
|
// Initialize a report.
|
|
14
14
|
const data = {
|
|
@@ -125,7 +125,7 @@ exports.reporter = async (page, withItems) => {
|
|
|
125
125
|
labelee.tagName === 'BUTTON'
|
|
126
126
|
|| (labelee.tagName === 'INPUT' && labelee.type === 'submit')
|
|
127
127
|
) {
|
|
128
|
-
item.content = texts.content ||
|
|
128
|
+
item.content = debloat(texts.content) || debloat(labelee.outerHTML);
|
|
129
129
|
}
|
|
130
130
|
data.items.unlabeled.push(item);
|
|
131
131
|
}
|
|
@@ -146,7 +146,53 @@ exports.reporter = async (page, withItems) => {
|
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
});
|
|
149
|
-
|
|
149
|
+
const totals = [0, 0, data.totals.mislabeled, data.totals.unlabeled];
|
|
150
|
+
const standardInstances = [];
|
|
151
|
+
if (data.items) {
|
|
152
|
+
['mislabeled', 'unlabeled'].forEach(issue => {
|
|
153
|
+
let diagnosis;
|
|
154
|
+
let excerptTail;
|
|
155
|
+
data.items[issue].forEach(item => {
|
|
156
|
+
if (issue === 'mislabeled') {
|
|
157
|
+
diagnosis = `has clashing labels of types: ${item.labelTypes.join(', ')}`;
|
|
158
|
+
excerptTail = debloat(Object.values(item.texts).join(' '));
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
diagnosis = 'is unlabeled';
|
|
162
|
+
excerptTail = item.content || '';
|
|
163
|
+
}
|
|
164
|
+
standardInstances.push({
|
|
165
|
+
issueID: `labClash-${issue}`,
|
|
166
|
+
what: `Element ${item.tagName} ${diagnosis}`,
|
|
167
|
+
ordinalSeverity: issue === 'mislabeled' ? 2 : 3,
|
|
168
|
+
location: {
|
|
169
|
+
doc: '',
|
|
170
|
+
type: '',
|
|
171
|
+
spec: ''
|
|
172
|
+
},
|
|
173
|
+
excerpt: `${item.tagName}: ${excerptTail}`
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
else if (data.totals.mislabeled || data.totals.unlabeled) {
|
|
179
|
+
standardInstances.push({
|
|
180
|
+
issueID: 'labClash',
|
|
181
|
+
what: 'Element labels are conflicting or missing',
|
|
182
|
+
ordinalSeverity: data.totals.unlabeled ? 3 : 2,
|
|
183
|
+
location: {
|
|
184
|
+
doc: '',
|
|
185
|
+
type: '',
|
|
186
|
+
spec: ''
|
|
187
|
+
},
|
|
188
|
+
excerpt: ''
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
data,
|
|
193
|
+
totals,
|
|
194
|
+
standardInstances
|
|
195
|
+
};
|
|
150
196
|
}, withItems)
|
|
151
197
|
.catch(error => {
|
|
152
198
|
console.log(`ERROR: labClash failed (${error.message})`);
|
|
@@ -154,6 +200,10 @@ exports.reporter = async (page, withItems) => {
|
|
|
154
200
|
prevented: true,
|
|
155
201
|
error: 'ERROR: labClash failed'
|
|
156
202
|
};
|
|
157
|
-
return {
|
|
203
|
+
return {
|
|
204
|
+
data,
|
|
205
|
+
totals: [],
|
|
206
|
+
standardInstances: []
|
|
207
|
+
};
|
|
158
208
|
});
|
|
159
209
|
};
|
|
@@ -18,8 +18,40 @@ exports.reporter = async (page, withItems) => {
|
|
|
18
18
|
const data = {
|
|
19
19
|
total: badLinkTexts.length
|
|
20
20
|
};
|
|
21
|
+
const totals = [0, 0, data.total, 0];
|
|
22
|
+
const standardInstances = [];
|
|
21
23
|
if (withItems) {
|
|
22
24
|
data.items = badLinkTexts;
|
|
25
|
+
data.items.forEach(item => {
|
|
26
|
+
standardInstances.push({
|
|
27
|
+
issueID: 'linkTo',
|
|
28
|
+
what: 'Element a has no href attribute',
|
|
29
|
+
ordinalSeverity: 2,
|
|
30
|
+
location: {
|
|
31
|
+
doc: '',
|
|
32
|
+
type: '',
|
|
33
|
+
spec: ''
|
|
34
|
+
},
|
|
35
|
+
excerpt: item
|
|
36
|
+
});
|
|
37
|
+
});
|
|
23
38
|
}
|
|
24
|
-
|
|
39
|
+
else if (data.total) {
|
|
40
|
+
standardInstances.push({
|
|
41
|
+
issueID: 'linkTo',
|
|
42
|
+
what: 'Links are missing href attributes',
|
|
43
|
+
ordinalSeverity: 2,
|
|
44
|
+
location: {
|
|
45
|
+
doc: '',
|
|
46
|
+
type: '',
|
|
47
|
+
spec: ''
|
|
48
|
+
},
|
|
49
|
+
excerpt: ''
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
data,
|
|
54
|
+
totals,
|
|
55
|
+
standardInstances
|
|
56
|
+
};
|
|
25
57
|
};
|
|
@@ -16,7 +16,10 @@ exports.reporter = async (page, withItems) => {
|
|
|
16
16
|
const linkTypes = args[1];
|
|
17
17
|
// FUNCTION DEFINITION START
|
|
18
18
|
// Returns a space-minimized copy of a string.
|
|
19
|
-
const compact = string => string
|
|
19
|
+
const compact = string => string
|
|
20
|
+
.replace(/\s+/g, ' ')
|
|
21
|
+
.trim()
|
|
22
|
+
.slice(0, 100);
|
|
20
23
|
// FUNCTION DEFINITION END
|
|
21
24
|
// Identify the adjacent links.
|
|
22
25
|
const adjacentLinks = linkTypes.adjacent;
|
|
@@ -27,7 +30,7 @@ exports.reporter = async (page, withItems) => {
|
|
|
27
30
|
// For each of them:
|
|
28
31
|
adjacentLinks.forEach(link => {
|
|
29
32
|
// Identify the text of the link if itemization is required.
|
|
30
|
-
const text = withItems ? compact(link.textContent) : '';
|
|
33
|
+
const text = withItems ? compact(link.textContent) || compact(link.outerHTML) : '';
|
|
31
34
|
// If it is underlined:
|
|
32
35
|
if (window.getComputedStyle(link).textDecorationLine === 'underline') {
|
|
33
36
|
// Increment the count of underlined inline links.
|
|
@@ -45,8 +48,8 @@ exports.reporter = async (page, withItems) => {
|
|
|
45
48
|
});
|
|
46
49
|
// Get the percentage of underlined links among all inline links.
|
|
47
50
|
const underlinedPercent = adjacentLinkCount
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
? Math.floor(100 * underlined / adjacentLinkCount)
|
|
52
|
+
: 'N/A';
|
|
50
53
|
const data = {
|
|
51
54
|
totals: {
|
|
52
55
|
links: adjacentLinks.length + linkTypes.list.length,
|
|
@@ -63,6 +66,41 @@ exports.reporter = async (page, withItems) => {
|
|
|
63
66
|
notUnderlined: nulAdjacentLinkTexts
|
|
64
67
|
};
|
|
65
68
|
}
|
|
66
|
-
|
|
69
|
+
const {adjacent} = data.totals;
|
|
70
|
+
const totals = [0, adjacent.total - adjacent.underlined, 0, 0];
|
|
71
|
+
const standardInstances = [];
|
|
72
|
+
if (data.items && data.items.notUnderlined) {
|
|
73
|
+
data.items.notUnderlined.forEach(item => {
|
|
74
|
+
standardInstances.push({
|
|
75
|
+
issueID: 'linkUl',
|
|
76
|
+
what: 'Element a is inline but has no underline',
|
|
77
|
+
ordinalSeverity: 1,
|
|
78
|
+
location: {
|
|
79
|
+
doc: '',
|
|
80
|
+
type: '',
|
|
81
|
+
spec: ''
|
|
82
|
+
},
|
|
83
|
+
excerpt: item
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else if (adjacent.total - adjacent.underlined > 0) {
|
|
88
|
+
standardInstances.push({
|
|
89
|
+
issueID: 'linkUl',
|
|
90
|
+
what: 'Inline links are missing underlines',
|
|
91
|
+
ordinalSeverity: 1,
|
|
92
|
+
location: {
|
|
93
|
+
doc: '',
|
|
94
|
+
type: '',
|
|
95
|
+
spec: ''
|
|
96
|
+
},
|
|
97
|
+
excerpt: ''
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
data,
|
|
102
|
+
totals,
|
|
103
|
+
standardInstances
|
|
104
|
+
};
|
|
67
105
|
}, [withItems, linkTypes]);
|
|
68
106
|
};
|
|
@@ -260,5 +260,46 @@ exports.reporter = async (page, withItems) => {
|
|
|
260
260
|
// FUNCTION DEFINITIONS END
|
|
261
261
|
await testMenus(menus);
|
|
262
262
|
}
|
|
263
|
-
|
|
263
|
+
const totals = data.totals ? [
|
|
264
|
+
data.totals.navigations.all.incorrect,
|
|
265
|
+
data.totals.menuItems.incorrect,
|
|
266
|
+
data.totals.menus.incorrect,
|
|
267
|
+
0
|
|
268
|
+
] : [];
|
|
269
|
+
const standardInstances = [];
|
|
270
|
+
if (data.menuItems && data.menuItems.incorrect) {
|
|
271
|
+
data.menuItems.incorrect.forEach(item => {
|
|
272
|
+
standardInstances.push({
|
|
273
|
+
issueID: 'menuNav',
|
|
274
|
+
what: `Element ${item.tagName} is a menu item but has nonstandard navigation`,
|
|
275
|
+
ordinalSeverity: 1,
|
|
276
|
+
location: {
|
|
277
|
+
doc: '',
|
|
278
|
+
type: '',
|
|
279
|
+
spec: ''
|
|
280
|
+
},
|
|
281
|
+
excerpt: `${item.tagName}: ${item.text}`
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
else if (data.totals.menuItems.incorrect) {
|
|
286
|
+
standardInstances.push({
|
|
287
|
+
issueID: 'menuNav',
|
|
288
|
+
what: 'Menus and menu items have nonstandard navigation',
|
|
289
|
+
ordinalSeverity: 2,
|
|
290
|
+
location: {
|
|
291
|
+
doc: '',
|
|
292
|
+
type: '',
|
|
293
|
+
spec: ''
|
|
294
|
+
},
|
|
295
|
+
excerpt: ''
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
// Reload the page.
|
|
299
|
+
await page.reload({timeout: 15000});
|
|
300
|
+
return {
|
|
301
|
+
data,
|
|
302
|
+
totals,
|
|
303
|
+
standardInstances
|
|
304
|
+
};
|
|
264
305
|
};
|
|
@@ -41,8 +41,39 @@ exports.reporter = async (page, withItems) => {
|
|
|
41
41
|
const data = {
|
|
42
42
|
total: miniTexts.length
|
|
43
43
|
};
|
|
44
|
+
const standardInstances = [];
|
|
44
45
|
if (withItems) {
|
|
45
46
|
data.items = miniTexts;
|
|
47
|
+
miniTexts.forEach(text => {
|
|
48
|
+
standardInstances.push({
|
|
49
|
+
issueID: 'miniText',
|
|
50
|
+
what: 'Text font is smaller than 11 pixels',
|
|
51
|
+
ordinalSeverity: 2,
|
|
52
|
+
location: {
|
|
53
|
+
doc: '',
|
|
54
|
+
type: '',
|
|
55
|
+
spec: ''
|
|
56
|
+
},
|
|
57
|
+
excerpt: text
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else if (data.total) {
|
|
62
|
+
standardInstances.push({
|
|
63
|
+
issueID: 'miniText',
|
|
64
|
+
what: 'Texts have fonts smaller than 11 pixels',
|
|
65
|
+
ordinalSeverity: 2,
|
|
66
|
+
location: {
|
|
67
|
+
doc: '',
|
|
68
|
+
type: '',
|
|
69
|
+
spec: ''
|
|
70
|
+
},
|
|
71
|
+
excerpt: ''
|
|
72
|
+
});
|
|
46
73
|
}
|
|
47
|
-
return {
|
|
74
|
+
return {
|
|
75
|
+
data,
|
|
76
|
+
totals: [0, 0, data.total, 0],
|
|
77
|
+
standardInstances
|
|
78
|
+
};
|
|
48
79
|
};
|