testaro 78.0.8 → 78.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/.gitattributes +94 -0
  2. package/.github/workflows/ci.yml +58 -0
  3. package/.github/workflows/publish.yml +49 -0
  4. package/.github/workflows/typescript.yml +35 -0
  5. package/AGENTS.md +2 -2
  6. package/CLAUDE.md +24 -18
  7. package/CONTAINERS.md +9 -6
  8. package/CONTRIBUTING.md +29 -3
  9. package/Dockerfile +1 -1
  10. package/README.md +73 -19
  11. package/UPGRADES.md +4 -0
  12. package/actSpecs-doc.md +13 -1
  13. package/actSpecs.js +29 -5
  14. package/call.js +6 -5
  15. package/docker-compose.yml +8 -2
  16. package/docs/checkpoint-scanning.md +199 -0
  17. package/docs/standard-result-outcome.md +165 -0
  18. package/env.example +44 -10
  19. package/eslint.config.mjs +101 -0
  20. package/netWatch.js +372 -222
  21. package/package.json +46 -31
  22. package/pour/README.md +47 -0
  23. package/pour/pour.min.js +8 -0
  24. package/procs/actDo.js +808 -0
  25. package/procs/catalog.d.ts +17 -0
  26. package/procs/catalog.js +312 -221
  27. package/procs/catalog.ts +398 -0
  28. package/procs/checkpoint.js +110 -0
  29. package/procs/config.d.ts +35 -0
  30. package/procs/config.js +62 -0
  31. package/procs/dateTime.js +2 -1
  32. package/procs/doActs.js +442 -849
  33. package/procs/doTestAct.js +27 -121
  34. package/procs/flow.js +221 -0
  35. package/procs/generateRuleRegistry.js +94 -0
  36. package/procs/getSource.d.ts +26 -0
  37. package/procs/job.js +115 -1
  38. package/procs/launch.d.ts +40 -0
  39. package/procs/launch.js +239 -108
  40. package/procs/nu.d.ts +48 -0
  41. package/procs/scope.js +196 -0
  42. package/procs/shoot.d.ts +33 -0
  43. package/procs/standard.d.ts +18 -0
  44. package/procs/standard.js +83 -0
  45. package/procs/standard.ts +126 -0
  46. package/procs/testAct.js +145 -0
  47. package/procs/testaro.d.ts +20 -0
  48. package/procs/testaro.js +236 -189
  49. package/procs/testaro.ts +321 -0
  50. package/procs/userPath.js +126 -0
  51. package/procs/xPath.d.ts +4 -0
  52. package/procs/xPath.js +81 -69
  53. package/procs/xPath.ts +106 -0
  54. package/procs/xPathScript.d.ts +6 -0
  55. package/procs/xPathScript.js +70 -0
  56. package/run.js +3 -2
  57. package/surea11y/README.md +44 -0
  58. package/surea11y/surea11y.browser.js +14 -0
  59. package/testaro/adbID.d.ts +3 -0
  60. package/testaro/adbID.js +38 -41
  61. package/testaro/adbID.ts +66 -0
  62. package/testaro/allCapStyle.d.ts +3 -0
  63. package/testaro/allCapStyle.js +31 -34
  64. package/testaro/allCapStyle.ts +55 -0
  65. package/testaro/allCaps.d.ts +16 -0
  66. package/testaro/allCaps.js +179 -151
  67. package/testaro/allCaps.ts +228 -0
  68. package/testaro/allHidden.d.ts +13 -0
  69. package/testaro/allHidden.js +29 -30
  70. package/testaro/allHidden.ts +50 -0
  71. package/testaro/allSlanted.d.ts +3 -0
  72. package/testaro/allSlanted.js +30 -33
  73. package/testaro/allSlanted.ts +54 -0
  74. package/testaro/altScheme.d.ts +3 -0
  75. package/testaro/altScheme.js +27 -30
  76. package/testaro/altScheme.ts +50 -0
  77. package/testaro/attVal.d.ts +3 -0
  78. package/testaro/attVal.js +20 -21
  79. package/testaro/attVal.ts +52 -0
  80. package/testaro/autocomplete.d.ts +3 -0
  81. package/testaro/autocomplete.js +59 -75
  82. package/testaro/autocomplete.ts +101 -0
  83. package/testaro/bulk.d.ts +13 -0
  84. package/testaro/bulk.js +32 -33
  85. package/testaro/bulk.ts +55 -0
  86. package/testaro/buttonMenu.d.ts +9 -0
  87. package/testaro/buttonMenu.js +317 -319
  88. package/testaro/buttonMenu.ts +391 -0
  89. package/testaro/captionLoc.d.ts +3 -0
  90. package/testaro/captionLoc.js +17 -20
  91. package/testaro/captionLoc.ts +40 -0
  92. package/testaro/datalistRef.d.ts +3 -0
  93. package/testaro/datalistRef.js +33 -36
  94. package/testaro/datalistRef.ts +55 -0
  95. package/testaro/distortion.d.ts +3 -0
  96. package/testaro/distortion.js +57 -26
  97. package/testaro/distortion.ts +81 -0
  98. package/testaro/docType.d.ts +15 -0
  99. package/testaro/docType.js +25 -25
  100. package/testaro/docType.ts +45 -0
  101. package/testaro/dupAtt.d.ts +16 -0
  102. package/testaro/dupAtt.js +113 -104
  103. package/testaro/dupAtt.ts +144 -0
  104. package/testaro/elements.d.ts +6 -0
  105. package/testaro/elements.js +153 -153
  106. package/testaro/elements.ts +215 -0
  107. package/testaro/embAc.d.ts +3 -0
  108. package/testaro/embAc.js +19 -20
  109. package/testaro/embAc.ts +40 -0
  110. package/testaro/focAll.d.ts +13 -0
  111. package/testaro/focAll.js +185 -191
  112. package/testaro/focAll.ts +217 -0
  113. package/testaro/focAndOp.d.ts +3 -0
  114. package/testaro/focAndOp.js +100 -104
  115. package/testaro/focAndOp.ts +128 -0
  116. package/testaro/focInd.d.ts +3 -0
  117. package/testaro/focInd.js +64 -66
  118. package/testaro/focInd.ts +96 -0
  119. package/testaro/focVis.d.ts +3 -0
  120. package/testaro/focVis.js +28 -30
  121. package/testaro/focVis.ts +52 -0
  122. package/testaro/headEl.d.ts +10 -0
  123. package/testaro/headEl.js +61 -62
  124. package/testaro/headEl.ts +82 -0
  125. package/testaro/headingAmb.d.ts +3 -0
  126. package/testaro/headingAmb.js +54 -63
  127. package/testaro/headingAmb.ts +72 -0
  128. package/testaro/hovInd.d.ts +12 -0
  129. package/testaro/hovInd.js +163 -130
  130. package/testaro/hovInd.ts +199 -0
  131. package/testaro/hover.d.ts +3 -0
  132. package/testaro/hover.js +155 -126
  133. package/testaro/hover.ts +154 -0
  134. package/testaro/hr.d.ts +3 -0
  135. package/testaro/hr.js +14 -17
  136. package/testaro/hr.ts +36 -0
  137. package/testaro/imageLink.d.ts +3 -0
  138. package/testaro/imageLink.js +17 -20
  139. package/testaro/imageLink.ts +42 -0
  140. package/testaro/labClash.d.ts +3 -0
  141. package/testaro/labClash.js +31 -33
  142. package/testaro/labClash.ts +54 -0
  143. package/testaro/legendLoc.d.ts +3 -0
  144. package/testaro/legendLoc.js +17 -20
  145. package/testaro/legendLoc.ts +42 -0
  146. package/testaro/lineHeight.d.ts +3 -0
  147. package/testaro/lineHeight.js +43 -48
  148. package/testaro/lineHeight.ts +70 -0
  149. package/testaro/linkAmb.d.ts +7 -0
  150. package/testaro/linkAmb.js +79 -80
  151. package/testaro/linkAmb.ts +105 -0
  152. package/testaro/linkExt.d.ts +3 -0
  153. package/testaro/linkExt.js +13 -16
  154. package/testaro/linkExt.ts +35 -0
  155. package/testaro/linkOldAtt.d.ts +3 -0
  156. package/testaro/linkOldAtt.js +25 -28
  157. package/testaro/linkOldAtt.ts +48 -0
  158. package/testaro/linkTo.d.ts +3 -0
  159. package/testaro/linkTo.js +22 -22
  160. package/testaro/linkTo.ts +43 -0
  161. package/testaro/linkUl.d.ts +3 -0
  162. package/testaro/linkUl.js +30 -34
  163. package/testaro/linkUl.ts +54 -0
  164. package/testaro/miniText.d.ts +3 -0
  165. package/testaro/miniText.js +41 -44
  166. package/testaro/miniText.ts +68 -0
  167. package/testaro/motion.d.ts +10 -0
  168. package/testaro/motion.js +92 -96
  169. package/testaro/motion.ts +125 -0
  170. package/testaro/nonTable.d.ts +3 -0
  171. package/testaro/nonTable.js +39 -45
  172. package/testaro/nonTable.ts +66 -0
  173. package/testaro/optRoleSel.d.ts +3 -0
  174. package/testaro/optRoleSel.js +16 -19
  175. package/testaro/optRoleSel.ts +41 -0
  176. package/testaro/phOnly.d.ts +3 -0
  177. package/testaro/phOnly.js +18 -21
  178. package/testaro/phOnly.ts +43 -0
  179. package/testaro/pseudoP.d.ts +3 -0
  180. package/testaro/pseudoP.js +36 -38
  181. package/testaro/pseudoP.ts +59 -0
  182. package/testaro/radioSet.d.ts +3 -0
  183. package/testaro/radioSet.js +57 -59
  184. package/testaro/radioSet.ts +79 -0
  185. package/testaro/registry.d.ts +63 -0
  186. package/testaro/registry.js +67 -0
  187. package/testaro/registry.ts +141 -0
  188. package/testaro/role.d.ts +3 -0
  189. package/testaro/role.js +27 -29
  190. package/testaro/role.ts +53 -0
  191. package/testaro/secHeading.d.ts +3 -0
  192. package/testaro/secHeading.js +30 -33
  193. package/testaro/secHeading.ts +53 -0
  194. package/testaro/styleDiff.d.ts +25 -0
  195. package/testaro/styleDiff.js +248 -252
  196. package/testaro/styleDiff.ts +303 -0
  197. package/testaro/tabNav.d.ts +33 -0
  198. package/testaro/tabNav.js +272 -342
  199. package/testaro/tabNav.ts +454 -0
  200. package/testaro/targetsNear.d.ts +9 -0
  201. package/testaro/targetsNear.js +130 -132
  202. package/testaro/targetsNear.ts +160 -0
  203. package/testaro/textNodes.d.ts +6 -0
  204. package/testaro/textNodes.js +139 -135
  205. package/testaro/textNodes.ts +185 -0
  206. package/testaro/textSem.d.ts +3 -0
  207. package/testaro/textSem.js +25 -28
  208. package/testaro/textSem.ts +47 -0
  209. package/testaro/title.d.ts +9 -0
  210. package/testaro/title.js +16 -13
  211. package/testaro/title.ts +31 -0
  212. package/testaro/titledEl.d.ts +3 -0
  213. package/testaro/titledEl.js +15 -18
  214. package/testaro/titledEl.ts +38 -0
  215. package/testaro/zIndex.d.ts +3 -0
  216. package/testaro/zIndex.js +19 -22
  217. package/testaro/zIndex.ts +42 -0
  218. package/tests/alfa.d.ts +45 -0
  219. package/tests/alfa.js +138 -141
  220. package/tests/alfa.ts +214 -0
  221. package/tests/aslint.d.ts +33 -0
  222. package/tests/aslint.js +272 -249
  223. package/tests/aslint.ts +301 -0
  224. package/tests/axe.d.ts +27 -0
  225. package/tests/axe.js +199 -200
  226. package/tests/axe.ts +277 -0
  227. package/tests/ed11y.d.ts +28 -0
  228. package/tests/ed11y.js +141 -99
  229. package/tests/ed11y.ts +178 -0
  230. package/tests/htmlcs.d.ts +21 -0
  231. package/tests/htmlcs.js +174 -140
  232. package/tests/htmlcs.ts +181 -0
  233. package/tests/ibm.d.ts +52 -0
  234. package/tests/ibm.js +164 -166
  235. package/tests/ibm.ts +251 -0
  236. package/tests/nuVal.d.ts +13 -0
  237. package/tests/nuVal.js +107 -112
  238. package/tests/nuVal.ts +145 -0
  239. package/tests/nuVnu.d.ts +15 -0
  240. package/tests/nuVnu.js +141 -111
  241. package/tests/nuVnu.ts +144 -0
  242. package/tests/pour.d.ts +31 -0
  243. package/tests/pour.js +242 -0
  244. package/tests/pour.ts +273 -0
  245. package/tests/qualWeb.d.ts +39 -0
  246. package/tests/qualWeb.js +302 -272
  247. package/tests/qualWeb.ts +415 -0
  248. package/tests/surea11y.d.ts +33 -0
  249. package/tests/surea11y.js +288 -0
  250. package/tests/surea11y.ts +334 -0
  251. package/tests/testaro.d.ts +25 -0
  252. package/tests/testaro.js +745 -652
  253. package/tests/testaro.ts +862 -0
  254. package/tests/wave.d.ts +46 -0
  255. package/tests/wave.js +166 -177
  256. package/tests/wave.ts +252 -0
  257. package/tsconfig.json +17 -0
  258. package/types.d.ts +243 -0
  259. package/types.js +10 -0
  260. package/types.ts +376 -0
  261. package/validation/act/README.md +46 -0
  262. package/validation/act/capture.js +424 -0
  263. package/validation/act/chromium-issue-draft.md +66 -0
  264. package/validation/act/fp-triage-2026-08-22.md +86 -0
  265. package/validation/act/isolation-notes.md +159 -0
  266. package/validation/act/playwright-issue-draft.md +73 -0
  267. package/validation/act/propose-mappings.js +0 -0
  268. package/validation/act/repro-cdp-raw.js +105 -0
  269. package/validation/act/repro-metarefresh.js +65 -0
  270. package/validation/act/score.js +184 -0
  271. package/validation/act/stage3a-stress-report.md +69 -0
  272. package/validation/act/stage3b-mapping-proposals.md +94 -0
  273. package/validation/act/stage3b-triage-draft.md +138 -0
  274. package/validation/act/surea11y-track-a-2026-09-01.md +50 -0
  275. package/validation/executors/netWatch.js +180 -90
  276. package/validation/executors/test.js +17 -2
  277. package/validation/executors/tests.js +118 -10
  278. package/validation/jobs/reports/raw/260901T1000-surea11y-validation.json +964 -0
  279. package/validation/jobs/todo/240101T1200-simple-example.json +14 -6
  280. package/validation/jobs/todo/240101T1300-shoot-example.json +2 -1
  281. package/validation/jobs/todo/260821T1900-pour-validation.json +45 -0
  282. package/validation/jobs/todo/260901T1000-surea11y-validation.json +45 -0
  283. package/validation/knownFailures.json +1 -0
  284. package/validation/tests/jobProperties/adbID.json +27 -2
  285. package/validation/tests/jobProperties/{focOp.json → allCapStyle.json} +56 -53
  286. package/validation/tests/jobProperties/allCaps.json +25 -0
  287. package/validation/tests/jobProperties/allHidden.json +133 -13
  288. package/validation/tests/jobProperties/allSlanted.json +3 -3
  289. package/validation/tests/jobProperties/altScheme.json +23 -8
  290. package/validation/tests/jobProperties/attVal.json +57 -57
  291. package/validation/tests/jobProperties/autocomplete.json +11 -1
  292. package/validation/tests/jobProperties/bulk.json +6 -1
  293. package/validation/tests/jobProperties/buttonMenu.json +63 -42
  294. package/validation/tests/jobProperties/captionLoc.json +1 -6
  295. package/validation/tests/jobProperties/checkpoint-browser.json +401 -0
  296. package/validation/tests/jobProperties/checkpoint-page.json +397 -0
  297. package/validation/tests/jobProperties/checkpoint.json +395 -0
  298. package/validation/tests/jobProperties/datalistRef.json +20 -5
  299. package/validation/tests/jobProperties/distortion.json +28 -3
  300. package/validation/tests/jobProperties/docType.json +2 -2
  301. package/validation/tests/jobProperties/dupAtt.json +48 -33
  302. package/validation/tests/jobProperties/elements.json +28 -28
  303. package/validation/tests/jobProperties/embAc.json +36 -31
  304. package/validation/tests/jobProperties/focAndOp.json +284 -0
  305. package/validation/tests/jobProperties/focInd.json +34 -34
  306. package/validation/tests/jobProperties/focVis.json +1 -1
  307. package/validation/tests/jobProperties/hover.json +39 -37
  308. package/validation/tests/jobProperties/hr.json +13 -3
  309. package/validation/tests/jobProperties/imageLink.json +0 -5
  310. package/validation/tests/jobProperties/labClash.json +68 -33
  311. package/validation/tests/jobProperties/legendLoc.json +1 -6
  312. package/validation/tests/jobProperties/lineHeight.json +2 -2
  313. package/validation/tests/jobProperties/linkAmb.json +13 -18
  314. package/validation/tests/jobProperties/linkExt.json +1 -1
  315. package/validation/tests/jobProperties/linkOldAtt.json +12 -2
  316. package/validation/tests/jobProperties/linkTo.json +1 -1
  317. package/validation/tests/jobProperties/linkUl.json +65 -65
  318. package/validation/tests/jobProperties/miniText.json +7 -2
  319. package/validation/tests/jobProperties/motion.json +4 -50
  320. package/validation/tests/jobProperties/nonTable.json +48 -3
  321. package/validation/tests/jobProperties/optRoleSel.json +12 -2
  322. package/validation/tests/jobProperties/phOnly.json +6 -16
  323. package/validation/tests/jobProperties/pseudoP.json +17 -2
  324. package/validation/tests/jobProperties/radioSet.json +30 -30
  325. package/validation/tests/jobProperties/role.json +25 -5
  326. package/validation/tests/jobProperties/secHeading.json +26 -21
  327. package/validation/tests/jobProperties/styleDiff.json +35 -5
  328. package/validation/tests/jobProperties/tabNav.json +3 -1
  329. package/validation/tests/jobProperties/targetsNear.json +237 -0
  330. package/validation/tests/jobProperties/textNodes.json +29 -29
  331. package/validation/tests/jobProperties/textSem.json +26 -1
  332. package/validation/tests/jobProperties/title.json +12 -2
  333. package/validation/tests/jobProperties/titledEl.json +39 -9
  334. package/validation/tests/jobProperties/userPath.json +317 -0
  335. package/validation/tests/jobProperties/zIndex.json +40 -35
  336. package/validation/tests/targets/allCapStyle/index.html +26 -0
  337. package/validation/tests/targets/checkpoint/index.html +38 -0
  338. package/validation/tests/targets/datalistRef/index.html +1 -1
  339. package/validation/tests/targets/focAndOp/bad.html +29 -0
  340. package/validation/tests/targets/{focOp → focAndOp}/good.html +3 -1
  341. package/validation/tests/targets/focInd/bad.html +2 -1
  342. package/validation/tests/targets/headEl/index.html +10 -1
  343. package/validation/tests/targets/{targetSmall → targetsNear}/index.html +15 -1
  344. package/validation/tests/targets/userPath/index.html +42 -0
  345. package/validation/validateTest.js +61 -9
  346. package/.claude/settings.local.json +0 -11
  347. package/.eslintrc.json +0 -41
  348. package/htmlcs/.eslintrc.json +0 -67
  349. package/validation/tests/jobProperties/linkTitle.json +0 -127
  350. package/validation/tests/jobProperties/opFoc.json +0 -164
  351. package/validation/tests/jobProperties/targetSmall.json +0 -152
  352. package/validation/tests/jobProperties/targetTiny.json +0 -142
  353. package/validation/tests/targets/focOp/bad.html +0 -25
  354. package/validation/tests/targets/linkTitle/index.html +0 -24
  355. package/validation/tests/targets/opFoc/bad.html +0 -26
  356. package/validation/tests/targets/opFoc/good.html +0 -23
@@ -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 {};