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
@@ -0,0 +1,303 @@
1
+ /*
2
+ © 2021–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
+ © 2026 Jeff Witt.
4
+ © 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 {getXPathCatalogIndex} from '../procs/xPath';
15
+ import type {Report} from '../types';
16
+
17
+ // TYPES
18
+
19
+ // Style-count totals for one element type.
20
+ interface StyleDiffTotals {
21
+ total: number;
22
+ subtotals?: number[];
23
+ }
24
+
25
+ /*
26
+ styleDiff
27
+ This test reports style differences among links, buttons, and headings. It assumes that an accessible page employs few or only one style for adjacent links, and likewise for list links, buttons, and headings at each level. The test considers only particular style properties, listed in the 'mainStyles' and 'headingStyles' arrays.
28
+ Compiled to styleDiff.js by tsc (issue #73); edit this file, not the emitted one.
29
+ */
30
+
31
+ // FUNCTIONS
32
+
33
+ // Returns an object classifying the links in a page by layout.
34
+ const linksByType = async (page: Page) => await page.evaluateHandle(() => {
35
+ // FUNCTION DEFINITIONS START
36
+ // Removes spacing characters from a text.
37
+ const despace = (text: string) => text.replace(/\s/g, '');
38
+ // Returns whether a list is a list entirely of links.
39
+ const isLinkList = (list: Element) => {
40
+ const listItems = Array.from(list.children);
41
+ if (listItems.length > 1) {
42
+ return listItems.length > 1 && listItems.every(item => {
43
+ if (item.tagName === 'LI') {
44
+ const {children} = item;
45
+ if (children.length === 1) {
46
+ const link = children[0];
47
+ if (link.tagName === 'A') {
48
+ const itemText = despace(item.textContent!);
49
+ const linkText = despace(link.textContent!);
50
+ return itemText.length === linkText.length;
51
+ }
52
+ else {
53
+ return false;
54
+ }
55
+ }
56
+ else {
57
+ return false;
58
+ }
59
+ }
60
+ else {
61
+ return false;
62
+ }
63
+ });
64
+ }
65
+ else {
66
+ return false;
67
+ }
68
+ };
69
+ // FUNCTION DEFINITIONS END
70
+ // Identify the lists in the page.
71
+ const lists = Array.from(document.body.querySelectorAll('ul, ol'));
72
+ // Initialize an array of list links.
73
+ const listLinks: HTMLAnchorElement[] = [];
74
+ // For each one:
75
+ lists.forEach(list => {
76
+ // If it is a list of links:
77
+ if (isLinkList(list)) {
78
+ // Add all its links to the array. Formerly one link per list was sampled as a representative, which made totals vary run to run (issue #113) and let the unsampled list links be counted as inline links, so a uniformly styled link list was reported as an inline-link style difference. Using every list link is deterministic and also detects style differences within a list.
79
+ const links = Array.from(list.querySelectorAll(':scope > li > a'));
80
+ listLinks.push(...(links as HTMLAnchorElement[]));
81
+ }
82
+ });
83
+ // Identify the inline links in the page, i.e. the links that are not list links.
84
+ const allLinks = Array.from(document.body.querySelectorAll('a'));
85
+ const inlineLinks = allLinks.filter(link => ! listLinks.includes(link as HTMLAnchorElement));
86
+ // Return the data.
87
+ return {
88
+ adjacent: inlineLinks,
89
+ list: listLinks
90
+ };
91
+ });
92
+ // Runs the test and returns the result.
93
+ export const reporter = async (page: Page, report: Report, _: unknown, withItems: boolean) => {
94
+ // Get an object with arrays of list links and adjacent links as properties.
95
+ const linkTypes = await linksByType(page);
96
+ const catalogIndex = getXPathCatalogIndex(report, '/html/body');
97
+ return await page.evaluate(args => {
98
+ const [linkTypes, withItems, catalogIndex] = args;
99
+ const {body} = document;
100
+ // Identify the settable style properties to be compared for all tag names.
101
+ const mainStyles = [
102
+ 'fontStyle',
103
+ 'fontWeight',
104
+ 'opacity',
105
+ 'textDecorationLine',
106
+ 'textDecorationStyle',
107
+ 'textDecorationThickness'
108
+ ];
109
+ // Identify those only for buttons.
110
+ const buttonStyles = [
111
+ 'borderStyle',
112
+ 'borderWidth',
113
+ 'height',
114
+ 'lineHeight',
115
+ 'maxHeight',
116
+ 'maxWidth',
117
+ 'minHeight',
118
+ 'minWidth',
119
+ 'outlineOffset',
120
+ 'outlineStyle',
121
+ 'outlineWidth'
122
+ ];
123
+ // Identify those for headings.
124
+ const headingStyles = [
125
+ 'color',
126
+ 'fontSize'
127
+ ];
128
+ // Identify those for list links.
129
+ const listLinkStyles = [
130
+ 'color',
131
+ 'fontSize',
132
+ 'lineHeight'
133
+ ];
134
+ // Initialize the data to be returned.
135
+ const data: {
136
+ mainStyles: string[];
137
+ buttonStyles: string[];
138
+ headingStyles: string[];
139
+ listLinkStyles: string[];
140
+ totals: Record<string, StyleDiffTotals>;
141
+ items?: Record<string, Record<string, Record<string, string[]>>>;
142
+ } = {
143
+ mainStyles,
144
+ buttonStyles,
145
+ headingStyles,
146
+ listLinkStyles,
147
+ totals: {}
148
+ };
149
+ if (withItems) {
150
+ data.items = {};
151
+ }
152
+ // Initialize an object of elements to be analyzed, including links.
153
+ const elements: {
154
+ buttons: Element[];
155
+ headings: Record<string, Element[]>;
156
+ links: {adjacent: Element[]; list: Element[]};
157
+ } = {
158
+ buttons: [],
159
+ headings: {
160
+ h1: [],
161
+ h2: [],
162
+ h3: [],
163
+ h4: [],
164
+ h5: [],
165
+ h6: []
166
+ },
167
+ links: {
168
+ adjacent: linkTypes.adjacent,
169
+ list: linkTypes.list
170
+ }
171
+ };
172
+ // Identify the heading tag names to be analyzed.
173
+ const headingNames = Object.keys(elements.headings);
174
+ // Add the buttons to the object.
175
+ elements.buttons = Array.from(body.querySelectorAll('button, input[type=button]'));
176
+ // For each heading tag name:
177
+ headingNames.forEach(tagName => {
178
+ // Add its elements to the object.
179
+ elements.headings[tagName] = Array.from(body.getElementsByTagName(tagName));
180
+ });
181
+ // FUNCTION DEFINITION START
182
+ // Tabulates the distribution of style properties for elements of a type.
183
+ const tallyStyles = (
184
+ typeName: string, elements: Element[], typeStyles: string[], withItems: boolean
185
+ ) => {
186
+ // If there are any elements:
187
+ const elementCount = elements.length;
188
+ if (elementCount) {
189
+ const styleProps: Record<string, Record<string, Record<string, string[]>>> = {};
190
+ const styleTexts: Record<string, number> = {};
191
+ // For each element:
192
+ elements.forEach(element => {
193
+ // Get its values on the style properties to be compared.
194
+ const styleDec = window.getComputedStyle(element);
195
+ const style: Record<string, string> = {};
196
+ const styles = mainStyles.concat(typeStyles);
197
+ styles.forEach(styleName => {
198
+ style[styleName] = (styleDec as unknown as Record<string, string>)[styleName];
199
+ });
200
+ // Get a text representation of the style, limited to those properties.
201
+ const styleText = JSON.stringify(style);
202
+ // Increment the total of elements with that style.
203
+ styleTexts[styleText] = ++styleTexts[styleText] || 1;
204
+ // If details are to be reported:
205
+ if (withItems) {
206
+ // Add the element’s values and text to the style details.
207
+ if (! styleProps[typeName]) {
208
+ styleProps[typeName] = {};
209
+ }
210
+ const elementText = (element.textContent!.trim() || element.outerHTML.trim())
211
+ .replace(/\s+/g, ' ')
212
+ .slice(0, 100);
213
+ // For each style property being compared:
214
+ styles.forEach(styleName => {
215
+ if (! styleProps[typeName][styleName]) {
216
+ styleProps[typeName][styleName] = {};
217
+ }
218
+ if (! styleProps[typeName][styleName][style[styleName]]) {
219
+ styleProps[typeName][styleName][style[styleName]] = [];
220
+ }
221
+ // Add the element text to the style details.
222
+ styleProps[typeName][styleName][style[styleName]].push(elementText);
223
+ });
224
+ }
225
+ });
226
+ // Add the total to the result.
227
+ data.totals[typeName] = {total: elementCount};
228
+ const styleCounts = Object.values(styleTexts);
229
+ // If the elements of the type differ in style:
230
+ if (styleCounts.length > 1) {
231
+ // Add the distribution of its style counts to the result.
232
+ data.totals[typeName].subtotals = styleCounts.sort((a, b) => b - a);
233
+ // If details are to be reported:
234
+ if (withItems) {
235
+ // Delete the data on uniform style properties.
236
+ Object.keys(styleProps[typeName]).forEach(styleName => {
237
+ if (Object.keys(styleProps[typeName][styleName]).length === 1) {
238
+ delete styleProps[typeName][styleName];
239
+ }
240
+ });
241
+ // Add the element values and texts to the result.
242
+ data.items![typeName] = styleProps[typeName];
243
+ }
244
+ }
245
+ }
246
+ };
247
+ // FUNCTION DEFINITION END
248
+ // Report the style-property distributions for the element types.
249
+ tallyStyles('button', elements.buttons, buttonStyles, withItems);
250
+ tallyStyles('adjacentLink', elements.links.adjacent, [], withItems);
251
+ tallyStyles('listLink', elements.links.list, listLinkStyles, withItems);
252
+ headingNames.forEach(headingName => {
253
+ tallyStyles(headingName, elements.headings[headingName], headingStyles, withItems);
254
+ });
255
+ // Report the standandardized data.
256
+ const totals = [0, 0, 0, 0];
257
+ const standardInstances: {
258
+ ruleID: string;
259
+ what: string;
260
+ ordinalSeverity: number;
261
+ count: number;
262
+ catalogIndex: string;
263
+ }[] = [];
264
+ const elementData: Record<string, [number, string, string]> = {
265
+ adjacentLink: [0, 'In-line links', 'A'],
266
+ listLink: [1, 'Links in columns', 'A'],
267
+ button: [2, 'Buttons', 'BUTTON'],
268
+ h1: [3, 'Level-1 headings', 'H1'],
269
+ h2: [3, 'Level-2 headings', 'H2'],
270
+ h3: [3, 'Level-3 headings', 'H3'],
271
+ h4: [3, 'Level-4 headings', 'H4'],
272
+ h5: [3, 'Level-5 headings', 'H5'],
273
+ h6: [3, 'Level-6 headings', 'H6'],
274
+ };
275
+ // For each eligible element type:
276
+ Object.keys(elementData).forEach(elementName => {
277
+ // If it has more than 1 style:
278
+ const elementTotal = data.totals[elementName];
279
+ if (elementTotal && elementTotal.subtotals) {
280
+ const currentData = elementData[elementName];
281
+ const severity = currentData[0];
282
+ const elementSubtotals = elementTotal.subtotals;
283
+ // Treat the count of its styles in excess of 1 as the instance count for that element type.
284
+ const extraCount = elementSubtotals.length - 1;
285
+ totals[severity] += extraCount;
286
+ // Add a summary standard instance for that element type.
287
+ standardInstances.push({
288
+ ruleID: 'styleDiff',
289
+ what: `${currentData[1]} have ${elementSubtotals.length} different styles`,
290
+ ordinalSeverity: severity,
291
+ count: extraCount,
292
+ catalogIndex
293
+ });
294
+ }
295
+ });
296
+ // Return the result.
297
+ return {
298
+ data,
299
+ totals,
300
+ standardInstances
301
+ };
302
+ }, [linkTypes, withItems, catalogIndex] as const);
303
+ };
@@ -0,0 +1,33 @@
1
+ import type { Page } from 'playwright';
2
+ import type { Report, StandardInstance } from '../types';
3
+ interface NavTally {
4
+ total: number;
5
+ correct: number;
6
+ incorrect: number;
7
+ }
8
+ interface TabItemData {
9
+ xPath?: string | null;
10
+ navigationErrors?: string[];
11
+ text?: string;
12
+ }
13
+ interface TabNavData {
14
+ totals: {
15
+ navigations: {
16
+ all: NavTally;
17
+ specific: Record<string, NavTally>;
18
+ };
19
+ tabElements: NavTally;
20
+ tabLists: NavTally;
21
+ };
22
+ tabElements?: {
23
+ incorrect: TabItemData[];
24
+ correct: TabItemData[];
25
+ };
26
+ prevented?: boolean;
27
+ }
28
+ export declare const reporter: (page: Page, report: Report, _: unknown, withItems: boolean) => Promise<{
29
+ data: TabNavData;
30
+ totals: number[];
31
+ standardInstances: StandardInstance[];
32
+ }>;
33
+ export {};