testaro 78.0.6 → 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 (361) 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 +25 -19
  7. package/CONTAINERS.md +10 -6
  8. package/CONTRIBUTING.md +29 -3
  9. package/Dockerfile +1 -1
  10. package/README.md +75 -20
  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 +373 -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 +313 -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 +63 -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/getSource.js +1 -0
  38. package/procs/job.js +116 -1
  39. package/procs/launch.d.ts +40 -0
  40. package/procs/launch.js +239 -108
  41. package/procs/nu.d.ts +48 -0
  42. package/procs/nu.js +1 -0
  43. package/procs/scope.js +196 -0
  44. package/procs/shoot.d.ts +33 -0
  45. package/procs/shoot.js +3 -1
  46. package/procs/standard.d.ts +18 -0
  47. package/procs/standard.js +83 -0
  48. package/procs/standard.ts +126 -0
  49. package/procs/testAct.js +145 -0
  50. package/procs/testaro.d.ts +20 -0
  51. package/procs/testaro.js +237 -189
  52. package/procs/testaro.ts +321 -0
  53. package/procs/userPath.js +126 -0
  54. package/procs/xPath.d.ts +4 -0
  55. package/procs/xPath.js +82 -64
  56. package/procs/xPath.ts +106 -0
  57. package/procs/xPathScript.d.ts +6 -0
  58. package/procs/xPathScript.js +70 -0
  59. package/run.js +3 -2
  60. package/surea11y/README.md +44 -0
  61. package/surea11y/surea11y.browser.js +14 -0
  62. package/testaro/adbID.d.ts +3 -0
  63. package/testaro/adbID.js +39 -41
  64. package/testaro/adbID.ts +66 -0
  65. package/testaro/allCapStyle.d.ts +3 -0
  66. package/testaro/allCapStyle.js +32 -34
  67. package/testaro/allCapStyle.ts +55 -0
  68. package/testaro/allCaps.d.ts +16 -0
  69. package/testaro/allCaps.js +179 -151
  70. package/testaro/allCaps.ts +228 -0
  71. package/testaro/allHidden.d.ts +13 -0
  72. package/testaro/allHidden.js +30 -30
  73. package/testaro/allHidden.ts +50 -0
  74. package/testaro/allSlanted.d.ts +3 -0
  75. package/testaro/allSlanted.js +31 -33
  76. package/testaro/allSlanted.ts +54 -0
  77. package/testaro/altScheme.d.ts +3 -0
  78. package/testaro/altScheme.js +28 -30
  79. package/testaro/altScheme.ts +50 -0
  80. package/testaro/attVal.d.ts +3 -0
  81. package/testaro/attVal.js +21 -21
  82. package/testaro/attVal.ts +52 -0
  83. package/testaro/autocomplete.d.ts +3 -0
  84. package/testaro/autocomplete.js +60 -75
  85. package/testaro/autocomplete.ts +101 -0
  86. package/testaro/bulk.d.ts +13 -0
  87. package/testaro/bulk.js +33 -33
  88. package/testaro/bulk.ts +55 -0
  89. package/testaro/buttonMenu.d.ts +9 -0
  90. package/testaro/buttonMenu.js +318 -319
  91. package/testaro/buttonMenu.ts +391 -0
  92. package/testaro/captionLoc.d.ts +3 -0
  93. package/testaro/captionLoc.js +18 -20
  94. package/testaro/captionLoc.ts +40 -0
  95. package/testaro/datalistRef.d.ts +3 -0
  96. package/testaro/datalistRef.js +34 -36
  97. package/testaro/datalistRef.ts +55 -0
  98. package/testaro/distortion.d.ts +3 -0
  99. package/testaro/distortion.js +58 -26
  100. package/testaro/distortion.ts +81 -0
  101. package/testaro/docType.d.ts +15 -0
  102. package/testaro/docType.js +26 -25
  103. package/testaro/docType.ts +45 -0
  104. package/testaro/dupAtt.d.ts +16 -0
  105. package/testaro/dupAtt.js +114 -104
  106. package/testaro/dupAtt.ts +144 -0
  107. package/testaro/elements.d.ts +6 -0
  108. package/testaro/elements.js +153 -153
  109. package/testaro/elements.ts +215 -0
  110. package/testaro/embAc.d.ts +3 -0
  111. package/testaro/embAc.js +20 -20
  112. package/testaro/embAc.ts +40 -0
  113. package/testaro/focAll.d.ts +13 -0
  114. package/testaro/focAll.js +186 -191
  115. package/testaro/focAll.ts +217 -0
  116. package/testaro/focAndOp.d.ts +3 -0
  117. package/testaro/focAndOp.js +101 -104
  118. package/testaro/focAndOp.ts +128 -0
  119. package/testaro/focInd.d.ts +3 -0
  120. package/testaro/focInd.js +65 -66
  121. package/testaro/focInd.ts +96 -0
  122. package/testaro/focVis.d.ts +3 -0
  123. package/testaro/focVis.js +29 -30
  124. package/testaro/focVis.ts +52 -0
  125. package/testaro/headEl.d.ts +10 -0
  126. package/testaro/headEl.js +62 -62
  127. package/testaro/headEl.ts +82 -0
  128. package/testaro/headingAmb.d.ts +3 -0
  129. package/testaro/headingAmb.js +55 -63
  130. package/testaro/headingAmb.ts +72 -0
  131. package/testaro/hovInd.d.ts +12 -0
  132. package/testaro/hovInd.js +164 -130
  133. package/testaro/hovInd.ts +199 -0
  134. package/testaro/hover.d.ts +3 -0
  135. package/testaro/hover.js +156 -126
  136. package/testaro/hover.ts +154 -0
  137. package/testaro/hr.d.ts +3 -0
  138. package/testaro/hr.js +15 -17
  139. package/testaro/hr.ts +36 -0
  140. package/testaro/imageLink.d.ts +3 -0
  141. package/testaro/imageLink.js +18 -20
  142. package/testaro/imageLink.ts +42 -0
  143. package/testaro/labClash.d.ts +3 -0
  144. package/testaro/labClash.js +32 -33
  145. package/testaro/labClash.ts +54 -0
  146. package/testaro/legendLoc.d.ts +3 -0
  147. package/testaro/legendLoc.js +18 -20
  148. package/testaro/legendLoc.ts +42 -0
  149. package/testaro/lineHeight.d.ts +3 -0
  150. package/testaro/lineHeight.js +44 -48
  151. package/testaro/lineHeight.ts +70 -0
  152. package/testaro/linkAmb.d.ts +7 -0
  153. package/testaro/linkAmb.js +80 -80
  154. package/testaro/linkAmb.ts +105 -0
  155. package/testaro/linkExt.d.ts +3 -0
  156. package/testaro/linkExt.js +14 -16
  157. package/testaro/linkExt.ts +35 -0
  158. package/testaro/linkOldAtt.d.ts +3 -0
  159. package/testaro/linkOldAtt.js +26 -28
  160. package/testaro/linkOldAtt.ts +48 -0
  161. package/testaro/linkTo.d.ts +3 -0
  162. package/testaro/linkTo.js +23 -22
  163. package/testaro/linkTo.ts +43 -0
  164. package/testaro/linkUl.d.ts +3 -0
  165. package/testaro/linkUl.js +31 -34
  166. package/testaro/linkUl.ts +54 -0
  167. package/testaro/miniText.d.ts +3 -0
  168. package/testaro/miniText.js +42 -44
  169. package/testaro/miniText.ts +68 -0
  170. package/testaro/motion.d.ts +10 -0
  171. package/testaro/motion.js +93 -96
  172. package/testaro/motion.ts +125 -0
  173. package/testaro/nonTable.d.ts +3 -0
  174. package/testaro/nonTable.js +40 -45
  175. package/testaro/nonTable.ts +66 -0
  176. package/testaro/optRoleSel.d.ts +3 -0
  177. package/testaro/optRoleSel.js +17 -19
  178. package/testaro/optRoleSel.ts +41 -0
  179. package/testaro/phOnly.d.ts +3 -0
  180. package/testaro/phOnly.js +19 -21
  181. package/testaro/phOnly.ts +43 -0
  182. package/testaro/pseudoP.d.ts +3 -0
  183. package/testaro/pseudoP.js +37 -38
  184. package/testaro/pseudoP.ts +59 -0
  185. package/testaro/radioSet.d.ts +3 -0
  186. package/testaro/radioSet.js +58 -59
  187. package/testaro/radioSet.ts +79 -0
  188. package/testaro/registry.d.ts +63 -0
  189. package/testaro/registry.js +67 -0
  190. package/testaro/registry.ts +141 -0
  191. package/testaro/role.d.ts +3 -0
  192. package/testaro/role.js +28 -29
  193. package/testaro/role.ts +53 -0
  194. package/testaro/secHeading.d.ts +3 -0
  195. package/testaro/secHeading.js +31 -33
  196. package/testaro/secHeading.ts +53 -0
  197. package/testaro/styleDiff.d.ts +25 -0
  198. package/testaro/styleDiff.js +249 -252
  199. package/testaro/styleDiff.ts +303 -0
  200. package/testaro/tabNav.d.ts +33 -0
  201. package/testaro/tabNav.js +273 -342
  202. package/testaro/tabNav.ts +454 -0
  203. package/testaro/targetsNear.d.ts +9 -0
  204. package/testaro/targetsNear.js +131 -132
  205. package/testaro/targetsNear.ts +160 -0
  206. package/testaro/textNodes.d.ts +6 -0
  207. package/testaro/textNodes.js +139 -135
  208. package/testaro/textNodes.ts +185 -0
  209. package/testaro/textSem.d.ts +3 -0
  210. package/testaro/textSem.js +26 -28
  211. package/testaro/textSem.ts +47 -0
  212. package/testaro/title.d.ts +9 -0
  213. package/testaro/title.js +16 -13
  214. package/testaro/title.ts +31 -0
  215. package/testaro/titledEl.d.ts +3 -0
  216. package/testaro/titledEl.js +16 -18
  217. package/testaro/titledEl.ts +38 -0
  218. package/testaro/zIndex.d.ts +3 -0
  219. package/testaro/zIndex.js +20 -22
  220. package/testaro/zIndex.ts +42 -0
  221. package/tests/alfa.d.ts +45 -0
  222. package/tests/alfa.js +139 -141
  223. package/tests/alfa.ts +214 -0
  224. package/tests/aslint.d.ts +33 -0
  225. package/tests/aslint.js +273 -249
  226. package/tests/aslint.ts +301 -0
  227. package/tests/axe.d.ts +27 -0
  228. package/tests/axe.js +200 -200
  229. package/tests/axe.ts +277 -0
  230. package/tests/ed11y.d.ts +28 -0
  231. package/tests/ed11y.js +142 -99
  232. package/tests/ed11y.ts +178 -0
  233. package/tests/htmlcs.d.ts +21 -0
  234. package/tests/htmlcs.js +175 -140
  235. package/tests/htmlcs.ts +181 -0
  236. package/tests/ibm.d.ts +52 -0
  237. package/tests/ibm.js +165 -166
  238. package/tests/ibm.ts +251 -0
  239. package/tests/nuVal.d.ts +13 -0
  240. package/tests/nuVal.js +107 -112
  241. package/tests/nuVal.ts +145 -0
  242. package/tests/nuVnu.d.ts +15 -0
  243. package/tests/nuVnu.js +142 -111
  244. package/tests/nuVnu.ts +144 -0
  245. package/tests/pour.d.ts +31 -0
  246. package/tests/pour.js +242 -0
  247. package/tests/pour.ts +273 -0
  248. package/tests/qualWeb.d.ts +39 -0
  249. package/tests/qualWeb.js +303 -272
  250. package/tests/qualWeb.ts +415 -0
  251. package/tests/surea11y.d.ts +33 -0
  252. package/tests/surea11y.js +288 -0
  253. package/tests/surea11y.ts +334 -0
  254. package/tests/testaro.d.ts +25 -0
  255. package/tests/testaro.js +746 -652
  256. package/tests/testaro.ts +862 -0
  257. package/tests/wave.d.ts +46 -0
  258. package/tests/wave.js +167 -177
  259. package/tests/wave.ts +252 -0
  260. package/tsconfig.json +17 -0
  261. package/types.d.ts +243 -0
  262. package/types.js +10 -0
  263. package/types.ts +376 -0
  264. package/validation/act/README.md +46 -0
  265. package/validation/act/capture.js +424 -0
  266. package/validation/act/chromium-issue-draft.md +66 -0
  267. package/validation/act/fp-triage-2026-08-22.md +86 -0
  268. package/validation/act/isolation-notes.md +159 -0
  269. package/validation/act/playwright-issue-draft.md +73 -0
  270. package/validation/act/propose-mappings.js +0 -0
  271. package/validation/act/repro-cdp-raw.js +105 -0
  272. package/validation/act/repro-metarefresh.js +65 -0
  273. package/validation/act/score.js +184 -0
  274. package/validation/act/stage3a-stress-report.md +69 -0
  275. package/validation/act/stage3b-mapping-proposals.md +94 -0
  276. package/validation/act/stage3b-triage-draft.md +138 -0
  277. package/validation/act/surea11y-track-a-2026-09-01.md +50 -0
  278. package/validation/executors/netWatch.js +180 -90
  279. package/validation/executors/test.js +17 -2
  280. package/validation/executors/tests.js +118 -10
  281. package/validation/jobs/reports/raw/260901T1000-surea11y-validation.json +964 -0
  282. package/validation/jobs/todo/240101T1200-simple-example.json +14 -6
  283. package/validation/jobs/todo/240101T1300-shoot-example.json +2 -1
  284. package/validation/jobs/todo/260821T1900-pour-validation.json +45 -0
  285. package/validation/jobs/todo/260901T1000-surea11y-validation.json +45 -0
  286. package/validation/knownFailures.json +1 -0
  287. package/validation/tests/jobProperties/adbID.json +27 -2
  288. package/validation/tests/jobProperties/{focOp.json → allCapStyle.json} +56 -53
  289. package/validation/tests/jobProperties/allCaps.json +25 -0
  290. package/validation/tests/jobProperties/allHidden.json +133 -13
  291. package/validation/tests/jobProperties/allSlanted.json +3 -3
  292. package/validation/tests/jobProperties/altScheme.json +23 -8
  293. package/validation/tests/jobProperties/attVal.json +57 -57
  294. package/validation/tests/jobProperties/autocomplete.json +11 -1
  295. package/validation/tests/jobProperties/bulk.json +6 -1
  296. package/validation/tests/jobProperties/buttonMenu.json +63 -42
  297. package/validation/tests/jobProperties/captionLoc.json +1 -6
  298. package/validation/tests/jobProperties/checkpoint-browser.json +401 -0
  299. package/validation/tests/jobProperties/checkpoint-page.json +397 -0
  300. package/validation/tests/jobProperties/checkpoint.json +395 -0
  301. package/validation/tests/jobProperties/datalistRef.json +20 -5
  302. package/validation/tests/jobProperties/distortion.json +28 -3
  303. package/validation/tests/jobProperties/docType.json +2 -2
  304. package/validation/tests/jobProperties/dupAtt.json +48 -33
  305. package/validation/tests/jobProperties/elements.json +28 -28
  306. package/validation/tests/jobProperties/embAc.json +36 -31
  307. package/validation/tests/jobProperties/focAndOp.json +284 -0
  308. package/validation/tests/jobProperties/focInd.json +34 -34
  309. package/validation/tests/jobProperties/focVis.json +1 -1
  310. package/validation/tests/jobProperties/hover.json +39 -37
  311. package/validation/tests/jobProperties/hr.json +13 -3
  312. package/validation/tests/jobProperties/imageLink.json +0 -5
  313. package/validation/tests/jobProperties/labClash.json +68 -33
  314. package/validation/tests/jobProperties/legendLoc.json +1 -6
  315. package/validation/tests/jobProperties/lineHeight.json +2 -2
  316. package/validation/tests/jobProperties/linkAmb.json +13 -18
  317. package/validation/tests/jobProperties/linkExt.json +1 -1
  318. package/validation/tests/jobProperties/linkOldAtt.json +12 -2
  319. package/validation/tests/jobProperties/linkTo.json +1 -1
  320. package/validation/tests/jobProperties/linkUl.json +65 -65
  321. package/validation/tests/jobProperties/miniText.json +7 -2
  322. package/validation/tests/jobProperties/motion.json +4 -50
  323. package/validation/tests/jobProperties/nonTable.json +48 -3
  324. package/validation/tests/jobProperties/optRoleSel.json +12 -2
  325. package/validation/tests/jobProperties/phOnly.json +6 -16
  326. package/validation/tests/jobProperties/pseudoP.json +17 -2
  327. package/validation/tests/jobProperties/radioSet.json +30 -30
  328. package/validation/tests/jobProperties/role.json +25 -5
  329. package/validation/tests/jobProperties/secHeading.json +26 -21
  330. package/validation/tests/jobProperties/styleDiff.json +35 -5
  331. package/validation/tests/jobProperties/tabNav.json +3 -1
  332. package/validation/tests/jobProperties/targetsNear.json +237 -0
  333. package/validation/tests/jobProperties/textNodes.json +29 -29
  334. package/validation/tests/jobProperties/textSem.json +26 -1
  335. package/validation/tests/jobProperties/title.json +12 -2
  336. package/validation/tests/jobProperties/titledEl.json +39 -9
  337. package/validation/tests/jobProperties/userPath.json +317 -0
  338. package/validation/tests/jobProperties/zIndex.json +40 -35
  339. package/validation/tests/targets/allCapStyle/index.html +26 -0
  340. package/validation/tests/targets/checkpoint/index.html +38 -0
  341. package/validation/tests/targets/datalistRef/index.html +1 -1
  342. package/validation/tests/targets/focAndOp/bad.html +29 -0
  343. package/validation/tests/targets/{focOp → focAndOp}/good.html +3 -1
  344. package/validation/tests/targets/focInd/bad.html +2 -1
  345. package/validation/tests/targets/headEl/index.html +10 -1
  346. package/validation/tests/targets/{targetSmall → targetsNear}/index.html +15 -1
  347. package/validation/tests/targets/userPath/index.html +42 -0
  348. package/validation/validateTest.js +62 -10
  349. package/.claude/settings.local.json +0 -11
  350. package/.eslintrc.json +0 -41
  351. package/htmlcs/.eslintrc.json +0 -67
  352. package/memory/MEMORY.md +0 -3
  353. package/memory/project_validation_pause.md +0 -10
  354. package/validation/tests/jobProperties/linkTitle.json +0 -127
  355. package/validation/tests/jobProperties/opFoc.json +0 -164
  356. package/validation/tests/jobProperties/targetSmall.json +0 -152
  357. package/validation/tests/jobProperties/targetTiny.json +0 -142
  358. package/validation/tests/targets/focOp/bad.html +0 -25
  359. package/validation/tests/targets/linkTitle/index.html +0 -24
  360. package/validation/tests/targets/opFoc/bad.html +0 -26
  361. 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,43 +1,41 @@
1
+ "use strict";
1
2
  /*
2
3
  © 2025 CVS Health and/or one of its affiliates. All rights reserved.
4
+ © 2026 Jeff Witt.
3
5
  © 2025–2026 Jonathan Robert Pool.
4
6
 
5
7
  Licensed under the MIT License. See LICENSE file at the project root or https://opensource.org/license/mit/ for details.
6
8
 
7
9
  SPDX-License-Identifier: MIT
8
10
  */
9
-
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.reporter = void 0;
13
+ const testaro_1 = require("../procs/testaro");
10
14
  /*
11
15
  textSem
12
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.
13
18
  */
14
-
15
- // IMPORTS
16
-
17
- const {doTest} = require('../procs/testaro');
18
-
19
19
  // FUNCTIONS
20
-
21
20
  // Runs the test and returns the result.
22
- exports.reporter = async (page, report, _, withItems) => {
23
- const getBadWhat = element => {
24
- const isVisible = element.checkVisibility({
25
- contentVisibilityAuto: true,
26
- opacityProperty: true,
27
- visibilityProperty: true
28
- });
29
- // If the element is visible:
30
- if (isVisible) {
31
- // If it has text content:
32
- if (element.textContent.trim().replace(/\s/g, '')) {
33
- // Return a violation description.
34
- return `Element type (${element.tagName}) is semantically vague`;
35
- }
36
- }
37
- };
38
- const selector = 'body i, body b, body small';
39
- const whats = 'Semantically vague elements i, b, and/or small are used';
40
- return await doTest(
41
- page, report, withItems, 'textSem', selector, whats, 0, getBadWhat.toString()
42
- );
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());
43
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;