testaro 69.7.1 → 70.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testaro",
3
- "version": "69.7.1",
3
+ "version": "70.0.0",
4
4
  "description": "Run 1000 web accessibility tests from 11 tools and get a standardized report",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/procs/catalog.js CHANGED
@@ -86,7 +86,7 @@ exports.getCatalog = async report => {
86
86
  ? ['x', 'y', 'width', 'height'].map(key => Math.round(domRect[key])).join(':')
87
87
  : '';
88
88
  // Get its path ID.
89
- const pathID = window.getXPath(element);
89
+ const pathID = window.getXPath(element) ?? '/html';
90
90
  // If it is a heading that nullifies an existing current heading index:
91
91
  if (
92
92
  headingIndex
@@ -112,12 +112,9 @@ exports.getCatalog = async report => {
112
112
  // Assign its index to the current heading index.
113
113
  headingIndex = index;
114
114
  }
115
- // If the element has a path ID:
116
- if (pathID) {
117
- // Add it to the temporary path ID directory in the catalog.
118
- cat.pathID ??= {};
119
- cat.pathID[pathID] = index;
120
- }
115
+ // Add the path ID to the temporary path ID property of the catalog.
116
+ cat.pathID ??= {};
117
+ cat.pathID[pathID] = index;
121
118
  }
122
119
  // For each text in the catalog:
123
120
  Object.keys(texts).forEach(text => {
@@ -160,16 +157,17 @@ exports.getCatalog = async report => {
160
157
  };
161
158
  // Prunes a catalog.
162
159
  exports.pruneCatalog = report => {
160
+ console.log('Pruning catalog');
163
161
  const {acts, catalog} = report;
164
162
  const citedElementIndexes = new Set();
165
163
  // For each act in the report:
166
164
  acts.forEach(act => {
167
165
  // If it is a test with a standard result:
168
166
  if (act.type === 'test' && act.result?.standardResult) {
169
- const {instances} = act.result.standardResult;
167
+ const {instances} = act.result?.standardResult ?? [];
170
168
  // For each instance of the standard result:
171
169
  instances.forEach(instance => {
172
- const {catalogIndex} = instance;
170
+ const catalogIndex = instance?.catalogIndex;
173
171
  // If the instance has a catalog index:
174
172
  if (catalogIndex) {
175
173
  // Ensure the index is classified as cited.
@@ -184,7 +182,7 @@ exports.pruneCatalog = report => {
184
182
  });
185
183
  }
186
184
  });
187
- // Delete the temporary path ID directory.
185
+ // Delete the temporary path ID property.
188
186
  delete catalog.pathID;
189
187
  // For each element in the catalog:
190
188
  Object.keys(catalog).forEach(elementIndex => {
@@ -195,25 +193,3 @@ exports.pruneCatalog = report => {
195
193
  }
196
194
  });
197
195
  };
198
- // Adds a catalog index or, if necessary, an XPath to a proto-instance.
199
- exports.addCatalogIndex = async (protoInstance, locator, catalog) => {
200
- // Get the XPath of the element referenced by the locator.
201
- const xPath = await locator.evaluate(element => window.getXPath(element));
202
- // If the acquisition succeeded:
203
- if (xPath) {
204
- // Get the catalog index of the element.
205
- const catalogIndex = getXPathCatalogIndex(catalog, xPath);
206
- // If the acquisition succeeded:
207
- if (catalogIndex) {
208
- // Add it to the proto-instance.
209
- protoInstance.catalogIndex = catalogIndex;
210
- }
211
- // Otherwise, i.e. if the acquisition failed:
212
- else {
213
- // Add the XPath to the proto-instance.
214
- protoInstance.pathID = xPath;
215
- }
216
- }
217
- // Return the proto-instance with any modification.
218
- return protoInstance;
219
- };
package/procs/doActs.js CHANGED
@@ -1203,8 +1203,8 @@ exports.doActs = async (report, opts = {}) => {
1203
1203
  for (const instance of instances) {
1204
1204
  // Increment the instance count.
1205
1205
  actCatalogData.instanceCount++;
1206
- const {catalogIndex} = instance;
1207
- // If the instance has a catalogIndex value:
1206
+ const catalogIndex = instance?.catalogIndex;
1207
+ // If the instance has a catalog index:
1208
1208
  if (catalogIndex) {
1209
1209
  // Increment the catalog count.
1210
1210
  actCatalogData.catalogCount++;
package/procs/testaro.js CHANGED
@@ -14,8 +14,6 @@
14
14
 
15
15
  // ########## IMPORTS
16
16
 
17
- // Function to add a catalog index to a standard instance.
18
- const {addCatalogIndex} = require('./catalog');
19
17
  // Function to get a catalog index from an XPath.
20
18
  const {getXPathCatalogIndex} = require('./xPath');
21
19
 
@@ -84,12 +82,13 @@ exports.doTest = async (
84
82
  totals[ordinalSeverity]++;
85
83
  // If itemization is required:
86
84
  if (withItems) {
87
- // Add a proto-instance to the proto-instances.
88
- protoInstances.push({
85
+ const protoInstance = {
89
86
  what: ruleWhat,
90
87
  ordinalSeverity,
91
- pathID: window.getXPath(candidate)
92
- });
88
+ xPath: window.getXPath(candidate) ?? '/html'
89
+ };
90
+ // Add a proto-instance to the proto-instances.
91
+ protoInstances.push(protoInstance);
93
92
  }
94
93
  }
95
94
  }
@@ -112,7 +111,7 @@ exports.doTest = async (
112
111
  if (withItems) {
113
112
  // For each proto-instance:
114
113
  protoInstances.forEach(protoInstance => {
115
- const {what, ordinalSeverity, pathID} = protoInstance;
114
+ const {what, ordinalSeverity, xPath} = protoInstance;
116
115
  // Initialize a standard instance.
117
116
  const standardInstance = {
118
117
  ruleID,
@@ -121,19 +120,9 @@ exports.doTest = async (
121
120
  count: 1
122
121
  };
123
122
  // If the proto-instance includes an XPath:
124
- if (pathID) {
125
- // Use it to get the catalog index of the element.
126
- const catalogIndex = getXPathCatalogIndex(catalog, pathID);
127
- // If the acquisition succeeded:
128
- if (catalogIndex) {
129
- // Add the catalog index to the standard instance.
130
- standardInstance.catalogIndex = catalogIndex;
131
- }
132
- // Otherwise, i.e. if the acquisition failed:
133
- else {
134
- // Add the XPath to the standard instance as its path ID.
135
- standardInstance.pathID = pathID;
136
- }
123
+ if (xPath) {
124
+ // Add the catalog index to the standard instance.
125
+ standardInstance.catalogIndex = getXPathCatalogIndex(catalog, xPath);
137
126
  }
138
127
  // Add the standard instance to the standard instances.
139
128
  standardInstances.push(standardInstance);
@@ -162,6 +151,15 @@ exports.doTest = async (
162
151
  standardInstances
163
152
  };
164
153
  };
154
+ // Adds a catalog index or, if necessary, an XPath to a proto-instance.
155
+ const addCatalogIndex = async (protoInstance, locator, catalog) => {
156
+ // Get the XPath of the element referenced by the locator.
157
+ const xPath = await locator.evaluate(element => window.getXPath(element) ?? '/html');
158
+ // Add a catalog index to the proto-instance.
159
+ protoInstance.catalogIndex = getXPathCatalogIndex(catalog, xPath);
160
+ // Return the proto-instance with any modification.
161
+ return protoInstance;
162
+ };
165
163
  // Tests for a doTest-ineligible Testaro rule.
166
164
  exports.getBasicResult = async (
167
165
  catalog, withItems, ruleID, ordinalSeverity, whats, data, violations
@@ -191,7 +189,7 @@ exports.getBasicResult = async (
191
189
  ordinalSeverity,
192
190
  count: 1
193
191
  };
194
- // Add a catalog index or path ID to it.
192
+ // Add a catalog index to it.
195
193
  addCatalogIndex(protoInstance, loc, catalog);
196
194
  // Add the standard instance to the standard instances.
197
195
  standardInstances.push(protoInstance);
package/procs/xPath.js CHANGED
@@ -47,16 +47,32 @@ exports.getNormalizedXPath = xPath => {
47
47
  return normalizedSegments.join('/');
48
48
  }
49
49
  else {
50
- return '';
50
+ return '/html';
51
51
  }
52
52
  };
53
53
  // Gets an XPath from a data-xpath attribute in an HTML excerpt.
54
54
  exports.getAttributeXPath = html => {
55
55
  const match = html.match(/ data-xpath="([^" ]+)"/);
56
- return match ? match[1] : '';
56
+ return match ? match[1] : '/html';
57
+ };
58
+ // Gets a tag name from an XPath.
59
+ const getXPathTagName = xPath => {
60
+ return xPath.split('/').pop().replace(/\[.+/, '').toUpperCase();
57
61
  };
58
62
  // Gets a catalog index as a string from an XPath.
59
63
  exports.getXPathCatalogIndex = (catalog, xPath) => {
60
- const index = catalog.pathID[xPath] ?? '';
64
+ // Get the index of the catalog item with the XPath.
65
+ const index = catalog.pathID[xPath];
66
+ // If no such item exists:
67
+ if (! index) {
68
+ // Add an item to the catalog.
69
+ const newIndex = Object.keys(catalog).length;
70
+ catalog[newIndex] = {
71
+ pathID: xPath,
72
+ tagName: getXPathTagName(xPath)
73
+ };
74
+ catalog.pathID[xPath] = `${newIndex}`;
75
+ return newIndex;
76
+ }
61
77
  return index;
62
78
  };
@@ -12,10 +12,14 @@
12
12
  This test reports a page that is entirely or mainly hidden.
13
13
  */
14
14
 
15
+ // IMPORTS
16
+
17
+ const {getXPathCatalogIndex} = require('../procs/xPath');
18
+
15
19
  // FUNCTIONS
16
20
 
17
21
  // Runs the test and returns the result.
18
- exports.reporter = async page => {
22
+ exports.reporter = async (page, catalog) => {
19
23
  // Get a count of elements deemed visible by Playwright.
20
24
  const visibleElementCount = await page.locator('body :visible').count();
21
25
  // If no element is visible:
@@ -28,7 +32,8 @@ exports.reporter = async page => {
28
32
  ruleID: 'allHidden',
29
33
  what: 'The entire page body is hidden or empty',
30
34
  ordinalSeverity: 3,
31
- count: 1
35
+ count: 1,
36
+ catalogIndex: getXPathCatalogIndex(catalog, '/html/body')
32
37
  }]
33
38
  };
34
39
  }
package/testaro/bulk.js CHANGED
@@ -13,8 +13,14 @@
13
13
  This test reports the count of visible elements. The test assumes that simplicity and compactness, with one page having one purpose, is an accessibility virtue. Users with visual, motor, and cognitive disabilities often have trouble finding what they want or understanding the purpose of a page if the page is cluttered with content.
14
14
  */
15
15
 
16
+ // IMPORTS
17
+
18
+ const {getXPathCatalogIndex} = require('../procs/xPath');
19
+
20
+ // FUNCTIONS
21
+
16
22
  // Runs the test and returns the result.
17
- exports.reporter = async page => {
23
+ exports.reporter = async (page, catalog) => {
18
24
  // Get a count of elements deemed visible by Playwright.
19
25
  const visibleElementCount = await page.locator('body :visible').count();
20
26
  // Convert the count to a severity level, treating up to 400 as non-reportable.
@@ -31,7 +37,8 @@ exports.reporter = async page => {
31
37
  ruleID: 'bulk',
32
38
  what: `Page contains ${visibleElementCount} visible elements`,
33
39
  ordinalSeverity: severity,
34
- count: 1
40
+ count: 1,
41
+ catalogIndex: getXPathCatalogIndex(catalog, '/html')
35
42
  }]
36
43
  };
37
44
  }
@@ -13,6 +13,10 @@
13
13
  This test reports nonstandard navigation among menu items of button-controlled menus. Standards are based on https://www.w3.org/TR/wai-aria-practices-1.1/#menu. The trialKeys argument is an array of strings, each of which may be 'Home', 'End', '+', or '-'. The '+' string represents the ArrowDown or ArrowRight key, and the '-' string represents the ArrowUp or ArrowLeft key, depending on the orientation of the current menu. When the trialKeys argument is missing or is an empty array, 12 keys are selected at random.
14
14
  */
15
15
 
16
+ // IMPORTS
17
+
18
+ const {addCatalogIndex} = require('../procs/catalog');
19
+
16
20
  // ########## FUNCTIONS
17
21
 
18
22
  // Returns data about the element referenced by a locator.
@@ -292,17 +296,16 @@ exports.reporter = async (page, catalog, withItems, trialKeySpecs = []) => {
292
296
  totals[2]++;
293
297
  // If itemization is required:
294
298
  if (withItems) {
295
- // Create a proto-instance.
296
- const protoInstance = {
299
+ // Get the XPath of the menu button.
300
+ const mbXPath = await mbLoc.evaluate(element => window.getXPath(element));
301
+ // Add an instance to the standard instances.
302
+ standardInstances.push({
297
303
  ruleID: 'buttonMenu',
298
304
  what: `Menu responds nonstandardly to the ${key} key`,
299
305
  ordinalSeverity: 2,
300
- count: 1
301
- };
302
- // Add a catalog index or XPath to it if possible.
303
- addCatalogIndex(protoInstance, mbLoc, catalog);
304
- // Add the proto-instance to the standard instances.
305
- standardInstances.push(protoInstance);
306
+ count: 1,
307
+ catalogIndex: getXPathCatalogIndex(catalog, mbXPath)
308
+ });
306
309
  }
307
310
  // Stop testing the menu button.
308
311
  break;
@@ -328,17 +331,16 @@ exports.reporter = async (page, catalog, withItems, trialKeySpecs = []) => {
328
331
  totals[2]++;
329
332
  // If itemization is required:
330
333
  if (withItems) {
331
- // Create a proto-instance.
332
- const protoInstance = {
334
+ // Get the XPath of the menu button.
335
+ const mbXPath = await mbLoc.evaluate(element => window.getXPath(element));
336
+ // Add an instance to the standard instances.
337
+ standardInstances.push({
333
338
  ruleID: 'buttonMenu',
334
339
  what: 'Menu button does not control exactly 1 menu',
335
340
  ordinalSeverity: 2,
336
- count: 1
337
- };
338
- // Add a catalog index or XPath to it if possible.
339
- addCatalogIndex(protoInstance, mbLoc, catalog);
340
- // Add the proto-instance to the standard instances.
341
- standardInstances.push(protoInstance);
341
+ count: 1,
342
+ catalogIndex: getXPathCatalogIndex(catalog, mbXPath)
343
+ });
342
344
  }
343
345
  }
344
346
  }
@@ -349,7 +351,7 @@ exports.reporter = async (page, catalog, withItems, trialKeySpecs = []) => {
349
351
  ruleID: 'buttonMenu',
350
352
  what: 'Menu buttons and menus behave nonstandardly',
351
353
  count: totals[2],
352
- ordinalSeverity: 2,
354
+ ordinalSeverity: 2
353
355
  });
354
356
  }
355
357
  return {
@@ -15,7 +15,7 @@
15
15
  */
16
16
 
17
17
  // Runs the test and returns the result.
18
- exports.reporter = async page => {
18
+ exports.reporter = async (page, catalog) => {
19
19
  // Returns whether the page declares a document type.
20
20
  const docHasType = await page.evaluate(() => {
21
21
  const docType = document.doctype;
@@ -30,7 +30,8 @@ exports.reporter = async page => {
30
30
  ruleID: 'docType',
31
31
  what: 'Document has no standard HTML doctype preamble',
32
32
  ordinalSeverity: 3,
33
- count: 1
33
+ count: 1,
34
+ catalogIndex: getXPathCatalogIndex('/html')
34
35
  }]
35
36
  };
36
37
  };
package/testaro/dupAtt.js CHANGED
@@ -14,13 +14,13 @@
14
14
 
15
15
  // ########## IMPORTS
16
16
 
17
- // Module to get the document source.
18
17
  const {getSource} = require('../procs/getSource');
18
+ const {getXPathCatalogIndex} = require('../procs/xPath');
19
19
 
20
20
  // ########## FUNCTIONS
21
21
 
22
22
  // Runs the test and returns the result.
23
- exports.reporter = async (page, _, withItems) => {
23
+ exports.reporter = async (page, catalog, withItems) => {
24
24
  // Initialize the data and standard result.
25
25
  const data = {total: 0};
26
26
  if (withItems) {
@@ -95,7 +95,8 @@ exports.reporter = async (page, _, withItems) => {
95
95
  ruleID: 'dupAtt',
96
96
  what: `${item.tagName} element has 2 attributes named ${item.duplicatedAttribute}`,
97
97
  ordinalSeverity: 2,
98
- count: 1
98
+ count: 1,
99
+ catalogIndex: getXPathCatalogIndex(catalog, '/html/body')
99
100
  });
100
101
  });
101
102
  }
@@ -16,6 +16,8 @@
16
16
  3. Data on each specified element also include data on its sibling nodes.
17
17
  */
18
18
 
19
+ // FUNCTIONS
20
+
19
21
  exports.reporter = async (
20
22
  page, _, _, detailLevel = 0, tagName = null, onlyVisible = false, attribute
21
23
  ) => {
package/testaro/focAll.js CHANGED
@@ -12,8 +12,14 @@
12
12
  This test reports discrepancies between focusable and Tab-focused element counts. The test first counts all the visible focusable (i.e. with tabIndex 0) elements (except counting each group of radio buttons as only one focusable element). Then it repeatedly presses the Tab (or Option-Tab in webkit) key until it has reached all the elements it can and counts those elements. If the two counts differ, navigation can be made more difficult. The cause may be surprising changes in content during navigation with the Tab key, or inability to reach every focusable element (or widget, such as one radio button or tab in each group) merely by pressing the Tab key.
13
13
  */
14
14
 
15
+ // IMPORTS
16
+
17
+ const {getXPathCatalogIndex} = require('../procs/xPath');
18
+
19
+ // FUNCTIONS
20
+
15
21
  // Runs the test and returns the result.
16
- exports.reporter = async page => {
22
+ exports.reporter = async (page, catalog) => {
17
23
  // Get locators of visible elements.
18
24
  const locAll = await page.locator('body *:visible');
19
25
  // Get the count of focusable elements.
@@ -67,7 +73,8 @@ exports.reporter = async page => {
67
73
  ruleID: 'focAll',
68
74
  what: 'Some focusable elements are not Tab-focusable or vice versa',
69
75
  ordinalSeverity: 2,
70
- count
76
+ count,
77
+ catalogIndex: getXPathCatalogIndex(catalog, '/html/body')
71
78
  }] : []
72
79
  };
73
80
  };
package/testaro/headEl.js CHANGED
@@ -13,10 +13,14 @@
13
13
  This test reports invalid descendants of the head of the document.
14
14
  */
15
15
 
16
+ // IMPORTS
17
+
18
+ const {getXPathCatalogIndex} = require('../procs/xPath');
19
+
16
20
  // ########## FUNCTIONS
17
21
 
18
22
  // Runs the test and returns the result.
19
- exports.reporter = async page => {
23
+ exports.reporter = async (page, catalog) => {
20
24
  // Initialize the data and standard result.
21
25
  const data = {
22
26
  total: 0,
@@ -60,7 +64,8 @@ exports.reporter = async page => {
60
64
  ruleID: 'headEl',
61
65
  what: `Invalid elements within the head: ${data.badTagNames.join(', ')}`,
62
66
  ordinalSeverity: 2,
63
- count: data.total
67
+ count: data.total,
68
+ catalogIndex: getXPathCatalogIndex(catalog, '/html/head')
64
69
  });
65
70
  }
66
71
  totals = [0, 0, data.total, 0];
package/testaro/hovInd.js CHANGED
@@ -19,7 +19,7 @@ const {doTest} = require('../procs/testaro');
19
19
  // FUNCTIONS
20
20
 
21
21
  // Runs the test and returns the result.
22
- exports.reporter = async (page, _, withItems) => {
22
+ exports.reporter = async (page, catalog, withItems) => {
23
23
  const getBadWhat = element => {
24
24
  const violationTypes = [];
25
25
  const isVisible = element.checkVisibility({
@@ -140,5 +140,5 @@ exports.reporter = async (page, _, withItems) => {
140
140
  };
141
141
  const selector = 'a, button, input, [onmouseenter], [onmouseover]';
142
142
  const whats = 'elements have confusing hover indicators';
143
- return await doTest(page, withItems, 'hovInd', selector, whats, 1, getBadWhat.toString());
143
+ return await doTest(page, catalog, withItems, 'hovInd', selector, whats, 1, getBadWhat.toString());
144
144
  };
@@ -14,11 +14,17 @@
14
14
  This test reports text contents that are shared by links with distinct destinations. Text contents are compared case-insensitively.
15
15
  */
16
16
 
17
+ // IMPORTS
18
+
19
+ const {getXPathCatalogIndex} = require('../procs/xPath');
20
+
17
21
  // FUNCTIONS
18
22
 
19
23
  // Runs the test and returns the result.
20
- exports.reporter = async (page, _, withItems) => {
21
- return await page.evaluate(withItems => {
24
+ exports.reporter = async (page, catalog, withItems) => {
25
+ const catalogIndex = getXPathCatalogIndex(catalog, '/html/body');
26
+ return await page.evaluate(args => {
27
+ const [withItems, catalogIndex] = args;
22
28
  // Get all links.
23
29
  const allLinks = Array.from(document.body.getElementsByTagName('a'));
24
30
  // Get the visible ones.
@@ -65,7 +71,8 @@ exports.reporter = async (page, _, withItems) => {
65
71
  ruleID: 'linkAmb',
66
72
  what,
67
73
  ordinalSeverity: 2,
68
- count: linkCount
74
+ count: linkCount,
75
+ catalogIndex
69
76
  });
70
77
  }
71
78
  }
@@ -78,7 +85,8 @@ exports.reporter = async (page, _, withItems) => {
78
85
  ruleID: 'linkAmb',
79
86
  what,
80
87
  ordinalSeverity: 2,
81
- count: violationCount
88
+ count: violationCount,
89
+ catalogIndex
82
90
  });
83
91
  }
84
92
  return {
@@ -86,5 +94,5 @@ exports.reporter = async (page, _, withItems) => {
86
94
  totals: [0, 0, violationCount, 0],
87
95
  standardInstances
88
96
  };
89
- }, withItems);
97
+ }, [withItems, catalogIndex]);
90
98
  };
package/testaro/motion.js CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  // IMPORTS
16
16
 
17
+ const {getXPathCatalogIndex} = require('../procs/xPath');
17
18
  const fs = require('fs/promises');
18
19
  const os = require('os');
19
20
  const blazediff = require('@blazediff/core').diff;
@@ -26,7 +27,7 @@ const tmpDir = os.tmpdir();
26
27
  // FUNCTIONS
27
28
 
28
29
  // Runs the test and returns the result.
29
- exports.reporter = async page => {
30
+ exports.reporter = async (_, catalog) => {
30
31
  // Initialize the totals and standard instances.
31
32
  const data = {};
32
33
  const totals = [0, 0, 0, 0];
@@ -78,7 +79,8 @@ exports.reporter = async page => {
78
79
  ruleID: 'motion',
79
80
  what: violationWhat,
80
81
  ordinalSeverity,
81
- count: 1
82
+ count: 1,
83
+ catalogIndex: getXPathCatalogIndex(catalog, '/html/body')
82
84
  });
83
85
  }
84
86
  }
@@ -12,6 +12,10 @@
12
12
  This test reports style differences among links, buttons, and headings. It assumes that an accessible page employs few or only one style for adjacent links, and likewise for list links, buttons, and headings at each level. The test considers only particular style properties, listed in the 'mainStyles' and 'headingStyles' arrays.
13
13
  */
14
14
 
15
+ // IMPORTS
16
+
17
+ const {getXPathCatalogIndex} = require('../procs/xPath');
18
+
15
19
  // FUNCTIONS
16
20
 
17
21
  // Returns an object classifying the links in a page by layout.
@@ -77,12 +81,12 @@ const linksByType = async page => await page.evaluateHandle(() => {
77
81
  };
78
82
  });
79
83
  // Runs the test and returns the result.
80
- exports.reporter = async (page, _, withItems) => {
84
+ exports.reporter = async (page, catalog, withItems) => {
81
85
  // Get an object with arrays of list links and adjacent links as properties.
82
86
  const linkTypes = await linksByType(page);
87
+ const catalogIndex = getXPathCatalogIndex(catalog, '/html/body');
83
88
  return await page.evaluate(args => {
84
- const linkTypes = args[0];
85
- const withItems = args[1];
89
+ const [linkTypes, withItems, catalogIndex] = args;
86
90
  const {body} = document;
87
91
  // Identify the settable style properties to be compared for all tag names.
88
92
  const mainStyles = [
@@ -256,7 +260,8 @@ exports.reporter = async (page, _, withItems) => {
256
260
  ruleID: 'styleDiff',
257
261
  what: `${currentData[1]} have ${elementSubtotals.length} different styles`,
258
262
  ordinalSeverity: severity,
259
- count: extraCount
263
+ count: extraCount,
264
+ catalogIndex
260
265
  });
261
266
  }
262
267
  });
@@ -266,5 +271,5 @@ exports.reporter = async (page, _, withItems) => {
266
271
  totals,
267
272
  standardInstances
268
273
  };
269
- }, [linkTypes, withItems]);
274
+ }, [linkTypes, withItems, catalogIndex]);
270
275
  };
package/testaro/tabNav.js CHANGED
@@ -164,7 +164,7 @@ const testTabs = async (tabs, index, listOrientation, listIsCorrect, withItems,
164
164
  const itemData = {};
165
165
  // If itemization is required:
166
166
  if (withItems) {
167
- // Initialize a report on the element.
167
+ // Initialize data on the element.
168
168
  itemData.xPath = await page.evaluate(element => window.getXPath(element), currentTab);
169
169
  itemData.navigationErrors = [];
170
170
  }
@@ -368,32 +368,19 @@ exports.reporter = async (page, catalog, withItems) => {
368
368
  if (withItems) {
369
369
  // For each bad tab:
370
370
  data.tabElements.incorrect.forEach(item => {
371
- // Create a proto-instance.
372
- const protoInstance = {
371
+ // Add an instance to the standard instances.
372
+ standardInstances.push({
373
373
  ruleID: 'tabNav',
374
374
  what: `Tab responds nonstandardly to ${item.navigationErrors.join(', ')}`,
375
375
  ordinalSeverity: 1,
376
- count: 1
377
- };
378
- // Try to get a catalog index from the xPath of the tab.
379
- const catalogIndex = getXPathCatalogIndex(catalog, item.xPath);
380
- // If the acquisition succeeded:
381
- if (catalogIndex) {
382
- // Add the catalog index to the proto-instance.
383
- protoInstance.catalogIndex = catalogIndex;
384
- }
385
- // Otherwise, i.e. if the acquisition failed:
386
- else {
387
- // Add the XPath to the proto-instance as a path ID.
388
- protoInstance.pathID = item.xPath;
389
- }
390
- // Add the proto-instance to the standard instances.
391
- standardInstances.push(protoInstance);
376
+ count: 1,
377
+ catalogIndex: getXPathCatalogIndex(catalog, item.xPath)
378
+ });
392
379
  });
393
380
  }
394
381
  // Otherwise, if navigation is not required and any navigations were bad:
395
382
  else if (data.totals.navigations.all.incorrect) {
396
- // Create a standard instance.
383
+ // Add a summary instance to the standard instances.
397
384
  standardInstances.push({
398
385
  ruleID: 'tabNav',
399
386
  what: 'Tab lists have nonstandard navigation',
@@ -13,10 +13,14 @@
13
13
  This test reports visible pointer targets, i.e. labels, buttons, inputs, and links, that are small enough or near enough to other targets to make pointer interaction difficult. This test relates to WCAG 2.2 Success Criteria 2.5.5 and 2.5.8, but does not attempt to implement either of them precisely. For example, the test reports a small pointer target that is far from all other targets, although it conforms to the Success Criteria.
14
14
  */
15
15
 
16
+ // IMPORTS
17
+
18
+ const {getXPathCatalogIndex} = require('../procs/xPath');
19
+
16
20
  // FUNCTIONS
17
21
 
18
22
  // Runs the test and returns the result.
19
- exports.reporter = async (page, _, withItems) => {
23
+ exports.reporter = async (page, catalog, withItems) => {
20
24
  // Return totals and standard instances for the rule.
21
25
  const protoResult = await page.evaluate(withItems => {
22
26
  // Get all pointer targets.
@@ -76,7 +80,7 @@ exports.reporter = async (page, _, withItems) => {
76
80
  what,
77
81
  ordinalSeverity,
78
82
  count: 1,
79
- xPath: window.getXPath(element)
83
+ xPath: window.getXPath(element) ?? '/html'
80
84
  });
81
85
  }
82
86
  }
@@ -111,6 +115,12 @@ exports.reporter = async (page, _, withItems) => {
111
115
  standardInstances: protoInstances
112
116
  };
113
117
  }, withItems);
118
+ // Convert the XPaths of the proto-instances to catalog indexes.
119
+ protoResult.standardInstances = protoResult.standardInstances.map(instance => {
120
+ instance.catalogIndex = getXPathCatalogIndex(catalog, instance.xPath);
121
+ delete instance.xPath;
122
+ return instance;
123
+ });
114
124
  // Return the result.
115
125
  return protoResult;
116
126
  };
package/tests/alfa.js CHANGED
@@ -125,29 +125,15 @@ exports.reporter = async (page, report, actIndex) => {
125
125
  }
126
126
  // Increment the standard total.
127
127
  standardResult.totals[ordinalSeverity]++;
128
- // Initialize a proto-instance.
129
- const protoInstance = {
128
+ const xPath = getNormalizedXPath(item.path?.replace(/\/text\(\).*$/, '') || '/html');
129
+ // Add an instance to the standard instances.
130
+ standardResult.instances.push({
130
131
  ruleID,
131
132
  what,
132
133
  ordinalSeverity,
133
- count: 1
134
- };
135
- // Get the pathID of the element or, if none, the document pathID.
136
- const pathID = getNormalizedXPath(item.path.replace(/\/text\(\).*$/, '')) || '/html';
137
- // Use it to get the index of the element in the catalog.
138
- const catalogIndex = getXPathCatalogIndex(catalog, pathID);
139
- // If the acquisition succeeded:
140
- if (catalogIndex) {
141
- // Add the catalog index to the proto-instance.
142
- protoInstance.catalogIndex = catalogIndex;
143
- }
144
- // Otherwise, i.e. if the acquisition failed:
145
- else {
146
- // Add the pathID to the proto-instance.
147
- protoInstance.pathID = pathID;
148
- }
149
- // Add the proto-instance to the instances of the standard result.
150
- standardResult.instances.push(protoInstance);
134
+ count: 1,
135
+ catalogIndex: getXPathCatalogIndex(catalog, xPath)
136
+ });
151
137
  }
152
138
  }
153
139
  }
package/tests/axe.js CHANGED
@@ -155,14 +155,12 @@ exports.reporter = async (page, report, actIndex) => {
155
155
  standardResult.totals[ordinalSeverity]++;
156
156
  // Get the XPath of the suspected element from its data-xpath attribute.
157
157
  const xPath = getAttributeXPath(node.html);
158
- // Get the catalog index of the suspected element from its XPath.
159
- const catalogIndex = getXPathCatalogIndex(report.catalog, xPath) ?? '';
160
158
  const instance = {
161
159
  ruleID: rule.id,
162
160
  what: Array.from(whatSet.values()).join('; '),
163
161
  ordinalSeverity,
164
162
  count: 1,
165
- catalogIndex
163
+ catalogIndex: getXPathCatalogIndex(report.catalog, xPath)
166
164
  };
167
165
  standardResult.instances.push(instance);
168
166
  });
package/tests/ed11y.js CHANGED
@@ -110,9 +110,6 @@ exports.reporter = async (page, report, actIndex) => {
110
110
  instance.ordinalSeverity = dismissalKey ? 0 : 2;
111
111
  instance.count = 1;
112
112
  instance.catalogIndex = getXPathCatalogIndex(report.catalog, xPath);
113
- if (! instance.catalogIndex) {
114
- instance.pathID = xPath;
115
- }
116
113
  standardResult.instances.push(instance);
117
114
  });
118
115
  }
package/tests/htmlcs.js CHANGED
@@ -128,18 +128,14 @@ exports.reporter = async (page, report, actIndex) => {
128
128
  }
129
129
  // If standard results are to be reported and the message reports an error or warning:
130
130
  if (standard && ['Error', 'Warning'].includes(parts[0])) {
131
+ const xPath = getAttributeXPath(parts[5]);
131
132
  const instance = {
132
133
  ruleID: `${parts[0][0]}-${parts[1]}`,
133
134
  what: parts[4],
134
135
  ordinalSeverity: parts[0] === 'Warning' ? 0 : 2,
135
- count: 1
136
+ count: 1,
137
+ catalogIndex: getXPathCatalogIndex(report.catalog, xPath)
136
138
  };
137
- const xPath = getAttributeXPath(parts[5]) || '/html';
138
- const catalogIndex = getXPathCatalogIndex(report.catalog, xPath);
139
- instance.catalogIndex = catalogIndex ?? '';
140
- if (! catalogIndex) {
141
- instance.pathID = xPath;
142
- }
143
139
  standardResult.instances.push(instance);
144
140
  }
145
141
  }
package/tests/ibm.js CHANGED
@@ -173,16 +173,10 @@ exports.reporter = async (page, report, actIndex) => {
173
173
  };
174
174
  // Get the XPath from the added attribute, because path.dom is wrong.
175
175
  const xPath = getAttributeXPath(item.snippet);
176
- const catalogIndex = getXPathCatalogIndex(report.catalog, xPath);
177
- // If a catalog index was found:
178
- if (catalogIndex) {
179
- // Add it to the standard instance.
180
- standardItem.catalogIndex = catalogIndex;
181
- }
182
- // Otherwise, if no catalog index was found but the item has an XPath:
183
- else if (xPath) {
184
- // Add the XPath to the standard instance.
185
- standardItem.pathID = xPath;
176
+ // If the XPath was obtained:
177
+ if (xPath) {
178
+ // Add the catalog index to the standard instance.
179
+ standardItem.catalogIndex = getXPathCatalogIndex(report.catalog, xPath);
186
180
  }
187
181
  // Add the standard instance to the standard result.
188
182
  standardResult.instances.push(standardItem);
package/tests/nuVal.js CHANGED
@@ -104,18 +104,8 @@ exports.reporter = async (page, report, actIndex) => {
104
104
  const xPath = getAttributeXPath(message.extract);
105
105
  // If the acquisition succeeded:
106
106
  if (xPath) {
107
- // Get the catalog index of the element from the XPath.
108
- const catalogIndex = getXPathCatalogIndex(report.catalog, xPath);
109
- // If the acquisition succeeded:
110
- if (catalogIndex) {
111
- // Add the catalog index to the standard instance.
112
- standardInstance.catalogIndex = catalogIndex;
113
- }
114
- // Otherwise, i.e. if the acquisition failed:
115
- else {
116
- // Add the XPath of the standard instance as its pathID.
117
- standardInstance.pathID = xPath;
118
- }
107
+ // Add the catalog index to the standard instance.
108
+ standardInstance.catalogIndex = getXPathCatalogIndex(report.catalog, xPath);
119
109
  }
120
110
  // Add the standard instance to the standard result.
121
111
  standardResult.instances.push(standardInstance);
package/tests/nuVnu.js CHANGED
@@ -102,23 +102,8 @@ exports.reporter = async (page, report, actIndex) => {
102
102
  const xPath = getAttributeXPath(message.extract);
103
103
  // If the acquisition succeeded:
104
104
  if (xPath) {
105
- // Get the catalog index of the element from the XPath.
106
- const catalogIndex = getXPathCatalogIndex(report.catalog, xPath);
107
- // If the acquisition succeeded:
108
- if (catalogIndex) {
109
- // Add the catalog index to the standard instance.
110
- standardInstance.catalogIndex = catalogIndex;
111
- }
112
- // Otherwise, i.e. if the acquisition failed:
113
- else {
114
- // Add the XPath of the standard instance as its pathID.
115
- standardInstance.pathID = xPath;
116
- }
117
- }
118
- // Otherwise, i.e. if the acquisition failed:
119
- else {
120
- // Add the extract of the native instance to the standard instance.
121
- standardInstance.excerpt = message.extract ?? '';
105
+ // Add the catalog index to the standard instance.
106
+ standardInstance.catalogIndex = getXPathCatalogIndex(report.catalog, xPath);
122
107
  }
123
108
  // Add the standard instance to the standard result.
124
109
  standardResult.instances.push(standardInstance);
package/tests/qualWeb.js CHANGED
@@ -234,27 +234,14 @@ exports.reporter = async (page, report, actIndex, timeLimit) => {
234
234
  standardResult.totals[ordinalSeverity]++;
235
235
  // Initialize a standard instance.
236
236
  const what = `[${verdict}] ${raResult.description}`;
237
+ const xPath = getAttributeXPath(element.htmlCode);
237
238
  const instance = {
238
239
  ruleID,
239
240
  what,
240
241
  ordinalSeverity: ordinalSeverities[section][verdict],
241
- count: 1
242
+ count: 1,
243
+ catalogIndex: getXPathCatalogIndex(report.catalog, xPath)
242
244
  };
243
- // Get the pathID of the element or, if none, the document pathID.
244
- const pathID = getAttributeXPath(element.htmlCode) || '/html';
245
- const {catalog} = report;
246
- // Use it to get the catalog index.
247
- const catalogIndex = getXPathCatalogIndex(catalog, pathID);
248
- // If the acquisition succeeded:
249
- if (catalogIndex) {
250
- // Add the catalog index to the instance.
251
- instance.catalogIndex = catalogIndex;
252
- }
253
- // Otherwise, i.e. if the acquisition failed:
254
- else {
255
- // Add the XPath to the instance.
256
- instance.pathID = pathID;
257
- }
258
245
  // Add the instance to the standard result.
259
246
  standardResult.instances.push(instance);
260
247
  }
package/tests/testaro.js CHANGED
@@ -610,7 +610,7 @@ exports.reporter = async (page, report, actIndex) => {
610
610
  standardResult.totals[index] += Math.round(total);
611
611
  });
612
612
  }
613
- if (ruleResult.instances) {
613
+ if (ruleResult.instances?.length) {
614
614
  standardResult.instances.push(... ruleResult.instances);
615
615
  }
616
616
  justPrevented = false;
package/tests/wave.js CHANGED
@@ -152,22 +152,9 @@ exports.reporter = async (page, report, actIndex) => {
152
152
  ordinalSeverity,
153
153
  count: 1
154
154
  };
155
- const pathID = violation[1];
156
- // If the path ID of the violator was found:
157
- if (pathID) {
158
- // Get the catalog index of the violator.
159
- const catalogIndex = getXPathCatalogIndex(report.catalog, pathID);
160
- // If the acquisition succeeded:
161
- if (catalogIndex) {
162
- // Add the catalog index to the instance.
163
- instance.catalogIndex = catalogIndex;
164
- }
165
- // Otherwise, i.e. if the acquisition failed:
166
- else {
167
- // Add the path ID to the instance.
168
- instance.pathID = pathID;
169
- }
170
- }
155
+ const xPath = violation[1];
156
+ // Add the catalog index to the instance.
157
+ instance.catalogIndex = getXPathCatalogIndex(report.catalog, xPath);
171
158
  // Add the instance to the standard result.
172
159
  instances.push(instance);
173
160
  }
package/tests/wax.js CHANGED
@@ -89,21 +89,11 @@ exports.reporter = async (page, report, actIndex) => {
89
89
  const pathID = getAttributeXPath(element);
90
90
  // If the acquisition succeeded:
91
91
  if (pathID) {
92
- // Get the catalog index of the element.
93
- const catalogIndex = getXPathCatalogIndex(report.catalog, pathID);
94
- // If the acquisition succeeded:
95
- if (catalogIndex) {
96
- // Add the catalog index to the standard instance.
97
- instance.catalogIndex = catalogIndex;
98
- }
99
- // Otherwise, i.e. if the acquisition failed:
100
- else {
101
- // Add the path ID to the standard instance.
102
- instance.pathID = pathID;
103
- }
104
- // Add the standard instance to the standard result.
105
- instances.push(instance);
92
+ // Add the catalog index to the standard instance.
93
+ instance.catalogIndex = getXPathCatalogIndex(report.catalog, pathID);
106
94
  }
95
+ // Add the standard instance to the standard result.
96
+ instances.push(instance);
107
97
  });
108
98
  }
109
99
  }