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 CHANGED
@@ -204,10 +204,13 @@ If the `STANDARD` environment variable has the value `also` (which it has by def
204
204
 
205
205
  The standard format of each tool report has two properties:
206
206
  - `totals`: an array of 4 integers, representing the counts of issue instances classified by the tool into 4 ordinal degrees of severity. For example, `[2, 13, 0, 5]` would mean that the tool reported 2 instances at the lowest severity, 13 at the next-lowest, none at the third-lowest, and 5 at the highest.
207
- - `instances`: an array of objects describing facts about issue instances reported by the tool. Insofar as each tool permits, this object has these properties:
207
+ - `instances`: an array of objects describing facts about issue instances reported by the tool. This object has these properties, some of which have empty strings as values when the tool does not provide values:
208
208
  - `issueID`: a code identifying the issue
209
209
  - `what`: a description of the issue
210
+ - `count` (optional): the count of instances if this instance represents multiple instances
210
211
  - `ordinalSeverity`: how the tool ranks the severity of the instance, on a 4-point ordinal scale
212
+ - `tagName`: upper-case tagName of the affected element
213
+ - `id`: value of the `id` property of that element
211
214
  - `location`: an object with three properties:
212
215
  - `doc`: whether the source (`source`) or the browser rendition (`dom`) was tested
213
216
  - `type`: the type of location information provided by the tool (`line`, `selector`, or `xpath`)
@@ -218,12 +221,14 @@ The original result of a test act is recorded as the value of a `result` propert
218
221
 
219
222
  ``` javascript
220
223
  standardResult: {
221
- totals: [2, 0, 1, 0],
224
+ totals: [2, 0, 17, 0],
222
225
  instances: [
223
226
  {
224
227
  issueID: 'rule01',
225
- what: 'button type invalid',
228
+ what: 'Button type invalid',
226
229
  ordinalSeverity: 0,
230
+ tagName: 'BUTTON'
231
+ id: '',
227
232
  location: {
228
233
  doc: 'dom',
229
234
  type: 'line',
@@ -233,8 +238,10 @@ standardResult: {
233
238
  },
234
239
  {
235
240
  issueID: 'rule01',
236
- what: 'button type invalid',
241
+ what: 'Button type invalid',
237
242
  ordinalSeverity: 1,
243
+ tagName: 'BUTTON',
244
+ id: 'submitbutton',
238
245
  location: {
239
246
  doc: 'dom',
240
247
  type: 'line',
@@ -244,20 +251,23 @@ standardResult: {
244
251
  },
245
252
  {
246
253
  issueID: 'rule02',
247
- what: 'link href empty',
254
+ what: 'Links have empty href attributes',
255
+ count: 17,
248
256
  ordinalSeverity: 3,
257
+ tagName: 'A',
258
+ id: '',
249
259
  location: {
250
- doc: 'dom',
251
- type: 'selector',
252
- spec: '#helplink'
260
+ doc: '',
261
+ type: '',
262
+ spec: ''
253
263
  },
254
- excerpt: '<a id="helplink" href>help</a>'
264
+ excerpt: ''
255
265
  }
256
266
  ]
257
267
  }
258
268
  ```
259
269
 
260
- If a tool has the option to be used without itemization and is being so used, the `instances` array will be empty.
270
+ If a tool has the option to be used without itemization and is being so used, the `instances` array may be empty.
261
271
 
262
272
  ### Acts
263
273
 
@@ -454,29 +464,6 @@ The `continuum` tests makes use of the files in the `continuum` directory. The t
454
464
 
455
465
  Level Access on 22 August 2022 granted authorization for the copying of the `AccessEngine.community.js` file insofar as necessary for allowing Continuum community edition tests to be included in Testaro.
456
466
 
457
- ###### IBM Equal Access
458
-
459
- The `ibm` tests require the `aceconfig.js` file.
460
-
461
- As of 2 March 2023 (version 3.1.45 of `accessibility-checker`), the `ibm` tool threw errors when hosted under the Windows operating system. To prevent these errors, it was possible to edit two files in the `accessibility-checker` package as follows:
462
-
463
- In `node_modules/accessibility-checker/lib/ACEngineManager.js`, remove or comment out these lines starting on line 169:
464
-
465
- ```javaScript
466
- if (nodePath.charAt(0) !== '/') {
467
- nodePath = "../../" + nodePath;
468
- }
469
- ```
470
-
471
- In `node_modules/accessibility-checker/lib/reporters/ACReporterJSON.js`, add these lines starting on line 106, immediately before the line `var resultsFileName = pathLib.join(resultDir, results.label + '.json');`:
472
-
473
- ```javaScript
474
- // Replace the colons in the label with hyphen-minuses.
475
- results.label = results.label.replace(/:/g, '-');
476
- ```
477
-
478
- These changes were proposed as pull requests 1333 and 1334 (https://github.com/IBMa/equal-access/pulls).
479
-
480
467
  ###### HTML CodeSniffer
481
468
 
482
469
  The `htmlcs` tool makes use of the `htmlcs/HTMLCS.js` file. That file was created, and can be recreated if necessary, as follows:
@@ -509,6 +496,31 @@ The changes in `htmlcs/HTMLCS.js` are:
509
496
  > );
510
497
  ```
511
498
 
499
+ ###### IBM Equal Access
500
+
501
+ The `ibm` tests require the `aceconfig.js` file.
502
+
503
+ As of 2 March 2023 (version 3.1.45 of `accessibility-checker`), the `ibm` tool threw errors when hosted under the Windows operating system. To prevent these errors, it was possible to edit two files in the `accessibility-checker` package as follows:
504
+
505
+ In `node_modules/accessibility-checker/lib/ACEngineManager.js`, remove or comment out these lines starting on line 169:
506
+
507
+ ```javaScript
508
+ if (nodePath.charAt(0) !== '/') {
509
+ nodePath = "../../" + nodePath;
510
+ }
511
+ ```
512
+
513
+ In `node_modules/accessibility-checker/lib/reporters/ACReporterJSON.js`, add these lines starting on line 106, immediately before the line `var resultsFileName = pathLib.join(resultDir, results.label + '.json');`:
514
+
515
+ ```javaScript
516
+ // Replace the colons in the label with hyphen-minuses.
517
+ results.label = results.label.replace(/:/g, '-');
518
+ ```
519
+
520
+ These changes were proposed as pull requests 1333 and 1334 (https://github.com/IBMa/equal-access/pulls).
521
+
522
+ The `ibm` tool is one of two tools (`testaro` is the other) with a `withItems` property. If you set `withItems` to `false`, the result includes the counts of “violations” and “recommendations”, but no information about the rules that gave rise to them.
523
+
512
524
  ###### QualWeb
513
525
 
514
526
  The `qualWeb` tool performs the ACT rules, WCAG Techniques, and best-practices tests of QualWeb. Only failures and warnings are included in the report. The EARL report of QualWeb is not generated, because it is equivalent to the report of the ACT rules tests.
@@ -555,6 +567,14 @@ Tenon recommends giving it a public URL rather than giving it the content of a p
555
567
 
556
568
  If a `tenon` test act is included in a job, environment variables named `TENON_USER` and `TENON_PASSWORD` must exist, with your Tenon username and password, respectively, as their values. These could be obtained from [Tenon](https://tenon.io/documentation/overview) until Tenon was closed to new subscribers in or about October 2022.
557
569
 
570
+ ###### Testaro
571
+
572
+ If you do not specify rules when using the `testaro` tool, Testaro will test for the rules listed in the `evalRules` object of the `tests/testaro.js` file.
573
+
574
+ It has been found that the `motion` test of the `testaro` tool measures motion only when the `webkit` browser type is in use. If you want to use `testaro` with different browser types for different tests, you can include 2 or 3 `testaro` test acts in your job, specifying different browser types and different rules.
575
+
576
+ The `testaro` tool (like the `ibm` tool) has a `withItems` property. If you set it to `false`, the `standardResult` object of `testaro` will contain an `instances` property with summaries that identify issues and instance counts. If you set it to `true`, some of the instances will be itemized.
577
+
558
578
  ###### WAVE
559
579
 
560
580
  If a `wave` test act is included in the job, an environment variable named `WAVE_KEY` must exist, with your WAVE API key as its value. You can get it from [WebAIM](https://wave.webaim.org/api/).
package/actSpecs.js CHANGED
@@ -200,7 +200,7 @@ exports.actSpecs = {
200
200
  false,
201
201
  'array',
202
202
  'areStrings',
203
- 'message specifications (e.g., error:Bad value), if not all'
203
+ 'message specifications (type and start of message, e.g., error:Bad value), if not all'
204
204
  ]
205
205
  }
206
206
  ],
package/call.js CHANGED
@@ -71,6 +71,7 @@ if (fn === 'run' && fnArgs.length === 1) {
71
71
  callRun(fnArgs)
72
72
  .then(() => {
73
73
  console.log('Execution completed');
74
+ process.exit(0);
74
75
  });
75
76
  }
76
77
  else if (fn === 'watch' && fnArgs.length === 3) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testaro",
3
- "version": "14.2.6",
3
+ "version": "14.4.0",
4
4
  "description": "Automation of accessibility testing",
5
5
  "main": "index.js",
6
6
  "scripts": {
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
- const testReport = await require(`./tests/${act.which}`).reporter(...args);
998
- const expectations = act.expect;
999
- // If the test has expectations:
1000
- if (expectations) {
1001
- // Initialize whether they were fulfilled.
1002
- testReport.result.expectations = [];
1003
- let failureCount = 0;
1004
- // For each expectation:
1005
- expectations.forEach(spec => {
1006
- const truth = isTrue(testReport, spec);
1007
- testReport.result.expectations.push({
1008
- property: spec[0],
1009
- relation: spec[1],
1010
- criterion: spec[2],
1011
- actual: truth[0],
1012
- passed: truth[1]
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
- if (! truth[1]) {
1015
- failureCount++;
1016
- }
1017
- });
1018
- testReport.result.failureCount = failureCount;
1024
+ testReport.result.failureCount = failureCount;
1025
+ }
1026
+ testReport.result.success = true;
1019
1027
  }
1020
- testReport.result.success = true;
1021
- report.jobData.testTimes.push([act.which, Math.round((Date.now() - startTime) / 1000)]);
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(`${tagName ? tagName + ': ' : ''}${code || ''}`)
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(element.htmlCode)
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 = (testName, result, standardResult) => {
232
+ const convert = (toolName, result, standardResult) => {
171
233
  // alfa
172
- if (testName === 'alfa' && result.totals) {
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(item.target.codeLines.join(' '))
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
- testName === 'axe'
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 (testName === 'continuum' && Array.isArray(result) && result.length) {
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: 0,
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 (testName === 'htmlcs' && result) {
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 (testName === 'ibm' && result.totals) {
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 (testName === 'nuVal' && (result.pageContent || result.rawPage)) {
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
- testName === 'qualWeb'
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 (testName === 'tenon' && result.data && result.data.resultSet) {
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 (testName === 'testaro') {
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
- testName === 'wave'
452
+ toolName === 'wave'
336
453
  && result.categories
337
454
  && (
338
455
  result.categories.error
@@ -3,14 +3,17 @@
3
3
  This test reports a page that is entirely or mainly hidden.
4
4
  */
5
5
  exports.reporter = async page => {
6
+ // Gets the hiddennesses of the document, body, and main region.
6
7
  const data = await page.evaluate(() => {
8
+ // Identify the styles of the document, its body, and its main region.
7
9
  const {body} = document;
8
- const main = body && body.querySelector('main');
10
+ const main = body && body.querySelector('main, [role=main]');
9
11
  const styles = {
10
12
  doc: window.getComputedStyle(document.documentElement),
11
13
  body: body && window.getComputedStyle(body),
12
14
  main: main && window.getComputedStyle(main)
13
15
  };
16
+ // Get the hiddennesses of the regions.
14
17
  const data = {
15
18
  hidden: {
16
19
  document: document.documentElement.hidden,
@@ -36,8 +39,19 @@ exports.reporter = async page => {
36
39
  document: document.documentElement.ariaHidden === 'true',
37
40
  body: body ? body.ariaHidden === 'true' : false,
38
41
  main: main ? main.ariaHidden === 'true' : false
42
+ },
43
+ tagName: {
44
+ document: 'HTML',
45
+ body: 'BODY',
46
+ main: main ? main.tagName : ''
47
+ },
48
+ id: {
49
+ document: document.id,
50
+ body: body.id,
51
+ main: main ? main.id : ''
39
52
  }
40
53
  };
54
+ // Identify whether each region is really hidden.
41
55
  ['document', 'body', 'main'].forEach(element => {
42
56
  if (data.hidden[element] && ! ['block', 'flex'].includes(data.display[element])) {
43
57
  data.reallyHidden[element] = true;
@@ -45,10 +59,11 @@ exports.reporter = async page => {
45
59
  });
46
60
  return data;
47
61
  });
62
+ // For each combination of region and hiddenness:
48
63
  const standardInstances = [];
49
64
  const reportables = {
50
- hidden: [0, 'hidden'],
51
- reallyHidden: [1, 'effectively hidden'],
65
+ hidden: [1, 'hidden'],
66
+ reallyHidden: [2, 'effectively hidden'],
52
67
  visHidden: [0, 'visually hidden'],
53
68
  ariaHidden: [1, 'hidden by ARIA'],
54
69
  document: [1, 'Document', 'document.documentElement'],
@@ -57,11 +72,15 @@ exports.reporter = async page => {
57
72
  };
58
73
  ['document', 'body', 'main'].forEach(region => {
59
74
  ['hidden', 'reallyHidden', 'visHidden', 'ariaHidden'].forEach(hider => {
75
+ // If the region has that hiddenness:
60
76
  if (data[hider][region]) {
77
+ // Add a standard instance for that combination.
61
78
  standardInstances.push({
62
79
  issueID: `allHidden-${hider}-${region}`,
63
80
  what: `${reportables[region][1]} ${reportables[hider][1]}`,
64
81
  ordinalSeverity: reportables[region][0] + reportables[hider][0] || 0,
82
+ tagName: region.tagName,
83
+ id: region.id,
65
84
  location: {
66
85
  doc: 'dom',
67
86
  type: 'selector',
@@ -72,6 +91,7 @@ exports.reporter = async page => {
72
91
  }
73
92
  });
74
93
  });
94
+ // Get the severity totals.
75
95
  const totals = [0, 0, 0, 0];
76
96
  standardInstances.forEach(instance => {
77
97
  totals[instance.ordinalSeverity]++;
package/testaro/attVal.js CHANGED
@@ -32,6 +32,7 @@ exports.reporter = async (page, withItems, attributeName, areLicit, values) => {
32
32
  });
33
33
  const report = badElements.map(el => ({
34
34
  tagName: el.tagName,
35
+ id: el.id,
35
36
  textStart: textOf(el, 70),
36
37
  attributeValue: el.getAttribute(attributeName)
37
38
  }));
@@ -51,6 +52,8 @@ exports.reporter = async (page, withItems, attributeName, areLicit, values) => {
51
52
  what:
52
53
  `${item.tagName} element has attribute ${attributeName} with illicit value ${item.attributeValue}`,
53
54
  ordinalSeverity: 2,
55
+ tagName: item.tagName,
56
+ id: item.id,
54
57
  location: {
55
58
  doc: '',
56
59
  type: '',
@@ -64,7 +67,10 @@ exports.reporter = async (page, withItems, attributeName, areLicit, values) => {
64
67
  standardInstances.push({
65
68
  issueID: 'attVal',
66
69
  what: 'Elements have attributes with illicit values',
70
+ count: data.total,
67
71
  ordinalSeverity: 2,
72
+ tagName: '',
73
+ id: '',
68
74
  location: {
69
75
  doc: '',
70
76
  type: '',