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.
Files changed (100) hide show
  1. package/README.md +190 -94
  2. package/actSpecs.js +17 -158
  3. package/package.json +1 -1
  4. package/run.js +31 -31
  5. package/standardize.js +338 -0
  6. package/{tests → testaro}/allHidden.js +36 -1
  7. package/{tests → testaro}/attVal.js +36 -2
  8. package/{tests → testaro}/autocomplete.js +34 -1
  9. package/{tests → testaro}/bulk.js +15 -1
  10. package/{tests → testaro}/docType.js +15 -1
  11. package/{tests → testaro}/dupAtt.js +34 -1
  12. package/{tests → testaro}/elements.js +9 -3
  13. package/testaro/embAc.js +78 -0
  14. package/{tests → testaro}/filter.js +35 -1
  15. package/{tests → testaro}/focAll.js +20 -3
  16. package/{tests → testaro}/focInd.js +45 -3
  17. package/{tests → testaro}/focOp.js +61 -2
  18. package/{tests → testaro}/focVis.js +35 -1
  19. package/{tests → testaro}/hover.js +67 -5
  20. package/{tests → testaro}/labClash.js +54 -4
  21. package/{tests → testaro}/linkTo.js +33 -1
  22. package/{tests → testaro}/linkUl.js +43 -5
  23. package/{tests → testaro}/menuNav.js +42 -1
  24. package/{tests → testaro}/miniText.js +32 -1
  25. package/{tests → testaro}/motion.js +27 -4
  26. package/{tests → testaro}/nonTable.js +32 -1
  27. package/{tests → testaro}/radioSet.js +33 -2
  28. package/{tests → testaro}/role.js +38 -1
  29. package/{tests → testaro}/styleDiff.js +43 -2
  30. package/{tests → testaro}/tabNav.js +42 -1
  31. package/{tests → testaro}/textNodes.js +6 -2
  32. package/{tests → testaro}/title.js +8 -4
  33. package/{tests → testaro}/titledEl.js +32 -1
  34. package/{tests → testaro}/zIndex.js +40 -2
  35. package/tests/alfa.js +72 -75
  36. package/tests/continuum.js +6 -2
  37. package/tests/ibm.js +14 -42
  38. package/tests/testaro.js +73 -0
  39. package/validation/tests/jobs/allHidden.json +877 -174
  40. package/validation/tests/jobs/attVal.json +57 -19
  41. package/validation/tests/jobs/autocomplete.json +34 -8
  42. package/validation/tests/jobs/bulk.json +33 -7
  43. package/validation/tests/jobs/docType.json +23 -5
  44. package/validation/tests/jobs/dupAtt.json +47 -8
  45. package/validation/tests/jobs/elements.json +231 -70
  46. package/validation/tests/jobs/embAc.json +70 -15
  47. package/validation/tests/jobs/filter.json +56 -12
  48. package/validation/tests/jobs/focAll.json +64 -16
  49. package/validation/tests/jobs/focInd.json +107 -23
  50. package/validation/tests/jobs/focOp.json +93 -21
  51. package/validation/tests/jobs/focVis.json +16 -4
  52. package/validation/tests/jobs/hover.json +246 -56
  53. package/validation/tests/jobs/labClash.json +43 -11
  54. package/validation/tests/jobs/linkTo.json +16 -4
  55. package/validation/tests/jobs/linkUl.json +79 -19
  56. package/validation/tests/jobs/menuNav.json +313 -65
  57. package/validation/tests/jobs/miniText.json +21 -5
  58. package/validation/tests/jobs/motion.json +81 -23
  59. package/validation/tests/jobs/nonTable.json +26 -6
  60. package/validation/tests/jobs/radioSet.json +43 -11
  61. package/validation/tests/jobs/role.json +93 -19
  62. package/validation/tests/jobs/styleDiff.json +124 -28
  63. package/validation/tests/jobs/tabNav.json +313 -65
  64. package/validation/tests/jobs/textNodes.json +190 -49
  65. package/validation/tests/jobs/title.json +23 -5
  66. package/validation/tests/jobs/titledEl.json +26 -6
  67. package/validation/tests/jobs/zIndex.json +28 -8
  68. package/validation/tests/old/allHidden.json +314 -0
  69. package/validation/tests/old/attVal.json +60 -0
  70. package/validation/tests/old/autocomplete.json +51 -0
  71. package/validation/tests/old/bulk.json +48 -0
  72. package/validation/tests/old/docType.json +46 -0
  73. package/validation/tests/old/dupAtt.json +51 -0
  74. package/validation/tests/old/elements.json +140 -0
  75. package/validation/tests/old/embAc.json +54 -0
  76. package/validation/tests/old/filter.json +55 -0
  77. package/validation/tests/old/focAll.json +68 -0
  78. package/validation/tests/old/focInd.json +69 -0
  79. package/validation/tests/old/focOp.json +62 -0
  80. package/validation/tests/old/focVis.json +35 -0
  81. package/validation/tests/old/hover.json +118 -0
  82. package/validation/tests/old/labClash.json +52 -0
  83. package/validation/tests/old/linkTo.json +35 -0
  84. package/validation/tests/old/linkUl.json +71 -0
  85. package/validation/tests/old/menuNav.json +106 -0
  86. package/validation/tests/old/miniText.json +36 -0
  87. package/validation/tests/old/motion.json +62 -0
  88. package/validation/tests/old/nonTable.json +37 -0
  89. package/validation/tests/old/radioSet.json +52 -0
  90. package/validation/tests/old/role.json +60 -0
  91. package/validation/tests/old/styleDiff.json +71 -0
  92. package/validation/tests/old/tabNav.json +106 -0
  93. package/validation/tests/old/temp.js +28 -0
  94. package/validation/tests/old/textNodes.json +98 -0
  95. package/validation/tests/old/title.json +46 -0
  96. package/validation/tests/old/titledEl.json +37 -0
  97. package/validation/tests/old/zIndex.json +49 -0
  98. package/validation/tests/targets/attVal/good.html +1 -1
  99. package/validation/tests/targets/elements/index.html +1 -0
  100. 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
- return {result: data};
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
- // Return the result.
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, withItems) => {
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{2,}/g, ' ').slice(0, 100)
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
- return {result: data};
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, 80)
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
- return {result: data};
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
- return {result: data};
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], 50)
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], 50),
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, withItems) => {
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 {result: data};
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 || `{${debloat(labelee.outerHTML)}}`;
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
- return {result: data};
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 {result: data};
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
- return {result: data};
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.replace(/[\t\n]/g, '').replace(/\s{2,}/g, ' ').trim();
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
- ? Math.floor(100 * underlined / adjacentLinkCount)
49
- : 'N/A';
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
- return {result: data};
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
- return {result: data};
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 {result: data};
74
+ return {
75
+ data,
76
+ totals: [0, 0, data.total, 0],
77
+ standardInstances
78
+ };
48
79
  };