testaro 60.13.0 → 60.15.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 (201) hide show
  1. package/AGENTS.md +6 -2
  2. package/CONTRIBUTING.md +9 -24
  3. package/LICENSE +1 -1
  4. package/README.md +7 -24
  5. package/UPGRADES.md +13 -28
  6. package/VALIDATION_README.md +7 -24
  7. package/aceconfig.js +3 -18
  8. package/actSpecs.js +4 -19
  9. package/call.js +3 -18
  10. package/data/template.js +3 -18
  11. package/dirWatch.js +3 -18
  12. package/netWatch.js +4 -19
  13. package/package.json +2 -1
  14. package/procs/aslint.js +3 -18
  15. package/procs/dateOf.js +3 -18
  16. package/procs/doTestAct.js +4 -19
  17. package/procs/getLocatorData.js +3 -18
  18. package/procs/getSource.js +3 -18
  19. package/procs/identify.js +3 -18
  20. package/procs/isInlineLink.js +5 -19
  21. package/procs/job.js +3 -18
  22. package/procs/sample.js +3 -18
  23. package/procs/screenShot.js +1 -1
  24. package/procs/shoot.js +1 -1
  25. package/procs/standardize.js +4 -19
  26. package/procs/target.js +4 -19
  27. package/procs/tellServer.js +3 -18
  28. package/procs/testaro.js +5 -19
  29. package/procs/visChange.js +4 -19
  30. package/pw-aslint-claude.js +1 -1
  31. package/run.js +9 -23
  32. package/scripts/dumpAlts.js +4 -19
  33. package/testaro/adbID.js +5 -20
  34. package/testaro/allCaps.js +4 -19
  35. package/testaro/allHidden.js +4 -19
  36. package/testaro/allSlanted.js +4 -19
  37. package/testaro/altScheme.js +5 -20
  38. package/testaro/attVal.js +3 -18
  39. package/testaro/autocomplete.js +4 -19
  40. package/testaro/bulk.js +4 -19
  41. package/testaro/buttonMenu.js +4 -19
  42. package/testaro/captionLoc.js +5 -20
  43. package/testaro/datalistRef.js +5 -20
  44. package/testaro/distortion.js +4 -19
  45. package/testaro/docType.js +3 -18
  46. package/testaro/dupAtt.js +3 -18
  47. package/testaro/elements.js +3 -18
  48. package/testaro/embAc.js +3 -18
  49. package/testaro/focAll.js +4 -19
  50. package/testaro/focAndOp.js +4 -19
  51. package/testaro/focInd.js +4 -19
  52. package/testaro/focVis.js +4 -19
  53. package/testaro/headEl.js +4 -19
  54. package/testaro/headingAmb.js +3 -18
  55. package/testaro/hovInd.js +4 -19
  56. package/testaro/hover.js +6 -21
  57. package/testaro/imageLink.js +4 -19
  58. package/testaro/labClash.js +29 -48
  59. package/testaro/legendLoc.js +4 -19
  60. package/testaro/lineHeight.js +4 -19
  61. package/testaro/linkAmb.js +67 -54
  62. package/testaro/linkTitle.js +4 -19
  63. package/testaro/linkUl.js +4 -19
  64. package/testaro/miniText.js +5 -20
  65. package/testaro/motion.js +2 -2
  66. package/testaro/motionSolo.js +4 -19
  67. package/testaro/nonTable.js +4 -19
  68. package/testaro/optRoleSel.js +4 -19
  69. package/testaro/phOnly.js +27 -52
  70. package/testaro/pseudoP.json +10 -0
  71. package/testaro/radioSet.js +60 -107
  72. package/testaro/role.js +25 -80
  73. package/testaro/secHeading.js +40 -45
  74. package/testaro/shoot0.js +1 -1
  75. package/testaro/shoot1.js +1 -1
  76. package/testaro/styleDiff.js +3 -18
  77. package/testaro/tabNav.js +4 -19
  78. package/testaro/targetSmall.js +4 -19
  79. package/testaro/targetTiny.js +4 -19
  80. package/testaro/textNodes.js +3 -18
  81. package/testaro/textSem.js +4 -19
  82. package/testaro/title.js +3 -18
  83. package/testaro/zIndex.js +3 -18
  84. package/tests/alfa.js +4 -19
  85. package/tests/aslint.js +4 -19
  86. package/tests/axe.js +4 -19
  87. package/tests/ed11y.js +4 -19
  88. package/tests/htmlcs.js +3 -18
  89. package/tests/ibm.js +4 -19
  90. package/tests/nuVal.js +3 -18
  91. package/tests/qualWeb.js +3 -18
  92. package/tests/testaro.js +7 -22
  93. package/tests/wave.js +3 -18
  94. package/tests/wax.js +4 -19
  95. package/validation/done/README.md +8 -23
  96. package/validation/executors/dirWatch.js +4 -19
  97. package/validation/executors/netWatch.js +3 -18
  98. package/validation/executors/run.js +3 -18
  99. package/validation/executors/test.js +3 -18
  100. package/validation/executors/tests.js +3 -18
  101. package/validation/jobs/done/README.md +9 -0
  102. package/validation/jobs/todo/README.md +3 -16
  103. package/validation/tests/targets/adbID/index.html +3 -18
  104. package/validation/tests/targets/allCaps/index.html +3 -18
  105. package/validation/tests/targets/allHidden/ariaHiddenBody.html +3 -18
  106. package/validation/tests/targets/allHidden/good.html +3 -18
  107. package/validation/tests/targets/allHidden/hiddenMain.html +3 -18
  108. package/validation/tests/targets/allHidden/mixedHidden.html +3 -18
  109. package/validation/tests/targets/allHidden/noBody.html +4 -19
  110. package/validation/tests/targets/allHidden/noMain.html +4 -19
  111. package/validation/tests/targets/allHidden/noneDoc.html +3 -18
  112. package/validation/tests/targets/allHidden/visHiddenMain.html +3 -18
  113. package/validation/tests/targets/allSlanted/index.html +3 -18
  114. package/validation/tests/targets/altScheme/index.html +3 -18
  115. package/validation/tests/targets/attVal/bad.html +3 -18
  116. package/validation/tests/targets/attVal/good.html +3 -18
  117. package/validation/tests/targets/autocomplete/bad.html +3 -18
  118. package/validation/tests/targets/autocomplete/good.html +3 -18
  119. package/validation/tests/targets/bulk/bad.html +3 -18
  120. package/validation/tests/targets/bulk/good.html +3 -18
  121. package/validation/tests/targets/buttonMenu/bad.html +3 -18
  122. package/validation/tests/targets/buttonMenu/bad.js +3 -18
  123. package/validation/tests/targets/buttonMenu/good.html +3 -18
  124. package/validation/tests/targets/buttonMenu/good.js +3 -18
  125. package/validation/tests/targets/buttonMenu/style.css +3 -18
  126. package/validation/tests/targets/captionLoc/index.html +3 -18
  127. package/validation/tests/targets/datalistRef/index.html +3 -18
  128. package/validation/tests/targets/distortion/index.html +3 -18
  129. package/validation/tests/targets/docType/bad.html +3 -18
  130. package/validation/tests/targets/docType/good.html +3 -18
  131. package/validation/tests/targets/dupAtt/bad.html +3 -18
  132. package/validation/tests/targets/dupAtt/good.html +3 -18
  133. package/validation/tests/targets/elements/index.html +3 -18
  134. package/validation/tests/targets/embAc/bad.html +3 -18
  135. package/validation/tests/targets/embAc/good.html +3 -18
  136. package/validation/tests/targets/focAll/good.html +3 -18
  137. package/validation/tests/targets/focAll/less.html +3 -18
  138. package/validation/tests/targets/focAll/more.html +3 -18
  139. package/validation/tests/targets/focInd/bad.html +4 -19
  140. package/validation/tests/targets/focInd/good.html +3 -18
  141. package/validation/tests/targets/focOp/bad.html +3 -18
  142. package/validation/tests/targets/focOp/good.html +3 -18
  143. package/validation/tests/targets/focVis/index.html +3 -18
  144. package/validation/tests/targets/headEl/index.html +3 -18
  145. package/validation/tests/targets/headingAmb/index.html +3 -18
  146. package/validation/tests/targets/hovInd/index.html +4 -19
  147. package/validation/tests/targets/hover/bad.html +3 -18
  148. package/validation/tests/targets/hover/good.html +3 -18
  149. package/validation/tests/targets/hr/index.html +3 -18
  150. package/validation/tests/targets/imageLink/index.html +3 -18
  151. package/validation/tests/targets/labClash/bad.html +3 -18
  152. package/validation/tests/targets/labClash/good.html +3 -18
  153. package/validation/tests/targets/legendLoc/index.html +3 -18
  154. package/validation/tests/targets/lineHeight/index.html +3 -18
  155. package/validation/tests/targets/linkAmb/index.html +5 -20
  156. package/validation/tests/targets/linkExt/index.html +3 -18
  157. package/validation/tests/targets/linkOldAtt/index.html +3 -18
  158. package/validation/tests/targets/linkTitle/index.html +3 -18
  159. package/validation/tests/targets/linkTo/index.html +3 -18
  160. package/validation/tests/targets/linkUl/bad.html +4 -19
  161. package/validation/tests/targets/linkUl/good.html +4 -19
  162. package/validation/tests/targets/linkUl/na.html +4 -19
  163. package/validation/tests/targets/miniText/index.html +3 -18
  164. package/validation/tests/targets/motion/bad.css +3 -18
  165. package/validation/tests/targets/motion/bad.html +3 -18
  166. package/validation/tests/targets/motion/good.html +3 -18
  167. package/validation/tests/targets/nonTable/index.html +3 -18
  168. package/validation/tests/targets/opFoc/bad.html +3 -18
  169. package/validation/tests/targets/opFoc/good.html +3 -18
  170. package/validation/tests/targets/optRoleSel/index.html +3 -18
  171. package/validation/tests/targets/phOnly/index.html +4 -19
  172. package/validation/tests/targets/pseudoP/index.html +3 -18
  173. package/validation/tests/targets/radioSet/bad.html +3 -18
  174. package/validation/tests/targets/radioSet/good.html +3 -18
  175. package/validation/tests/targets/role/bad.html +4 -19
  176. package/validation/tests/targets/role/good.html +3 -18
  177. package/validation/tests/targets/secHeading/index.html +7 -22
  178. package/validation/tests/targets/styleDiff/bad.html +3 -18
  179. package/validation/tests/targets/styleDiff/good.html +3 -18
  180. package/validation/tests/targets/tabNav/bad.html +3 -18
  181. package/validation/tests/targets/tabNav/bad.js +3 -18
  182. package/validation/tests/targets/tabNav/good.html +3 -18
  183. package/validation/tests/targets/tabNav/good.js +3 -18
  184. package/validation/tests/targets/tabNav/style.css +3 -18
  185. package/validation/tests/targets/targetSize/index.html +4 -19
  186. package/validation/tests/targets/textNodes/index.html +3 -18
  187. package/validation/tests/targets/textSem/index.html +3 -18
  188. package/validation/tests/targets/title/bad.html +3 -18
  189. package/validation/tests/targets/title/good.html +3 -18
  190. package/validation/tests/targets/titledEl/index.html +3 -18
  191. package/validation/tests/targets/zIndex/bad.html +3 -18
  192. package/validation/tests/targets/zIndex/good.html +3 -18
  193. package/validation/validateTest.js +4 -19
  194. package/validation/watch/done/README.md +5 -20
  195. package/validation/watch/todo/README.md +5 -20
  196. package/testaro/hover-draft0.js +0 -110
  197. package/testaro/hover-draft1.js +0 -185
  198. package/testaro/hover-draft2.js +0 -183
  199. package/testaro/hover-draft3.js +0 -143
  200. package/testaro/hover-orig.js +0 -109
  201. package/testaro/pseudoP.js +0 -66
@@ -1,26 +1,11 @@
1
1
  /*
2
2
  © 2023–2025 CVS Health and/or one of its affiliates. All rights reserved.
3
- © 2025 Jonathan Robert Pool. All rights reserved.
3
+ © 2025 Jonathan Robert Pool.
4
4
 
5
- MIT License
5
+ Licensed under the MIT License. See LICENSE file at the project root or
6
+ https://opensource.org/license/mit/ for details.
6
7
 
7
- Permission is hereby granted, free of charge, to any person obtaining a copy
8
- of this software and associated documentation files (the "Software"), to deal
9
- in the Software without restriction, including without limitation the rights
10
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- copies of the Software, and to permit persons to whom the Software is
12
- furnished to do so, subject to the following conditions:
13
-
14
- The above copyright notice and this permission notice shall be included in all
15
- copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- SOFTWARE.
8
+ SPDX-License-Identifier: MIT
24
9
  */
25
10
 
26
11
  /*
@@ -30,46 +15,74 @@
30
15
  Text contents are compared case-insensitively.
31
16
  */
32
17
 
18
+ // IMPORTS
19
+
33
20
  // Module to perform common operations.
34
- const {init, getRuleResult} = require('../procs/testaro');
35
- // Module to get locator data.
36
- const {getLocatorData} = require('../procs/getLocatorData');
21
+ const {getBasicResult} = require('../procs/testaro');
37
22
 
38
- // ########## FUNCTIONS
23
+ // FUNCTIONS
39
24
 
40
25
  // Runs the test and returns the result.
41
26
  exports.reporter = async (page, withItems) => {
42
- // Initialize the locators and result.
43
- const all = await init(100, page, 'a[href]:visible');
44
- const linksData = [];
45
- // For each locator:
46
- for (const loc of all.allLocs) {
47
- // Get its text.
48
- const elData = await getLocatorData(loc);
49
- const linkText = elData.excerpt.toLowerCase();
50
- // Get its destination.
51
- const linkTo = await loc.getAttribute('href');
52
- // If the text and destination exist:
53
- if (linkText && linkTo) {
54
- // If a previous link has the same text but a different destination:
55
- if (linksData.some(linkData => linkData.text === linkText && linkData.to !== linkTo)) {
56
- // Add the locator to the array of violators.
57
- all.locs.push(loc);
58
- }
59
- // Otherwise, i.e. if no previous link has the same taxt but a different destination:
60
- else {
61
- // Record its text and destination.
62
- linksData.push({
63
- text: linkText,
64
- to: linkTo
65
- });
27
+ // Return totals and standard instances for the rule.
28
+ return await page.evaluate(withItems => {
29
+ // Get all links.
30
+ const allLinks = Array.from(document.body.getElementsByTagName('a'));
31
+ // Get the visible ones.
32
+ const visibleLinks = allLinks.filter(link => link.checkVisibility({
33
+ contentVisibilityAuto: true,
34
+ opacityProperty: true,
35
+ visibilityProperty: true
36
+ }));
37
+ // Initialize the data.
38
+ const linksData = {
39
+ elementData: [],
40
+ textTotals: {}
41
+ };
42
+ // For each visible link:
43
+ visibleLinks.forEach(element => {
44
+ // Get its trimmed and lowercased text.
45
+ const text = element.textContent.trim().toLowerCase();
46
+ // Get its destination.
47
+ const href = element.getAttribute('href');
48
+ // Add to the data.
49
+ linksData.elementData.push([text, href]);
50
+ linksData.textTotals[text] ??= {
51
+ linkCount: 0,
52
+ hrefs: new Set()
53
+ };
54
+ const linkData = linksData.textTotals[text];
55
+ linkData.linkCount++;
56
+ linkData.hrefs.add(href);
57
+ });
58
+ let violationCount = 0;
59
+ const instances = [];
60
+ // For each visible link:
61
+ visibleLinks.forEach((element, index) => {
62
+ const text = linksData.elementData[index][0];
63
+ const {linkCount, hrefs} = linksData.textTotals[text];
64
+ // If it violates the rule:
65
+ if (hrefs.size > 1) {
66
+ // Increment the violation count.
67
+ violationCount++;
68
+ // If itemization is required:
69
+ if (withItems) {
70
+ const what = `${linkCount} links with this text have ${hrefs.size} different destinations`;
71
+ // Add an instance to the instances.
72
+ instances.push(window.getInstance(element, 'linkAmb', what, 1, 2));
73
+ }
66
74
  }
75
+ });
76
+ // If there were any violations and itemization is not required:
77
+ if (violationCount && ! withItems) {
78
+ const what = 'Links have the same text but different destinations';
79
+ // Add a summary instance to the instances.
80
+ instances.push(window.getInstance(null, 'linkAmb', what, violationCount, 2, 'A'));
67
81
  }
68
- }
69
- // Populate and return the result.
70
- const whats = [
71
- 'Link has the same text as, but a different destination from, another',
72
- 'Links have the same texts but different destinations'
73
- ];
74
- return await getRuleResult(withItems, all, 'linkAmb', whats, 2);
82
+ return {
83
+ data: {},
84
+ totals: [0, 0, violationCount, 0],
85
+ standardInstances: instances
86
+ };
87
+ }, withItems);
75
88
  };
@@ -1,26 +1,11 @@
1
1
  /*
2
2
  © 2023 CVS Health and/or one of its affiliates. All rights reserved.
3
- © 2025 Jonathan Robert Pool. All rights reserved.
3
+ © 2025 Jonathan Robert Pool.
4
4
 
5
- MIT License
5
+ Licensed under the MIT License. See LICENSE file at the project root or
6
+ https://opensource.org/license/mit/ for details.
6
7
 
7
- Permission is hereby granted, free of charge, to any person obtaining a copy
8
- of this software and associated documentation files (the "Software"), to deal
9
- in the Software without restriction, including without limitation the rights
10
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- copies of the Software, and to permit persons to whom the Software is
12
- furnished to do so, subject to the following conditions:
13
-
14
- The above copyright notice and this permission notice shall be included in all
15
- copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- SOFTWARE.
8
+ SPDX-License-Identifier: MIT
24
9
  */
25
10
 
26
11
  /*
package/testaro/linkUl.js CHANGED
@@ -1,26 +1,11 @@
1
1
  /*
2
2
  © 2021–2023 CVS Health and/or one of its affiliates. All rights reserved.
3
- © 2025 Jonathan Robert Pool. All rights reserved.
3
+ © 2025 Jonathan Robert Pool.
4
4
 
5
- MIT License
5
+ Licensed under the MIT License. See LICENSE file at the project root or
6
+ https://opensource.org/license/mit/ for details.
6
7
 
7
- Permission is hereby granted, free of charge, to any person obtaining a copy
8
- of this software and associated documentation files (the "Software"), to deal
9
- in the Software without restriction, including without limitation the rights
10
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- copies of the Software, and to permit persons to whom the Software is
12
- furnished to do so, subject to the following conditions:
13
-
14
- The above copyright notice and this permission notice shall be included in all
15
- copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- SOFTWARE.
8
+ SPDX-License-Identifier: MIT
24
9
  */
25
10
 
26
11
  /*
@@ -1,26 +1,11 @@
1
1
  /*
2
2
  © 2022–2023 CVS Health and/or one of its affiliates. All rights reserved.
3
- © 2025 Jonathan Robert Pool. All rights reserved.
3
+ © 2025 Jonathan Robert Pool.
4
4
 
5
- MIT License
5
+ Licensed under the MIT License. See LICENSE file at the project root or
6
+ https://opensource.org/license/mit/ for details.
6
7
 
7
- Permission is hereby granted, free of charge, to any person obtaining a copy
8
- of this software and associated documentation files (the "Software"), to deal
9
- in the Software without restriction, including without limitation the rights
10
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- copies of the Software, and to permit persons to whom the Software is
12
- furnished to do so, subject to the following conditions:
13
-
14
- The above copyright notice and this permission notice shall be included in all
15
- copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- SOFTWARE.
8
+ SPDX-License-Identifier: MIT
24
9
  */
25
10
 
26
11
  /*
@@ -62,6 +47,6 @@ exports.reporter = async (page, withItems) => {
62
47
  };
63
48
  const whats = 'Visible elements have font sizes smaller than 11 pixels';
64
49
  return await doTest(
65
- page, withItems, 'miniText', 'body *:not(script, style)', whats, 2, '', getBadWhat.toString()
50
+ page, withItems, 'miniText', 'body *:not(script, style)', whats, 2, null, getBadWhat.toString()
66
51
  );
67
52
  };
package/testaro/motion.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- © 2025 Jonathan Robert Pool. All rights reserved.
2
+ © 2025 Jonathan Robert Pool.
3
3
  Licensed under the MIT License. See LICENSE for details.
4
4
  */
5
5
 
@@ -45,7 +45,7 @@ exports.reporter = async page => {
45
45
  // Get the screenshot PNG buffers made by the shoot0 and shoot1 tests.
46
46
  let shoot0PNGBuffer = await fs.readFile(`${tmpDir}/testaro-shoot-0.png`);
47
47
  let shoot1PNGBuffer = await fs.readFile(`${tmpDir}/testaro-shoot-1.png`);
48
- // Delete the buffers files.
48
+ // Delete the buffer files.
49
49
  await fs.unlink(`${tmpDir}/testaro-shoot-0.png`);
50
50
  await fs.unlink(`${tmpDir}/testaro-shoot-1.png`);
51
51
  // If both buffers exist:
@@ -1,26 +1,11 @@
1
1
  /*
2
2
  © 2021–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
- © 2025 Jonathan Robert Pool. All rights reserved.
3
+ © 2025 Jonathan Robert Pool.
4
4
 
5
- MIT License
5
+ Licensed under the MIT License. See LICENSE file at the project root or
6
+ https://opensource.org/license/mit/ for details.
6
7
 
7
- Permission is hereby granted, free of charge, to any person obtaining a copy
8
- of this software and associated documentation files (the "Software"), to deal
9
- in the Software without restriction, including without limitation the rights
10
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- copies of the Software, and to permit persons to whom the Software is
12
- furnished to do so, subject to the following conditions:
13
-
14
- The above copyright notice and this permission notice shall be included in all
15
- copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- SOFTWARE.
8
+ SPDX-License-Identifier: MIT
24
9
  */
25
10
 
26
11
  /*
@@ -1,26 +1,11 @@
1
1
  /*
2
2
  © 2022–2023 CVS Health and/or one of its affiliates. All rights reserved.
3
- © 2025 Jonathan Robert Pool. All rights reserved.
3
+ © 2025 Jonathan Robert Pool.
4
4
 
5
- MIT License
5
+ Licensed under the MIT License. See LICENSE file at the project root or
6
+ https://opensource.org/license/mit/ for details.
6
7
 
7
- Permission is hereby granted, free of charge, to any person obtaining a copy
8
- of this software and associated documentation files (the "Software"), to deal
9
- in the Software without restriction, including without limitation the rights
10
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- copies of the Software, and to permit persons to whom the Software is
12
- furnished to do so, subject to the following conditions:
13
-
14
- The above copyright notice and this permission notice shall be included in all
15
- copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- SOFTWARE.
8
+ SPDX-License-Identifier: MIT
24
9
  */
25
10
 
26
11
  /*
@@ -1,26 +1,11 @@
1
1
  /*
2
2
  © 2025 CVS Health and/or one of its affiliates. All rights reserved.
3
- © 2025 Juan S. Casado. All rights reserved.
3
+ © 2025 Juan S. Casado.
4
4
 
5
- MIT License
5
+ Licensed under the MIT License. See LICENSE file at the project root or
6
+ https://opensource.org/license/mit/ for details.
6
7
 
7
- Permission is hereby granted, free of charge, to any person obtaining a copy
8
- of this software and associated documentation files (the "Software"), to deal
9
- in the Software without restriction, including without limitation the rights
10
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- copies of the Software, and to permit persons to whom the Software is
12
- furnished to do so, subject to the following conditions:
13
-
14
- The above copyright notice and this permission notice shall be included in all
15
- copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- SOFTWARE.
8
+ SPDX-License-Identifier: MIT
24
9
  */
25
10
 
26
11
  /*
package/testaro/phOnly.js CHANGED
@@ -1,66 +1,41 @@
1
1
  /*
2
2
  © 2025 CVS Health and/or one of its affiliates. All rights reserved.
3
- © 2025 Juan S. Casado. All rights reserved.
3
+ © 2025 Juan S. Casado.
4
+ © 2025 Jonathan Robert Pool.
4
5
 
5
- MIT License
6
+ Licensed under the MIT License. See LICENSE file at the project root or
7
+ https://opensource.org/license/mit/ for details.
6
8
 
7
- Permission is hereby granted, free of charge, to any person obtaining a copy
8
- of this software and associated documentation files (the "Software"), to deal
9
- in the Software without restriction, including without limitation the rights
10
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- copies of the Software, and to permit persons to whom the Software is
12
- furnished to do so, subject to the following conditions:
13
-
14
- The above copyright notice and this permission notice shall be included in all
15
- copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- SOFTWARE.
9
+ SPDX-License-Identifier: MIT
24
10
  */
25
11
 
26
12
  /*
27
13
  phOnly
28
- Clean-room rule: input elements that have a placeholder but no accessible name (no label/title/aria-label/aria-labelledby)
14
+ Clean-room rule: This test reports input elements that have placeholders but no accessible names.
15
+ The standard for accessible name computation is employed; it accepts title attributes as
16
+ sources for accessible names. Thus, this test does not report reliance on title attributes for
17
+ accessible names, although such reliance is generally considered a poor practice.
29
18
  */
30
19
 
31
- const {init, getRuleResult} = require('../procs/testaro');
20
+ // IMPORTS
32
21
 
33
- const hasAccessibleName = async (loc) => {
34
- return await loc.evaluate(el => {
35
- // Quick accessible name checks: aria-label, aria-labelledby, associated <label>
36
- // NOTE: `title` is intentionally NOT considered a reliable accessible name here
37
- // because the validation targets expect placeholders with title attributes to be flagged.
38
- if (el.hasAttribute('aria-label')) return true;
39
- if (el.hasAttribute('aria-labelledby')) return true;
40
- // check for label[for]
41
- const id = el.getAttribute('id');
42
- if (id) {
43
- if (document.querySelector(`label[for="${CSS.escape(id)}"]`)) return true;
44
- }
45
- // check implicit ancestor label
46
- let parent = el.parentElement;
47
- while (parent) {
48
- if (parent.tagName && parent.tagName.toUpperCase() === 'LABEL') return true;
49
- parent = parent.parentElement;
50
- }
51
- return false;
52
- });
53
- };
22
+ const {doTest} = require('../procs/testaro');
23
+
24
+ // FUNCTIONS
54
25
 
26
+ // Runs the test and returns the result.
55
27
  exports.reporter = async (page, withItems) => {
56
- const all = await init(200, page, 'input[placeholder]');
57
- for (const loc of all.allLocs) {
58
- const isBad = await hasAccessibleName(loc).then(has => !has);
59
- if (isBad) all.locs.push(loc);
60
- }
61
- const whats = [
62
- 'Element has a placeholder but no accessible name',
63
- 'input elements have placeholders but no accessible names'
64
- ];
65
- return await getRuleResult(withItems, all, 'phOnly', whats, 2, 'INPUT');
28
+ const getBadWhat = element => {
29
+ // Get the accessible name of the element.
30
+ const accessibleName = window.getAccessibleName(element);
31
+ // If there is none:
32
+ if (! accessibleName) {
33
+ // Return a violation description.
34
+ return 'Element has a placeholder but no accessible name';
35
+ }
36
+ };
37
+ const whats = 'input elements have placeholders but no accessible names';
38
+ return await doTest(
39
+ page, withItems, 'phOnly', 'input[placeholder]', whats, 2, 'INPUT', getBadWhat.toString()
40
+ );
66
41
  };
@@ -0,0 +1,10 @@
1
+ {
2
+ "ruleID": "pseudoP",
3
+ "selector": "body br + br",
4
+ "complaints": {
5
+ "instance": "br element follows another br element, likely acting as a pseudo-paragraph",
6
+ "summary": "br elements follow other br elements, likely acting as pseudo-paragraphs"
7
+ },
8
+ "ordinalSeverity": 0,
9
+ "summaryTagName": "BR"
10
+ }
@@ -1,124 +1,77 @@
1
1
  /*
2
2
  © 2021–2023 CVS Health and/or one of its affiliates. All rights reserved.
3
+ © 2025 Jonathan Robert Pool.
3
4
 
4
- MIT License
5
+ Licensed under the MIT License. See LICENSE file at the project root or
6
+ https://opensource.org/license/mit/ for details.
5
7
 
6
- Permission is hereby granted, free of charge, to any person obtaining a copy
7
- of this software and associated documentation files (the "Software"), to deal
8
- in the Software without restriction, including without limitation the rights
9
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- copies of the Software, and to permit persons to whom the Software is
11
- furnished to do so, subject to the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be included in all
14
- copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- SOFTWARE.
8
+ SPDX-License-Identifier: MIT
23
9
  */
24
10
 
25
11
  /*
26
12
  radioSet
27
- This test reports nonstandard grouping of radio buttons. It defines standard grouping to require
28
- that two or more radio buttons with the same name, and no other radio buttons, be grouped in a
29
- 'fieldset' element with a valid 'legend' element.
13
+ This test reports nonstandard groupings of radio buttons. It defines a standard grouping to
14
+ require that two or more radio buttons with the same name, and no other radio buttons, be grouped
15
+ in a fieldset element with a valid legend element.
30
16
  */
31
17
 
32
- // ########## IMPORTS
18
+ // IMPORTS
33
19
 
34
- // Module to perform common operations.
35
- const {init, getRuleResult} = require('../procs/testaro');
20
+ const {doTest} = require('../procs/testaro');
36
21
 
37
- // ########## FUNCTIONS
22
+ // FUNCTIONS
38
23
 
39
24
  // Runs the test and returns the result.
40
25
  exports.reporter = async (page, withItems) => {
41
- // Initialize the locators and result.
42
- const all = await init(100, page, 'input[type=radio]');
43
- const params = {
44
- nameLeak: 'shares a name with others outside its field set',
45
- fsMixed: 'shares a field set with others having different names',
46
- only1RB: 'is the only one with its name in its field set',
47
- legendBad: 'is in a field set without a valid legend',
48
- noFS: 'is not in a field set',
49
- noName: 'has no name attribute'
50
- };
51
- // For each locator:
52
- for (const loc of all.allLocs) {
53
- // Get whether and, if so, how it violates the rule.
54
- const howBad = await loc.evaluate(el => {
55
- // Get its name.
56
- const elName = el.name;
57
- // If it has one:
58
- if (elName) {
59
- // Identify the field set of the element.
60
- const elFS = el.closest('fieldset');
61
- // If it has one:
62
- if (elFS) {
63
- // Get the first child element of the field set.
64
- const fsChild1 = elFS.firstElementChild;
65
- // Get whether the child is a legend with text content.
66
- const legendOK = fsChild1.tagName === 'LEGEND'
67
- && fsChild1.textContent.replace(/\s/g, '').length;
68
- // If it is:
69
- if (legendOK) {
70
- // Get the count of radio buttons with the same name in the field set.
71
- const nameGroupSize = elFS
72
- .querySelectorAll(`input[type=radio][name=${elName}]`)
73
- .length;
74
- // If the count is at least 2:
75
- if (nameGroupSize > 1) {
76
- // Get the count of radio buttons in the field set.
77
- const groupSize = elFS.querySelectorAll('input[type=radio]').length;
78
- // If it is the same:
79
- if (groupSize === nameGroupSize) {
80
- // Get the count of radio buttons with the same name in the document.
81
- const nameDocSize = document
82
- .querySelectorAll(`input[type=radio][name=${elName}]`)
83
- .length;
84
- // If none of them is outside the field set:
85
- if (nameDocSize === nameGroupSize) {
86
- // Return rule conformance.
87
- return false;
88
- }
89
- else {
90
- return 'nameLeak';
91
- }
92
- }
93
- else {
94
- return 'fsMixed';
95
- }
96
- }
97
- else {
98
- return 'only1RB';
99
- }
100
- }
101
- else {
102
- return 'legendBad';
103
- }
104
- }
105
- else {
106
- return 'noFS';
107
- }
108
- }
109
- else {
110
- return 'noName';
111
- }
112
- });
113
- // If it does:
114
- if (howBad) {
115
- // Add the locator to the array of violators.
116
- all.locs.push([loc, params[howBad]]);
26
+ const getBadWhat = element => {
27
+ // Get the name of the element.
28
+ const elName = element.name;
29
+ // If it has none:
30
+ if (! elName) {
31
+ // Return a violation description.
32
+ return 'radio button has no name attribute';
33
+ }
34
+ // Identify the field set of the element.
35
+ const elFS = element.closest('fieldset');
36
+ // If it has none:
37
+ if (! elFS) {
38
+ // Return a violation description.
39
+ return 'radio button is not in a field set';
40
+ }
41
+ // Get the first child element of the field set.
42
+ const fsChild1 = elFS.firstElementChild;
43
+ // Get whether the child is a legend with text content.
44
+ const legendOK = fsChild1.tagName === 'LEGEND'
45
+ && fsChild1.textContent.replace(/\s/g, '').length;
46
+ // If it is not:
47
+ if (! legendOK) {
48
+ // Return a violation description.
49
+ return 'radio button is in a field set without a valid legend';
117
50
  }
118
- }
119
- // Populate and return the result.
120
- const whats = [
121
- 'Radio button __param__', 'Radio buttons are not validly grouped in fieldsets with legends'
122
- ];
123
- return await getRuleResult(withItems, all, 'radioSet', whats, 2, 'INPUT');
51
+ // Get the count of radio buttons with the same name in the field set.
52
+ const nameGroupSize = elFS.querySelectorAll(`input[type=radio][name=${elName}]`).length;
53
+ // If the count is only 1:
54
+ if (nameGroupSize === 1) {
55
+ // Return a violation description.
56
+ return 'radio button is the only one with its name in its field set';
57
+ }
58
+ // Get the count of radio buttons in the field set.
59
+ const groupSize = elFS.querySelectorAll('input[type=radio]').length;
60
+ // If it is greater than the count of radio buttons with the same name in the field set:
61
+ if (groupSize > nameGroupSize) {
62
+ // Return a violation description.
63
+ return 'radio button shares a field set with differently named others';
64
+ }
65
+ // Get the count of radio buttons with the same name in the document.
66
+ const nameDocSize = document.querySelectorAll(`input[type=radio][name=${elName}]`).length;
67
+ // If it is greater, and thus some such radio button is outside the field set:
68
+ if (nameDocSize > nameGroupSize) {
69
+ // Return a violation description.
70
+ return 'radio button shares a name with others outside its field set';
71
+ }
72
+ };
73
+ const whats = 'Radio buttons are not validly grouped in fieldsets with legends';
74
+ return await doTest(
75
+ page, withItems, 'radioSet', 'input[type=radio]', whats, 2, 'INPUT', getBadWhat.toString()
76
+ );
124
77
  };