testaro 78.0.8 → 78.6.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 (357) hide show
  1. package/.gitattributes +94 -0
  2. package/.github/workflows/ci.yml +58 -0
  3. package/.github/workflows/publish.yml +50 -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 +143 -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/dist/nameComputation.js +1 -0
  16. package/docker-compose.yml +8 -2
  17. package/docs/checkpoint-scanning.md +199 -0
  18. package/docs/standard-result-outcome.md +165 -0
  19. package/env.example +49 -10
  20. package/eslint.config.mjs +101 -0
  21. package/netWatch.js +372 -222
  22. package/package.json +46 -31
  23. package/pour/README.md +47 -0
  24. package/pour/pour.min.js +8 -0
  25. package/procs/actDo.js +808 -0
  26. package/procs/catalog.d.ts +17 -0
  27. package/procs/catalog.js +312 -221
  28. package/procs/catalog.ts +398 -0
  29. package/procs/checkpoint.js +110 -0
  30. package/procs/config.d.ts +41 -0
  31. package/procs/config.js +98 -0
  32. package/procs/dateTime.js +2 -1
  33. package/procs/doActs.js +442 -849
  34. package/procs/doTestAct.js +27 -121
  35. package/procs/flow.js +221 -0
  36. package/procs/generateRuleRegistry.js +94 -0
  37. package/procs/getSource.d.ts +26 -0
  38. package/procs/job.js +115 -1
  39. package/procs/launch.d.ts +40 -0
  40. package/procs/launch.js +243 -108
  41. package/procs/nu.d.ts +48 -0
  42. package/procs/scope.js +196 -0
  43. package/procs/shoot.d.ts +33 -0
  44. package/procs/standard.d.ts +18 -0
  45. package/procs/standard.js +83 -0
  46. package/procs/standard.ts +126 -0
  47. package/procs/testAct.js +145 -0
  48. package/procs/testaro.d.ts +20 -0
  49. package/procs/testaro.js +236 -189
  50. package/procs/testaro.ts +321 -0
  51. package/procs/userPath.js +126 -0
  52. package/procs/xPath.d.ts +4 -0
  53. package/procs/xPath.js +81 -69
  54. package/procs/xPath.ts +106 -0
  55. package/procs/xPathScript.d.ts +6 -0
  56. package/procs/xPathScript.js +70 -0
  57. package/run.js +3 -2
  58. package/surea11y/README.md +44 -0
  59. package/surea11y/surea11y.browser.js +14 -0
  60. package/testaro/adbID.d.ts +3 -0
  61. package/testaro/adbID.js +38 -41
  62. package/testaro/adbID.ts +66 -0
  63. package/testaro/allCapStyle.d.ts +3 -0
  64. package/testaro/allCapStyle.js +31 -34
  65. package/testaro/allCapStyle.ts +55 -0
  66. package/testaro/allCaps.d.ts +16 -0
  67. package/testaro/allCaps.js +179 -151
  68. package/testaro/allCaps.ts +228 -0
  69. package/testaro/allHidden.d.ts +13 -0
  70. package/testaro/allHidden.js +29 -30
  71. package/testaro/allHidden.ts +50 -0
  72. package/testaro/allSlanted.d.ts +3 -0
  73. package/testaro/allSlanted.js +30 -33
  74. package/testaro/allSlanted.ts +54 -0
  75. package/testaro/altScheme.d.ts +3 -0
  76. package/testaro/altScheme.js +27 -30
  77. package/testaro/altScheme.ts +50 -0
  78. package/testaro/attVal.d.ts +3 -0
  79. package/testaro/attVal.js +20 -21
  80. package/testaro/attVal.ts +52 -0
  81. package/testaro/autocomplete.d.ts +3 -0
  82. package/testaro/autocomplete.js +59 -75
  83. package/testaro/autocomplete.ts +101 -0
  84. package/testaro/bulk.d.ts +13 -0
  85. package/testaro/bulk.js +32 -33
  86. package/testaro/bulk.ts +55 -0
  87. package/testaro/buttonMenu.d.ts +9 -0
  88. package/testaro/buttonMenu.js +317 -319
  89. package/testaro/buttonMenu.ts +391 -0
  90. package/testaro/captionLoc.d.ts +3 -0
  91. package/testaro/captionLoc.js +17 -20
  92. package/testaro/captionLoc.ts +40 -0
  93. package/testaro/datalistRef.d.ts +3 -0
  94. package/testaro/datalistRef.js +33 -36
  95. package/testaro/datalistRef.ts +55 -0
  96. package/testaro/distortion.d.ts +3 -0
  97. package/testaro/distortion.js +57 -26
  98. package/testaro/distortion.ts +81 -0
  99. package/testaro/docType.d.ts +15 -0
  100. package/testaro/docType.js +25 -25
  101. package/testaro/docType.ts +45 -0
  102. package/testaro/dupAtt.d.ts +16 -0
  103. package/testaro/dupAtt.js +113 -104
  104. package/testaro/dupAtt.ts +144 -0
  105. package/testaro/elements.d.ts +6 -0
  106. package/testaro/elements.js +153 -153
  107. package/testaro/elements.ts +215 -0
  108. package/testaro/embAc.d.ts +3 -0
  109. package/testaro/embAc.js +19 -20
  110. package/testaro/embAc.ts +40 -0
  111. package/testaro/focAll.d.ts +13 -0
  112. package/testaro/focAll.js +185 -191
  113. package/testaro/focAll.ts +217 -0
  114. package/testaro/focAndOp.d.ts +3 -0
  115. package/testaro/focAndOp.js +100 -104
  116. package/testaro/focAndOp.ts +128 -0
  117. package/testaro/focInd.d.ts +3 -0
  118. package/testaro/focInd.js +64 -66
  119. package/testaro/focInd.ts +96 -0
  120. package/testaro/focVis.d.ts +3 -0
  121. package/testaro/focVis.js +28 -30
  122. package/testaro/focVis.ts +52 -0
  123. package/testaro/headEl.d.ts +10 -0
  124. package/testaro/headEl.js +61 -62
  125. package/testaro/headEl.ts +82 -0
  126. package/testaro/headingAmb.d.ts +3 -0
  127. package/testaro/headingAmb.js +54 -63
  128. package/testaro/headingAmb.ts +72 -0
  129. package/testaro/hovInd.d.ts +12 -0
  130. package/testaro/hovInd.js +163 -130
  131. package/testaro/hovInd.ts +199 -0
  132. package/testaro/hover.d.ts +3 -0
  133. package/testaro/hover.js +155 -126
  134. package/testaro/hover.ts +154 -0
  135. package/testaro/hr.d.ts +3 -0
  136. package/testaro/hr.js +14 -17
  137. package/testaro/hr.ts +36 -0
  138. package/testaro/imageLink.d.ts +3 -0
  139. package/testaro/imageLink.js +17 -20
  140. package/testaro/imageLink.ts +42 -0
  141. package/testaro/labClash.d.ts +3 -0
  142. package/testaro/labClash.js +31 -33
  143. package/testaro/labClash.ts +54 -0
  144. package/testaro/legendLoc.d.ts +3 -0
  145. package/testaro/legendLoc.js +17 -20
  146. package/testaro/legendLoc.ts +42 -0
  147. package/testaro/lineHeight.d.ts +3 -0
  148. package/testaro/lineHeight.js +43 -48
  149. package/testaro/lineHeight.ts +70 -0
  150. package/testaro/linkAmb.d.ts +7 -0
  151. package/testaro/linkAmb.js +79 -80
  152. package/testaro/linkAmb.ts +105 -0
  153. package/testaro/linkExt.d.ts +3 -0
  154. package/testaro/linkExt.js +13 -16
  155. package/testaro/linkExt.ts +35 -0
  156. package/testaro/linkOldAtt.d.ts +3 -0
  157. package/testaro/linkOldAtt.js +25 -28
  158. package/testaro/linkOldAtt.ts +48 -0
  159. package/testaro/linkTo.d.ts +3 -0
  160. package/testaro/linkTo.js +22 -22
  161. package/testaro/linkTo.ts +43 -0
  162. package/testaro/linkUl.d.ts +3 -0
  163. package/testaro/linkUl.js +30 -34
  164. package/testaro/linkUl.ts +54 -0
  165. package/testaro/miniText.d.ts +3 -0
  166. package/testaro/miniText.js +41 -44
  167. package/testaro/miniText.ts +68 -0
  168. package/testaro/motion.d.ts +10 -0
  169. package/testaro/motion.js +92 -96
  170. package/testaro/motion.ts +125 -0
  171. package/testaro/nonTable.d.ts +3 -0
  172. package/testaro/nonTable.js +39 -45
  173. package/testaro/nonTable.ts +66 -0
  174. package/testaro/optRoleSel.d.ts +3 -0
  175. package/testaro/optRoleSel.js +16 -19
  176. package/testaro/optRoleSel.ts +41 -0
  177. package/testaro/phOnly.d.ts +3 -0
  178. package/testaro/phOnly.js +18 -21
  179. package/testaro/phOnly.ts +43 -0
  180. package/testaro/pseudoP.d.ts +3 -0
  181. package/testaro/pseudoP.js +36 -38
  182. package/testaro/pseudoP.ts +59 -0
  183. package/testaro/radioSet.d.ts +3 -0
  184. package/testaro/radioSet.js +57 -59
  185. package/testaro/radioSet.ts +79 -0
  186. package/testaro/registry.d.ts +63 -0
  187. package/testaro/registry.js +67 -0
  188. package/testaro/registry.ts +141 -0
  189. package/testaro/role.d.ts +3 -0
  190. package/testaro/role.js +27 -29
  191. package/testaro/role.ts +53 -0
  192. package/testaro/secHeading.d.ts +3 -0
  193. package/testaro/secHeading.js +30 -33
  194. package/testaro/secHeading.ts +53 -0
  195. package/testaro/styleDiff.d.ts +25 -0
  196. package/testaro/styleDiff.js +248 -252
  197. package/testaro/styleDiff.ts +303 -0
  198. package/testaro/tabNav.d.ts +33 -0
  199. package/testaro/tabNav.js +272 -342
  200. package/testaro/tabNav.ts +454 -0
  201. package/testaro/targetsNear.d.ts +9 -0
  202. package/testaro/targetsNear.js +130 -132
  203. package/testaro/targetsNear.ts +160 -0
  204. package/testaro/textNodes.d.ts +6 -0
  205. package/testaro/textNodes.js +139 -135
  206. package/testaro/textNodes.ts +185 -0
  207. package/testaro/textSem.d.ts +3 -0
  208. package/testaro/textSem.js +25 -28
  209. package/testaro/textSem.ts +47 -0
  210. package/testaro/title.d.ts +9 -0
  211. package/testaro/title.js +16 -13
  212. package/testaro/title.ts +31 -0
  213. package/testaro/titledEl.d.ts +3 -0
  214. package/testaro/titledEl.js +15 -18
  215. package/testaro/titledEl.ts +38 -0
  216. package/testaro/zIndex.d.ts +3 -0
  217. package/testaro/zIndex.js +19 -22
  218. package/testaro/zIndex.ts +42 -0
  219. package/tests/alfa.d.ts +45 -0
  220. package/tests/alfa.js +138 -141
  221. package/tests/alfa.ts +214 -0
  222. package/tests/aslint.d.ts +33 -0
  223. package/tests/aslint.js +272 -249
  224. package/tests/aslint.ts +301 -0
  225. package/tests/axe.d.ts +27 -0
  226. package/tests/axe.js +199 -200
  227. package/tests/axe.ts +277 -0
  228. package/tests/ed11y.d.ts +28 -0
  229. package/tests/ed11y.js +141 -99
  230. package/tests/ed11y.ts +178 -0
  231. package/tests/htmlcs.d.ts +21 -0
  232. package/tests/htmlcs.js +174 -140
  233. package/tests/htmlcs.ts +181 -0
  234. package/tests/ibm.d.ts +57 -0
  235. package/tests/ibm.js +182 -175
  236. package/tests/ibm.ts +287 -0
  237. package/tests/nuVal.d.ts +13 -0
  238. package/tests/nuVal.js +107 -112
  239. package/tests/nuVal.ts +145 -0
  240. package/tests/nuVnu.d.ts +15 -0
  241. package/tests/nuVnu.js +141 -111
  242. package/tests/nuVnu.ts +144 -0
  243. package/tests/pour.d.ts +31 -0
  244. package/tests/pour.js +242 -0
  245. package/tests/pour.ts +273 -0
  246. package/tests/qualWeb.d.ts +39 -0
  247. package/tests/qualWeb.js +262 -273
  248. package/tests/qualWeb.ts +344 -0
  249. package/tests/surea11y.d.ts +33 -0
  250. package/tests/surea11y.js +288 -0
  251. package/tests/surea11y.ts +334 -0
  252. package/tests/testaro.d.ts +25 -0
  253. package/tests/testaro.js +745 -652
  254. package/tests/testaro.ts +862 -0
  255. package/tests/wave.d.ts +46 -0
  256. package/tests/wave.js +166 -177
  257. package/tests/wave.ts +252 -0
  258. package/tsconfig.json +17 -0
  259. package/types.d.ts +243 -0
  260. package/types.js +10 -0
  261. package/types.ts +376 -0
  262. package/validation/act/README.md +46 -0
  263. package/validation/act/capture.js +877 -0
  264. package/validation/act/chromium-issue-draft.md +66 -0
  265. package/validation/act/fp-triage-2026-08-22.md +86 -0
  266. package/validation/act/isolation-notes.md +159 -0
  267. package/validation/act/playwright-issue-draft.md +73 -0
  268. package/validation/act/propose-mappings.js +0 -0
  269. package/validation/act/repro-cdp-raw.js +105 -0
  270. package/validation/act/repro-metarefresh.js +65 -0
  271. package/validation/act/score.js +184 -0
  272. package/validation/act/stage3a-stress-report.md +69 -0
  273. package/validation/act/stage3b-mapping-proposals.md +94 -0
  274. package/validation/act/stage3b-triage-draft.md +138 -0
  275. package/validation/act/surea11y-track-a-2026-09-01.md +50 -0
  276. package/validation/executors/netWatch.js +180 -90
  277. package/validation/executors/test.js +17 -2
  278. package/validation/executors/tests.js +118 -10
  279. package/validation/jobs/reports/raw/260901T1000-surea11y-validation.json +964 -0
  280. package/validation/jobs/todo/240101T1200-simple-example.json +14 -6
  281. package/validation/jobs/todo/240101T1300-shoot-example.json +2 -1
  282. package/validation/jobs/todo/260821T1900-pour-validation.json +45 -0
  283. package/validation/jobs/todo/260901T1000-surea11y-validation.json +45 -0
  284. package/validation/knownFailures.json +1 -0
  285. package/validation/tests/jobProperties/adbID.json +27 -2
  286. package/validation/tests/jobProperties/{focOp.json → allCapStyle.json} +56 -53
  287. package/validation/tests/jobProperties/allCaps.json +25 -0
  288. package/validation/tests/jobProperties/allHidden.json +133 -13
  289. package/validation/tests/jobProperties/allSlanted.json +3 -3
  290. package/validation/tests/jobProperties/altScheme.json +23 -8
  291. package/validation/tests/jobProperties/attVal.json +57 -57
  292. package/validation/tests/jobProperties/autocomplete.json +11 -1
  293. package/validation/tests/jobProperties/bulk.json +6 -1
  294. package/validation/tests/jobProperties/buttonMenu.json +63 -42
  295. package/validation/tests/jobProperties/captionLoc.json +1 -6
  296. package/validation/tests/jobProperties/checkpoint-browser.json +401 -0
  297. package/validation/tests/jobProperties/checkpoint-page.json +397 -0
  298. package/validation/tests/jobProperties/checkpoint.json +395 -0
  299. package/validation/tests/jobProperties/datalistRef.json +20 -5
  300. package/validation/tests/jobProperties/distortion.json +28 -3
  301. package/validation/tests/jobProperties/docType.json +2 -2
  302. package/validation/tests/jobProperties/dupAtt.json +48 -33
  303. package/validation/tests/jobProperties/elements.json +28 -28
  304. package/validation/tests/jobProperties/embAc.json +36 -31
  305. package/validation/tests/jobProperties/focAndOp.json +284 -0
  306. package/validation/tests/jobProperties/focInd.json +34 -34
  307. package/validation/tests/jobProperties/focVis.json +1 -1
  308. package/validation/tests/jobProperties/hover.json +39 -37
  309. package/validation/tests/jobProperties/hr.json +13 -3
  310. package/validation/tests/jobProperties/imageLink.json +0 -5
  311. package/validation/tests/jobProperties/labClash.json +68 -33
  312. package/validation/tests/jobProperties/legendLoc.json +1 -6
  313. package/validation/tests/jobProperties/lineHeight.json +2 -2
  314. package/validation/tests/jobProperties/linkAmb.json +13 -18
  315. package/validation/tests/jobProperties/linkExt.json +1 -1
  316. package/validation/tests/jobProperties/linkOldAtt.json +12 -2
  317. package/validation/tests/jobProperties/linkTo.json +1 -1
  318. package/validation/tests/jobProperties/linkUl.json +65 -65
  319. package/validation/tests/jobProperties/miniText.json +7 -2
  320. package/validation/tests/jobProperties/motion.json +4 -50
  321. package/validation/tests/jobProperties/nonTable.json +48 -3
  322. package/validation/tests/jobProperties/optRoleSel.json +12 -2
  323. package/validation/tests/jobProperties/phOnly.json +6 -16
  324. package/validation/tests/jobProperties/pseudoP.json +17 -2
  325. package/validation/tests/jobProperties/radioSet.json +30 -30
  326. package/validation/tests/jobProperties/role.json +25 -5
  327. package/validation/tests/jobProperties/secHeading.json +26 -21
  328. package/validation/tests/jobProperties/styleDiff.json +35 -5
  329. package/validation/tests/jobProperties/tabNav.json +3 -1
  330. package/validation/tests/jobProperties/targetsNear.json +237 -0
  331. package/validation/tests/jobProperties/textNodes.json +29 -29
  332. package/validation/tests/jobProperties/textSem.json +26 -1
  333. package/validation/tests/jobProperties/title.json +12 -2
  334. package/validation/tests/jobProperties/titledEl.json +39 -9
  335. package/validation/tests/jobProperties/userPath.json +317 -0
  336. package/validation/tests/jobProperties/zIndex.json +40 -35
  337. package/validation/tests/targets/allCapStyle/index.html +26 -0
  338. package/validation/tests/targets/checkpoint/index.html +38 -0
  339. package/validation/tests/targets/datalistRef/index.html +1 -1
  340. package/validation/tests/targets/focAndOp/bad.html +29 -0
  341. package/validation/tests/targets/{focOp → focAndOp}/good.html +3 -1
  342. package/validation/tests/targets/focInd/bad.html +2 -1
  343. package/validation/tests/targets/headEl/index.html +10 -1
  344. package/validation/tests/targets/{targetSmall → targetsNear}/index.html +15 -1
  345. package/validation/tests/targets/userPath/index.html +42 -0
  346. package/validation/validateTest.js +61 -9
  347. package/.claude/settings.local.json +0 -11
  348. package/.eslintrc.json +0 -41
  349. package/htmlcs/.eslintrc.json +0 -67
  350. package/validation/tests/jobProperties/linkTitle.json +0 -127
  351. package/validation/tests/jobProperties/opFoc.json +0 -164
  352. package/validation/tests/jobProperties/targetSmall.json +0 -152
  353. package/validation/tests/jobProperties/targetTiny.json +0 -142
  354. package/validation/tests/targets/focOp/bad.html +0 -25
  355. package/validation/tests/targets/linkTitle/index.html +0 -24
  356. package/validation/tests/targets/opFoc/bad.html +0 -26
  357. package/validation/tests/targets/opFoc/good.html +0 -23
@@ -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 Jeff Witt.
@@ -8,58 +9,54 @@
8
9
 
9
10
  SPDX-License-Identifier: MIT
10
11
  */
11
-
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.reporter = void 0;
14
+ const testaro_1 = require("../procs/testaro");
12
15
  /*
13
16
  miniText
14
17
  Derived from the bbc-a11y textCannotBeTooSmall test.
15
18
  Related to Tenon rule 134.
16
19
  This test reports elements with font sizes smaller than 11 pixels.
20
+ Compiled to miniText.js by tsc (issue #73); edit this file, not the emitted one.
17
21
  */
18
-
19
- // IMPORTS
20
-
21
- const {doTest} = require('../procs/testaro');
22
-
23
22
  // FUNCTIONS
24
-
25
23
  // Runs the test and returns the result.
26
- exports.reporter = async (page, report, _, withItems) => {
27
- const getBadWhat = element => {
28
- const rawText = element.textContent || '';
29
- // If the element has text content with any non-whitespace:
30
- if (/[^\s]/.test(rawText)) {
31
- const isVisible = element.checkVisibility({
32
- contentVisibilityAuto: true,
33
- opacityProperty: true,
34
- visibilityProperty: true
35
- });
36
- // If the element is visible:
37
- if (isVisible) {
38
- const styleDec = window.getComputedStyle(element);
39
- // Get its font size.
40
- const fontSizeString = styleDec.fontSize;
41
- const fontSize = Number.parseFloat(fontSizeString);
42
- // If its font size is smaller than 11 pixels:
43
- if (fontSize < 11) {
44
- const parent = element.parentElement;
45
- // If the element has a parent:
46
- if (parent) {
47
- const parentStyleDec = window.getComputedStyle(parent);
48
- const parentFontSize = Number.parseFloat(parentStyleDec.fontSize);
49
- // If the parent also has a font size smaller than 11 pixels:
50
- if (parentFontSize < 11) {
51
- // Do not report a violation, because the font size may be inherited.
52
- return null;
24
+ const reporter = async (page, report, _, withItems) => {
25
+ const getBadWhat = element => {
26
+ const rawText = element.textContent || '';
27
+ // If the element has text content with any non-whitespace:
28
+ if (/[^\s]/.test(rawText)) {
29
+ const isVisible = element.checkVisibility({
30
+ contentVisibilityAuto: true,
31
+ opacityProperty: true,
32
+ visibilityProperty: true
33
+ });
34
+ // If the element is visible:
35
+ if (isVisible) {
36
+ const styleDec = window.getComputedStyle(element);
37
+ // Get its font size.
38
+ const fontSizeString = styleDec.fontSize;
39
+ const fontSize = Number.parseFloat(fontSizeString);
40
+ // If its font size is smaller than 11 pixels:
41
+ if (fontSize < 11) {
42
+ const parent = element.parentElement;
43
+ // If the element has a parent:
44
+ if (parent) {
45
+ const parentStyleDec = window.getComputedStyle(parent);
46
+ const parentFontSize = Number.parseFloat(parentStyleDec.fontSize);
47
+ // If the parent also has a font size smaller than 11 pixels:
48
+ if (parentFontSize < 11) {
49
+ // Do not report a violation, because the font size may be inherited.
50
+ return null;
51
+ }
52
+ }
53
+ // Return a violation description.
54
+ return `Element is visible but its font size is ${fontSize}px, smaller than 11px`;
55
+ }
53
56
  }
54
- }
55
- // Return a violation description.
56
- return `Element is visible but its font size is ${fontSize}px, smaller than 11px`;
57
57
  }
58
- }
59
- }
60
- };
61
- const whats = 'Visible elements have font sizes smaller than 11 pixels';
62
- return await doTest(
63
- page, report, withItems, 'miniText', 'body, body *:not(script, style)', whats, 2, getBadWhat.toString()
64
- );
58
+ };
59
+ const whats = 'Visible elements have font sizes smaller than 11 pixels';
60
+ return await (0, testaro_1.doTest)(page, report, withItems, 'miniText', 'body, body *:not(script, style)', whats, 2, getBadWhat.toString());
65
61
  };
62
+ exports.reporter = reporter;
@@ -0,0 +1,68 @@
1
+ /*
2
+ © 2022–2023 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
7
+ https://opensource.org/license/mit/ for details.
8
+
9
+ SPDX-License-Identifier: MIT
10
+ */
11
+
12
+ // IMPORTS
13
+
14
+ import type {Page} from 'playwright';
15
+ import {doTest} from '../procs/testaro';
16
+ import type {GetBadWhat, Report} from '../types';
17
+
18
+ /*
19
+ miniText
20
+ Derived from the bbc-a11y textCannotBeTooSmall test.
21
+ Related to Tenon rule 134.
22
+ This test reports elements with font sizes smaller than 11 pixels.
23
+ Compiled to miniText.js by tsc (issue #73); edit this file, not the emitted one.
24
+ */
25
+
26
+ // FUNCTIONS
27
+
28
+ // Runs the test and returns the result.
29
+ export const reporter = async (page: Page, report: Report, _: unknown, withItems: boolean) => {
30
+ const getBadWhat: GetBadWhat = element => {
31
+ const rawText = element.textContent || '';
32
+ // If the element has text content with any non-whitespace:
33
+ if (/[^\s]/.test(rawText)) {
34
+ const isVisible = element.checkVisibility({
35
+ contentVisibilityAuto: true,
36
+ opacityProperty: true,
37
+ visibilityProperty: true
38
+ });
39
+ // If the element is visible:
40
+ if (isVisible) {
41
+ const styleDec = window.getComputedStyle(element);
42
+ // Get its font size.
43
+ const fontSizeString = styleDec.fontSize;
44
+ const fontSize = Number.parseFloat(fontSizeString);
45
+ // If its font size is smaller than 11 pixels:
46
+ if (fontSize < 11) {
47
+ const parent = element.parentElement;
48
+ // If the element has a parent:
49
+ if (parent) {
50
+ const parentStyleDec = window.getComputedStyle(parent);
51
+ const parentFontSize = Number.parseFloat(parentStyleDec.fontSize);
52
+ // If the parent also has a font size smaller than 11 pixels:
53
+ if (parentFontSize < 11) {
54
+ // Do not report a violation, because the font size may be inherited.
55
+ return null;
56
+ }
57
+ }
58
+ // Return a violation description.
59
+ return `Element is visible but its font size is ${fontSize}px, smaller than 11px`;
60
+ }
61
+ }
62
+ }
63
+ };
64
+ const whats = 'Visible elements have font sizes smaller than 11 pixels';
65
+ return await doTest(
66
+ page, report, withItems, 'miniText', 'body, body *:not(script, style)', whats, 2, getBadWhat.toString()
67
+ );
68
+ };
@@ -0,0 +1,10 @@
1
+ import type { Page } from 'playwright';
2
+ import type { Report, StandardInstance } from '../types';
3
+ export declare const reporter: (page: Page, report: Report) => Promise<{
4
+ data: {
5
+ prevented?: boolean;
6
+ error?: string;
7
+ };
8
+ totals: number[];
9
+ standardInstances: StandardInstance[];
10
+ }>;
package/testaro/motion.js CHANGED
@@ -1,9 +1,16 @@
1
+ "use strict";
1
2
  /*
2
3
  © 2026 Jeff Witt.
3
4
  © 2025–2026 Jonathan Robert Pool.
4
5
  Licensed under the MIT License. See LICENSE for details.
5
6
  */
6
-
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.reporter = void 0;
9
+ const xPath_1 = require("../procs/xPath");
10
+ const shoot_1 = require("../procs/shoot");
11
+ // pixelmatch and pngjs ship no bundled declarations, so their imports stay requires, untyped.
12
+ const pixelmatch = require('pixelmatch').default;
13
+ const { PNG } = require('pngjs');
7
14
  /*
8
15
  motion
9
16
  This test reports motion in a page by making a page image and comparing it with the initial one, i.e. the one made by the catalog proc.
@@ -11,107 +18,96 @@
11
18
  For minimal accessibility, standards require motion to be brief, or else stoppable by the user. But stopping motion can be difficult or impossible, and, by the time a user manages to stop motion, the motion may have caused annoyance or harm. For superior accessibility, a page contains no motion until and unless the user authorizes it. The test reports a rule violation if any pixels differ between the screenshots. The larger the change fraction, the greater the ordinal severity.
12
19
 
13
20
  WARNING: The shoot test uses the procs/screenShot module. See the warning in that module about browser types.
14
- */
15
-
16
- // IMPORTS
17
-
18
- const {getXPathCatalogIndex} = require('../procs/xPath');
19
- const {shoot} = require('../procs/shoot');
20
- const pixelmatch = require('pixelmatch').default;
21
- const {PNG} = require('pngjs');
22
21
 
22
+ Compiled to motion.js by tsc (issue #73); edit this file, not the emitted one.
23
+ */
23
24
  // FUNCTIONS
24
-
25
25
  // Runs the test and returns the result.
26
- exports.reporter = async (page, report) => {
27
- // Initialize the totals and standard instances.
28
- const data = {};
29
- const totals = [0, 0, 0, 0];
30
- const standardInstances = [];
31
- // If the initial image exists:
32
- if (report.images?.length) {
33
- let violationWhat = '';
34
- let ordinalSeverity = 0;
35
- // Make an image with the same color type as the initial one and get its base64 encoding.
36
- const png = await shoot(page, report, {
37
- exclusionSelector: null,
38
- colorType: report.imageColor,
39
- action: 'return'
40
- });
41
- // If this succeeded:
42
- if (png) {
43
- // Parse both base64 encodings into PNG objects.
44
- const initialPNG = PNG.sync.read(Buffer.from(report.images[0], 'base64'));
45
- const finalPNG = PNG.sync.read(Buffer.from(png, 'base64'));
46
- // If their dimensions differ:
47
- if (finalPNG.width !== initialPNG.width || finalPNG.height !== initialPNG.height) {
48
- const fromSize = `${initialPNG.width}×${initialPNG.height}`;
49
- const toSize = `${finalPNG.width}×${finalPNG.height}`;
50
- // Describe the violation.
51
- violationWhat = `Page size changes spontaneously (from ${fromSize} to ${toSize})`;
52
- }
53
- // Otherwise, i.e. if their dimensions are identical:
54
- else {
55
- // Get the count of differing pixels between the images, using the default sensitivity.
56
- try {
57
- const pixelChanges = pixelmatch(
58
- initialPNG.data,
59
- finalPNG.data,
60
- null,
61
- initialPNG.width,
62
- initialPNG.height,
63
- {
64
- threshold: 0.1
26
+ const reporter = async (page, report) => {
27
+ // Initialize the totals and standard instances.
28
+ const data = {};
29
+ const totals = [0, 0, 0, 0];
30
+ const standardInstances = [];
31
+ // Identify the image of the checkpoint being tested (images[0] for checkpoint 0).
32
+ const checkpointIndex = report.activeCheckpoint ?? 0;
33
+ const imageIndex = report.checkpoints?.[checkpointIndex]?.imageIndexes?.[0] ?? 0;
34
+ // If the initial image exists:
35
+ if (report.images?.[imageIndex] !== undefined) {
36
+ let violationWhat = '';
37
+ let ordinalSeverity = 0;
38
+ // Make an image with the same color type as the initial one and get its base64 encoding.
39
+ const png = await (0, shoot_1.shoot)(page, report, {
40
+ exclusionSelector: null,
41
+ colorType: report.imageColor,
42
+ action: 'return'
43
+ });
44
+ // If this succeeded:
45
+ if (png) {
46
+ // Parse both base64 encodings into PNG objects.
47
+ const initialPNG = PNG.sync.read(Buffer.from(report.images[imageIndex], 'base64'));
48
+ const finalPNG = PNG.sync.read(Buffer.from(png, 'base64'));
49
+ // If their dimensions differ:
50
+ if (finalPNG.width !== initialPNG.width || finalPNG.height !== initialPNG.height) {
51
+ const fromSize = `${initialPNG.width}×${initialPNG.height}`;
52
+ const toSize = `${finalPNG.width}×${finalPNG.height}`;
53
+ // Describe the violation.
54
+ violationWhat = `Page size changes spontaneously (from ${fromSize} to ${toSize})`;
55
+ }
56
+ // Otherwise, i.e. if their dimensions are identical:
57
+ else {
58
+ // Get the count of differing pixels between the images, using the default sensitivity.
59
+ try {
60
+ const pixelChanges = pixelmatch(initialPNG.data, finalPNG.data, null, initialPNG.width, initialPNG.height, {
61
+ threshold: 0.1
62
+ });
63
+ // Get the ratio of differing to all pixels as a percentage.
64
+ const changePercent = Math.round(100 * pixelChanges / (initialPNG.width * initialPNG.height));
65
+ // If any pixels were changed:
66
+ if (pixelChanges) {
67
+ // Describe the violation.
68
+ violationWhat = `Content changes spontaneously (${changePercent}% of pixels changed)`;
69
+ // Get the ordinal severity from the fractional pixel change.
70
+ ordinalSeverity = Math.floor(Math.min(3, 0.4 * Math.sqrt(changePercent)));
71
+ }
72
+ }
73
+ catch (err) {
74
+ console.log(`pixelmatch error: ${err.message}, ${err.stack}`);
75
+ data.prevented = true;
76
+ data.error = `Pixel comparison failed: ${err.message}`;
77
+ }
78
+ }
79
+ // If there was a violation:
80
+ if (violationWhat) {
81
+ // Add to the totals.
82
+ totals[ordinalSeverity] = 1;
83
+ // Get a summary standard instance.
84
+ standardInstances.push({
85
+ ruleID: 'motion',
86
+ what: violationWhat,
87
+ ordinalSeverity: ordinalSeverity,
88
+ count: 1,
89
+ catalogIndex: (0, xPath_1.getXPathCatalogIndex)(report, '/html/body')
90
+ });
65
91
  }
66
- );
67
- // Get the ratio of differing to all pixels as a percentage.
68
- const changePercent = Math.round(
69
- 100 * pixelChanges / (initialPNG.width * initialPNG.height)
70
- );
71
- // If any pixels were changed:
72
- if (pixelChanges) {
73
- // Describe the violation.
74
- violationWhat = `Content changes spontaneously (${changePercent}% of pixels changed)`;
75
- // Get the ordinal severity from the fractional pixel change.
76
- ordinalSeverity = Math.floor(Math.min(3, 0.4 * Math.sqrt(changePercent)));
77
- }
78
- } catch (err) {
79
- console.log(`pixelmatch error: ${err.message}, ${err.stack}`);
80
- data.prevented = true;
81
- data.error = `Pixel comparison failed: ${err.message}`;
82
92
  }
83
- }
84
- // If there was a violation:
85
- if (violationWhat) {
86
- // Add to the totals.
87
- totals[ordinalSeverity] = 1;
88
- // Get a summary standard instance.
89
- standardInstances.push({
90
- ruleID: 'motion',
91
- what: violationWhat,
92
- ordinalSeverity,
93
- count: 1,
94
- catalogIndex: getXPathCatalogIndex(report, '/html/body')
95
- });
96
- }
93
+ // Otherwise, i.e. if it failed:
94
+ else {
95
+ // Report this.
96
+ data.prevented = true;
97
+ data.error = 'Image creation failed';
98
+ }
97
99
  }
98
- // Otherwise, i.e. if it failed:
100
+ // Otherwise, i.e. if the initial image does not exist:
99
101
  else {
100
- // Report this.
101
- data.prevented = true;
102
- data.error = 'Image creation failed';
102
+ // Report this.
103
+ data.prevented = true;
104
+ data.error = 'Initial image missing';
103
105
  }
104
- }
105
- // Otherwise, i.e. if the initial image does not exist:
106
- else {
107
- // Report this.
108
- data.prevented = true;
109
- data.error = 'Initial image missing';
110
- }
111
- // Return the result.
112
- return {
113
- data,
114
- totals,
115
- standardInstances
116
- };
106
+ // Return the result.
107
+ return {
108
+ data,
109
+ totals,
110
+ standardInstances
111
+ };
117
112
  };
113
+ exports.reporter = reporter;
@@ -0,0 +1,125 @@
1
+ /*
2
+ © 2026 Jeff Witt.
3
+ © 2025–2026 Jonathan Robert Pool.
4
+ Licensed under the MIT License. See LICENSE for details.
5
+ */
6
+
7
+ // IMPORTS
8
+
9
+ import type {Page} from 'playwright';
10
+ import {getXPathCatalogIndex} from '../procs/xPath';
11
+ import {shoot} from '../procs/shoot';
12
+ import type {Report, StandardInstance} from '../types';
13
+ // pixelmatch and pngjs ship no bundled declarations, so their imports stay requires, untyped.
14
+ const pixelmatch = require('pixelmatch').default;
15
+ const {PNG} = require('pngjs');
16
+
17
+ /*
18
+ motion
19
+ This test reports motion in a page by making a page image and comparing it with the initial one, i.e. the one made by the catalog proc.
20
+
21
+ For minimal accessibility, standards require motion to be brief, or else stoppable by the user. But stopping motion can be difficult or impossible, and, by the time a user manages to stop motion, the motion may have caused annoyance or harm. For superior accessibility, a page contains no motion until and unless the user authorizes it. The test reports a rule violation if any pixels differ between the screenshots. The larger the change fraction, the greater the ordinal severity.
22
+
23
+ WARNING: The shoot test uses the procs/screenShot module. See the warning in that module about browser types.
24
+
25
+ Compiled to motion.js by tsc (issue #73); edit this file, not the emitted one.
26
+ */
27
+
28
+ // FUNCTIONS
29
+
30
+ // Runs the test and returns the result.
31
+ export const reporter = async (page: Page, report: Report) => {
32
+ // Initialize the totals and standard instances.
33
+ const data: {prevented?: boolean; error?: string} = {};
34
+ const totals = [0, 0, 0, 0];
35
+ const standardInstances: StandardInstance[] = [];
36
+ // Identify the image of the checkpoint being tested (images[0] for checkpoint 0).
37
+ const checkpointIndex = report.activeCheckpoint ?? 0;
38
+ const imageIndex = report.checkpoints?.[checkpointIndex]?.imageIndexes?.[0] ?? 0;
39
+ // If the initial image exists:
40
+ if (report.images?.[imageIndex] !== undefined) {
41
+ let violationWhat = '';
42
+ let ordinalSeverity = 0;
43
+ // Make an image with the same color type as the initial one and get its base64 encoding.
44
+ const png = await shoot(page, report, {
45
+ exclusionSelector: null,
46
+ colorType: report.imageColor,
47
+ action: 'return'
48
+ });
49
+ // If this succeeded:
50
+ if (png) {
51
+ // Parse both base64 encodings into PNG objects.
52
+ const initialPNG = PNG.sync.read(Buffer.from(report.images[imageIndex], 'base64'));
53
+ const finalPNG = PNG.sync.read(Buffer.from(png, 'base64'));
54
+ // If their dimensions differ:
55
+ if (finalPNG.width !== initialPNG.width || finalPNG.height !== initialPNG.height) {
56
+ const fromSize = `${initialPNG.width}×${initialPNG.height}`;
57
+ const toSize = `${finalPNG.width}×${finalPNG.height}`;
58
+ // Describe the violation.
59
+ violationWhat = `Page size changes spontaneously (from ${fromSize} to ${toSize})`;
60
+ }
61
+ // Otherwise, i.e. if their dimensions are identical:
62
+ else {
63
+ // Get the count of differing pixels between the images, using the default sensitivity.
64
+ try {
65
+ const pixelChanges = pixelmatch(
66
+ initialPNG.data,
67
+ finalPNG.data,
68
+ null,
69
+ initialPNG.width,
70
+ initialPNG.height,
71
+ {
72
+ threshold: 0.1
73
+ }
74
+ );
75
+ // Get the ratio of differing to all pixels as a percentage.
76
+ const changePercent = Math.round(
77
+ 100 * pixelChanges / (initialPNG.width * initialPNG.height)
78
+ );
79
+ // If any pixels were changed:
80
+ if (pixelChanges) {
81
+ // Describe the violation.
82
+ violationWhat = `Content changes spontaneously (${changePercent}% of pixels changed)`;
83
+ // Get the ordinal severity from the fractional pixel change.
84
+ ordinalSeverity = Math.floor(Math.min(3, 0.4 * Math.sqrt(changePercent)));
85
+ }
86
+ } catch (err) {
87
+ console.log(`pixelmatch error: ${(err as Error).message}, ${(err as Error).stack}`);
88
+ data.prevented = true;
89
+ data.error = `Pixel comparison failed: ${(err as Error).message}`;
90
+ }
91
+ }
92
+ // If there was a violation:
93
+ if (violationWhat) {
94
+ // Add to the totals.
95
+ totals[ordinalSeverity] = 1;
96
+ // Get a summary standard instance.
97
+ standardInstances.push({
98
+ ruleID: 'motion',
99
+ what: violationWhat,
100
+ ordinalSeverity: ordinalSeverity as StandardInstance['ordinalSeverity'],
101
+ count: 1,
102
+ catalogIndex: getXPathCatalogIndex(report, '/html/body')
103
+ });
104
+ }
105
+ }
106
+ // Otherwise, i.e. if it failed:
107
+ else {
108
+ // Report this.
109
+ data.prevented = true;
110
+ data.error = 'Image creation failed';
111
+ }
112
+ }
113
+ // Otherwise, i.e. if the initial image does not exist:
114
+ else {
115
+ // Report this.
116
+ data.prevented = true;
117
+ data.error = 'Initial image missing';
118
+ }
119
+ // Return the result.
120
+ return {
121
+ data,
122
+ totals,
123
+ standardInstances
124
+ };
125
+ };
@@ -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
  © 2022–2023 CVS Health and/or one of its affiliates. All rights reserved.
3
4
  © 2026 Jeff Witt.
@@ -7,56 +8,49 @@
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
  nonTable
13
16
  Derived from the bbc-a11y useTablesForData test. Crude heuristics omitted.
14
17
  This test reports tables used for layout.
18
+ Compiled to nonTable.js by tsc (issue #73); edit this file, not the emitted one.
15
19
  */
16
-
17
- // IMPORTS
18
-
19
- const {doTest} = require('../procs/testaro');
20
-
21
20
  // FUNCTIONS
22
-
23
21
  // Runs the test and returns the result.
24
- exports.reporter = async (page, report, _, withItems) => {
25
- const getBadWhat = element => {
26
- // If the element contains another table:
27
- if (element.querySelector('table')) {
28
- // Return a violation description.
29
- return 'Element contains another table';
30
- }
31
- const rowCount = element.querySelectorAll('tr').length;
32
- const columnCount = Math.max(
33
- ... Array
34
- .from(element.querySelectorAll('tr'))
35
- .map(row => Array.from(row.querySelectorAll('th, td')).length)
36
- );
37
- // Otherwise, if it has only 1 column or 1 row:
38
- if (rowCount === 1 || columnCount === 1) {
39
- // Return a violation description.
40
- return 'Element has only one row or one column';
41
- }
42
- // Otherwise, if it contains an object or player:
43
- if (element.querySelector('object, embed, applet, audio, video')) {
44
- // Return a violation description.
45
- return 'Element contains an object or player';
46
- }
47
- const role = element.getAttribute('role');
48
- // Otherwise, if it has no table-compatible explicit role or descendant element:
49
- if (! (
50
- ['grid', 'treegrid'].includes(role)
51
- || element.caption
52
- || element.querySelector('col, colgroup, tfoot, th, thead')
53
- )) {
54
- // Return a violation description.
55
- return 'Element has no table-compatible explicit role or descendant element';
56
- }
57
- };
58
- const whats = 'table elements are misused for non-table content';
59
- return await doTest(
60
- page, report, withItems, 'nonTable', 'body table', whats, 2, getBadWhat.toString()
61
- );
22
+ const reporter = async (page, report, _, withItems) => {
23
+ // The candidate selector yields table elements.
24
+ const getBadWhat = (element) => {
25
+ // If the element contains another table:
26
+ if (element.querySelector('table')) {
27
+ // Return a violation description.
28
+ return 'Element contains another table';
29
+ }
30
+ const rowCount = element.querySelectorAll('tr').length;
31
+ const columnCount = Math.max(...Array
32
+ .from(element.querySelectorAll('tr'))
33
+ .map(row => Array.from(row.querySelectorAll('th, td')).length));
34
+ // Otherwise, if it has only 1 column or 1 row:
35
+ if (rowCount === 1 || columnCount === 1) {
36
+ // Return a violation description.
37
+ return 'Element has only one row or one column';
38
+ }
39
+ // Otherwise, if it contains an object or player:
40
+ if (element.querySelector('object, embed, applet, audio, video')) {
41
+ // Return a violation description.
42
+ return 'Element contains an object or player';
43
+ }
44
+ const role = element.getAttribute('role');
45
+ // Otherwise, if it has no table-compatible explicit role or descendant element:
46
+ if (!(['grid', 'treegrid'].includes(role)
47
+ || element.caption
48
+ || element.querySelector('col, colgroup, tfoot, th, thead'))) {
49
+ // Return a violation description.
50
+ return 'Element has no table-compatible explicit role or descendant element';
51
+ }
52
+ };
53
+ const whats = 'table elements are misused for non-table content';
54
+ return await (0, testaro_1.doTest)(page, report, withItems, 'nonTable', 'body table', whats, 2, getBadWhat.toString());
62
55
  };
56
+ exports.reporter = reporter;