testaro 78.0.8 → 78.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/.gitattributes +94 -0
  2. package/.github/workflows/ci.yml +58 -0
  3. package/.github/workflows/publish.yml +49 -0
  4. package/.github/workflows/typescript.yml +35 -0
  5. package/AGENTS.md +2 -2
  6. package/CLAUDE.md +24 -18
  7. package/CONTAINERS.md +9 -6
  8. package/CONTRIBUTING.md +29 -3
  9. package/Dockerfile +1 -1
  10. package/README.md +73 -19
  11. package/UPGRADES.md +4 -0
  12. package/actSpecs-doc.md +13 -1
  13. package/actSpecs.js +29 -5
  14. package/call.js +6 -5
  15. package/docker-compose.yml +8 -2
  16. package/docs/checkpoint-scanning.md +199 -0
  17. package/docs/standard-result-outcome.md +165 -0
  18. package/env.example +44 -10
  19. package/eslint.config.mjs +101 -0
  20. package/netWatch.js +372 -222
  21. package/package.json +46 -31
  22. package/pour/README.md +47 -0
  23. package/pour/pour.min.js +8 -0
  24. package/procs/actDo.js +808 -0
  25. package/procs/catalog.d.ts +17 -0
  26. package/procs/catalog.js +312 -221
  27. package/procs/catalog.ts +398 -0
  28. package/procs/checkpoint.js +110 -0
  29. package/procs/config.d.ts +35 -0
  30. package/procs/config.js +62 -0
  31. package/procs/dateTime.js +2 -1
  32. package/procs/doActs.js +442 -849
  33. package/procs/doTestAct.js +27 -121
  34. package/procs/flow.js +221 -0
  35. package/procs/generateRuleRegistry.js +94 -0
  36. package/procs/getSource.d.ts +26 -0
  37. package/procs/job.js +115 -1
  38. package/procs/launch.d.ts +40 -0
  39. package/procs/launch.js +239 -108
  40. package/procs/nu.d.ts +48 -0
  41. package/procs/scope.js +196 -0
  42. package/procs/shoot.d.ts +33 -0
  43. package/procs/standard.d.ts +18 -0
  44. package/procs/standard.js +83 -0
  45. package/procs/standard.ts +126 -0
  46. package/procs/testAct.js +145 -0
  47. package/procs/testaro.d.ts +20 -0
  48. package/procs/testaro.js +236 -189
  49. package/procs/testaro.ts +321 -0
  50. package/procs/userPath.js +126 -0
  51. package/procs/xPath.d.ts +4 -0
  52. package/procs/xPath.js +81 -69
  53. package/procs/xPath.ts +106 -0
  54. package/procs/xPathScript.d.ts +6 -0
  55. package/procs/xPathScript.js +70 -0
  56. package/run.js +3 -2
  57. package/surea11y/README.md +44 -0
  58. package/surea11y/surea11y.browser.js +14 -0
  59. package/testaro/adbID.d.ts +3 -0
  60. package/testaro/adbID.js +38 -41
  61. package/testaro/adbID.ts +66 -0
  62. package/testaro/allCapStyle.d.ts +3 -0
  63. package/testaro/allCapStyle.js +31 -34
  64. package/testaro/allCapStyle.ts +55 -0
  65. package/testaro/allCaps.d.ts +16 -0
  66. package/testaro/allCaps.js +179 -151
  67. package/testaro/allCaps.ts +228 -0
  68. package/testaro/allHidden.d.ts +13 -0
  69. package/testaro/allHidden.js +29 -30
  70. package/testaro/allHidden.ts +50 -0
  71. package/testaro/allSlanted.d.ts +3 -0
  72. package/testaro/allSlanted.js +30 -33
  73. package/testaro/allSlanted.ts +54 -0
  74. package/testaro/altScheme.d.ts +3 -0
  75. package/testaro/altScheme.js +27 -30
  76. package/testaro/altScheme.ts +50 -0
  77. package/testaro/attVal.d.ts +3 -0
  78. package/testaro/attVal.js +20 -21
  79. package/testaro/attVal.ts +52 -0
  80. package/testaro/autocomplete.d.ts +3 -0
  81. package/testaro/autocomplete.js +59 -75
  82. package/testaro/autocomplete.ts +101 -0
  83. package/testaro/bulk.d.ts +13 -0
  84. package/testaro/bulk.js +32 -33
  85. package/testaro/bulk.ts +55 -0
  86. package/testaro/buttonMenu.d.ts +9 -0
  87. package/testaro/buttonMenu.js +317 -319
  88. package/testaro/buttonMenu.ts +391 -0
  89. package/testaro/captionLoc.d.ts +3 -0
  90. package/testaro/captionLoc.js +17 -20
  91. package/testaro/captionLoc.ts +40 -0
  92. package/testaro/datalistRef.d.ts +3 -0
  93. package/testaro/datalistRef.js +33 -36
  94. package/testaro/datalistRef.ts +55 -0
  95. package/testaro/distortion.d.ts +3 -0
  96. package/testaro/distortion.js +57 -26
  97. package/testaro/distortion.ts +81 -0
  98. package/testaro/docType.d.ts +15 -0
  99. package/testaro/docType.js +25 -25
  100. package/testaro/docType.ts +45 -0
  101. package/testaro/dupAtt.d.ts +16 -0
  102. package/testaro/dupAtt.js +113 -104
  103. package/testaro/dupAtt.ts +144 -0
  104. package/testaro/elements.d.ts +6 -0
  105. package/testaro/elements.js +153 -153
  106. package/testaro/elements.ts +215 -0
  107. package/testaro/embAc.d.ts +3 -0
  108. package/testaro/embAc.js +19 -20
  109. package/testaro/embAc.ts +40 -0
  110. package/testaro/focAll.d.ts +13 -0
  111. package/testaro/focAll.js +185 -191
  112. package/testaro/focAll.ts +217 -0
  113. package/testaro/focAndOp.d.ts +3 -0
  114. package/testaro/focAndOp.js +100 -104
  115. package/testaro/focAndOp.ts +128 -0
  116. package/testaro/focInd.d.ts +3 -0
  117. package/testaro/focInd.js +64 -66
  118. package/testaro/focInd.ts +96 -0
  119. package/testaro/focVis.d.ts +3 -0
  120. package/testaro/focVis.js +28 -30
  121. package/testaro/focVis.ts +52 -0
  122. package/testaro/headEl.d.ts +10 -0
  123. package/testaro/headEl.js +61 -62
  124. package/testaro/headEl.ts +82 -0
  125. package/testaro/headingAmb.d.ts +3 -0
  126. package/testaro/headingAmb.js +54 -63
  127. package/testaro/headingAmb.ts +72 -0
  128. package/testaro/hovInd.d.ts +12 -0
  129. package/testaro/hovInd.js +163 -130
  130. package/testaro/hovInd.ts +199 -0
  131. package/testaro/hover.d.ts +3 -0
  132. package/testaro/hover.js +155 -126
  133. package/testaro/hover.ts +154 -0
  134. package/testaro/hr.d.ts +3 -0
  135. package/testaro/hr.js +14 -17
  136. package/testaro/hr.ts +36 -0
  137. package/testaro/imageLink.d.ts +3 -0
  138. package/testaro/imageLink.js +17 -20
  139. package/testaro/imageLink.ts +42 -0
  140. package/testaro/labClash.d.ts +3 -0
  141. package/testaro/labClash.js +31 -33
  142. package/testaro/labClash.ts +54 -0
  143. package/testaro/legendLoc.d.ts +3 -0
  144. package/testaro/legendLoc.js +17 -20
  145. package/testaro/legendLoc.ts +42 -0
  146. package/testaro/lineHeight.d.ts +3 -0
  147. package/testaro/lineHeight.js +43 -48
  148. package/testaro/lineHeight.ts +70 -0
  149. package/testaro/linkAmb.d.ts +7 -0
  150. package/testaro/linkAmb.js +79 -80
  151. package/testaro/linkAmb.ts +105 -0
  152. package/testaro/linkExt.d.ts +3 -0
  153. package/testaro/linkExt.js +13 -16
  154. package/testaro/linkExt.ts +35 -0
  155. package/testaro/linkOldAtt.d.ts +3 -0
  156. package/testaro/linkOldAtt.js +25 -28
  157. package/testaro/linkOldAtt.ts +48 -0
  158. package/testaro/linkTo.d.ts +3 -0
  159. package/testaro/linkTo.js +22 -22
  160. package/testaro/linkTo.ts +43 -0
  161. package/testaro/linkUl.d.ts +3 -0
  162. package/testaro/linkUl.js +30 -34
  163. package/testaro/linkUl.ts +54 -0
  164. package/testaro/miniText.d.ts +3 -0
  165. package/testaro/miniText.js +41 -44
  166. package/testaro/miniText.ts +68 -0
  167. package/testaro/motion.d.ts +10 -0
  168. package/testaro/motion.js +92 -96
  169. package/testaro/motion.ts +125 -0
  170. package/testaro/nonTable.d.ts +3 -0
  171. package/testaro/nonTable.js +39 -45
  172. package/testaro/nonTable.ts +66 -0
  173. package/testaro/optRoleSel.d.ts +3 -0
  174. package/testaro/optRoleSel.js +16 -19
  175. package/testaro/optRoleSel.ts +41 -0
  176. package/testaro/phOnly.d.ts +3 -0
  177. package/testaro/phOnly.js +18 -21
  178. package/testaro/phOnly.ts +43 -0
  179. package/testaro/pseudoP.d.ts +3 -0
  180. package/testaro/pseudoP.js +36 -38
  181. package/testaro/pseudoP.ts +59 -0
  182. package/testaro/radioSet.d.ts +3 -0
  183. package/testaro/radioSet.js +57 -59
  184. package/testaro/radioSet.ts +79 -0
  185. package/testaro/registry.d.ts +63 -0
  186. package/testaro/registry.js +67 -0
  187. package/testaro/registry.ts +141 -0
  188. package/testaro/role.d.ts +3 -0
  189. package/testaro/role.js +27 -29
  190. package/testaro/role.ts +53 -0
  191. package/testaro/secHeading.d.ts +3 -0
  192. package/testaro/secHeading.js +30 -33
  193. package/testaro/secHeading.ts +53 -0
  194. package/testaro/styleDiff.d.ts +25 -0
  195. package/testaro/styleDiff.js +248 -252
  196. package/testaro/styleDiff.ts +303 -0
  197. package/testaro/tabNav.d.ts +33 -0
  198. package/testaro/tabNav.js +272 -342
  199. package/testaro/tabNav.ts +454 -0
  200. package/testaro/targetsNear.d.ts +9 -0
  201. package/testaro/targetsNear.js +130 -132
  202. package/testaro/targetsNear.ts +160 -0
  203. package/testaro/textNodes.d.ts +6 -0
  204. package/testaro/textNodes.js +139 -135
  205. package/testaro/textNodes.ts +185 -0
  206. package/testaro/textSem.d.ts +3 -0
  207. package/testaro/textSem.js +25 -28
  208. package/testaro/textSem.ts +47 -0
  209. package/testaro/title.d.ts +9 -0
  210. package/testaro/title.js +16 -13
  211. package/testaro/title.ts +31 -0
  212. package/testaro/titledEl.d.ts +3 -0
  213. package/testaro/titledEl.js +15 -18
  214. package/testaro/titledEl.ts +38 -0
  215. package/testaro/zIndex.d.ts +3 -0
  216. package/testaro/zIndex.js +19 -22
  217. package/testaro/zIndex.ts +42 -0
  218. package/tests/alfa.d.ts +45 -0
  219. package/tests/alfa.js +138 -141
  220. package/tests/alfa.ts +214 -0
  221. package/tests/aslint.d.ts +33 -0
  222. package/tests/aslint.js +272 -249
  223. package/tests/aslint.ts +301 -0
  224. package/tests/axe.d.ts +27 -0
  225. package/tests/axe.js +199 -200
  226. package/tests/axe.ts +277 -0
  227. package/tests/ed11y.d.ts +28 -0
  228. package/tests/ed11y.js +141 -99
  229. package/tests/ed11y.ts +178 -0
  230. package/tests/htmlcs.d.ts +21 -0
  231. package/tests/htmlcs.js +174 -140
  232. package/tests/htmlcs.ts +181 -0
  233. package/tests/ibm.d.ts +52 -0
  234. package/tests/ibm.js +164 -166
  235. package/tests/ibm.ts +251 -0
  236. package/tests/nuVal.d.ts +13 -0
  237. package/tests/nuVal.js +107 -112
  238. package/tests/nuVal.ts +145 -0
  239. package/tests/nuVnu.d.ts +15 -0
  240. package/tests/nuVnu.js +141 -111
  241. package/tests/nuVnu.ts +144 -0
  242. package/tests/pour.d.ts +31 -0
  243. package/tests/pour.js +242 -0
  244. package/tests/pour.ts +273 -0
  245. package/tests/qualWeb.d.ts +39 -0
  246. package/tests/qualWeb.js +302 -272
  247. package/tests/qualWeb.ts +415 -0
  248. package/tests/surea11y.d.ts +33 -0
  249. package/tests/surea11y.js +288 -0
  250. package/tests/surea11y.ts +334 -0
  251. package/tests/testaro.d.ts +25 -0
  252. package/tests/testaro.js +745 -652
  253. package/tests/testaro.ts +862 -0
  254. package/tests/wave.d.ts +46 -0
  255. package/tests/wave.js +166 -177
  256. package/tests/wave.ts +252 -0
  257. package/tsconfig.json +17 -0
  258. package/types.d.ts +243 -0
  259. package/types.js +10 -0
  260. package/types.ts +376 -0
  261. package/validation/act/README.md +46 -0
  262. package/validation/act/capture.js +424 -0
  263. package/validation/act/chromium-issue-draft.md +66 -0
  264. package/validation/act/fp-triage-2026-08-22.md +86 -0
  265. package/validation/act/isolation-notes.md +159 -0
  266. package/validation/act/playwright-issue-draft.md +73 -0
  267. package/validation/act/propose-mappings.js +0 -0
  268. package/validation/act/repro-cdp-raw.js +105 -0
  269. package/validation/act/repro-metarefresh.js +65 -0
  270. package/validation/act/score.js +184 -0
  271. package/validation/act/stage3a-stress-report.md +69 -0
  272. package/validation/act/stage3b-mapping-proposals.md +94 -0
  273. package/validation/act/stage3b-triage-draft.md +138 -0
  274. package/validation/act/surea11y-track-a-2026-09-01.md +50 -0
  275. package/validation/executors/netWatch.js +180 -90
  276. package/validation/executors/test.js +17 -2
  277. package/validation/executors/tests.js +118 -10
  278. package/validation/jobs/reports/raw/260901T1000-surea11y-validation.json +964 -0
  279. package/validation/jobs/todo/240101T1200-simple-example.json +14 -6
  280. package/validation/jobs/todo/240101T1300-shoot-example.json +2 -1
  281. package/validation/jobs/todo/260821T1900-pour-validation.json +45 -0
  282. package/validation/jobs/todo/260901T1000-surea11y-validation.json +45 -0
  283. package/validation/knownFailures.json +1 -0
  284. package/validation/tests/jobProperties/adbID.json +27 -2
  285. package/validation/tests/jobProperties/{focOp.json → allCapStyle.json} +56 -53
  286. package/validation/tests/jobProperties/allCaps.json +25 -0
  287. package/validation/tests/jobProperties/allHidden.json +133 -13
  288. package/validation/tests/jobProperties/allSlanted.json +3 -3
  289. package/validation/tests/jobProperties/altScheme.json +23 -8
  290. package/validation/tests/jobProperties/attVal.json +57 -57
  291. package/validation/tests/jobProperties/autocomplete.json +11 -1
  292. package/validation/tests/jobProperties/bulk.json +6 -1
  293. package/validation/tests/jobProperties/buttonMenu.json +63 -42
  294. package/validation/tests/jobProperties/captionLoc.json +1 -6
  295. package/validation/tests/jobProperties/checkpoint-browser.json +401 -0
  296. package/validation/tests/jobProperties/checkpoint-page.json +397 -0
  297. package/validation/tests/jobProperties/checkpoint.json +395 -0
  298. package/validation/tests/jobProperties/datalistRef.json +20 -5
  299. package/validation/tests/jobProperties/distortion.json +28 -3
  300. package/validation/tests/jobProperties/docType.json +2 -2
  301. package/validation/tests/jobProperties/dupAtt.json +48 -33
  302. package/validation/tests/jobProperties/elements.json +28 -28
  303. package/validation/tests/jobProperties/embAc.json +36 -31
  304. package/validation/tests/jobProperties/focAndOp.json +284 -0
  305. package/validation/tests/jobProperties/focInd.json +34 -34
  306. package/validation/tests/jobProperties/focVis.json +1 -1
  307. package/validation/tests/jobProperties/hover.json +39 -37
  308. package/validation/tests/jobProperties/hr.json +13 -3
  309. package/validation/tests/jobProperties/imageLink.json +0 -5
  310. package/validation/tests/jobProperties/labClash.json +68 -33
  311. package/validation/tests/jobProperties/legendLoc.json +1 -6
  312. package/validation/tests/jobProperties/lineHeight.json +2 -2
  313. package/validation/tests/jobProperties/linkAmb.json +13 -18
  314. package/validation/tests/jobProperties/linkExt.json +1 -1
  315. package/validation/tests/jobProperties/linkOldAtt.json +12 -2
  316. package/validation/tests/jobProperties/linkTo.json +1 -1
  317. package/validation/tests/jobProperties/linkUl.json +65 -65
  318. package/validation/tests/jobProperties/miniText.json +7 -2
  319. package/validation/tests/jobProperties/motion.json +4 -50
  320. package/validation/tests/jobProperties/nonTable.json +48 -3
  321. package/validation/tests/jobProperties/optRoleSel.json +12 -2
  322. package/validation/tests/jobProperties/phOnly.json +6 -16
  323. package/validation/tests/jobProperties/pseudoP.json +17 -2
  324. package/validation/tests/jobProperties/radioSet.json +30 -30
  325. package/validation/tests/jobProperties/role.json +25 -5
  326. package/validation/tests/jobProperties/secHeading.json +26 -21
  327. package/validation/tests/jobProperties/styleDiff.json +35 -5
  328. package/validation/tests/jobProperties/tabNav.json +3 -1
  329. package/validation/tests/jobProperties/targetsNear.json +237 -0
  330. package/validation/tests/jobProperties/textNodes.json +29 -29
  331. package/validation/tests/jobProperties/textSem.json +26 -1
  332. package/validation/tests/jobProperties/title.json +12 -2
  333. package/validation/tests/jobProperties/titledEl.json +39 -9
  334. package/validation/tests/jobProperties/userPath.json +317 -0
  335. package/validation/tests/jobProperties/zIndex.json +40 -35
  336. package/validation/tests/targets/allCapStyle/index.html +26 -0
  337. package/validation/tests/targets/checkpoint/index.html +38 -0
  338. package/validation/tests/targets/datalistRef/index.html +1 -1
  339. package/validation/tests/targets/focAndOp/bad.html +29 -0
  340. package/validation/tests/targets/{focOp → focAndOp}/good.html +3 -1
  341. package/validation/tests/targets/focInd/bad.html +2 -1
  342. package/validation/tests/targets/headEl/index.html +10 -1
  343. package/validation/tests/targets/{targetSmall → targetsNear}/index.html +15 -1
  344. package/validation/tests/targets/userPath/index.html +42 -0
  345. package/validation/validateTest.js +61 -9
  346. package/.claude/settings.local.json +0 -11
  347. package/.eslintrc.json +0 -41
  348. package/htmlcs/.eslintrc.json +0 -67
  349. package/validation/tests/jobProperties/linkTitle.json +0 -127
  350. package/validation/tests/jobProperties/opFoc.json +0 -164
  351. package/validation/tests/jobProperties/targetSmall.json +0 -152
  352. package/validation/tests/jobProperties/targetTiny.json +0 -142
  353. package/validation/tests/targets/focOp/bad.html +0 -25
  354. package/validation/tests/targets/linkTitle/index.html +0 -24
  355. package/validation/tests/targets/opFoc/bad.html +0 -26
  356. package/validation/tests/targets/opFoc/good.html +0 -23
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /*
2
3
  © 2023–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
4
  © 2026 Jonathan Robert Pool.
@@ -7,150 +8,153 @@
7
8
 
8
9
  SPDX-License-Identifier: MIT
9
10
  */
10
-
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.reporter = void 0;
11
13
  /*
12
14
  textNodes
13
15
  This test reports data about specified text nodes. Meanings of detailLevel values:
14
16
  0. Only total node count; no detail.
15
17
  1-3. Count of ancestry levels to provide data on (1 = text node, 2 = also parent, 3 = also grandparent)
18
+ Compiled to textNodes.js by tsc (issue #73); edit this file, not the emitted one.
16
19
  */
17
-
18
20
  // FUNCTIONS
19
-
20
21
  // Runs the test and returns the result.
21
- exports.reporter = async (page, _0, _1, _2, detailLevel, text = '') => {
22
- let data = {};
23
- // Get the data on the text nodes.
24
- try {
25
- data = await page.evaluate(args => {
26
- const detailLevel = args[0];
27
- const text = args[1];
28
- const matchNodes = [];
29
- // Collapse any adjacent text nodes.
30
- document.body.normalize();
31
- // Remove the irrelevant text content.
32
- const extraElements = Array.from(document.body.querySelectorAll('style, script, svg'));
33
- extraElements.forEach(element => {
34
- element.textContent = '';
35
- });
36
- // FUNCTION DEFINITIONS START
37
- // Compacts a string.
38
- const compact = string => string.replace(/\s+/g, ' ').trim();
39
- // Compacts and lower-cases a string.
40
- const toStandardString = string => compact(string).toLowerCase();
41
- /*
42
- Gets data (tagName, text if specified, attributes, refLabels, labels, and children)
43
- on an element.
44
- */
45
- const getElementData = (element, withText) => {
46
- // Initialize the data.
47
- const data = {
48
- tagName: element.tagName
49
- };
50
- if (! ['STYLE', 'SCRIPT', 'SVG', 'svg'].includes(element.tagName)) {
51
- if (withText) {
52
- data.text = compact(element.textContent);
53
- }
54
- // Add data on its attributes, if any, to the data.
55
- const {attributes} = element;
56
- if (attributes) {
57
- data.attributes = [];
58
- for (const attribute of attributes) {
59
- const {name, value} = attribute;
60
- data.attributes.push({
61
- name,
62
- value
63
- });
64
- // If any attribute is a labeler reference:
65
- if (name === 'aria-labelledby') {
66
- // Add the label texts to the data.
67
- const labelerIDs = value.split(/\s+/);
68
- data.refLabels = [];
69
- labelerIDs.forEach(id => {
70
- const labeler = document.getElementById(id);
71
- if (labeler) {
72
- data.refLabels.push(compact(labeler.textContent));
73
- }
74
- });
75
- }
76
- }
77
- }
78
- // Add data on its labels, if any, to the data.
79
- const {labels} = element;
80
- if (labels && labels.length) {
81
- data.labels = Array.from(labels).map(label => compact(label.textContent));
82
- }
83
- // Add data on its child elements, if any, to the data.
84
- if (element.childElementCount) {
85
- const children = Array.from(element.children);
86
- data.children = [];
87
- children.forEach(child => {
88
- data.children.push(getElementData(child, true));
22
+ const reporter = async (page, _0, _1, _2, detailLevel, text = '') => {
23
+ let data = {};
24
+ // Get the data on the text nodes.
25
+ try {
26
+ data = await page.evaluate(args => {
27
+ const detailLevel = args[0];
28
+ const text = args[1];
29
+ const matchNodes = [];
30
+ // Collapse any adjacent text nodes.
31
+ document.body.normalize();
32
+ // Remove the irrelevant text content.
33
+ const extraElements = Array.from(document.body.querySelectorAll('style, script, svg'));
34
+ extraElements.forEach(element => {
35
+ element.textContent = '';
89
36
  });
90
- }
91
- }
92
- return data;
93
- };
94
- // FUNCTION DEFINITIONS END
95
- const stdText = toStandardString(text);
96
- // Create a collection of the text nodes.
97
- const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
98
- // Get their count.
99
- const data = {nodeCount: 0};
100
- let more = true;
101
- while(more) {
102
- if (walker.nextNode()) {
103
- const stdCurrent = toStandardString(walker.currentNode.nodeValue);
104
- if (stdCurrent.includes(stdText)) {
105
- data.nodeCount++;
106
- matchNodes.push(walker.currentNode);
107
- }
108
- }
109
- else {
110
- more = false;
111
- }
112
- }
113
- // If itemization is required:
114
- if (detailLevel > 0) {
115
- // Initialize the item data.
116
- data.items = [];
117
- // For each text node matching any specified text:
118
- matchNodes.forEach(node => {
119
- // Initialize the data on it.
120
- const itemData = {text: compact(node.nodeValue)};
121
- // If ancestral itemization is required:
122
- if (detailLevel > 1) {
123
- // Add the ancestral data, starting with the parent, to the item data.
124
- itemData.ancestors = [];
125
- let base = node;
126
- let currentLevel = 1;
127
- // For each specified ancestral distance:
128
- while(currentLevel++ < detailLevel) {
129
- // Add data on it to the data on the text node.
130
- const newBase = base.parentElement;
131
- // Omit the text of the text node if the ancestor is its parent.
132
- itemData.ancestors.push(getElementData(newBase, currentLevel > 2));
133
- base = newBase;
37
+ // FUNCTION DEFINITIONS START
38
+ // Compacts a string.
39
+ const compact = (string) => string.replace(/\s+/g, ' ').trim();
40
+ // Compacts and lower-cases a string.
41
+ const toStandardString = (string) => compact(string).toLowerCase();
42
+ /*
43
+ Gets data (tagName, text if specified, attributes, refLabels, labels, and children)
44
+ on an element.
45
+ */
46
+ const getElementData = (element, withText) => {
47
+ // Initialize the data.
48
+ const data = {
49
+ tagName: element.tagName
50
+ };
51
+ if (!['STYLE', 'SCRIPT', 'SVG', 'svg'].includes(element.tagName)) {
52
+ if (withText) {
53
+ data.text = compact(element.textContent);
54
+ }
55
+ // Add data on its attributes, if any, to the data.
56
+ const { attributes } = element;
57
+ if (attributes) {
58
+ data.attributes = [];
59
+ for (const attribute of attributes) {
60
+ const { name, value } = attribute;
61
+ data.attributes.push({
62
+ name,
63
+ value
64
+ });
65
+ // If any attribute is a labeler reference:
66
+ if (name === 'aria-labelledby') {
67
+ // Add the label texts to the data.
68
+ const labelerIDs = value.split(/\s+/);
69
+ data.refLabels = [];
70
+ labelerIDs.forEach(id => {
71
+ const labeler = document.getElementById(id);
72
+ if (labeler) {
73
+ data.refLabels.push(compact(labeler.textContent));
74
+ }
75
+ });
76
+ }
77
+ }
78
+ }
79
+ // Add data on its labels, if any, to the data.
80
+ const { labels } = element;
81
+ if (labels && labels.length) {
82
+ data.labels = Array.from(labels).map(label => compact(label.textContent));
83
+ }
84
+ // Add data on its child elements, if any, to the data.
85
+ if (element.childElementCount) {
86
+ const children = Array.from(element.children);
87
+ data.children = [];
88
+ children.forEach(child => {
89
+ data.children.push(getElementData(child, true));
90
+ });
91
+ }
92
+ }
93
+ return data;
94
+ };
95
+ // FUNCTION DEFINITIONS END
96
+ const stdText = toStandardString(text);
97
+ // Create a collection of the text nodes.
98
+ const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
99
+ // Get their count.
100
+ const data = { nodeCount: 0 };
101
+ let more = true;
102
+ while (more) {
103
+ if (walker.nextNode()) {
104
+ const stdCurrent = toStandardString(walker.currentNode.nodeValue);
105
+ if (stdCurrent.includes(stdText)) {
106
+ data.nodeCount++;
107
+ matchNodes.push(walker.currentNode);
108
+ }
109
+ }
110
+ else {
111
+ more = false;
112
+ }
113
+ }
114
+ // If itemization is required:
115
+ if (detailLevel > 0) {
116
+ // Initialize the item data.
117
+ data.items = [];
118
+ // For each text node matching any specified text:
119
+ matchNodes.forEach(node => {
120
+ // Initialize the data on it.
121
+ const itemData = {
122
+ text: compact(node.nodeValue)
123
+ };
124
+ // If ancestral itemization is required:
125
+ if (detailLevel > 1) {
126
+ // Add the ancestral data, starting with the parent, to the item data.
127
+ itemData.ancestors = [];
128
+ let base = node;
129
+ let currentLevel = 1;
130
+ // For each specified ancestral distance:
131
+ while (currentLevel++ < detailLevel) {
132
+ // Add data on it to the data on the text node.
133
+ const newBase = base.parentElement;
134
+ // Omit the text of the text node if the ancestor is its parent.
135
+ itemData.ancestors.push(getElementData(newBase, currentLevel > 2));
136
+ base = newBase;
137
+ }
138
+ }
139
+ // Add the node data to the itemization.
140
+ data.items.push(itemData);
141
+ });
134
142
  }
135
- }
136
- // Add the node data to the itemization.
137
- data.items.push(itemData);
138
- });
139
- }
140
- return data;
141
- }, [detailLevel, text]);
142
- }
143
- catch(error) {
144
- console.log(`ERROR performing test (${error.message.replace(/\n.+/s, '')})`);
145
- data = {
146
- prevented: true,
147
- error: 'Test failed'
143
+ return data;
144
+ }, [detailLevel, text]);
145
+ }
146
+ catch (error) {
147
+ console.log(`ERROR performing test (${error.message.replace(/\n.+/s, '')})`);
148
+ data = {
149
+ prevented: true,
150
+ error: 'Test failed'
151
+ };
152
+ }
153
+ // Return the result.
154
+ return {
155
+ data,
156
+ totals: [],
157
+ standardInstances: []
148
158
  };
149
- }
150
- // Return the result.
151
- return {
152
- data,
153
- totals: [],
154
- standardInstances: []
155
- };
156
159
  };
160
+ exports.reporter = reporter;
@@ -0,0 +1,185 @@
1
+ /*
2
+ © 2023–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
+ © 2026 Jonathan Robert Pool.
4
+
5
+ Licensed under the MIT License. See LICENSE file at the project root or
6
+ https://opensource.org/license/mit/ for details.
7
+
8
+ SPDX-License-Identifier: MIT
9
+ */
10
+
11
+ // IMPORTS
12
+
13
+ import type {Page} from 'playwright';
14
+
15
+ // TYPES
16
+
17
+ // Data on one attribute of an element.
18
+ interface AttributeDatum {
19
+ name: string;
20
+ value: string;
21
+ }
22
+ // Data on an element, possibly with data on its descendants.
23
+ interface ElementData {
24
+ tagName: string;
25
+ text?: string;
26
+ attributes?: AttributeDatum[];
27
+ refLabels?: string[];
28
+ labels?: string[];
29
+ children?: ElementData[];
30
+ }
31
+
32
+ /*
33
+ textNodes
34
+ This test reports data about specified text nodes. Meanings of detailLevel values:
35
+ 0. Only total node count; no detail.
36
+ 1-3. Count of ancestry levels to provide data on (1 = text node, 2 = also parent, 3 = also grandparent)
37
+ Compiled to textNodes.js by tsc (issue #73); edit this file, not the emitted one.
38
+ */
39
+
40
+ // FUNCTIONS
41
+
42
+ // Runs the test and returns the result.
43
+ export const reporter = async (
44
+ page: Page, _0: unknown, _1: unknown, _2: unknown, detailLevel: number, text = ''
45
+ ) => {
46
+ let data: Record<string, unknown> = {};
47
+ // Get the data on the text nodes.
48
+ try {
49
+ data = await page.evaluate(args => {
50
+ const detailLevel = args[0];
51
+ const text = args[1];
52
+ const matchNodes: Node[] = [];
53
+ // Collapse any adjacent text nodes.
54
+ document.body.normalize();
55
+ // Remove the irrelevant text content.
56
+ const extraElements = Array.from(document.body.querySelectorAll('style, script, svg'));
57
+ extraElements.forEach(element => {
58
+ element.textContent = '';
59
+ });
60
+ // FUNCTION DEFINITIONS START
61
+ // Compacts a string.
62
+ const compact = (string: string) => string.replace(/\s+/g, ' ').trim();
63
+ // Compacts and lower-cases a string.
64
+ const toStandardString = (string: string) => compact(string).toLowerCase();
65
+ /*
66
+ Gets data (tagName, text if specified, attributes, refLabels, labels, and children)
67
+ on an element.
68
+ */
69
+ const getElementData = (element: Element, withText: boolean): ElementData => {
70
+ // Initialize the data.
71
+ const data: ElementData = {
72
+ tagName: element.tagName
73
+ };
74
+ if (! ['STYLE', 'SCRIPT', 'SVG', 'svg'].includes(element.tagName)) {
75
+ if (withText) {
76
+ data.text = compact(element.textContent!);
77
+ }
78
+ // Add data on its attributes, if any, to the data.
79
+ const {attributes} = element;
80
+ if (attributes) {
81
+ data.attributes = [];
82
+ for (const attribute of attributes) {
83
+ const {name, value} = attribute;
84
+ data.attributes.push({
85
+ name,
86
+ value
87
+ });
88
+ // If any attribute is a labeler reference:
89
+ if (name === 'aria-labelledby') {
90
+ // Add the label texts to the data.
91
+ const labelerIDs = value.split(/\s+/);
92
+ data.refLabels = [];
93
+ labelerIDs.forEach(id => {
94
+ const labeler = document.getElementById(id);
95
+ if (labeler) {
96
+ data.refLabels!.push(compact(labeler.textContent!));
97
+ }
98
+ });
99
+ }
100
+ }
101
+ }
102
+ // Add data on its labels, if any, to the data.
103
+ const {labels} = element as HTMLInputElement;
104
+ if (labels && labels.length) {
105
+ data.labels = Array.from(labels).map(label => compact(label.textContent!));
106
+ }
107
+ // Add data on its child elements, if any, to the data.
108
+ if (element.childElementCount) {
109
+ const children = Array.from(element.children);
110
+ data.children = [];
111
+ children.forEach(child => {
112
+ data.children!.push(getElementData(child, true));
113
+ });
114
+ }
115
+ }
116
+ return data;
117
+ };
118
+ // FUNCTION DEFINITIONS END
119
+ const stdText = toStandardString(text);
120
+ // Create a collection of the text nodes.
121
+ const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
122
+ // Get their count.
123
+ const data: {
124
+ nodeCount: number;
125
+ items?: {text: string; ancestors?: ElementData[]}[];
126
+ } = {nodeCount: 0};
127
+ let more = true;
128
+ while(more) {
129
+ if (walker.nextNode()) {
130
+ const stdCurrent = toStandardString(walker.currentNode.nodeValue!);
131
+ if (stdCurrent.includes(stdText)) {
132
+ data.nodeCount++;
133
+ matchNodes.push(walker.currentNode);
134
+ }
135
+ }
136
+ else {
137
+ more = false;
138
+ }
139
+ }
140
+ // If itemization is required:
141
+ if (detailLevel > 0) {
142
+ // Initialize the item data.
143
+ data.items = [];
144
+ // For each text node matching any specified text:
145
+ matchNodes.forEach(node => {
146
+ // Initialize the data on it.
147
+ const itemData: {text: string; ancestors?: ElementData[]} = {
148
+ text: compact(node.nodeValue!)
149
+ };
150
+ // If ancestral itemization is required:
151
+ if (detailLevel > 1) {
152
+ // Add the ancestral data, starting with the parent, to the item data.
153
+ itemData.ancestors = [];
154
+ let base: Node = node;
155
+ let currentLevel = 1;
156
+ // For each specified ancestral distance:
157
+ while(currentLevel++ < detailLevel) {
158
+ // Add data on it to the data on the text node.
159
+ const newBase = base.parentElement;
160
+ // Omit the text of the text node if the ancestor is its parent.
161
+ itemData.ancestors!.push(getElementData(newBase!, currentLevel > 2));
162
+ base = newBase!;
163
+ }
164
+ }
165
+ // Add the node data to the itemization.
166
+ data.items!.push(itemData);
167
+ });
168
+ }
169
+ return data;
170
+ }, [detailLevel, text] as const);
171
+ }
172
+ catch(error) {
173
+ console.log(`ERROR performing test (${(error as Error).message.replace(/\n.+/s, '')})`);
174
+ data = {
175
+ prevented: true,
176
+ error: 'Test failed'
177
+ };
178
+ }
179
+ // Return the result.
180
+ return {
181
+ data,
182
+ totals: [],
183
+ standardInstances: []
184
+ };
185
+ };
@@ -0,0 +1,3 @@
1
+ import type { Page } from 'playwright';
2
+ import type { Report } from '../types';
3
+ export declare const reporter: (page: Page, report: Report, _: unknown, withItems: boolean) => Promise<import("../procs/testaro").RuleResult>;
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /*
2
3
  © 2025 CVS Health and/or one of its affiliates. All rights reserved.
3
4
  © 2026 Jeff Witt.
@@ -7,38 +8,34 @@
7
8
 
8
9
  SPDX-License-Identifier: MIT
9
10
  */
10
-
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.reporter = void 0;
13
+ const testaro_1 = require("../procs/testaro");
11
14
  /*
12
15
  textSem
13
16
  This test reports semantically vague inline elements: i, b, small.
17
+ Compiled to textSem.js by tsc (issue #73); edit this file, not the emitted one.
14
18
  */
15
-
16
- // IMPORTS
17
-
18
- const {doTest} = require('../procs/testaro');
19
-
20
19
  // FUNCTIONS
21
-
22
20
  // Runs the test and returns the result.
23
- exports.reporter = async (page, report, _, withItems) => {
24
- const getBadWhat = element => {
25
- const isVisible = element.checkVisibility({
26
- contentVisibilityAuto: true,
27
- opacityProperty: true,
28
- visibilityProperty: true
29
- });
30
- // If the element is visible:
31
- if (isVisible) {
32
- // If it has text content:
33
- if (element.textContent.trim().replace(/\s/g, '')) {
34
- // Return a violation description.
35
- return `Element type (${element.tagName}) is semantically vague`;
36
- }
37
- }
38
- };
39
- const selector = 'body i, body b, body small';
40
- const whats = 'Semantically vague elements i, b, and/or small are used';
41
- return await doTest(
42
- page, report, withItems, 'textSem', selector, whats, 0, getBadWhat.toString()
43
- );
21
+ const reporter = async (page, report, _, withItems) => {
22
+ const getBadWhat = element => {
23
+ const isVisible = element.checkVisibility({
24
+ contentVisibilityAuto: true,
25
+ opacityProperty: true,
26
+ visibilityProperty: true
27
+ });
28
+ // If the element is visible:
29
+ if (isVisible) {
30
+ // If it has text content:
31
+ if (element.textContent.trim().replace(/\s/g, '')) {
32
+ // Return a violation description.
33
+ return `Element type (${element.tagName}) is semantically vague`;
34
+ }
35
+ }
36
+ };
37
+ const selector = 'body i, body b, body small';
38
+ const whats = 'Semantically vague elements i, b, and/or small are used';
39
+ return await (0, testaro_1.doTest)(page, report, withItems, 'textSem', selector, whats, 0, getBadWhat.toString());
44
40
  };
41
+ exports.reporter = reporter;
@@ -0,0 +1,47 @@
1
+ /*
2
+ © 2025 CVS Health and/or one of its affiliates. All rights reserved.
3
+ © 2026 Jeff Witt.
4
+ © 2025–2026 Jonathan Robert Pool.
5
+
6
+ Licensed under the MIT License. See LICENSE file at the project root or https://opensource.org/license/mit/ for details.
7
+
8
+ SPDX-License-Identifier: MIT
9
+ */
10
+
11
+ // IMPORTS
12
+
13
+ import type {Page} from 'playwright';
14
+ import {doTest} from '../procs/testaro';
15
+ import type {GetBadWhat, Report} from '../types';
16
+
17
+ /*
18
+ textSem
19
+ This test reports semantically vague inline elements: i, b, small.
20
+ Compiled to textSem.js by tsc (issue #73); edit this file, not the emitted one.
21
+ */
22
+
23
+ // FUNCTIONS
24
+
25
+ // Runs the test and returns the result.
26
+ export const reporter = async (page: Page, report: Report, _: unknown, withItems: boolean) => {
27
+ const getBadWhat: GetBadWhat = element => {
28
+ const isVisible = element.checkVisibility({
29
+ contentVisibilityAuto: true,
30
+ opacityProperty: true,
31
+ visibilityProperty: true
32
+ });
33
+ // If the element is visible:
34
+ if (isVisible) {
35
+ // If it has text content:
36
+ if (element.textContent.trim().replace(/\s/g, '')) {
37
+ // Return a violation description.
38
+ return `Element type (${element.tagName}) is semantically vague`;
39
+ }
40
+ }
41
+ };
42
+ const selector = 'body i, body b, body small';
43
+ const whats = 'Semantically vague elements i, b, and/or small are used';
44
+ return await doTest(
45
+ page, report, withItems, 'textSem', selector, whats, 0, getBadWhat.toString()
46
+ );
47
+ };
@@ -0,0 +1,9 @@
1
+ import type { Page } from 'playwright';
2
+ export declare const reporter: (page: Page) => Promise<{
3
+ data: {
4
+ success: boolean;
5
+ title: string;
6
+ };
7
+ totals: never[];
8
+ standardInstances: never[];
9
+ }>;
package/testaro/title.js CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /*
2
3
  © 2022–2023 CVS Health and/or one of its affiliates. All rights reserved.
3
4
  © 2026 Jonathan Robert Pool.
@@ -6,21 +7,23 @@
6
7
 
7
8
  SPDX-License-Identifier: MIT
8
9
  */
9
-
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.reporter = void 0;
10
12
  /*
11
13
  title
12
- This test reports the page title.
14
+ This test reports the page title. Compiled to title.js by tsc (issue #73); edit this file,
15
+ not the emitted one.
13
16
  */
14
-
15
17
  // Runs the test and returns the result.
16
- exports.reporter = async page => {
17
- const title = await page.title();
18
- return {
19
- data: {
20
- success: true,
21
- title
22
- },
23
- totals: [],
24
- standardInstances: []
25
- };
18
+ const reporter = async (page) => {
19
+ const title = await page.title();
20
+ return {
21
+ data: {
22
+ success: true,
23
+ title
24
+ },
25
+ totals: [],
26
+ standardInstances: []
27
+ };
26
28
  };
29
+ exports.reporter = reporter;