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,5 +1,7 @@
1
+ "use strict";
1
2
  /*
2
3
  © 2022–2023 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
@@ -7,58 +9,54 @@
7
9
 
8
10
  SPDX-License-Identifier: MIT
9
11
  */
10
-
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.reporter = void 0;
14
+ const testaro_1 = require("../procs/testaro");
11
15
  /*
12
16
  miniText
13
17
  Derived from the bbc-a11y textCannotBeTooSmall test.
14
18
  Related to Tenon rule 134.
15
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.
16
21
  */
17
-
18
- // IMPORTS
19
-
20
- const {doTest} = require('../procs/testaro');
21
-
22
22
  // FUNCTIONS
23
-
24
23
  // Runs the test and returns the result.
25
- exports.reporter = async (page, report, _, withItems) => {
26
- const getBadWhat = element => {
27
- const rawText = element.textContent || '';
28
- // If the element has text content with any non-whitespace:
29
- if (/[^\s]/.test(rawText)) {
30
- const isVisible = element.checkVisibility({
31
- contentVisibilityAuto: true,
32
- opacityProperty: true,
33
- visibilityProperty: true
34
- });
35
- // If the element is visible:
36
- if (isVisible) {
37
- const styleDec = window.getComputedStyle(element);
38
- // Get its font size.
39
- const fontSizeString = styleDec.fontSize;
40
- const fontSize = Number.parseFloat(fontSizeString);
41
- // If its font size is smaller than 11 pixels:
42
- if (fontSize < 11) {
43
- const parent = element.parentElement;
44
- // If the element has a parent:
45
- if (parent) {
46
- const parentStyleDec = window.getComputedStyle(parent);
47
- const parentFontSize = Number.parseFloat(parentStyleDec.fontSize);
48
- // If the parent also has a font size smaller than 11 pixels:
49
- if (parentFontSize < 11) {
50
- // Do not report a violation, because the font size may be inherited.
51
- 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
+ }
52
56
  }
53
- }
54
- // Return a violation description.
55
- return `Element is visible but its font size is ${fontSize}px, smaller than 11px`;
56
57
  }
57
- }
58
- }
59
- };
60
- const whats = 'Visible elements have font sizes smaller than 11 pixels';
61
- return await doTest(
62
- page, report, withItems, 'miniText', 'body, body *:not(script, style)', whats, 2, getBadWhat.toString()
63
- );
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());
64
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,8 +1,16 @@
1
+ "use strict";
1
2
  /*
3
+ © 2026 Jeff Witt.
2
4
  © 2025–2026 Jonathan Robert Pool.
3
5
  Licensed under the MIT License. See LICENSE for details.
4
6
  */
5
-
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');
6
14
  /*
7
15
  motion
8
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.
@@ -10,107 +18,96 @@
10
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.
11
19
 
12
20
  WARNING: The shoot test uses the procs/screenShot module. See the warning in that module about browser types.
13
- */
14
-
15
- // IMPORTS
16
-
17
- const {getXPathCatalogIndex} = require('../procs/xPath');
18
- const {shoot} = require('../procs/shoot');
19
- const pixelmatch = require('pixelmatch').default;
20
- const {PNG} = require('pngjs');
21
21
 
22
+ Compiled to motion.js by tsc (issue #73); edit this file, not the emitted one.
23
+ */
22
24
  // FUNCTIONS
23
-
24
25
  // Runs the test and returns the result.
25
- exports.reporter = async (page, report) => {
26
- // Initialize the totals and standard instances.
27
- const data = {};
28
- const totals = [0, 0, 0, 0];
29
- const standardInstances = [];
30
- // If the initial image exists:
31
- if (report.images?.length) {
32
- let violationWhat = '';
33
- let ordinalSeverity = 0;
34
- // Make an image with the same color type as the initial one and get its base64 encoding.
35
- const png = await shoot(page, report, {
36
- exclusionSelector: null,
37
- colorType: report.imageColor,
38
- action: 'return'
39
- });
40
- // If this succeeded:
41
- if (png) {
42
- // Parse both base64 encodings into PNG objects.
43
- const initialPNG = PNG.sync.read(Buffer.from(report.images[0], 'base64'));
44
- const finalPNG = PNG.sync.read(Buffer.from(png, 'base64'));
45
- // If their dimensions differ:
46
- if (finalPNG.width !== initialPNG.width || finalPNG.height !== initialPNG.height) {
47
- const fromSize = `${initialPNG.width}×${initialPNG.height}`;
48
- const toSize = `${finalPNG.width}×${finalPNG.height}`;
49
- // Describe the violation.
50
- violationWhat = `Page size changes spontaneously (from ${fromSize} to ${toSize})`;
51
- }
52
- // Otherwise, i.e. if their dimensions are identical:
53
- else {
54
- // Get the count of differing pixels between the images, using the default sensitivity.
55
- try {
56
- const pixelChanges = pixelmatch(
57
- initialPNG.data,
58
- finalPNG.data,
59
- null,
60
- initialPNG.width,
61
- initialPNG.height,
62
- {
63
- 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
+ });
64
91
  }
65
- );
66
- // Get the ratio of differing to all pixels as a percentage.
67
- const changePercent = Math.round(
68
- 100 * pixelChanges / (initialPNG.width * initialPNG.height)
69
- );
70
- // If any pixels were changed:
71
- if (pixelChanges) {
72
- // Describe the violation.
73
- violationWhat = `Content changes spontaneously (${changePercent}% of pixels changed)`;
74
- // Get the ordinal severity from the fractional pixel change.
75
- ordinalSeverity = Math.floor(Math.min(3, 0.4 * Math.sqrt(changePercent)));
76
- }
77
- } catch (err) {
78
- console.log(`pixelmatch error: ${err.message}, ${err.stack}`);
79
- data.prevented = true;
80
- data.error = `Pixel comparison failed: ${err.message}`;
81
92
  }
82
- }
83
- // If there was a violation:
84
- if (violationWhat) {
85
- // Add to the totals.
86
- totals[ordinalSeverity] = 1;
87
- // Get a summary standard instance.
88
- standardInstances.push({
89
- ruleID: 'motion',
90
- what: violationWhat,
91
- ordinalSeverity,
92
- count: 1,
93
- catalogIndex: getXPathCatalogIndex(report, '/html/body')
94
- });
95
- }
93
+ // Otherwise, i.e. if it failed:
94
+ else {
95
+ // Report this.
96
+ data.prevented = true;
97
+ data.error = 'Image creation failed';
98
+ }
96
99
  }
97
- // Otherwise, i.e. if it failed:
100
+ // Otherwise, i.e. if the initial image does not exist:
98
101
  else {
99
- // Report this.
100
- data.prevented = true;
101
- data.error = 'Image creation failed';
102
+ // Report this.
103
+ data.prevented = true;
104
+ data.error = 'Initial image missing';
102
105
  }
103
- }
104
- // Otherwise, i.e. if the initial image does not exist:
105
- else {
106
- // Report this.
107
- data.prevented = true;
108
- data.error = 'Initial image missing';
109
- }
110
- // Return the result.
111
- return {
112
- data,
113
- totals,
114
- standardInstances
115
- };
106
+ // Return the result.
107
+ return {
108
+ data,
109
+ totals,
110
+ standardInstances
111
+ };
116
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,61 +1,56 @@
1
+ "use strict";
1
2
  /*
2
3
  © 2022–2023 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
  nonTable
12
16
  Derived from the bbc-a11y useTablesForData test. Crude heuristics omitted.
13
17
  This test reports tables used for layout.
18
+ Compiled to nonTable.js by tsc (issue #73); edit this file, not the emitted one.
14
19
  */
15
-
16
- // IMPORTS
17
-
18
- const {doTest} = require('../procs/testaro');
19
-
20
20
  // FUNCTIONS
21
-
22
21
  // Runs the test and returns the result.
23
- exports.reporter = async (page, report, _, withItems) => {
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(
32
- ... Array
33
- .from(element.querySelectorAll('tr'))
34
- .map(row => Array.from(row.querySelectorAll('th, td')).length)
35
- );
36
- // Otherwise, if it has only 1 column or 1 row:
37
- if (rowCount === 1 || columnCount === 1) {
38
- // Return a violation description.
39
- return 'Element has only one row or one column';
40
- }
41
- // Otherwise, if it contains an object or player:
42
- if (element.querySelector('object, embed, applet, audio, video')) {
43
- // Return a violation description.
44
- return 'Element contains an object or player';
45
- }
46
- const role = element.getAttribute('role');
47
- // Otherwise, if it has no table-compatible explicit role or descendant element:
48
- if (! (
49
- ['grid', 'treegrid'].includes(role)
50
- || element.caption
51
- || element.querySelector('col, colgroup, tfoot, th, thead')
52
- )) {
53
- // Return a violation description.
54
- return 'Element has no table-compatible explicit role or descendant element';
55
- }
56
- };
57
- const whats = 'table elements are misused for non-table content';
58
- return await doTest(
59
- page, report, withItems, 'nonTable', 'body table', whats, 2, getBadWhat.toString()
60
- );
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());
61
55
  };
56
+ exports.reporter = reporter;