testaro 14.7.5 → 14.9.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
@@ -6,9 +6,11 @@ Ensemble testing for web accessibility
6
6
 
7
7
  Testaro is a collection of web accessibility testing tools.
8
8
 
9
- The purpose of Testaro is to provide programmatic access to accessibility tests defined by several tools.
9
+ The purposes of Testaro are to:
10
+ - provide programmatic access to accessibility tests defined by several tools
11
+ - facilitate the integration of the reports of the tools into a unified report
10
12
 
11
- Testaro aims to increase the efficiency of multi-tool integration for accessibility testing. The need for multi-tool integration, and its costs, are analyzed in [Accessibility Metatesting: Comparing Nine Testing Tools](https://arxiv.org/abs/2304.07591).
13
+ The need for multi-tool integration, and its costs, are discussed in [Accessibility Metatesting: Comparing Nine Testing Tools](https://arxiv.org/abs/2304.07591).
12
14
 
13
15
  Testaro launches and controls web browsers, performing operations, conducting tests, and recording results.
14
16
 
@@ -52,27 +54,19 @@ Testaro performs tests of these tools:
52
54
 
53
55
  The [BBC Accessibility Standards Checker](https://github.com/bbc/bbc-a11y) is not a formal dependency, but some of the tests in the Testaro tool are adaptations of tests of that tool.
54
56
 
55
- As of this version, the counts of tests of the tools referenced above were:
56
- - Alfa: 103
57
- - Axe-core: 138
58
- - Continuum Community Edition: 267
59
- - Equal Access: 163
60
- - HTML CodeSniffer: 98
61
- - Nu Html Checker: 147
62
- - QualWeb core: 121
63
- - Tenon: 180
64
- - WAVE: 110
65
- - Testaro: 29
66
- - total: 1356
57
+ ## Rules
67
58
 
68
- Of the 29 Testaro tests, 26 are evaluative (they discover accessibility problems), and the other 3 (`elements`, `textNodes`, and `title`) are informative (they report conditions specified by the user).
59
+ Each tool accessed with Testaro defines _rules_ and tests _targets_ for compliance with its rules. The counts of the rules range from about 30, for Testaro itself, to about 270, for Continuum Community Edition. In total, the ten tools define about 1350 rules. Some of the tools are under active development, and their rule counts change over time.
69
60
 
70
- ## Quasi-tests
61
+ ## Job data
71
62
 
72
- Reports produced by Testaro contain data in addition to the results of these tests. Such data can be used like tests. In particular, the data include:
73
- - Latency (how long a time each tool takes to run its tests)
74
- - Test prevention (the failure of tools to run on particular targets)
75
- - Logging (browser messaging, including about document errors, during testing)
63
+ A report produced by Testaro discloses:
64
+ - raw results of tests conducted by tools
65
+ - standardized results of tests conducted by tools
66
+ - process data, including statistics on:
67
+ - latency (how long a time each tool takes to run its tests)
68
+ - test prevention (the failure of tools to run on particular targets)
69
+ - logging (browser messaging, including about document errors, during testing)
76
70
 
77
71
  ## Code organization
78
72
 
@@ -188,30 +182,31 @@ Job properties:
188
182
  #### Introduction
189
183
 
190
184
  While each tool produces a _tool report_ of the results of its tests, Testaro also produces a _job report_, combining all of the tool reports of a job.
191
- - Tools append their reports to their acts in a job. For example, if one act in a job specifies some Continuum tests to be run, Continuum appends its report to that act. In that way, the act now describes not only the Continuum tests that were run, but also the results of those tests.
192
- - Testaro further elaborates a job by reporting comprehensive results there. Testaro can add more facts to each of the tool reports and also adds whole-job facts, in a `jobData` property, to the job. Testaro thereby converts the job to a job report.
185
+ - Tools append their reports to their acts in a job. For example, if one act in a job specifies some Continuum tests to be run, Continuum appends its report to that act. In that way, the act now describes not only the Continuum tests that were run, but also the results of those tests. Testaro does some pruning of tool reports, removing content that is judged unlikely to be useful. You can examine and modify the pruning algorithms in the modules located in the `tests` directory.
186
+ - Testaro further elaborates a job by reporting comprehensive results in a job report. Testaro can add more facts to each of the tool reports and also adds whole-job facts, in a `jobData` property, to the job.
193
187
 
194
188
  #### Formats
195
189
 
196
- ##### Tool formats
190
+ ##### Tool-report formats
197
191
 
198
192
  The tools listed above as dependencies write their tool reports in various formats. They differ in how they organize multiple instances of the same problem, how they classify severity and certainty, how they point to the locations of problems, how they name problems, etc.
199
193
 
200
194
  ##### Standard format
201
195
 
202
- Testaro helps overcome this format diversity by offering to represent the main facts in the report of each tool in a single standardized format.
196
+ Testaro helps overcome this format diversity by offering to represent the main facts in each tool report in a single standardized format.
203
197
 
204
198
  In the conceptual scheme underlying the format standardization of Testaro, each tool has its own set of _rules_, where a rule is an algorithm for evaluating a target and determining whether instances of some kind of problem exist in it. With standardization, Testaro reports, in a uniform way, the outcomes from the application of rules by tools to a target.
205
199
 
206
- If the `STANDARD` environment variable has the value `also` (which it has by default) or `only`, Testaro converts some data in each tool report to a standard format. That permits you to ignore the format idiosyncrasies of the tools. If `STANDARD` has the value `also`, the job report includes both formats. If the value is `only`, the job report includes only the standard format. If the value is `no`, the job report includes only the original format of each tool.
200
+ If the `STANDARD` environment variable has the value `also` (which it has by default) or `only`, Testaro converts some data in each tool report to a standard format. That permits you to ignore the format idiosyncrasies of the tools. If `STANDARD` has the value `also`, the job report includes both formats. If the value is `only`, the job report includes only the standard format. If the value is `no`, the job report includes only the original format of each tool report.
207
201
 
208
- The standard format of each tool report has two properties:
202
+ The standard format of each tool report has these properties:
203
+ - `prevented`: `true` if the tool failed to run on the page, or otherwise omitted.
209
204
  - `totals`: an array of 4 integers, representing the counts of problem 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.
210
205
  - `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:
211
206
  - `ruleID`: a code identifying a rule
212
207
  - `what`: a description of the rule
213
208
  - `count` (optional): the count of instances if this instance represents multiple instances
214
- - `ordinalSeverity`: how the tool ranks the severity of the instance, on a 4-point ordinal scale
209
+ - `ordinalSeverity`: how the tool ranks the severity of the instance, on a 4-point ordinal scale from 0 to 3
215
210
  - `tagName`: upper-case tagName of the affected element
216
211
  - `id`: value of the `id` property of that element
217
212
  - `location`: an object with three properties:
@@ -229,7 +224,7 @@ standardResult: {
229
224
  {
230
225
  ruleID: 'rule01',
231
226
  what: 'Button type invalid',
232
- ordinalSeverity: 0,
227
+ ordinalSeverity: 2,
233
228
  tagName: 'BUTTON'
234
229
  id: '',
235
230
  location: {
@@ -272,7 +267,13 @@ standardResult: {
272
267
 
273
268
  If a tool has the option to be used without itemization and is being so used, the `instances` array may be empty.
274
269
 
275
- This standard format is not opinionated about issue classifications. A rule ID identifies something deemed to be an issue by a tool. Useful reporting from multi-tool testing still requires the classification of tool **rules** into **issues**. If tool `A` has `alt-incomplete` as a rule ID and tool `B` has `image_alt_stub` as a rule ID, Testaro does not decide whether those are really the same issue or different issues. That decision belongs to you. The standardization of tool reports by Testaro eliminates some of the drudgery in issue classification, but not any of the judgment required for issue classification.
270
+ This standard format reflects some judgments. For example:
271
+ - The `ordinalSeverity` property of an instance may have required interpretation. Tools may report severity, certainty, both, or neither; they may classify severity or certainty ordinally or metrically; and, if they classify ordinally, their scales may have more or fewer than 4 ranks. Testaro coerces each tool’s severity and/or certainty classification into a 4-rank ordinal classification. This classification is deemed to express the most common pattern among the tools.
272
+ - The `tagName` property of an instance may not always be obvious, because in some cases the rule being tested for requires a relationship among more than one element (e.g., “An X element may not have a Y element as its parent”).
273
+
274
+ You are not dependent on the judgments incorporated into the standard format, because Testaro can give you the original reports from the tools.
275
+
276
+ The standard format does not express opinions issue classifications. A rule ID identifies something deemed to be an issue by a tool. Useful reporting from multi-tool testing still requires the classification of tool **rules** into **issues**. If tool `A` has `alt-incomplete` as a rule ID and tool `B` has `image_alt_stub` as a rule ID, Testaro does not decide whether those are really the same issue or different issues. That decision belongs to you. The standardization of tool reports by Testaro eliminates some of the drudgery in issue classification, but not any of the judgment required for issue classification.
276
277
 
277
278
  ### Acts
278
279
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testaro",
3
- "version": "14.7.5",
3
+ "version": "14.9.0",
4
4
  "description": "Automation of accessibility testing",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/standardize.js CHANGED
@@ -116,7 +116,7 @@ const doNuVal = (result, standardResult, docType) => {
116
116
  identifiers[0] = tagNameLCArray[1].toUpperCase();
117
117
  }
118
118
  }
119
- // Include the message twice, because in scoring it is likely to be replaced by a pattern.
119
+ // Include the message twice. A scoring procedure may replace the ruleID with a pattern.
120
120
  const instance = {
121
121
  ruleID: item.message,
122
122
  what: item.message,
@@ -225,26 +225,29 @@ const doWAVE = (result, standardResult, categoryName) => {
225
225
  };
226
226
  // Converts a result.
227
227
  const convert = (toolName, result, standardResult) => {
228
+ // Prevention.
229
+ if (result.prevented) {
230
+ standardResult.prevented = true;
231
+ }
228
232
  // alfa
229
- if (toolName === 'alfa' && result.totals) {
233
+ else if (toolName === 'alfa' && result.totals) {
230
234
  standardResult.totals = [result.totals.warnings, 0, 0, result.totals.failures];
231
235
  result.items.forEach(item => {
232
236
  const {codeLines} = item.target;
233
237
  const code = Array.isArray(codeLines) ? codeLines.join(' ') : '';
234
238
  const identifiers = getIdentifiers(code);
235
- let tagName = item.target && item.target.tagName || '';
236
- if (! tagName) {
237
- const tagNameArray = item.target.path.match(/\/([a-z]+)\[\d+\]\/text\(\)\[\d+\]$/);
238
- if (tagNameArray && tagNameArray.length === 2) {
239
- tagName = tagNameArray[1];
240
- }
239
+ const tagNameArray = item.target
240
+ && item.target.path
241
+ && item.target.path.match(/^.*\/([a-z]+)\[\d+\]/);
242
+ if (tagNameArray && tagNameArray.length === 2) {
243
+ identifiers[0] = tagNameArray[1].toUpperCase();
241
244
  }
242
245
  const {rule, target} = item;
243
246
  const instance = {
244
247
  ruleID: rule.ruleID,
245
248
  what: rule.ruleSummary,
246
249
  ordinalSeverity: ['cantTell', '', '', 'failed'].indexOf(item.verdict),
247
- tagName: tagName.toUpperCase() || identifiers[0],
250
+ tagName: identifiers[0],
248
251
  id: identifiers[1],
249
252
  location: {
250
253
  doc: 'dom',
@@ -453,6 +456,10 @@ const convert = (toolName, result, standardResult) => {
453
456
  doWAVE(result, standardResult, categoryName);
454
457
  });
455
458
  }
459
+ // Any tool with no reported rule violations:
460
+ else {
461
+ standardResult.totals = [0, 0, 0, 0];
462
+ }
456
463
  };
457
464
  // Converts the results.
458
465
  exports.standardize = act => {
@@ -76,7 +76,7 @@ exports.reporter = async page => {
76
76
  if (data[hider][region]) {
77
77
  // Add a standard instance for that combination.
78
78
  standardInstances.push({
79
- issueID: `allHidden-${hider}-${region}`,
79
+ ruleID: 'allHidden',
80
80
  what: `${reportables[region][1]} ${reportables[hider][1]}`,
81
81
  ordinalSeverity: reportables[region][0] + reportables[hider][0] || 0,
82
82
  tagName: region.tagName,
package/testaro/attVal.js CHANGED
@@ -48,7 +48,7 @@ exports.reporter = async (page, withItems, attributeName, areLicit, values) => {
48
48
  data.items = badAttributeData;
49
49
  badAttributeData.forEach(item => {
50
50
  standardInstances.push({
51
- issueID: `attVal-${item.tagName}-${attributeName}`,
51
+ ruleID: 'attVal',
52
52
  what:
53
53
  `${item.tagName} element has attribute ${attributeName} with illicit value ${item.attributeValue}`,
54
54
  ordinalSeverity: 2,
@@ -65,7 +65,7 @@ exports.reporter = async (page, withItems, attributeName, areLicit, values) => {
65
65
  }
66
66
  else if (data.total) {
67
67
  standardInstances.push({
68
- issueID: 'attVal',
68
+ ruleID: 'attVal',
69
69
  what: 'Elements have attributes with illicit values',
70
70
  count: data.total,
71
71
  ordinalSeverity: 2,
@@ -74,7 +74,7 @@ exports.reporter = async (page, withItems) => {
74
74
  if (data.items) {
75
75
  data.items.forEach(item => {
76
76
  standardInstances.push({
77
- issueID: `autocomplete-${item[0]}`,
77
+ ruleID: 'autocomplete',
78
78
  what: `Input is missing the required autocomplete attribute with value ${item[0]}`,
79
79
  ordinalSeverity: 2,
80
80
  tagName: 'INPUT',
@@ -90,7 +90,7 @@ exports.reporter = async (page, withItems) => {
90
90
  }
91
91
  else if (data.total) {
92
92
  standardInstances.push({
93
- issueID: 'autocomplete',
93
+ ruleID: 'autocomplete',
94
94
  what: 'Inputs are missing required autocomplete attributes',
95
95
  ordinalSeverity: 2,
96
96
  tagName: '',
package/testaro/bulk.js CHANGED
@@ -23,7 +23,7 @@ exports.reporter = async page => {
23
23
  data,
24
24
  totals: [count, 0, 0, 0],
25
25
  standardInstances: data.visibleElements < 200 ? [] : [{
26
- issueID: 'bulk',
26
+ ruleID: 'bulk',
27
27
  what: 'Page contains a large number of visible elements',
28
28
  count,
29
29
  ordinalSeverity: 0,
@@ -14,7 +14,7 @@ exports.reporter = async page => {
14
14
  data: {docHasType},
15
15
  totals: [0, 0, 0, docHasType ? 0 : 1],
16
16
  standardInstances: docHasType ? [] : [{
17
- issueID: 'docType',
17
+ ruleID: 'docType',
18
18
  what: 'Document has no standard HTML doctype preamble',
19
19
  ordinalSeverity: 3,
20
20
  tagName: 'HTML',
package/testaro/dupAtt.js CHANGED
@@ -84,7 +84,7 @@ exports.reporter = async (page, withItems) => {
84
84
  if (data.items) {
85
85
  data.items.forEach(item => {
86
86
  standardInstances.push({
87
- issueID: 'dupAtt',
87
+ ruleID: 'dupAtt',
88
88
  what: `Element ${item.tagName} has 2 attributes with the same name`,
89
89
  ordinalSeverity: 2,
90
90
  tagName: item.tagName,
@@ -100,7 +100,7 @@ exports.reporter = async (page, withItems) => {
100
100
  }
101
101
  else if (data.total) {
102
102
  standardInstances.push({
103
- issueID: 'dupAtt',
103
+ ruleID: 'dupAtt',
104
104
  what: 'In some elements 2 attributes have the same name',
105
105
  ordinalSeverity: 2,
106
106
  location: {
package/testaro/embAc.js CHANGED
@@ -45,7 +45,7 @@ exports.reporter = async (page, withItems) => await page.$$eval(
45
45
  data.items = items;
46
46
  items.forEach(item => {
47
47
  standardInstances.push({
48
- issueID: `embAc-${item.embeddedElement}`,
48
+ ruleID: 'embAc',
49
49
  what: `${item.embeddedElement} element is embedded in a link or button`,
50
50
  ordinalSeverity: 2,
51
51
  tagName: item.embeddedElement,
@@ -61,7 +61,7 @@ exports.reporter = async (page, withItems) => await page.$$eval(
61
61
  }
62
62
  else if (total) {
63
63
  standardInstances.push({
64
- issueID: 'embAc',
64
+ ruleID: 'embAc',
65
65
  what: 'Interactive elements are contained by links or buttons',
66
66
  count: total,
67
67
  ordinalSeverity: 2,
package/testaro/filter.js CHANGED
@@ -53,7 +53,7 @@ exports.reporter = async (page, withItems) => {
53
53
  if (data.items) {
54
54
  data.items.forEach(item => {
55
55
  standardInstances.push({
56
- issueID: 'filterStyle',
56
+ ruleID: 'filterStyle',
57
57
  what: `${item.tagName} element has a filter style that impacts ${item.impact} elements`,
58
58
  ordinalSeverity: 2,
59
59
  tagName: item.toUpperCase(),
@@ -69,7 +69,7 @@ exports.reporter = async (page, withItems) => {
69
69
  }
70
70
  else if (data.totals.styledElements) {
71
71
  standardInstances.push({
72
- issueID: 'filterStyle',
72
+ ruleID: 'filterStyle',
73
73
  what: 'Elements have filter styles impacting other elements',
74
74
  ordinalSeverity: 2,
75
75
  tagName: '',
package/testaro/focAll.js CHANGED
@@ -65,7 +65,7 @@ exports.reporter = async page => {
65
65
  data,
66
66
  totals: [0, 0, Math.abs(data.discrepancy), 0],
67
67
  standardInstances: data.discrepancy ? [{
68
- issueID: 'focAll',
68
+ ruleID: 'focAll',
69
69
  what: 'Some focusable elements are not Tab-focusable or vice versa',
70
70
  count: Math.abs(data.discrepancy),
71
71
  ordinalSeverity: 2,
package/testaro/focInd.js CHANGED
@@ -174,7 +174,7 @@ exports.reporter = async (page, withItems, revealAll = false, allowedDelay = 250
174
174
  data.items[issueName].forEach(item => {
175
175
  const qualifier = issueName === 'nonoutline' ? 'a non-outline' : 'no';
176
176
  standardInstances.push({
177
- issueID: `focInd-${issueName}`,
177
+ issueID: 'focInd',
178
178
  what: `${item.tagName} element has ${qualifier} focus indicator`,
179
179
  ordinalSeverity: issueName === 'nonoutline' ? 2 : 3,
180
180
  tagName: item.tagName,
@@ -192,7 +192,7 @@ exports.reporter = async (page, withItems, revealAll = false, allowedDelay = 250
192
192
  else {
193
193
  if (types.missing.total) {
194
194
  standardInstances.push({
195
- issueID: 'focInd-missing',
195
+ issueID: 'focInd',
196
196
  what: 'Elements have missing focus indicators',
197
197
  count: types.missing.total,
198
198
  ordinalSeverity: 3,
@@ -208,7 +208,7 @@ exports.reporter = async (page, withItems, revealAll = false, allowedDelay = 250
208
208
  }
209
209
  if (types.nonoutline.total) {
210
210
  standardInstances.push({
211
- issueID: 'focInd-nonoutline',
211
+ issueID: 'focInd',
212
212
  what: 'Elements have non-outline focus indicators',
213
213
  count: types.nonoutline.total,
214
214
  ordinalSeverity: 2,
package/testaro/focOp.js CHANGED
@@ -150,17 +150,14 @@ exports.reporter = async (page, withItems) => {
150
150
  const standardInstances = [];
151
151
  if (data.items && data.items.onlyFocusable && data.items.onlyOperable) {
152
152
  ['onlyFocusable', 'onlyOperable'].forEach(issue => {
153
- const issueID = issue === 'onlyFocusable'
154
- ? 'focOp-focusable-inoperable'
155
- : 'focOp-operable-nonfocusable';
156
153
  const gripe = issue === 'onlyFocusable'
157
154
  ? 'is focusable but not operable'
158
155
  : 'is operable but not focusable';
159
156
  const ordinalSeverity = issue === 'onlyFocusable' ? 2 : 3;
160
157
  data.items[issue].forEach(item => {
161
158
  standardInstances.push({
162
- issueID,
163
- what: `${item.tagName} element ${gripe}`,
159
+ ruleID: 'focOp',
160
+ complaint: `${item.tagName} element ${gripe}`,
164
161
  ordinalSeverity,
165
162
  tagName: item.tagName,
166
163
  id: item.id,
@@ -177,8 +174,8 @@ exports.reporter = async (page, withItems) => {
177
174
  else {
178
175
  if (totals[2]) {
179
176
  standardInstances.push({
180
- issueID: 'focOp-onlyFocusable',
181
- what: 'Focusable elements are inoperable',
177
+ ruleID: 'focOp',
178
+ complaint: 'Focusable elements are inoperable',
182
179
  count: totals[2],
183
180
  ordinalSeverity: 2,
184
181
  tagName: '',
@@ -193,8 +190,8 @@ exports.reporter = async (page, withItems) => {
193
190
  }
194
191
  if (totals[3]) {
195
192
  standardInstances.push({
196
- issueID: 'focOp-onlyOperable',
197
- what: 'Operable elements are nonfocusable',
193
+ ruleID: 'focOp',
194
+ complaint: 'Operable elements are nonfocusable',
198
195
  count: totals[3],
199
196
  ordinalSeverity: 3,
200
197
  tagName: '',
package/testaro/focVis.js CHANGED
@@ -33,7 +33,7 @@ exports.reporter = async (page, withItems) => {
33
33
  if (data.items) {
34
34
  data.items.forEach(item => {
35
35
  standardInstances.push({
36
- issueID: 'focVis',
36
+ ruleID: 'focVis',
37
37
  what: 'Visible link is above or to the left of the display',
38
38
  ordinalSeverity: 2,
39
39
  tagName: 'A',
@@ -49,7 +49,7 @@ exports.reporter = async (page, withItems) => {
49
49
  }
50
50
  else if (data.total) {
51
51
  standardInstances.push({
52
- issueID: 'focVis',
52
+ ruleID: 'focVis',
53
53
  what: 'Visible links are above or to the left of the display',
54
54
  count: data.total,
55
55
  ordinalSeverity: 2,
package/testaro/hover.js CHANGED
@@ -406,7 +406,7 @@ exports.reporter = async (page, withItems, sampleSize = -1) => {
406
406
  Object.keys(data.items).forEach(issue => {
407
407
  data.items[issue].forEach(item => {
408
408
  standardInstances.push({
409
- issueID: `hover-${issue}`,
409
+ ruleID: `hover-${issue}`,
410
410
  what: what[issue],
411
411
  count: data.totals[issue],
412
412
  ordinalSeverity: severity[issue],
@@ -424,7 +424,7 @@ exports.reporter = async (page, withItems, sampleSize = -1) => {
424
424
  }
425
425
  else if (totals.some(total => total)) {
426
426
  standardInstances.push({
427
- issueID: 'hover',
427
+ ruleID: 'hover',
428
428
  what: 'Hovering has unexpected impacts',
429
429
  count: Object.values(data.totals).reduce((total, current) => total + current),
430
430
  ordinalSeverity: totals.reduce((max, current, index) => current ? index : max, 0),
@@ -164,7 +164,7 @@ exports.reporter = async (page, withItems) => {
164
164
  excerptTail = item.content || '';
165
165
  }
166
166
  standardInstances.push({
167
- issueID: `labClash-${issue}`,
167
+ ruleID: 'labClash',
168
168
  what: `Element ${item.tagName} ${diagnosis}`,
169
169
  ordinalSeverity: issue === 'mislabeled' ? 2 : 3,
170
170
  tagName: item.tagName,
@@ -182,7 +182,7 @@ exports.reporter = async (page, withItems) => {
182
182
  else {
183
183
  if (data.totals.unlabeled) {
184
184
  standardInstances.push({
185
- issueID: 'labClash-unlabeled',
185
+ ruleID: 'labClash',
186
186
  what: 'Element labels are missing',
187
187
  count: data.totals.unlabeled,
188
188
  ordinalSeverity: 3,
@@ -198,7 +198,7 @@ exports.reporter = async (page, withItems) => {
198
198
  }
199
199
  if (data.totals.mislabeled) {
200
200
  standardInstances.push({
201
- issueID: 'labClash-mislabeled',
201
+ ruleID: 'labClash',
202
202
  what: 'Element labels are conflicting',
203
203
  count: data.totals.mislabeled,
204
204
  ordinalSeverity: 2,
package/testaro/linkTo.js CHANGED
@@ -27,7 +27,7 @@ exports.reporter = async (page, withItems) => {
27
27
  data.items = badLinkData;
28
28
  data.items.forEach(item => {
29
29
  standardInstances.push({
30
- issueID: 'linkTo',
30
+ ruleID: 'linkTo',
31
31
  what: 'Element a has no href attribute',
32
32
  ordinalSeverity: 2,
33
33
  tagName: 'A',
@@ -43,7 +43,7 @@ exports.reporter = async (page, withItems) => {
43
43
  }
44
44
  else if (data.total) {
45
45
  standardInstances.push({
46
- issueID: 'linkTo',
46
+ ruleID: 'linkTo',
47
47
  what: 'Links are missing href attributes',
48
48
  count: data.total,
49
49
  ordinalSeverity: 2,
package/testaro/linkUl.js CHANGED
@@ -79,7 +79,7 @@ exports.reporter = async (page, withItems) => {
79
79
  if (data.items && data.items.notUnderlined) {
80
80
  data.items.notUnderlined.forEach(item => {
81
81
  standardInstances.push({
82
- issueID: 'linkUl',
82
+ ruleID: 'linkUl',
83
83
  what: 'Link is inline but has no underline',
84
84
  ordinalSeverity: 1,
85
85
  tagName: 'A',
@@ -95,7 +95,7 @@ exports.reporter = async (page, withItems) => {
95
95
  }
96
96
  else if (adjacent.total - adjacent.underlined > 0) {
97
97
  standardInstances.push({
98
- issueID: 'linkUl',
98
+ ruleID: 'linkUl',
99
99
  what: 'Inline links are missing underlines',
100
100
  count: adjacent.total - adjacent.underlined,
101
101
  ordinalSeverity: 1,
@@ -275,7 +275,7 @@ exports.reporter = async (page, withItems) => {
275
275
  if (data.menuItems && data.menuItems.incorrect) {
276
276
  data.menuItems.incorrect.forEach(item => {
277
277
  standardInstances.push({
278
- issueID: 'menuNav',
278
+ ruleID: 'menuNav',
279
279
  what: `Menu item responds nonstandardly to ${item.navigationErrors.join(', ')}`,
280
280
  count: item.navigationErrors.length,
281
281
  ordinalSeverity: 1,
@@ -292,7 +292,7 @@ exports.reporter = async (page, withItems) => {
292
292
  }
293
293
  else if (data.totals.menuItems.incorrect) {
294
294
  standardInstances.push({
295
- issueID: 'menuNav',
295
+ ruleID: 'menuNav',
296
296
  what: 'Menus and menu items have nonstandard navigation',
297
297
  count: data.totals.navigations.all.incorrect,
298
298
  ordinalSeverity: 1,
@@ -50,7 +50,7 @@ exports.reporter = async (page, withItems) => {
50
50
  data.items = miniTexts;
51
51
  miniTexts.forEach(text => {
52
52
  standardInstances.push({
53
- issueID: 'miniText',
53
+ ruleID: 'miniText',
54
54
  what: 'Text font is smaller than 11 pixels',
55
55
  ordinalSeverity: 2,
56
56
  tagName: text.tagName,
@@ -66,7 +66,7 @@ exports.reporter = async (page, withItems) => {
66
66
  }
67
67
  else if (data.total) {
68
68
  standardInstances.push({
69
- issueID: 'miniText',
69
+ ruleID: 'miniText',
70
70
  what: 'Texts have fonts smaller than 11 pixels',
71
71
  count: data.total,
72
72
  ordinalSeverity: 2,
package/testaro/motion.js CHANGED
@@ -124,7 +124,7 @@ exports.reporter = async (page, withItems, delay = 2500, interval = 2500, count
124
124
  0
125
125
  ],
126
126
  standardInstances: count ? [{
127
- issueID: 'motion',
127
+ ruleID: 'motion',
128
128
  what: 'Content moves or changes without user request',
129
129
  count,
130
130
  ordinalSeverity: 2,
@@ -68,7 +68,7 @@ exports.reporter = async (page, withItems) => {
68
68
  data.items = badTableTexts;
69
69
  data.items.forEach(item => {
70
70
  standardInstances.push({
71
- issueID: 'nonTable',
71
+ ruleID: 'nonTable',
72
72
  what: 'Table is misused to arrange content',
73
73
  ordinalSeverity: 0,
74
74
  tagName: 'TABLE',
@@ -84,7 +84,7 @@ exports.reporter = async (page, withItems) => {
84
84
  }
85
85
  else if (data.total) {
86
86
  standardInstances.push({
87
- issueID: 'nonTable',
87
+ ruleID: 'nonTable',
88
88
  what: 'Tables are misused to arrange content',
89
89
  count: data.total,
90
90
  ordinalSeverity: 0,
@@ -88,7 +88,7 @@ exports.reporter = async (page, withItems) => {
88
88
  }));
89
89
  items.notInSet.forEach(item => {
90
90
  standardInstances.push({
91
- issueID: 'radioSet',
91
+ ruleID: 'radioSet',
92
92
  what: 'Radio button and its peers are not in a fieldset with a legend',
93
93
  ordinalSeverity: 2,
94
94
  tagName: 'INPUT',
@@ -104,7 +104,7 @@ exports.reporter = async (page, withItems) => {
104
104
  }
105
105
  else if (loneRadios > 0) {
106
106
  standardInstances.push({
107
- issueID: 'radioSet',
107
+ ruleID: 'radioSet',
108
108
  what: 'Radio buttons are not validly grouped in fieldsets with legends',
109
109
  count: loneRadios,
110
110
  ordinalSeverity: 2,
package/testaro/role.js CHANGED
@@ -486,7 +486,7 @@ exports.reporter = async page => await page.$eval('body', body => {
486
486
  const redCount = pairTotals.redundant;
487
487
  if (redCount) {
488
488
  standardInstances.push({
489
- issueID: 'role-redundant',
489
+ ruleID: 'role',
490
490
  what: `${tagName} elements have redundant explicit role ${role} (count: ${redCount})`,
491
491
  count: redCount,
492
492
  ordinalSeverity: 1,
@@ -503,7 +503,7 @@ exports.reporter = async page => await page.$eval('body', body => {
503
503
  const badCount = pairTotals.bad;
504
504
  if (badCount) {
505
505
  standardInstances.push({
506
- issueID: 'role-bad',
506
+ ruleID: 'role',
507
507
  what:
508
508
  `${tagName} elements have invalid or native-replaceable explicit role ${role} (count: ${badCount})`,
509
509
  count: badCount,
@@ -174,7 +174,7 @@ exports.reporter = async (page, withItems) => {
174
174
  const extraCount = elementSubtotals.length - 1;
175
175
  totals[severity] += extraCount;
176
176
  standardInstances.push({
177
- issueID: 'styleDiff',
177
+ ruleID: 'styleDiff',
178
178
  what: `${currentData[1]} have ${elementSubtotals.length} different styles`,
179
179
  count: extraCount,
180
180
  ordinalSeverity: severity,
package/testaro/tabNav.js CHANGED
@@ -339,7 +339,7 @@ exports.reporter = async (page, withItems) => {
339
339
  if (data.tabElements && data.tabElements.incorrect) {
340
340
  data.tabElements.incorrect.forEach(item => {
341
341
  standardInstances.push({
342
- issueID: 'tabNav',
342
+ ruleID: 'tabNav',
343
343
  what:
344
344
  `${item.tagName} element responds nonstandardly to ${item.navigationErrors.join(', ')}`,
345
345
  count: item.navigationErrors.length,
@@ -357,7 +357,7 @@ exports.reporter = async (page, withItems) => {
357
357
  }
358
358
  else if (data.totals.navigations.all.incorrect) {
359
359
  standardInstances.push({
360
- issueID: 'tabNav',
360
+ ruleID: 'tabNav',
361
361
  what: 'Tablists have nonstandard navigation',
362
362
  count: data.totals.navigations.all.incorrect,
363
363
  ordinalSeverity: 1,
@@ -30,7 +30,7 @@ exports.reporter = async (page, withItems) => {
30
30
  data.items = badTitleElements;
31
31
  badTitleElements.forEach(element => {
32
32
  standardInstances.push({
33
- issueID: 'titledEl',
33
+ ruleID: 'titledEl',
34
34
  what: `${element.tagName} element has a title attribute`,
35
35
  ordinalSeverity: 2,
36
36
  tagName: element.tagName,
@@ -46,7 +46,7 @@ exports.reporter = async (page, withItems) => {
46
46
  }
47
47
  else if (data.total) {
48
48
  standardInstances.push({
49
- issueID: 'titledEl',
49
+ ruleID: 'titledEl',
50
50
  what: 'Ineligible elements have title attributes',
51
51
  count: data.total,
52
52
  ordinalSeverity: 2,
package/testaro/zIndex.js CHANGED
@@ -52,7 +52,7 @@ exports.reporter = async (page, withItems) => {
52
52
  if (data.items) {
53
53
  data.items.forEach(item => {
54
54
  standardInstances.push({
55
- issueID: 'zIndex',
55
+ ruleID: 'zIndex',
56
56
  what: `${item.tagName} element has a non-default Z index`,
57
57
  ordinalSeverity: 0,
58
58
  tagName: item.tagName,
@@ -68,7 +68,7 @@ exports.reporter = async (page, withItems) => {
68
68
  }
69
69
  else if (data.totals.total) {
70
70
  standardInstances.push({
71
- issueID: 'zIndex',
71
+ ruleID: 'zIndex',
72
72
  what: 'Elements have non-default Z indexes',
73
73
  count: data.totals.total,
74
74
  ordinalSeverity: 0,
@@ -28,9 +28,9 @@ exports.reporter = async (page, options) => {
28
28
  continuum.setUp(null, null, window);
29
29
  // If a set of rules to be employed was specified:
30
30
  let bigResultPromise;
31
- if (rules && Array.isArray(rules) && rules.length && rules.every(rule => typeof rule === 'number')) {
31
+ if (rules && Array.isArray(rules) && rules.length && rules.every(rule => typeof rule === 'string')) {
32
32
  // Run the tests for them.
33
- bigResultPromise = continuum.runTests(rules);
33
+ bigResultPromise = continuum.runTests(rules.map(rule => Number.parseInt(rule)));
34
34
  }
35
35
  // Otherwise, i.e. if no rules were specified:
36
36
  else {
package/tests/testaro.js CHANGED
@@ -26,7 +26,8 @@ const evalRules = {
26
26
  motion: 'motion without user request',
27
27
  nonTable: 'table elements used for layout',
28
28
  radioSet: 'radio buttons not grouped into standard field sets',
29
- role: 'invalid, inadvised, and redundant explicit roles',
29
+ roleBad: 'invalid and native-replacing explicit roles',
30
+ roleRedundant: 'redundant explicit roles',
30
31
  styleDiff: 'style inconsistencies',
31
32
  tabNav: 'nonstandard keyboard navigation between elements with the tab role',
32
33
  titledEl: 'title attributes on inappropriate elements',