testaro 67.0.0 → 68.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.
Files changed (95) hide show
  1. package/LICENSE +4 -16
  2. package/README.md +10 -2
  3. package/UPGRADES.md +1 -1
  4. package/dirWatch.js +2 -3
  5. package/ed11y/editoria11y.min.js +109 -690
  6. package/ed11y/editoria11y210.min.js +747 -0
  7. package/netWatch.js +6 -6
  8. package/package.json +1 -1
  9. package/procs/aslint.js +2 -2
  10. package/procs/catalog.js +190 -0
  11. package/procs/{dateOf.js → dateTime.js} +6 -4
  12. package/procs/doActs.js +1227 -0
  13. package/procs/doTestAct.js +63 -29
  14. package/procs/error.js +53 -0
  15. package/procs/job.js +64 -38
  16. package/procs/launch.js +596 -0
  17. package/procs/nu.js +3 -18
  18. package/procs/shoot.js +18 -2
  19. package/procs/testaro.js +102 -125
  20. package/procs/xPath.js +62 -0
  21. package/run.js +42 -1938
  22. package/scratch/README.md +9 -0
  23. package/testaro/adbID.js +3 -3
  24. package/testaro/allCaps.js +4 -5
  25. package/testaro/allHidden.js +19 -18
  26. package/testaro/allSlanted.js +4 -5
  27. package/testaro/altScheme.js +3 -3
  28. package/testaro/attVal.js +19 -35
  29. package/testaro/autocomplete.js +65 -62
  30. package/testaro/bulk.js +21 -20
  31. package/testaro/buttonMenu.js +112 -33
  32. package/testaro/captionLoc.js +3 -3
  33. package/testaro/datalistRef.js +4 -5
  34. package/testaro/distortion.js +3 -3
  35. package/testaro/docType.js +6 -9
  36. package/testaro/dupAtt.js +12 -25
  37. package/testaro/elements.js +4 -3
  38. package/testaro/embAc.js +4 -2
  39. package/testaro/focAll.js +6 -13
  40. package/testaro/focAndOp.js +3 -3
  41. package/testaro/focInd.js +3 -3
  42. package/testaro/focVis.js +4 -3
  43. package/testaro/headEl.js +5 -12
  44. package/testaro/headingAmb.js +45 -88
  45. package/testaro/hovInd.js +5 -5
  46. package/testaro/hover.js +44 -8
  47. package/testaro/hr.js +4 -4
  48. package/testaro/imageLink.js +3 -3
  49. package/testaro/labClash.js +3 -3
  50. package/testaro/legendLoc.js +3 -3
  51. package/testaro/lineHeight.js +3 -3
  52. package/testaro/linkAmb.js +25 -17
  53. package/testaro/linkExt.js +5 -5
  54. package/testaro/linkOldAtt.js +4 -3
  55. package/testaro/linkTo.js +4 -3
  56. package/testaro/linkUl.js +4 -5
  57. package/testaro/miniText.js +4 -3
  58. package/testaro/motion.js +3 -22
  59. package/testaro/nonTable.js +4 -5
  60. package/testaro/optRoleSel.js +3 -3
  61. package/testaro/phOnly.js +3 -3
  62. package/testaro/pseudoP.js +5 -5
  63. package/testaro/radioSet.js +4 -5
  64. package/testaro/role.js +4 -5
  65. package/testaro/secHeading.js +4 -5
  66. package/testaro/shoot0.js +3 -2
  67. package/testaro/shoot1.js +3 -2
  68. package/testaro/styleDiff.js +5 -12
  69. package/testaro/tabNav.js +30 -118
  70. package/testaro/targetSmall.js +30 -15
  71. package/testaro/textNodes.js +3 -1
  72. package/testaro/textSem.js +4 -5
  73. package/testaro/title.js +4 -2
  74. package/testaro/titledEl.js +3 -3
  75. package/testaro/zIndex.js +3 -3
  76. package/tests/alfa.js +28 -54
  77. package/tests/aslint.js +20 -53
  78. package/tests/axe.js +76 -13
  79. package/tests/ed11y.js +69 -141
  80. package/tests/htmlcs.js +69 -38
  81. package/tests/ibm.js +54 -9
  82. package/tests/nuVal.js +65 -12
  83. package/tests/nuVnu.js +76 -26
  84. package/tests/qualWeb.js +89 -44
  85. package/tests/testaro.js +288 -273
  86. package/tests/wave.js +142 -117
  87. package/tests/wax.js +61 -42
  88. package/procs/getLocatorData.js +0 -192
  89. package/procs/identify.js +0 -250
  90. package/procs/isInlineLink.js +0 -42
  91. package/procs/screenShot.js +0 -32
  92. package/procs/standardize.js +0 -524
  93. package/procs/target.js +0 -90
  94. package/procs/tellServer.js +0 -43
  95. package/scripts/dumpAlts.js +0 -28
package/tests/htmlcs.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  © 2022–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
- © 2025 Jonathan Robert Pool.
3
+ © 2025–2026 Jonathan Robert Pool.
4
4
 
5
5
  Licensed under the MIT License. See LICENSE file at the project root or
6
6
  https://opensource.org/license/mit/ for details.
@@ -15,11 +15,7 @@
15
15
 
16
16
  // IMPORTS
17
17
 
18
- // Module to add and use unique element IDs.
19
- const {addTestaroIDs} = require('../procs/testaro');
20
- // Module to get location data from an element.
21
- const {getElementData} = require('../procs/getLocatorData');
22
- // Module to handle files.
18
+ const {getAttributeXPath, getXPathCatalogIndex} = require('../procs/xPath');
23
19
  const fs = require('fs/promises');
24
20
 
25
21
  // FUNCTIONS
@@ -28,27 +24,47 @@ const fs = require('fs/promises');
28
24
  exports.reporter = async (page, report, actIndex) => {
29
25
  const act = report.acts[actIndex];
30
26
  const {rules} = act;
27
+ // Initialize the act report.
31
28
  const data = {};
32
- const result = {};
29
+ const result = {
30
+ nativeResult: {
31
+ totals: {
32
+ failed: 0,
33
+ cantTell: 0
34
+ },
35
+ error: [],
36
+ warning: []
37
+ },
38
+ standardResult: {}
39
+ };
40
+ const standard = report.standard !== 'no';
41
+ // If standard results are to be reported:
42
+ if (standard) {
43
+ // Initialize the standard result.
44
+ result.standardResult = {
45
+ prevented: false,
46
+ totals: [0, 0, 0, 0],
47
+ instances: []
48
+ };
49
+ }
50
+ const {nativeResult, standardResult} = result;
33
51
  // Get the HTMLCS script.
34
52
  const scriptText = await fs.readFile(`${__dirname}/../htmlcs/HTMLCS.js`, 'utf8');
35
53
  const scriptNonce = report.jobData && report.jobData.lastScriptNonce;
36
- // Annotate all elements on the page with unique identifiers.
37
- await addTestaroIDs(page);
38
54
  let messageStrings = [];
39
- // Define the rules to be employed as those of WCAG 2 level AAA.
55
+ // For each class of standards to be tested for:
40
56
  for (const actStandard of ['WCAG2AAA']) {
41
57
  const nextViolations = await page.evaluate(args => {
42
- // Add the HTMLCS script to the page.
58
+ const actStandard = args[0];
59
+ const rules = args[1];
43
60
  const scriptText = args[2];
44
61
  const scriptNonce = args[3];
45
62
  const script = document.createElement('script');
46
63
  script.nonce = scriptNonce;
47
64
  script.textContent = scriptText;
65
+ // Add the HTMLCS script to the page.
48
66
  document.head.insertAdjacentElement('beforeend', script);
49
67
  // If only some rules are to be employed:
50
- const actStandard = args[0];
51
- const rules = args[1];
52
68
  if (rules && Array.isArray(rules) && rules.length) {
53
69
  // Redefine WCAG 2 AAA as including only them.
54
70
  if (! window.HTMLCS_WCAG2AAA) {
@@ -64,56 +80,71 @@ exports.reporter = async (page, report, actIndex) => {
64
80
  catch(error) {
65
81
  console.log(`ERROR executing HTMLCS_RUNNER on ${document.URL} (${error.message})`);
66
82
  }
83
+ // Return the reported violations of that standard.
67
84
  return violations;
68
85
  }, [actStandard, rules, scriptText, scriptNonce]);
69
- if (nextViolations && nextViolations.every(violation => typeof violation === 'string')) {
86
+ // If all reported violations of the standard are validly described:
87
+ if (nextViolations?.every(violation => typeof violation === 'string')) {
88
+ // Add their descriptions to the violation descriptions.
70
89
  messageStrings.push(... nextViolations);
71
90
  }
91
+ // Otherwise, i.e. if any reported violations are invalidly described:
72
92
  else {
93
+ // Report this.
73
94
  data.prevented = true;
74
95
  data.error = 'ERROR executing HTMLCS_RUNNER in the page';
75
96
  break;
76
97
  }
77
98
  }
99
+ // If no error was thrown:
78
100
  if (! data.prevented) {
79
101
  // Sort the violations by class and standard.
80
102
  messageStrings.sort();
81
103
  // Remove any duplicate violations.
82
104
  messageStrings = [... new Set(messageStrings)];
83
- // Initialize the result.
84
- result.Error = {};
85
- result.Warning = {};
86
105
  // For each violation:
87
106
  for (const string of messageStrings) {
88
107
  // Split its message into severity class, rule ID, tagname, ID, rule description, and excerpt.
89
108
  const parts = string.split(/\|/, 6);
90
109
  const partCount = parts.length;
110
+ // If the message partitions are too few:
91
111
  if (partCount < 6) {
112
+ // Report this.
92
113
  console.log(`ERROR: Violation string ${string} has too few parts`);
93
114
  }
94
- // If it is an error or a warning (not a notice):
95
- else if (['Error', 'Warning'].includes(parts[0])) {
96
- /*
97
- Add the violation to a violationClass.violationCode.description array in the result.
98
- This saves space, because, although some descriptions are violation-specific, such as
99
- descriptions that state the contrast ratio of an element, most descriptions are
100
- generic, so typically many violations share a description.
101
- */
102
- const ruleID = parts[1].replace(/^WCAG2|\.Principle\d\.Guideline[\d_]+/g, '');
103
- result[parts[0]][ruleID] ??= {};
104
- result[parts[0]][ruleID][parts[4]] ??= [];
105
- const elementLocation = await getElementData(page, parts[5]);
106
- const {boxID, notInDOM, pathID} = elementLocation;
107
- result[parts[0]][ruleID][parts[4]].push({
108
- tagName: parts[2],
109
- id: parts[3],
110
- notInDOM,
111
- excerpt: parts[5],
112
- boxID,
113
- pathID
114
- });
115
+ // Otherwise, if the message reports an error:
116
+ else if (parts[0] === 'Error') {
117
+ // Add the rest of its message to the native-result errors.
118
+ nativeResult.error.push(parts.slice(1));
119
+ // Increment the error total.
120
+ nativeResult.totals.failed++;
121
+ }
122
+ // Otherwise, if the message reports a warning:
123
+ else if (parts[0] === 'Warning') {
124
+ // Add the rest of its message to the native-result warnings.
125
+ nativeResult.warning.push(parts.slice(1));
126
+ // Increment the warning total.
127
+ nativeResult.totals.cantTell++;
128
+ }
129
+ // If standard results are to be reported:
130
+ if (standard) {
131
+ const instance = {
132
+ ruleID: parts[1],
133
+ what: parts[4],
134
+ ordinalSeverity: parts[0] === 'Warning' ? 0 : 2,
135
+ count: 1
136
+ };
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
+ standardResult.instances.push(instance);
115
144
  }
116
145
  }
146
+ standardResult.totals[0] = nativeResult.totals.cantTell;
147
+ standardResult.totals[2] = nativeResult.totals.failed;
117
148
  }
118
149
  return {
119
150
  data,
package/tests/ibm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  © 2021–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
- © 2025 Jonathan Robert Pool.
3
+ © 2025–2026 Jonathan Robert Pool.
4
4
 
5
5
  Licensed under the MIT License. See LICENSE file at the project root or
6
6
  https://opensource.org/license/mit/ for details.
@@ -20,7 +20,7 @@
20
20
 
21
21
  // IMPORTS
22
22
 
23
- // Scanner. Importing and executing 'close' crashed the Node process.
23
+ const {getAttributeXPath, getXPathCatalogIndex} = require('../procs/xPath');
24
24
  const accessibilityChecker = require('accessibility-checker');
25
25
  const {getCompliance} = accessibilityChecker;
26
26
 
@@ -121,17 +121,33 @@ exports.reporter = async (page, report, actIndex) => {
121
121
  const act = report.acts[actIndex];
122
122
  const {withItems, withNewContent, rules} = act;
123
123
  const contentType = withNewContent ? 'new' : 'existing';
124
+ // Initialize the act report.
125
+ const result = {
126
+ nativeResult: {},
127
+ standardResult: {}
128
+ };
129
+ const standard = report.standard !== 'no';
130
+ // If standard results are to be reported:
131
+ if (standard) {
132
+ // Initialize the standard result.
133
+ result.standardResult = {
134
+ prevented: false,
135
+ totals: [0, 0, 0, 0],
136
+ instances: []
137
+ };
138
+ }
124
139
  try {
125
140
  const typeContent = contentType === 'existing' ? page : page.url();
126
141
  // Conduct the tests.
127
142
  const runReport = await run(typeContent);
128
- const {report} = runReport;
143
+ const actReport = runReport.report;
129
144
  // If there were results:
130
- if (report) {
145
+ if (actReport) {
131
146
  // Trim them.
132
- const trimmedReport = trimActReport(report, withItems, rules);
133
- const {error} = trimmedReport;
134
- // If the report was not trimmable:
147
+ result.nativeResult = trimActReport(actReport, withItems, rules);
148
+ const {nativeResult, standardResult} = result;
149
+ const {error, totals} = nativeResult;
150
+ // If they were not trimmable:
135
151
  if (error) {
136
152
  // Return an act report with this error.
137
153
  return {
@@ -142,10 +158,39 @@ exports.reporter = async (page, report, actIndex) => {
142
158
  result: {}
143
159
  }
144
160
  }
145
- // Otherwise, i.e. if the report was trimmable, return it.
161
+ // Otherwise, i.e. if they were trimmable, and if standard results are to be reported:
162
+ if (standard) {
163
+ // Populate the totals of the standard result.
164
+ standardResult.totals = [totals.recommendation, 0, totals.violation, 0];
165
+ // For each item of the native result:
166
+ nativeResult.items.forEach(item => {
167
+ // Populate a standard instance.
168
+ const standardItem = {
169
+ ruleID: item.ruleId,
170
+ what: item.message,
171
+ ordinalSeverity: item.level === 'recommendation' ? 0 : 2,
172
+ count: 1
173
+ };
174
+ // Get the XPath from the added attribute, because path.dom is wrong.
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;
186
+ }
187
+ // Add the standard instance to the standard result.
188
+ standardResult.instances.push(standardItem);
189
+ });
190
+ }
146
191
  return {
147
192
  data: {},
148
- result: trimmedReport
193
+ result
149
194
  };
150
195
  }
151
196
  // Otherwise, i.e. if there was only an error, return it in an act report.
package/tests/nuVal.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /*
2
2
  © 2022–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
+ © 2026 Jonathan Robert Pool.
3
4
 
4
5
  Licensed under the MIT License. See LICENSE file at the project root or
5
6
  https://opensource.org/license/mit/ for details.
@@ -15,8 +16,8 @@
15
16
 
16
17
  // IMPORTS
17
18
 
18
- // Module to get the content.
19
19
  const {curate, getContent} = require('../procs/nu');
20
+ const {getAttributeXPath, getXPathCatalogIndex} = require('../procs/xPath');
20
21
 
21
22
  // FUNCTIONS
22
23
 
@@ -24,27 +25,44 @@ const {curate, getContent} = require('../procs/nu');
24
25
  exports.reporter = async (page, report, actIndex) => {
25
26
  const act = report.acts[actIndex];
26
27
  const {rules, withSource} = act;
27
- // Get the content and add it to the data.
28
- const data = await getContent(page, withSource);
29
- let result;
30
- // If it was obtained:
31
- if (data.testTarget) {
32
- let nuData;
28
+ // Initialize the act report.
29
+ const data = {};
30
+ const result = {
31
+ nativeResult: {},
32
+ standardResult: {}
33
+ };
34
+ const standard = report.standard !== 'no';
35
+ // If standard results are to be reported:
36
+ if (standard) {
37
+ // Initialize the standard result.
38
+ result.standardResult = {
39
+ prevented: false,
40
+ totals: [0, 0, 0, 0],
41
+ instances: []
42
+ };
43
+ }
44
+ const {standardResult} = result;
45
+ // Get the content.
46
+ const content = await getContent(page, withSource);
47
+ const {testTarget} = content;
48
+ // If it was obtained and contains a test target:
49
+ if (testTarget) {
33
50
  const fetchOptions = {
34
51
  method: 'post',
35
52
  headers: {
36
53
  'User-Agent': 'Mozilla/5.0',
37
54
  'Content-Type': 'text/html; charset=utf-8'
38
- }
55
+ },
56
+ body: testTarget
39
57
  };
40
58
  const nuURL = 'https://validator.w3.org/nu/?parser=html&out=json';
59
+ let nuData;
41
60
  try {
42
- fetchOptions.body = data.testTarget;
43
61
  // Get a Nu Html Checker report from the W3C validator service.
44
62
  nuResponse = await fetch(nuURL, fetchOptions);
45
63
  // If the acquisition succeeded:
46
64
  if (nuResponse.ok) {
47
- // Get the response body as JSON.
65
+ // Get the response body as an object.
48
66
  nuData = await nuResponse.json();
49
67
  }
50
68
  // Otherwise, i.e. if the request failed:
@@ -64,8 +82,43 @@ exports.reporter = async (page, report, actIndex) => {
64
82
  data.prevented = true;
65
83
  data.error = message;
66
84
  };
67
- // Postprocess the response data.
68
- result = await curate(page, data, nuData, rules);
85
+ // Postprocess the response data and add the postprocessed data to the native result.
86
+ result.nativeResult = await curate(data, nuData, rules);
87
+ // If standard results are to be reported:
88
+ if (standard) {
89
+ // For each message in the native result:
90
+ result.nativeResult.messages.forEach(message => {
91
+ const ordinalSeverity = message.type === 'info' ? 0 : 3;
92
+ // Increment the applicable standard-result total.
93
+ standardResult.totals[ordinalSeverity]++;
94
+ // Initialize a standard instance.
95
+ const standardInstance = {
96
+ ruleID: message.message,
97
+ what: message.message,
98
+ ordinalSeverity,
99
+ count: 1,
100
+ };
101
+ // Get the XPath of the element from its extract.
102
+ const xPath = getAttributeXPath(message.extract);
103
+ // If the acquisition succeeded:
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
+ // Add the standard instance to the standard result.
119
+ standardResult.instances.push(standardInstance);
120
+ })
121
+ }
69
122
  }
70
123
  // Otherwise, i.e. if the page content was not obtained:
71
124
  else {
package/tests/nuVnu.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  © 2022–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
- © 2025 Jonathan Robert Pool.
3
+ © 2025–2026 Jonathan Robert Pool.
4
4
 
5
5
  Licensed under the MIT License. See LICENSE file at the project root or
6
6
  https://opensource.org/license/mit/ for details.
@@ -16,14 +16,11 @@
16
16
 
17
17
  // IMPORTS
18
18
 
19
- // Module to perform file operations.
20
19
  const fs = require('fs/promises');
21
- // Module to define the operating-system temporary-file directory.
22
20
  const os = require('os');
23
- // Module to run tests.
24
21
  const {vnu} = require('vnu-jar');
25
- // Module to get the content.
26
22
  const {curate, getContent} = require('../procs/nu');
23
+ const {getAttributeXPath, getXPathCatalogIndex} = require('../procs/xPath');
27
24
 
28
25
  // CONSTANTS
29
26
 
@@ -33,6 +30,23 @@ const tmpDir = os.tmpdir();
33
30
 
34
31
  // Conducts and reports the Nu Html Checker tests.
35
32
  exports.reporter = async (page, report, actIndex) => {
33
+ // Initialize the act report.
34
+ const data = {};
35
+ const result = {
36
+ nativeResult: {},
37
+ standardResult: {}
38
+ };
39
+ const standard = report.standard !== 'no';
40
+ // If standard results are to be reported:
41
+ if (standard) {
42
+ // Initialize the standard result.
43
+ result.standardResult = {
44
+ prevented: false,
45
+ totals: [0, 0, 0, 0],
46
+ instances: []
47
+ };
48
+ }
49
+ const {standardResult} = result;
36
50
  // Get the nuVal act, if it exists.
37
51
  const nuValAct = report.acts.find(act => act.type === 'test' && act.which === 'nuVal');
38
52
  // If it does not exist or it exists but was prevented:
@@ -40,13 +54,13 @@ exports.reporter = async (page, report, actIndex) => {
40
54
  const act = report.acts[actIndex];
41
55
  const {rules, withSource} = act;
42
56
  // Get the content.
43
- const data = await getContent(page, withSource);
44
- let result;
45
- // If it was obtained:
46
- if (data.testTarget) {
57
+ const content = await getContent(page, withSource);
58
+ const {testTarget} = content;
59
+ // If it was obtained and contains a test target:
60
+ if (testTarget) {
47
61
  const pagePath = `${tmpDir}/nuVnu-page-${report.id}.html`;
48
- // Save it in a temporary file.
49
- await fs.writeFile(pagePath, data.testTarget);
62
+ // Save the test target in a temporary file.
63
+ await fs.writeFile(pagePath, testTarget);
50
64
  let nuData;
51
65
  try {
52
66
  // Get Nu Html Checker output on it.
@@ -56,7 +70,7 @@ exports.reporter = async (page, report, actIndex) => {
56
70
  catch (error) {
57
71
  const errorMessage = error.message;
58
72
  try {
59
- // Parse it as JSON, i.e. a benign nuVnu result with at least 1 violation.
73
+ // Parse it as JSON, i.e. a benign nuVnu result with at least 1 violation.
60
74
  nuData = JSON.parse(error.message);
61
75
  }
62
76
  // If parsing it as JSON fails:
@@ -68,14 +82,50 @@ exports.reporter = async (page, report, actIndex) => {
68
82
  }
69
83
  // Delete the temporary file.
70
84
  await fs.unlink(pagePath);
71
- // Postprocess the result.
72
- result = await curate(page, data, nuData, rules);
73
- return {
74
- data,
75
- result
76
- };
85
+ // Postprocess the output and add the postprocessed output to the native result.
86
+ result.nativeResult = await curate(data, nuData, rules);
87
+ // If standard results are to be reported:
88
+ if (standard) {
89
+ // For each message in the native result:
90
+ result.nativeResult.messages.forEach(message => {
91
+ const ordinalSeverity = message.type === 'info' ? 0 : 3;
92
+ // Increment the applicable standard-result total.
93
+ standardResult.totals[ordinalSeverity]++;
94
+ // Initialize a standard instance.
95
+ const standardInstance = {
96
+ ruleID: message.message,
97
+ what: message.message,
98
+ ordinalSeverity,
99
+ count: 1,
100
+ };
101
+ // Get the XPath of the element from its extract.
102
+ const xPath = getAttributeXPath(message.extract);
103
+ // If the acquisition succeeded:
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 ?? '';
122
+ }
123
+ // Add the standard instance to the standard result.
124
+ standardResult.instances.push(standardInstance);
125
+ });
126
+ }
77
127
  }
78
- // Otherwise, i.e. if the content was not obtained:
128
+ // Otherwise, i.e. if the content was not obtained or contains no test target:
79
129
  else {
80
130
  // Report this.
81
131
  data.prevented = true;
@@ -85,12 +135,12 @@ exports.reporter = async (page, report, actIndex) => {
85
135
  // Otherwise, i.e. if the nuVal act exists and succeeded:
86
136
  else {
87
137
  // Abort this act and report this.
88
- return {
89
- data: {
90
- skipped: true,
91
- reason: 'nuVal succeeded'
92
- },
93
- result: {}
94
- };
138
+ data.skipped = true;
139
+ data.reason = 'nuVal succeeded';
95
140
  }
141
+ // Return the data and result.
142
+ return {
143
+ data,
144
+ result
145
+ };
96
146
  };